diff --git a/.dependabot/config.yml b/.dependabot/config.yml new file mode 100644 index 000000000000..69640b335c7f --- /dev/null +++ b/.dependabot/config.yml @@ -0,0 +1,34 @@ +version: 1 + +# update_schedule: live is only supported on javascript, ruby:bundler, python, php:composer, dotnet:nuget, rust:cargo, elixir:hex + +update_configs: + - package_manager: "dotnet:nuget" + directory: "/" + update_schedule: "live" + default_labels: + - "CL-BuildPackaging" + + - package_manager: "dotnet:nuget" + directory: "/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility" + update_schedule: "live" + default_labels: + - "CL-BuildPackaging" + + - package_manager: "dotnet:nuget" + directory: "/tools/packaging/projects/reference/System.Management.Automation" + update_schedule: "live" + default_labels: + - "CL-BuildPackaging" + + - package_manager: "dotnet:nuget" + directory: "/test/tools/Modules" + update_schedule: "live" + default_labels: + - "CL-BuildPackaging" + + - package_manager: "dotnet:nuget" + directory: "/src/Modules" + update_schedule: "live" + default_labels: + - "CL-BuildPackaging" diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000000..ab9dd52ad5de --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,24 @@ +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +FROM mcr.microsoft.com/dotnet/core/sdk:3.0.100-preview8 + +# Avoid warnings by switching to noninteractive +ENV DEBIAN_FRONTEND=noninteractive + +# Configure apt and install packages +RUN apt-get update \ + && apt-get -y install --no-install-recommends apt-utils 2>&1 \ + # + # Verify git, process tools, lsb-release (common in install instructions for CLIs) installed + && apt-get -y install git procps lsb-release \ + # + # Clean up + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +# Switch back to dialog for any ad-hoc use of apt-get +ENV DEBIAN_FRONTEND=dialog diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..4574e9ef7099 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,16 @@ +// See https://aka.ms/vscode-remote/devcontainer.json for format details. +{ + "name": ".NET Core 3.0-preview8, including pwsh (Debian 10)", + "dockerFile": "Dockerfile", + + // Uncomment the next line to run commands after the container is created. + "postCreateCommand": "cd src/powershell-unix && dotnet restore", + + "extensions": [ + "ms-azure-devops.azure-pipelines", + "ms-vscode.csharp", + "ms-vscode.powershell", + "DavidAnson.vscode-markdownlint", + "vitaliymaz.vscode-svg-previewer" + ] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000000..db4878792dcd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,158 @@ +# EditorConfig is awesome: https://EditorConfig.org +# .NET coding convention settings for EditorConfig +# https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference +# +# The .editorconfig comes from Roslyn and CoreFX repositories: +# https://github.com/dotnet/corefx/blob/master/.editorconfig +# https://github.com/dotnet/roslyn/blob/master/.editorconfig + +# Top-most EditorConfig file +root = true + +# Don't use tabs for indentation. +[*] +indent_style = space +# (Please don't specify an indent_size here; that has too many unintended consequences.) + +# Code files +[*.{cs,csx,cpp,h}] +indent_size = 4 +insert_final_newline = true +charset = utf-8 + +# Xml project files +[*.{csproj,resx,ps1xml}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Xml files +[*.{xml,stylecop,resx,ruleset}] +indent_size = 2 + +# Xml config files +[*.{props,targets,config,nuspec}] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,cpp}] +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true + +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Name all constant fields using PascalCase +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.required_modifiers = const + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# Static fields should have s_ prefix +dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion +dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields +dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style + +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static + +dotnet_naming_style.static_prefix_style.required_prefix = s_ +dotnet_naming_style.static_prefix_style.capitalization = camel_case + +# Internal and private fields should be _camelCase +dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion +dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields +dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style + +dotnet_naming_symbols.private_internal_fields.applicable_kinds = field +dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal + +dotnet_naming_style.camel_case_underscore_style.required_prefix = _ +dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# CSharp code style settings: +[*.cs] + +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = one_less_than_current + +# Only use var when it's obvious what the variable type is +csharp_style_var_for_built_in_types = false:none +csharp_style_var_when_type_is_apparent = false:none +csharp_style_var_elsewhere = false:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true diff --git a/.gitattributes b/.gitattributes index bb4da29acd30..10790ce3949a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,5 @@ CHANGELOG.md merge=union * text=auto *.png binary *.rtf binary +testablescript.ps1 text eol=lf +TestFileCatalog.txt text eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9a778e4b4cda..f1e9368cdab7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,16 +1,17 @@ # https://help.github.com/articles/about-codeowners/ # Areas are not limited to the filters defined in this file -# First Lets start with areas with no filters or paths +# First, let's start with areas with no filters or paths # Area: Performance -# @lzybkr @adityapatwardhan +# @adityapatwardhan # Area: Portability -# @BrucePay @JamesWTruher +# @JamesWTruher # Area: Security # @TravisEz13 @PaulHigin +src/System.Management.Automation/security/wldpNativeMethods.cs @TravisEz13 @PaulHigin # Area: Documentation .github/ @joeyaiello @TravisEz13 @@ -19,64 +20,58 @@ # @JamesWTruher @TravisEz13 @adityapatwardhan # Area: Cmdlets Core -# @JamesWTruher @SteveL-MSFT @anmenaga @chunqingchen +# @JamesWTruher @SteveL-MSFT @anmenaga -# Now Areas that should have paths or filters, although we might not have them defined -# According to the docs, Order here must be by precedence of the filter, with later rules overwritting +# Now, areas that should have paths or filters, although we might not have them defined +# According to the docs, order here must be by precedence of the filter, with later rules overwritting # but the feature seems to make taking a union of all the matching rules. -# Area: CmdLets Management +# Area: Cmdlets Management src/Microsoft.PowerShell.Commands.Management/ @daxian-dbw @adityapatwardhan -# Area: CmdLets Utility -src/Microsoft.PowerShell.Commands.Utility/ @JamesWTruher @dantraMSFT @PaulHigin +# Area: Utility Cmdlets +src/Microsoft.PowerShell.Commands.Utility/ @JamesWTruher @PaulHigin # Area: Console -src/Microsoft.PowerShell.ConsoleHost/ @daxian-dbw @lzybkr @anmenaga +src/Microsoft.PowerShell.ConsoleHost/ @daxian-dbw @anmenaga -# Area: Demo +# Area: Demos demos/ @joeyaiello @SteveL-MSFT @HemantMahawar # Area: DSC -src/System.Management.Automation/DscSupport @TravisEz13 @dantraMSFT +src/System.Management.Automation/DscSupport @TravisEz13 @SteveL-MSFT -# Area: engine -src/System.Management.Automation/engine @daxian-dbw @lzybkr @BrucePay +# Area: Engine +# src/System.Management.Automation/engine @daxian-dbw # Area: Debugging # Must be below engine to override -src/System.Management.Automation/engine/debugger/ @BrucePay @dantraMSFT @PaulHigin +src/System.Management.Automation/engine/debugger/ @PaulHigin -# Area: help -src/System.Management.Automation/help @Francisco-Gamino @adityapatwardhan +# Area: Help +src/System.Management.Automation/help @adityapatwardhan # Area: Intellisense -# @daxian-dbw @lzybkr @charub +# @daxian-dbw # Area: Language -src/System.Management.Automation/engine/parser @daxian-dbw @vors @lzybkr @BrucePay +src/System.Management.Automation/engine/parser @daxian-dbw # Area: Providers -src/System.Management.Automation/namespaces @BrucePay @anmenaga - -# Area: PSReadLine -src/Microsoft.PowerShell.PSReadLine @lzybkr @charub +src/System.Management.Automation/namespaces @anmenaga # Area: Remoting -src/System.Management.Automation/engine/remoting @dantraMSFT @mirichmo @PaulHigin - -# Area: Side-By-Side -# @mirichmo @charub +src/System.Management.Automation/engine/remoting @PaulHigin # Areas: Build # Must be last -*.config @daxian-dbw @TravisEz13 @adityapatwardhan -*.props @daxian-dbw @TravisEz13 @adityapatwardhan -*.yml @daxian-dbw @TravisEz13 @adityapatwardhan -*.csproj @daxian-dbw @TravisEz13 @adityapatwardhan -build.* @daxian-dbw @TravisEz13 @adityapatwardhan -tools/ @daxian-dbw @TravisEz13 @adityapatwardhan -docker/ @daxian-dbw @TravisEz13 @adityapatwardhan +*.config @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +*.props @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +*.yml @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +*.csproj @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +build.* @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +tools/ @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +docker/ @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin # Area: Compliance tools/terms @TravisEz13 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 37e83f1ed51b..bf4cefe654a7 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -31,12 +31,41 @@ Please read the rest of this document to ensure a smooth contribution process. making sure to follow the directions as best you can. * If the issue is marked as [`Up-for-Grabs`][up-for-grabs], the PowerShell Maintainers are looking for help with the issue. +* Issues marked as [`First-Time-Issue`][first-time-issue], + are identified as being easy and a great way to learn about this project and making + contributions. ## Contributing to Documentation ### Contributing to documentation related to PowerShell -Please see the [Contributor Guide in `PowerShell/PowerShell-Docs`](https://github.com/PowerShell/PowerShell-Docs/blob/staging/CONTRIBUTING.md). +Please see the [Contributor Guide in `MicrosoftDocs/PowerShell-Docs`](https://github.com/MicrosoftDocs/PowerShell-Docs/blob/staging/CONTRIBUTING.md). + +#### Quick steps if you're changing an existing cmdlet + +If you made a change to an existing cmdlet and would like to update the documentation using PlatyPS, +here are the quick steps: + +1. Install +`PlatyPS` +if you don't have it - +`Install-Module PlatyPS`. +1. Clone the +[`MicrosoftDocs/PowerShell-Docs`](https://github.com/MicrosoftDocs/PowerShell-Docs) +repo if you don't already have it. +1. Start your local build of PowerShell +(with the change to the cmdlet you made). +1. Find the cmdlet's markdown file in PowerShell Docs - usually under +`PowerShell-Docs/reference///.md` +(Ex. `PowerShell-Docs/reference/7/Microsoft.PowerShell.Utility/Select-String.md`) +1. Run +`Update-MarkdownHelp -Path ` +which will update the documentation for you. +1. Make any additional changes needed for the cmdlet to be properly documented. +1. Send a Pull Request to the PowerShell Docs repo with the changes that +`PlatyPS` +made. +1. Link your Docs PR to your original change PR. ### Contributing to documentation related to maintaining or contributing to the PowerShell project @@ -46,19 +75,32 @@ Please see the [Contributor Guide in `PowerShell/PowerShell-Docs`](https://githu #### Spellchecking documentation -Documentation are spellchecked. We make use of the +Documentation is spellchecked. We use the [markdown-spellcheck](https://github.com/lukeapage/node-markdown-spellcheck) command line tool, which can be run in interactive mode to correct typos or add words to the ignore list (`.spelling` at the repository root). -To run the spellchecker, follow the steps as follows: +To run the spellchecker, follow these steps: * install [Node.js](https://nodejs.org/en/) (v6.4.0 or up) * install [markdown-spellcheck](https://github.com/lukeapage/node-markdown-spellcheck) by `npm install -g markdown-spellcheck` (v0.11.0 or up) -* run `mdspell "**/*.md" --ignore-numbers --ignore-acronyms` +* run `mdspell "**/*.md" --ignore-numbers --ignore-acronyms --en-us` * if the `.spelling` file is updated, commit and push it +#### Checking links in documentation + +Documentation is link-checked. We make use of the +markdown-link-check command line tool, +which can be run to see if any links are dead. + +To run the link-checker, follow these steps: + +* install [Node.js](https://nodejs.org/en/) (v6.4.0 or up) +* install markdown-link-check by + `npm install -g markdown-link-check@3.7.2` (v3.7.2 **only**) +* run `find . \*.md -exec markdown-link-check {} \;` + ## Contributing to Code ### Code Editor @@ -98,6 +140,8 @@ Additional references: #### Before submitting +* If your change would fix a security vulnerability, + first follow the [vulnerability issue reporting policy][vuln-reporting], before submitting a PR. * To avoid merge conflicts, make sure your branch is rebased on the `master` branch of this repository. * Many code changes will require new tests, so make sure you've added a new test if existing tests do not effectively test the code changed. @@ -138,7 +182,7 @@ Additional references: and is recommended by the Git SCM developers. It is also used in the [Git commit messages](#common-engineering-practices). * If the change is related to a specific resource, please prefix the description with the resource name: - * Instead of "New parameter 'ConnectionCredential' in New-SqlConnection", + * Instead of "New parameter 'ConnectionCredential' in New-SqlConnection", write "New-SqlConnection: add parameter 'ConnectionCredential'". * If your change warrants an update to user-facing documentation, a Maintainer will add the `Documentation Needed` label to your PR and add an issue to the [PowerShell-Docs repository][PowerShell-Docs], @@ -147,6 +191,33 @@ Additional references: While not required, we appreciate any contributors who add this label and create the issue themselves. Even better, all contributors are free to contribute the documentation themselves. (See [Contributing to documentation related to PowerShell](#contributing-to-documentation-related-to-powershell) for more info.) +* If your change adds a new source file, ensure the appropriate copyright and license headers is on top. + It is standard practice to have both a copyright and license notice for each source file. + * For `.h`, `.cpp`, and `.cs` files use the copyright header with empty line after it: + + ```c# + // Copyright (c) Microsoft Corporation. All rights reserved. + // Licensed under the MIT License. + + ``` + + * For `.ps1` and `.psm1` files use the copyright header with empty line after it: + + ```powershell + # Copyright (c) Microsoft Corporation. All rights reserved. + # Licensed under the MIT License. + + ``` + +* If your change adds a new module manifest (.psd1 file), ensure that: + + ```powershell + Author = "PowerShell" + Company = "Microsoft Corporation" + Copyright = "Copyright (c) Microsoft Corporation. All rights reserved." + ``` + + is at the top. ### Pull Request - Work in Progress @@ -160,11 +231,23 @@ Additional references: * Make sure you follow the [Common Engineering Practices](#common-engineering-practices) and [testing guidelines](../docs/testing-guidelines/testing-guidelines.md). * After submitting your pull request, - our [CI system (Travis CI and AppVeyor)][ci-system] + our [CI system (Azure DevOps Pipelines)][ci-system] will run a suite of tests and automatically update the status of the pull request. -* Our CI contains automated spellchecking. If there is any false-positive, +* Our CI contains automated spellchecking and link checking for markdown files. If there is any false-positive, [run the spellchecker command line tool in interactive mode](#spellchecking-documentation) to add words to the `.spelling` file. +* Our packaging test may not pass and ask you to update `files.wxs` file if you add/remove/update nuget package references or add/remove assert files. + + You could update the file manually in accordance with messages in the test log file. Or you can use automatically generated file. To get the file you should build the msi package locally: + + ```powershell + Import-Module .\build.psm1 + Start-PSBuild -Clean -CrossGen -PSModuleRestore -Runtime win7-x64 -Configuration Release -ReleaseTag + Import-Module .\tools\packaging + Start-PSPackage -Type msi -ReleaseTag -WindowsRuntime 'win7-x64' -SkipReleaseChecks + ``` + + Last command will report where new file is located. #### Pull Request - Workflow @@ -187,7 +270,7 @@ Additional references: When updating your pull request, please **create new commits** and **don't rewrite the commits history**. This way it's very easy for the reviewers to see diff between iterations. If you rewrite the history in the pull request, review could be much slower. - The PR is likely to be squashed on merge to master by the *assignee*. + The PR is likely to be squash-merged to master by the *assignee*. 1. *Reviewers* are anyone who wants to contribute. They are responsible for ensuring the code: addresses the issue being fixed, does not create new issues (functional, performance, reliability, or security), and implements proper design. *Reviewers* should use the `Review changes` drop down to indicate they are done with their review. @@ -268,7 +351,7 @@ Using semantic line feeds (breaks that separate ideas) is also appropriate, as is using Markdown syntax. ``` -* These are based on Tim Pope's [guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), +* These are based on Tim Pope's [guidelines](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), Git SCM [submitting patches](https://git.kernel.org/cgit/git/git.git/tree/Documentation/SubmittingPatches), Brandon Rhodes' [semantic linefeeds][], and John Gruber's [Markdown syntax](https://daringfireball.net/projects/markdown/syntax). @@ -285,20 +368,21 @@ is also appropriate, as is using Markdown syntax. ## Contributor License Agreement (CLA) To speed up the acceptance of any contribution to any PowerShell repositories, -you could [sign a Microsoft Contribution Licensing Agreement (CLA)](https://cla.microsoft.com/) ahead of time. -If you've already contributed to PowerShell repositories in the past, congratulations! +you should to [sign a Microsoft Contribution Licensing Agreement (CLA)](https://cla.microsoft.com/) ahead of time. +If you've already contributed to PowerShell or Microsoft repositories in the past, congratulations! You've already completed this step. This a one-time requirement for the PowerShell project. Signing the CLA process is simple and can be done in less than a minute. You don't have to do this up-front. You can simply clone, fork, and submit your pull request as usual. -When your pull request is created, it is classified by a CLA bot. -If the change is trivial, it's classified as `cla-required`. -Once you sign a CLA, all your existing and future pull requests will be labeled as `cla-signed`. +When your pull request is created, it is checked by the CLA bot. +If you have signed the CLA, the status check will be set to `passing`. Otherwise, it will stay at `pending`. +Once you sign a CLA, all your existing and future pull requests will have the status check automatically set at `passing`. [testing-guidelines]: ../docs/testing-guidelines/testing-guidelines.md [running-tests-outside-of-ci]: ../docs/testing-guidelines/testing-guidelines.md#running-tests-outside-of-ci [issue-management]: ../docs/maintainers/issue-management.md +[vuln-reporting]: ./SECURITY.md [governance]: ../docs/community/governance.md [using-prs]: https://help.github.com/articles/using-pull-requests/ [fork-a-repo]: https://help.github.com/articles/fork-a-repo/ @@ -309,9 +393,10 @@ Once you sign a CLA, all your existing and future pull requests will be labeled [contribute-issues]: #contributing-to-issues [open-issue]: https://github.com/PowerShell/PowerShell/issues [up-for-grabs]: https://github.com/powershell/powershell/issues?q=is%3Aopen+is%3Aissue+label%3AUp-for-Grabs -[semantic linefeeds]: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ +[semantic linefeeds]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ [PowerShell-Docs]: https://github.com/powershell/powershell-docs/ [use-vscode-editor]: ../docs/learning-powershell/using-vscode.md#editing-with-visual-studio-code [repository-maintainer]: ../docs/community/governance.md#repository-maintainers [area-expert]: ../docs/community/governance.md#area-experts [ci-system]: ../docs/testing-guidelines/testing-guidelines.md#ci-system +[first-time-issue]: https://github.com/powershell/powershell/issues?q=is%3Aopen+is%3Aissue+label%3AFirst-Time-Issue diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index fc111db035ec..000000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,46 +0,0 @@ - - -Steps to reproduce ------------------- - -```powershell - -``` - -Expected behavior ------------------ - -```none - -``` - -Actual behavior ---------------- - -```none - -``` - -Environment data ----------------- - - - -```powershell -> $PSVersionTable - -``` diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.md b/.github/ISSUE_TEMPLATE/Bug_Report.md new file mode 100644 index 000000000000..f8383cabd6d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_Report.md @@ -0,0 +1,47 @@ +--- +name: Bug report 🐛 +about: Report errors or unexpected behavior 🤔 +title: "My bug report" +labels: Issue-Question +assignees: '' + +--- + + +# Steps to reproduce + +```powershell + +``` + +# Expected behavior + +```none + +``` + +# Actual behavior + +```none + +``` + +# Environment data + + + +```none + +``` diff --git a/.github/ISSUE_TEMPLATE/Distribution_Request.md b/.github/ISSUE_TEMPLATE/Distribution_Request.md new file mode 100644 index 000000000000..53fd8a81e5b0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Distribution_Request.md @@ -0,0 +1,25 @@ +--- +name: Distribution Support Request +about: Requests suppoort for a new distribution +title: "Distribution Support Request" +labels: Distribution-Request +assignees: '' + +--- + +# Details of the Distribution + +- Name of the Distribution: +- Version of the Distribution: +- [ ] The version of the Distribution is supported for at least one year. +- [ ] The version of the Distribution is not an [interim release](https://ubuntu.com/about/release-cycle) or equivalent. +- [ ] The version of the Distribution is [supported by .NET Core](https://github.com/dotnet/core/blob/master/release-notes/3.0/3.0-supported-os.md#linux). +- [ ] An issues has been filed to create a Docker image in https://github.com/powershell/powershell-docker + +## Progress - For PowerShell Team **ONLY** + +- [ ] Docker image created +- [ ] Docker image published +- [ ] Distribution tested +- [ ] Lifecycle updated +- [ ] Documentation Updated diff --git a/.github/ISSUE_TEMPLATE/Documentation_Issue.md b/.github/ISSUE_TEMPLATE/Documentation_Issue.md new file mode 100644 index 000000000000..97f60417b0ee --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Documentation_Issue.md @@ -0,0 +1,13 @@ +--- +name: Documentation Issue 📚 +about: File issues regarding documentation within the [PowerShell-Docs](https://github.com/MicrosoftDocs/PowerShell-Docs) repository +title: "Documentation Issue" +labels: Issue-Question,Area-Documentation +assignees: '' + +--- + +# Documentation Issue + +Please open documentation issues that are not specifically for documentation within the +PowerShell/PowerShell repository in the [PowerShell Docs](https://github.com/MicrosoftDocs/PowerShell-Docs/issues) repository. diff --git a/.github/ISSUE_TEMPLATE/Feature_Request.md b/.github/ISSUE_TEMPLATE/Feature_Request.md new file mode 100644 index 000000000000..2b724b2eac39 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_Request.md @@ -0,0 +1,23 @@ +--- +name: Feature Request/Idea 🚀 +about: Suggest a new feature or improvement (this does not mean you have to implement it) +title: "Feature Request" +labels: Issue-Enhancement +assignees: '' + +--- + +# Summary of the new feature/enhancement + + + +# Proposed technical implementation details (optional) + + diff --git a/.github/ISSUE_TEMPLATE/Release_Process.md b/.github/ISSUE_TEMPLATE/Release_Process.md new file mode 100644 index 000000000000..121b4b9d7713 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Release_Process.md @@ -0,0 +1,43 @@ +--- +name: Release Process +about: Maintainers Only - Release Process +title: "Release Process for v6.x.x" +labels: Issue-Meta +assignees: '' + +--- + + + +# Release Process for v6.x.x + +- [ ] Verify that `PowerShell-Native` has been updated/released as needed. +- [ ] Check for `PowerShellGet` and `PackageManagement` release plans. +- [ ] Start process to sync Azure DevOps artifacts feed such as modules and NuGet packages. +- [ ] Create a private branch named `release/v6.x.x` in Azure DevOps repository. + All release related changes should happen in this branch. +- [ ] Prepare packages + - [ ] Kick off coordinated build. +- [ ] Kick off Release pipeline. + - *These tasks are orchestrated by the release pipeline, but here as status to the community.* + - [ ] Prepare packages + - [ ] Sign the RPM package. + - [ ] Install and verify the packages. + - [ ] Trigger the docker staging builds (signing must be done). + - [ ] Create the release tag and push the tag to `PowerShell/PowerShell` repository. + - [ ] Run tests on all supported Linux distributions and publish results. + - [ ] Update documentation, and scripts. + - [ ] Update [CHANGELOG.md](../../CHANGELOG.md) with the finalized change log draft. + - [ ] Stage a PR to master to update other documents and + scripts to use the new package names, links, and `metadata.json`. + - [ ] For preview releases, + merge the release branch to GitHub `master` with a merge commit. + - [ ] For non-preview releases, + make sure all changes are either already in master or have a PR open. + - [ ] Delete the release branch. + - [ ] Trigger the Docker image release. + - [ ] Retain builds. + - [ ] Update https://github.com/dotnet/dotnet-docker/tree/master/3.0/sdk with new version and SHA hashes for global tool. diff --git a/.github/ISSUE_TEMPLATE/Security_Issue_Report.md b/.github/ISSUE_TEMPLATE/Security_Issue_Report.md new file mode 100644 index 000000000000..a0222650f6ad --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Security_Issue_Report.md @@ -0,0 +1,20 @@ +--- +name: Security Issue +about: Security Issue +title: "!!! READ TEMPLATE COMPLETELY FIRST!!!" +labels: Area-Security +assignees: 'TravisEz13' + +--- + +# Security Issue + +Excerpt from [Issue Management - Security Vulnerabilities](https://github.com/PowerShell/PowerShell/blob/master/.github/SECURITY.md) + +> If you believe that there is a security vulnerability in PowerShell, +it **must** be reported to [secure@microsoft.com](https://technet.microsoft.com/security/ff852094.aspx) +to allow for [Coordinated Vulnerability Disclosure](https://technet.microsoft.com/security/dn467923). +**Only** file an issue, if secure@microsoft.com has confirmed filing an issue is appropriate. + +When you have permission from [secure@microsoft.com](https://technet.microsoft.com/security/ff852094.aspx) to file an issue here, +please use the Bug Report template and state in the description that you are reporting the issue in coordination with [secure@microsoft.com](https://technet.microsoft.com/security/ff852094.aspx). diff --git a/.github/ISSUE_TEMPLATE/Support_Question.md b/.github/ISSUE_TEMPLATE/Support_Question.md new file mode 100644 index 000000000000..4c25c372f23d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Support_Question.md @@ -0,0 +1,22 @@ +--- +name: Support Question ❓ +about: If you have a question, you can try asking in the PowerShell Slack channel first. If you need official support, refer to the [PowerShell Support Lifecycle](https://aka.ms/pslifecycle) +title: "Support Question" +labels: Issue-Question +assignees: '' + +--- + +# Support Question + +## Official support + +[PowerShell Support Lifecycle](https://aka.ms/pslifecycle) + +## Community Resources + +[Slack][powershell-slack] and [Discord][powershell-discord] Community Chat - Interactive chat with other PowerShell enthusiasts. Both Slack and Discord are bridged via a bot and can seamlessly talk to each other. +[PowerShell.org Forum](https://powershell.org/forums/) - Search or post new general PowerShell usage questions + +[powershell-slack]: https://join.slack.com/t/powershell/shared_invite/enQtMzA3MDcxNTM5MTkxLTBmMWIyNzhkYzVjNGRiOTgxZmFlN2E0ZmVmOWU5NDczNTY2NDFhZjFlZTM1MTZiMWIzZDcwMGYzNjQ3YTRkNWM +[powershell-discord]: https://discordapp.com/invite/AtzXnJM diff --git a/.github/ISSUE_TEMPLATE/Windows_PowerShell.md b/.github/ISSUE_TEMPLATE/Windows_PowerShell.md new file mode 100644 index 000000000000..db40e19e5719 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Windows_PowerShell.md @@ -0,0 +1,14 @@ +--- +name: Windows PowerShell +about: Windows PowerShell issues/suggestions need to be reported to [UserVoice](https://windowsserver.uservoice.com/forums/301869-powershell) +labels: Issue-Question +assignees: '' + +--- + +# Windows PowerShell + +For Windows PowerShell 5.1 issues, suggestions, or feature requests please use the following link instead: +Windows PowerShell [UserVoice](https://windowsserver.uservoice.com/forums/301869-powershell) + +This repository is **ONLY** for PowerShell Core 6 issues. diff --git a/.github/Images/GitHub-PR.png b/.github/Images/GitHub-PR.png index 80bb77e4830b..1ae852aecd54 100644 Binary files a/.github/Images/GitHub-PR.png and b/.github/Images/GitHub-PR.png differ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a97cbf433a4d..efbe076a8b9e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,17 +1,40 @@ -## PR Summary - + -## PR Checklist +# PR Summary + + + +## PR Context -Note: Please mark anything not applicable to this PR `NA`. + + +## PR Checklist - [ ] [PR has a meaningful title](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - - [ ] Use the present tense and imperative mood when describing your changes + - Use the present tense and imperative mood when describing your changes - [ ] [Summarized changes](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) -- [ ] User facing [Documentation needed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - - [ ] Issue filed - Issue link: -- [ ] [Change is not breaking](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#making-breaking-changes) -- [ ] [Make sure you've added a new test if existing tests do not effectively test the code changed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#before-submitting) - - [ ] [Add `[feature]` if the change is significant or affectes feature tests](https://github.com/PowerShell/PowerShell/blob/master/docs/testing-guidelines/testing-guidelines.md#requesting-additional-tests-for-a-pr) +- [ ] [Make sure all `.h`, `.cpp`, `.cs`, `.ps1` and `.psm1` files have the correct copyright header](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - [ ] This PR is ready to merge and is not [Work in Progress](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---work-in-progress). - - If the PR is work in progress, please add the prefix `WIP:` to the beginning of the title and remove the prefix when the PR is ready. + - If the PR is work in progress, please add the prefix `WIP:` or `[ WIP ]` to the beginning of the title (the `WIP` bot will keep its status check at `Pending` while the prefix is present) and remove the prefix when the PR is ready. +- **[Breaking changes](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#making-breaking-changes)** + - [ ] None + - **OR** + - [ ] [Experimental feature(s) needed](https://github.com/MicrosoftDocs/PowerShell-Docs/blob/staging/reference/6/Microsoft.PowerShell.Core/About/about_Experimental_Features.md) + - [ ] Experimental feature name(s): +- **User-facing changes** + - [ ] Not Applicable + - **OR** + - [ ] [Documentation needed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) + - [ ] Issue filed: +- **Testing - New and feature** + - [ ] N/A or can only be tested interactively + - **OR** + - [ ] [Make sure you've added a new test if existing tests do not effectively test the code changed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#before-submitting) +- **Tooling** + - [ ] I have considered the user experience from a tooling perspective and don't believe tooling will be impacted. + - **OR** + - [ ] I have considered the user experience from a tooling perspective and enumerated concerns in the summary. This may include: + - Impact on [PowerShell Editor Services](https://github.com/PowerShell/PowerShellEditorServices) which is used in the [PowerShell extension](https://github.com/PowerShell/vscode-powershell) for VSCode (which runs in a different PS Host). + - Impact on Completions (both in the console and in editors) - one of PowerShell's most powerful features. + - Impact on [PSScriptAnalyzer](https://github.com/PowerShell/PSScriptAnalyzer) (which provides linting & formatting in the editor extensions). + - Impact on [EditorSyntax](https://github.com/PowerShell/EditorSyntax) (which provides syntax highlighting with in VSCode, GitHub, and many other editors). diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 000000000000..10633f0d6d15 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,12 @@ +# Security Vulnerabilities + +Security issues are treated very seriously and will, by default, +takes precedence over other considerations including usability, performance, +etc... Best effort will be used to mitigate side effects of a security +change, but PowerShell must be secure by default. + +## Reporting a security vulnerability + +If you believe that there is a security vulnerability in PowerShell, +it **must** be reported to [secure@microsoft.com](https://technet.microsoft.com/security/ff852094.aspx) to allow for [Coordinated Vulnerability Disclosure](https://technet.microsoft.com/security/dn467923). +**Only** file an issue, if [secure@microsoft.com](https://www.microsoft.com/en-us/msrc/faqs-report-an-issue?rtc=1) has confirmed filing an issue is appropriate. diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 000000000000..b4d25c3f4008 --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,13 @@ +# PowerShell Support + +If you have any problems, please consult the [known issues][], developer [FAQ][], and [GitHub issues][]. +If you do not see your problem captured, please file a [new issue][] and follow the provided template. +Also make sure to see the [Official Support Policy][]. +If you know how to fix the issue, feel free to send a pull request our way. (The [Contribution Guides][] apply to that pull request, you may want to give it a read!) + +[Official Support Policy]: https://docs.microsoft.com/en-us/powershell/scripting/powershell-support-lifecycle?view=powershell-6 +[FAQ]: https://github.com/PowerShell/PowerShell/tree/master/docs/FAQ.md +[Contribution Guides]: https://github.com/PowerShell/PowerShell/tree/master/.github/CONTRIBUTING.md +[known issues]: https://docs.microsoft.com/powershell/scripting/whats-new/known-issues-ps6?view=powershell-6 +[GitHub issues]: https://github.com/PowerShell/PowerShell/issues +[new issue]: https://github.com/PowerShell/PowerShell/issues/new diff --git a/.gitignore b/.gitignore index 5900f796f962..4c6f04a3afcc 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,9 @@ dotnet-uninstall-debian-packages.sh # Visual Studio IDE directory .vs/ +# VSCode directories that are not at the repository root +/**/.vscode/ + # Project Rider IDE files .idea.powershell/ @@ -31,10 +34,12 @@ dotnet-uninstall-debian-packages.sh *.exe *.msi *.appx +*.msix # Ignore binaries and symbols *.pdb *.dll +*.wixpdb # Ignore packages *.deb @@ -45,9 +50,6 @@ dotnet-uninstall-debian-packages.sh *.nupkg *.AppImage -# ignore the telemetry semaphore file -DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY - # default location for produced nuget packages /nuget-artifacts @@ -59,9 +61,30 @@ gen # macOS .DS_Store +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +.AppleDouble +.LSOverride # TestsResults TestsResults*.xml +ParallelXUnitResults.xml +xUnitResults.xml # Resharper settings PowerShell.sln.DotSettings.user +*.msp +StyleCop.Cache + +# Ignore SelfSignedCertificate autogenerated files +test/tools/Modules/SelfSignedCertificate/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index c677d18caffa..000000000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "src/libpsl-native/test/googletest"] - path = src/libpsl-native/test/googletest - url = https://github.com/google/googletest.git - ignore = dirty diff --git a/.poshchan/settings.json b/.poshchan/settings.json new file mode 100644 index 000000000000..bb3c3661696b --- /dev/null +++ b/.poshchan/settings.json @@ -0,0 +1,56 @@ +{ + "version": "0.1", + "azdevops": { + "build_targets": { + "static": "PowerShell-CI-static-analysis", + "windows": "PowerShell-CI-Windows", + "macos": "PowerShell-CI-macOS", + "linux": "PowerShell-CI-Linux", + "all": [ + "PowerShell-CI-static-analysis", + "PowerShell-CI-Windows", + "PowerShell-CI-macOS", + "PowerShell-CI-Linux" + ] + }, + "authorized_users": [ + "adityapatwardhan", + "anmenaga", + "bergmeister", + "daxian-dbw", + "iSazonov", + "JamesWTruher", + "KirkMunro", + "PaulHigin", + "rjmholt", + "SteveL-MSFT", + "TravisEz13", + "TylerLeonhardt", + "vexx32" + ] + }, + "failures": { + "authorized_users": [ + "adityapatwardhan", + "anmenaga", + "bergmeister", + "daxian-dbw", + "IISResetMe", + "iSazonov", + "JamesWTruher", + "KirkMunro", + "kwkam", + "PaulHigin", + "powercode", + "rjmholt", + "rkeithhill", + "SteveL-MSFT", + "TravisEz13", + "TylerLeonhardt", + "vexx32" + ] + }, + "reminders": { + "authorized_users": "*" + } +} diff --git a/.spelling b/.spelling index 55521163892e..05b0c3e5fb7f 100644 --- a/.spelling +++ b/.spelling @@ -3,1078 +3,893 @@ # global dictionary is at the start, file overrides afterwards # one word per line, to define a file override use ' - filename' # where filename is relative to this configuration file - -#region Global Dictionary +0-powershell-crossplatform +0xfeeddeadbeef +100ms 2ae5d07 +32-bit +64-bit +about_ +about_debuggers +about_jobs acl -ActiveDirectory +add-localgroupmember +add-ons +adelton +adhoc aditya adityapatwardhan +aiello +alexandair +alexjordan6 +alpha.10 +alpha.11 +alpha.12 +alpha.13 +alpha.14 alpha.15 +alpha.16 +alpha.17 +alpha.18 alpha.7 alpha.8 alpha.9 -AlternateStream +alternatestream amd64 -analyzing -AppImage -AppVeyor +andschwa +api +apis +appimage +applocker +appveyor +args argumentlist arm32 arm64 -artifact -artifacts -ASP.NET -AssemblyLoadContext -authenticode +asp.net +assemblyloadcontext authenticodesignature -behavior -behaviors +azdevops +azurerm.netcore.preview +azurerm.profile.netcore.preview +azurerm.resources.netcore.preview +backgrounded +backgrounding +bergmeister +beta.1 +beta.2 +beta.3 +beta.4 +beta.5 +beta.6 beta.7 -booleans -catalog -cataloged +beta.8 +beta.9 +beta2 +bgelens +Bhaal22 +bjh7242 +bool +breakpoint +brianbunke +brucepay +bugfix +build.json +build.psm1 +bulid +callmejoebob +catchable +cdxml +celsius CentOS +changelog +changelog.md +changeset +changesets +channel9 +charset +checkbox +checksum childitem -chucklu cimsession cimsupport +classlib +clear-itemproperty +cloudydino +cls cmake cmd cmdlet +cmdletproviderclasses cmdlets +codebase codecov.io -color -colors +codecoverage.zip +codefactor +codeowner +codepage +commanddiscovery +commandsearch comobject config -ConsoleHost -ConvertFrom-Json +connect-pssession +consolehost +consolehostrunspaceinit +consolehostuserinterface +consolelineoutput +contenttype +convertfrom-csv +convertfrom-json +convertfrom-sddlstring +convertfrom-securestring +convertfrom-stringdata +convertto-csv +convertto-html +convertto-json +convertto-securestring convertto-xml -CoreCLR -CoreFX +copy-itemproperty +coreclr +coreconsolehost +corefx +CorePsAssemblyLoadContext.cs +coveralls.exe +coveralls.io. +coveralls.net credssp +cron crontab crossgen -cs -CsPhysicallyInstalledMemory +crossgen'ing +crossplatform +csharp +csmacnz +csphysicallyinstalledmemory +ctrl +darquewarrior +darwinjs +daxian-dbw +dayofweek +dchristian3188 +ddwr debughandler -DevOps -DockerFile -DockerFiles -DotNetCore -DottedScopes -eBook +dee-see +deps +deserialization +deserialize +dest +dest.txt +dev +devblackops +deviceguard +devops +diddledan +disable-localuser +disable-psbreakpoint +disable-pstrace +disable-pswsmancombinedtrace +disable-runspacedebug +disable-wsmantrace +disconnect-pssession +displaydataquery +distro +distros +dll +dlls +dlwyatt +dockerbasedbuild +dockerfile +dockerfiles +dongbo +don'ts +dotcover +dotnet +dotnetcore +dottedscopes +downlevel +dropdown +e.g. +ebook +ebooks +enable-localuser +enable-psbreakpoint +enable-pstrace +enable-pswsmancombinedtrace +enable-runspacedebug +enable-wsmantrace +encodings +enter-pshostprocess +enter-pssession enum -env +enums ergo3114 +errorrecord +etl +excludeversion exe -favor -favorite +executables +executionpolicy +exit-pshostprocess +exit-pssession +export-binarymilog +export-clixml +export-csv +export-formatdata +export-modulemember +failurecode +failurecount +ffeldhaus +filecatalog +filename +filesystem +filesystemprovider +filterhashtable +find-dscresource +find-packageprovider +find-rolecapability +firefox +folderName +foreach +formatfileloading +formatviewbinding frontload -FullCLR +fullclr functionprovider -Get-Acl -Get-AuthenticodeSignature -Get-ChildItem -Get-ComputerInfo -Get-PSSessionConfiguration -Get-WinEvent +gabrielsroka +gamified +gc.regions.xml +get-apachemodule +get-apachevhost +get-childitem +get-cimassociatedinstance +get-cimclass +get-ciminstance +get-computerinfo +get-cronjob +get-eventsubscriber +get-filehash +get-formatdata +get-installedmodule +get-installedscript +get-itemproperty +get-itempropertyvalue +get-localgroup +get-localgroupmember +get-localuser +get-logproperties +get-packageprovider +get-packagesource +getparentprocess +get-psbreakpoint +get-pscallstack +get-pshostprocessinfo +get-psprovider +get-psreadlinekeyhandler +get-psreadlineoption +get-psrepository +get-pssession +get-pssessioncapability +get-runspacedebug +get-systemdjournal +gettype +get-typedata +get-uiculture +get-winevent +get-wsmaninstance +gitcommitid github +githug +gitter +glachancecmaisonneuve +globbing +GoogleTest +gzip +hackathons hashtable -hashtables +helloworld.ps1 helpproviderwithcache helpproviderwithfullcache helpsystem +hemant +hemantmahawar +himura2la homebrew +hostname hotfix httpbin.org -HttpBin's +httpbin's +https +hubuk +i.e. +idera ifdef'ed +iisresetme ilya -init -Invoke-RestMethod -Invoke-WebRequest +import-binarymilog +import-clixml +import-csv +import-localizeddata +import-packageprovider +import-powershelldatafile +includeide +includeusername +informationrecord +initializers +install-packageprovider +interactivetesting +interop +interoperation +invoke-cimmethod +invoke-restmethod +invoke-wsmanaction +iot +isazonov +iscore +iscoreclr isnot +itemtype +itpro +jameswtruher +Jawz84 +jazzdelightsme +jeffbi +jen +joandrsn +joeyaiello +jokajak +joshuacooper +journalctl +jpsnover json +jsonconfigfileaccessor +judgement +jumplist +jwmoss +kanjibates +kasper3 +katacoda +kevinmarquette +keyfileparameter +keyhandler +khansen00 +kirkmunro +kittholland korygill -labeled -linux-x64 -lockfile -macOS +kpis +kvprasoon +kwiknick +kwkam +kylesferrazza +labelling +lastwritetime +launch.json +ldspits +lee303 +libpsl +libpsl-native +libunwind8 +linux +locationglobber +loopback +lossless +louistio +lynda.com +lzybkr +mababio +macos +maertendmsft +mahawar +markekraus +marktiedemann +mcbobke md -Microsoft.PowerShell.Archive +meir017 +memberresolution +messageanalyzer +metadata +miaromero +microsoft +microsoft.com +microsoft.management.infrastructure.cimcmdlets +microsoft.management.infrastructure.native +microsoft.powershell.archive microsoft.powershell.commands.diagnostics microsoft.powershell.commands.management microsoft.powershell.commands.utility microsoft.powershell.consolehost +microsoft.powershell.core microsoft.powershell.coreclr.assemblyloadcontext microsoft.powershell.coreclr.eventing +microsoft.powershell.diagnostics +microsoft.powershell.localaccounts +microsoft.powershell.management +microsoft.powershell.markdownrender microsoft.powershell.psreadline microsoft.powershell.security +microsoft.powershell.utility microsoft.wsman.management microsoft.wsman.runtime -MSBuild -MS-PSRP -Multipart +mirichmo +mkdir +mklement0 +move-itemproperty +msbuild +msftrncs +mshsnapinloadunload +msi +ms-psrp +multiline +multipart +mv +mvps +mwrock myget namedpipe -New-PSSessionOption -New-PSTransportOption +namespace +nano +nanoserver +nativeexecution +netip.ps1. +netstandard.dll +new-apachevhost +new-ciminstance +new-cimsessionoption +new-cronjob +new-guid +new-itemproperty +new-localgroup +new-localuser +new-modulemanifest +new-psrolecapabilityfile +new-pssession +new-pssessionconfigurationfile +new-pssessionoption +new-pstransportoption +new-scriptfileinfo +new-temporaryfile +new-timespan +new-winevent +new-wsmaninstance +new-wsmansessionoption +non-22 +non-cim +non-https +non-r2 +noresume notcontains nuget -NuGet -NUnit -nunit +nugetfeed +nuget.exe +numberbytes nupkg -nuspec -OpenCover -OpenSSH -OpenSUSE -PackageManagement -param -parameterized +oauth +offthewoll +oising +omi +omnisharp +oneget.org +opencover +opencover.zip +openssh +openssl +opensuse +oss +p1 +packagemanagement +parameterbinderbase +parameterbindercontroller +parameterbinding +pathresolution +patochun patwardhan +paulhigin +pawamoy +payette +perfview +perfview.exe +petseral +plaintext +pluggable +pluralsight +poshcode +pougetat +powerbi +powercode powershell -PowerShell -PowerShell.Core.Instrumentation -powershell.exe -PowerShellGet +powershell.6 +powershell.com +powershell.core.instrumentation +powershell.org +powershellcore +powershellgallery +powershellget +powershellmagazine.com +powershellninja +powershellproperties +powershell-unix +ppadmavilasom +pre-build +pre-compiled +pre-generated +pre-installed +prepend +preprocessor +pre-release +pre-releases +pre-requisites +preview.1 +preview.2 +preview.3 +preview.4 +preview1-24530-04 +preview7 +productversion program.cs -ProgramFiles -ProxyCommand +prototyyppi +providername +proxycommand ps1 -PSCredential -PSObject +ps1xml +pscore +pscredential +psd1 +psdrive +psdriveinfo +pseudoparameterbinder +psgallery +psm1 +psobject psobjects psproxyjobs -PSReadline +psreadline psrp.windows -PSSessionConfiguration +psscriptanalyzer +pssessionconfiguration +pssnapinloadunload +pssnapins +psversion +psversiontable +pvs-studio +pwd +pwrshplughin.dll pwsh +qmfrederik +raghav710 +raspbian +rc +rc.1 +rc.2 +rc2-24027 +rc3-24011 +readme +readme.md +readonly +rebase +rebasing +receive-pssession +recurse +reddit +redhat +redistributable redistributables -Register-EngineEvent -Register-PSSessionConfiguration +register-argumentcompleter +register-cimindicationevent +register-engineevent +register-objectevent +register-packagesource +register-psrepository registryprovider +relationlink +remotesigned remoting -ResGen +remove-ciminstance +remove-cronjob +remove-itemproperty +remove-localgroup +remove-localgroupmember +remove-localuser +remove-psbreakpoint +remove-psreadlinekeyhandler +remove-pssession +remove-typedata +remove-wsmaninstance +rename-itemproperty +rename-localgroup +rename-localuser +reparse +repo +reportgenerator +resgen +responseheaders +rest.ps1 +restart-apachehttpserver resx -RFCs -runas -Runspace +richardszalay +Rin +rkeithhill +robo210 +ronn +rpalo +runspace +runspaceinit +runtime runtimes +sample-dotnet1 +sample-dotnet2 sarithsutha savehelp sazonov -SecureString +schvartzman +schwartzmeyer +scriptblock +securestring +seemethere +select-xml +semver +sessionid +sessionstate sessionstatecontainer sessionstateitem -Set-Acl -Set-AuthenticodeSignature -Set-ExecutionPolicy -ShouldBeErrorId +set-ciminstance +sethvs +set-itemproperty +set-localgroup +set-localuser +set-logproperties +set-packagesource +set-psbreakpoint +set-psdebug +set-psreadlinekeyhandler +set-psreadlineoption +set-psrepository +set-strictmode +set-wsmaninstance +set-wsmanquickconfig +shellexecute +shouldbeerrorid showcommandinfo -Singleline +simonwahlin +singleline +smes +snapcraft snapin -ssh -StackOverflow +snover +sometext +source.txt +src +ss64.com +stackoverflow +stanzilla +start-codecoveragerun +stdin +stevel-msft +stknohg +strawgate +streamdescribecifeaturescenariodescribecontextitcontextcontextbeforeallafterallbeforeeachaftereachshould +stringbuilder +stuntguy3000 submodule submodules sudo +superproject +swarfegagit +sxs +sydneyhsmith +symlink +symlinks +syscall +syslog +system.manage system.management.automation -TeamCity +systemd +tabcompletion +tadas +tandasat +test.ps1 +test.txt. +test1.txt +test2.txt +testcase +testdrive +test-modulemanifest +test-pssessionconfigurationfile +tests.zip +test-scriptfileinfo +tgz +theflyingcorpse thenewstellw +thezim +threadjob throttlelimit -toolset +throw-testcasesitmockdescribe +timcurwick +timestamp +timothywlewis +-title +tobias +tokenizing +tomconte toolchain -TraceSource -Unregister-Event -Unregister-PSSessionConfiguration +toolset +tracesource +travisez13 +travisty +truher +typecataloggen +typeconversion +typegen +typematch +ubuntu +unicode +unregister-event +unregister-packagesource +unregister-psrepository +unregister-pssessionconfiguration +untracked +un-versioned +update-formatdata +update-modulemanifest +update-scriptfileinfo +update-typedata +uri +urls +userdata +uservoice +utf8 +utf-8 +utf8nobom utils utils.cs -vscode -walkthrough -WebCmdlets -wget -whitespace -Win32 -win7 -WinRM -WiX -writingpestertests.md -WSMan -wsmansessionoption.cs -xUnit -#endregion - -#region ./tools/install-powershell.readme.md Overrides - - ./tools/install-powershell.readme.md -includeide -sed -#endregion - -#region CHANGELOG.md Overrides - - CHANGELOG.md -_ -_Jobs --Command --Exclude --File --Include --Title -0xfeeddeadbeef -acceptance -alpha.10 -alpha.11 -alpha.12 -alpha.13 -alpha.14 -alpha.16 -alpha.17 -alpha.18 -args -Bhaal22 -behavioral -bergmeister -beta.1 -beta.2 -beta.3 -beta.4 -beta.5 -beta.6 -beta.8 -beta.9 -binding -bool -CDXML -charset -CI -cleanup -CodeMethod -CodeOwner -codepage -CommandNotFoundException -ContentType -ConvertTo-Html -CoreConsoleHost -crossgen'ing -DarwinJS -dchristian3188 -DdWr -deserialization -deserialize -dlwyatt -dotnet -enums -EXE's -ExecutionPolicy -FileCatalog -FilterHashtable -foreach -GetParentProcess -GitCommitId -globbing -HelpersCommon.psm1 -Himura2la -honors -hostname -IISResetMe -IncludeUserName -InformationRecord -IoT -iSazonov -IsCore -IsCoreCLR -jeffbi -joandrsn -JsonConfigFileAccessor -KeyFileParameter -KeyHandler -KirkMunro -kittholland -kvprasoon -kwiknick -kylesferrazza -LDSpits -Lee303 -libpsl-native -libunwind8 -LoadFrom -markekraus -meta -MiaRomero -Microsoft.Management.Infrastructure.Native -Microsoft.PowerShell.LocalAccounts -mklement0 -mwrock -nanoserver-insider -non-22 -non-CIM -non-R2 -OAuth -offthewoll -oising -oneget.org -PetSerAl -powercode -PowershellNinja -PowerShellProperties -preview1-24530-04 -ProductVersion -PRs -PSDrive -PseudoParameterBinder -PSReadLine -PSScriptAnalyzer -PSVersion -PVS-Studio -Pwrshplughin.dll -raghav710 -Raspbian -rc -rc.2 -rc2-24027 -rc3-24011 -README.md -RelationLink -richardszalay -rkeithhill -SemVer -shebang -ShellExecute -showwindow -startup -startuptype -stdin -StringBuilder -SxS -system.manage -Tadas -TestCase -TheFlyingCorpse -thezim -TimCurwick -timestamp -TimeZone -TPA -Travis -travisty -TTY's -UserAgent -UserData -UserVoice -Utf8 -UTF8NoBOM v0.1.0 v0.2.0 v0.3.0 v0.4.0 v0.5.0 v0.6.0 -v6.0.0 -ValidateNotNullOrEmpty -WebListener -WebRequest -win7-x86 -Windos -WindowsVersion -WSManCredSSP -XPath -Youtube -#endregion - -#region CODE_OF_CONDUCT.md Overrides - - CODE_OF_CONDUCT.md -microsoft.com -opencode -#endregion - -#region demos/Apache/readme.md Overrides - - demos/Apache/readme.md -Get-ApacheModule -Get-ApacheVHost -New-ApacheVHost -Restart-ApacheHTTPserver -#endregion - -#region demos/Azure/README.md Overrides - - demos/Azure/README.md -AzureRM.NetCore.Preview -AzureRM.Profile.NetCore.Preview -AzureRM.Resources.NetCore.Preview -ExcludeVersion -ProviderName -#endregion - -#region demos/crontab/README.md Overrides - - demos/crontab/README.md -DayOfWeek -Get-CronJob -New-CronJob -Remove-CronJob -u -#endregion - -#region demos/DSC/readme.md Overrides - - demos/DSC/readme.md -#endregion - -#region demos/python/README.md Overrides - - demos/python/README.md -_script.ps1 -_script.ps1. -#endregion - -#region demos/rest/README.md Overrides - - demos/rest/README.md -rest.ps1 -#endregion - -#region demos/SSHRemoting/README.md Overrides - - demos/SSHRemoting/README.md -_config -2kCbnhT2dUE6WCGgVJ8Hyfu1z2wE4lifaJXLO7QJy0Y -com.openssh.sshd -ComputerName -ComputerType -ConfigurationName -Enter-PSSession -HostName -KeyFilePath -KeyPath -launchctl -New-PSSession -NoLogo -NoProfile -openssh-client -openssh-server -PasswordAuthentication -PSCredential -PSSessions -PubkeyAuthentication -RSAAuthentication -ssh.exe -sshd -sshd.exe -sshs -TestUser -UbuntuVM1 -UbuntuVM1s -usr -#endregion - -#region demos/SystemD/readme.md Overrides - - demos/SystemD/readme.md -Get-SystemDJournal -journalctl -SystemD -#endregion - -#region demos/WindowsPowerShellModules/README.md Overrides - - demos/WindowsPowerShellModules/README.md -PowerShellGallery -PSSnapins -WindowsPSModulePath -#endregion - -#region docker/README.md Overrides - - docker/README.md -andschwa's -CurrentUser -hub.docker.com -microsoft -NanoServer-Insider -nanoserver-insider-powershell -#endregion - -#region docs/building/internals.md Overrides - - docs/building/internals.md -_arm -_arm64 -Catalog -flavor -libpsl -MSBuild -nuget.exe -plugin -powershell-unix -src v141 -#endregion - -#region docs/building/macos.md Overrides - - docs/building/macos.md -preview3 -#endregion - -#region docs/cmdlet-example/command-line-simple-example.md Overrides -- docs/cmdlet-example/command-line-simple-example.md -aka -classlib -dotnet -netstandard.dll -wsl -#endregion - -#region docs/cmdlet-example/visual-studio-simple-example.md Overrides -- docs/cmdlet-example/visual-studio-simple-example.md -dropdown v3 -#endregion - -#region docs/community/governance.md Overrides - - docs/community/governance.md -Aiello -AngelCalvo -BrucePay -Calvo -daxian-dbw -Dongbo -DON'Ts -Hemant -HemantMahawar -JamesWTruher -joeyaiello -jpsnover -khansen00 -lzybkr -Mahawar -Payette -PRs -Snover -SteveL-MSFT -Truher -#endregion - -#region docs/debugging/README.md Overrides +v4 +v5.0 +v6 +v6.0. +v6.0.0 +v6.0.1 +v6.0.2 +v6.0.4 +v6.0.5 +v6.1.0 +v6.1.1 +v6.2.0 +v6.2.1 +v6.2.2 +validatenotnullorempty +versioned +versioning +visualstudio +vorobev +vors +vscode +vstsbuild.ps1 +walkthrough +webcmdlets +weblistener +webrequest +weltner +wesholton84 +wget +whitespace +wildcard +wildcarded +wildcards +win32 +win32-openssh +win7 +windos +windowspsmodulepath +windowsversion +winrm +wix +wpr +wprui.exe +writingpestertests.md +wsl +wsman +wsmancredssp +wsmansessionoption.cs +www.github.com +x64 +x86 +xpath +xtqqczze +xunit +yaml +youtube +zackjknight +vexx32 +perf +britishben +felixfbecker +vpondala +dependabot +jellyfrog +1redone +tommymaynard +vmsilvamolina +fbehrens +lockdown +lukexjeremy +deserializing +kiazhi +v6.1.2 +Menagarishvili +anmenaga +fxdependent +sba923 +replicaJunction +lupino3 +hvitved +unvalidated +Geweldig +mjanko5 +v7.0.0 +renehernandez +ece-jacob-scott +st0le +MohiTheFish +CodeFormatter +StyleCop +SytzeAndr +yashrajbharti + - CHANGELOG.md +aavdberg +asrosent +azkarmoulana +chucklu +Claustn +CVE-2018-8256 +CVE-2018-8415 +daviddreher2 +honour +iGotenz +jeis2497052 +Jocapear +lassehastrup +markwragg +nbkalex +NeoBeum +nycjan +paalbra +robdy +SeeminglyScience +StingyJack +ThreeFive-O +tobvil +uninstallation +vongrippen +yurko7 +zhenggu +analytics - docs/debugging/README.md -CmdletProviderClasses -CommandDiscovery -CommandSearch -ConsoleHostRunspaceInit -ConsoleHostUserInterface -ConsoleLineOutput corehost -DisplayDataQuery -FileSystemProvider -FormatFileLoading -FormatViewBinding -LocationGlobber -MemberResolution -MshSnapinLoadUnload -OmniSharp -ParameterBinderBase -ParameterBinderController -ParameterBinding -PathResolution -PSDriveInfo -PSSnapInLoadUnload -RunspaceInit -SessionState -TypeConversion -TypeMatch -XTerm -#endregion - -#region docs/dev-process/breaking-change-contract.md Overrides - - docs/dev-process/breaking-change-contract.md -cd -cdxml -int -p1 -#endregion - -#region docs/dev-process/coding-guidelines.md Overrides - - docs/dev-process/coding-guidelines.md -interop -PaulHigin -SMEs -TravisEz13 -uppercase -#endregion - -#region docs/FAQ.md Overrides - - docs/FAQ.md -PoshCode -SS64.com -TypeGen -v6.0.0 -#endregion - -#region docs/git/submodules.md Overrides - - docs/git/submodules.md -GoogleTest -superproject -#endregion - -#region docs/host-powershell/README.md Overrides - - docs/host-powershell/README.md -0-powershell -CorePsAssemblyLoadContext.cs -Kerberos-based -NTLM-based -post-6 -preview1-002106-00 -sample-dotnet1 -sample-dotnet2 -#endregion - -#region docs/installation/linux.md Overrides - - docs/installation/linux.md -compat-openssl10 -dockerfile -libc6 -libcurl -libcurl3 -libgcc1 -libgssapi-krb5-2 -libicu -libicu52 -libicu55 -libicu57 -liblttng-ust0 -libssl1.0.0 -libssl1.0.2 -libstdc -libunwind -libunwind8 -libuuid1 -openssl-libs -OpenSUSE -zlib1g -zypper -#endregion - -#region docs/installation/windows.md Overrides - - docs/installation/windows.md -Install-PowerShellRemoting -pwrshplugin.dll -System32 -Win8 -windir -#endregion - -#region docs/KNOWNISSUES.md Overrides - - docs/KNOWNISSUES.md -cp -globbing -pipelining -psl-omi-provider -Register-WmiEvent -System.Management.Automation.SemanticVersion -System.Timers.Timer -#endregion - -#region docs/learning-powershell/create-powershell-scripts.md Overrides - - docs/learning-powershell/create-powershell-scripts.md -NetIP.ps1. -RemoteSigned -#endregion - -#region docs/learning-powershell/debugging-from-commandline.md Overrides - - docs/learning-powershell/debugging-from-commandline.md -_Debuggers -celsius -Set-PSBreakpoint -test.ps1 -#endregion - -#region docs/learning-powershell/powershell-beginners-guide.md Overrides - - docs/learning-powershell/powershell-beginners-guide.md -dir -jen -LastWriteTime -#endregion - -#region docs/learning-powershell/README.md Overrides - docs/learning-powershell/README.md -Lynda.com -Pluralsight -PowerShell.com -PowerShellMagazine.com -ScriptCenter -TechNet -#endregion - -#region docs/learning-powershell/using-vscode.md Overrides - - docs/learning-powershell/using-vscode.md -helloworld.ps1 -launch.json -OSs -#endregion - -#region docs/learning-powershell/working-with-powershell-objects.md Overrides - - docs/learning-powershell/working-with-powershell-objects.md -ForEach-Object -#endregion - -#region docs/maintainers/issue-management.md Overrides - - docs/maintainers/issue-management.md -Microsoft.PowerShell.Core -Microsoft.PowerShell.Management -Microsoft.PowerShell.Utility -omi -#endregion - -#region docs/maintainers/pull-request-process.md Overrides - - docs/maintainers/pull-request-process.md -ci-system -#endregion - -#region docs/maintainers/README.md Overrides - - docs/maintainers/README.md -andschwa -daxian-dbw -Dongbo -mirichmo -Schwartzmeyer -Sergei -TravisEz13 -Vorobev -vors -#endregion - -#region docs/maintainers/releasing.md Overrides - - docs/maintainers/releasing.md -2012r2 -CHANGELOG.md -Dockerfiles -downlevel -Effing -PowerShellCore -Ronn -Toolset -v6 -#endregion - -#region docs/testing-guidelines/PowerShellCoreTestStatus.md Overrides - - docs/testing-guidelines/PowerShellCoreTestStatus.md -Add-LocalGroupMember -add-on -adhoc -Clear-ItemProperty -Connect-PSSession -Connect-WSMan -ConvertFrom-Csv -ConvertFrom-SddlString -ConvertFrom-SecureString -ConvertFrom-StringData -ConvertTo-Csv -ConvertTo-Json -ConvertTo-SecureString -ConvertTo-Xml -Copy-ItemProperty -Debug-Runspace -Disable-LocalUser -Disable-PSBreakpoint -Disable-PSSessionConfiguration -Disable-PSTrace -Disable-PSWSManCombinedTrace -Disable-RunspaceDebug -Disable-WSManCredSSP -Disable-WSManTrace -Disconnect-PSSession -Disconnect-WSMan -Enable-LocalUser -Enable-PSBreakpoint -Enable-PSSessionConfiguration -Enable-PSTrace -Enable-PSWSManCombinedTrace -Enable-RunspaceDebug -Enable-WSManCredSSP -Enable-WSManTrace -Enter-PSHostProcess -Exit-PSHostProcess -Exit-PSSession -Export-BinaryMiLog -Export-Clixml -Export-Csv -Export-FormatData -Export-ModuleMember -Find-DscResource -Find-PackageProvider -Find-RoleCapability -Get-CimAssociatedInstance -Get-CimClass -Get-CimInstance -Get-CimSession -Get-EventSubscriber -Get-ExecutionPolicy -Get-FileHash -Get-FormatData -Get-InstalledModule -Get-InstalledScript -Get-ItemProperty -Get-ItemPropertyValue -Get-LocalGroup -Get-LocalGroupMember -Get-LocalUser -Get-LogProperties -Get-PackageProvider -Get-PackageSource -Get-PSBreakpoint -Get-PSCallStack -Get-PSDrive -Get-PSHostProcessInfo -Get-PSProvider -Get-PSReadlineKeyHandler -Get-PSReadlineOption -Get-PSRepository -Get-PSSession -Get-PSSessionCapability -Get-Runspace -Get-RunspaceDebug -Get-TimeZone -Get-TypeData -Get-UICulture -Get-WSManCredSSP -Get-WSManInstance -Import-BinaryMiLog -Import-Clixml -Import-Csv -Import-LocalizedData -Import-PackageProvider -Import-PowerShellDataFile -Install-PackageProvider -Invoke-CimMethod -Invoke-WSManAction -Move-ItemProperty -New-CimInstance -New-CimSession -New-CimSessionOption -New-FileCatalog -New-Guid -New-ItemProperty -New-LocalGroup -New-LocalUser -New-ModuleManifest -New-PSDrive -New-PSRoleCapabilityFile -New-PSSessionConfigurationFile -New-ScriptFileInfo -New-TemporaryFile -New-WinEvent -New-WSManInstance -New-WSManSessionOption -Receive-PSSession -Register-ArgumentCompleter -Register-CimIndicationEvent -Register-ObjectEvent -Register-PackageSource -Register-PSRepository -Remove-CimInstance -Remove-CimSession -Remove-ItemProperty -Remove-LocalGroup -Remove-LocalGroupMember -Remove-LocalUser -Remove-PSBreakpoint -Remove-PSDrive -Remove-PSReadlineKeyHandler -Remove-PSSession -Remove-TypeData -Remove-WSManInstance -Rename-ItemProperty -Rename-LocalGroup -Rename-LocalUser -Select-xml -Set-CimInstance -Set-ItemProperty -Set-LocalGroup -Set-LocalUser -Set-LogProperties -Set-PackageSource -Set-PSDebug -Set-PSReadlineKeyHandler -Set-PSReadlineOption -Set-PSRepository -Set-PSSessionConfiguration -Set-StrictMode -Set-TimeZone -Set-WSManInstance -Set-WSManQuickConfig -Test-FileCatalog -Test-ModuleManifest -Test-PSSessionConfigurationFile -Test-ScriptFileInfo -Test-WSMan -Unregister-PackageSource -Unregister-PSRepository -Update-FormatData -Update-ModuleManifest -Update-ScriptFileInfo -Update-TypeData -#endregion - -#region docs/testing-guidelines/testing-guidelines.md Overrides - - docs/testing-guidelines/testing-guidelines.md -100ms -Api -build.psm1 -DotNet -Interop -MessageAnalyzer -Microsoft.PowerShell.Core -Microsoft.PowerShell.Diagnostics -Microsoft.PowerShell.Management -Microsoft.PowerShell.Security -Microsoft.PowerShell.Utility -NativeExecution -TabCompletion -#endregion - -#region docs/testing-guidelines/TestRoadmap.md Overrides +PSKoans + - docs/testing-guidelines/CodeCoverageAnalysis.md +de5f69c - docs/testing-guidelines/TestRoadmap.md -corefx -DotCover -Downlevel -KPIs -loopback -MVPs -OpenCover -org -PowerBI -Syslog -#endregion - -#region docs/testing-guidelines/WritingPesterTests.md Overrides +_no_ - docs/testing-guidelines/WritingPesterTests.md -ErrorRecord -FQErrorId -FullyQualifiedErrorId -HelpersCommon.psm1 nGet-ContentOut-String nGet-MultiLineString PSDefaultParameterValues-skip ShouldShouldIt -StreamDescribeCIFeatureScenarioDescribeContextItContextContextBeforeAllAfterAllBeforeEachAfterEachshould -TestDrive -throw-testcasesItMockDescribe -#endregion - -#region README.md Overrides - - README.md -Gitter -microsoft.com -msi -omnisharp-vscode -opencode -pkg -tgz -UserVoice -#endregion - -#region src/libpsl-native/README.md Overrides - - src/libpsl-native/README.md -Ansi -C#'s -codepage -libpsl-native -#endregion - -#region src/Microsoft.PowerShell.PSReadLine/en-US/PSReadline.md Overrides - - src/Microsoft.PowerShell.PSReadLine/en-US/PSReadline.md -_history.txt -_PSReadline -50ms -AddToHistoryHandler -AppData -BackgroundColor -BellStyle -BriefDescription -coloring -CompletionQueryItems -ConsoleColor -ConsoleKeyInfo -ContinuationPrompt -ContinuationPromptBackgroundColor -ContinuationPromptForegroundColor -DingDuration -DingTone -EditMode -EmphasisBackgroundColor -EmphasisForegroundColor -ErrorBackgroundColor -ErrorForegroundColor -ExtraPromptLineCount -ForegroundColor -ForwardWord -Func -HistoryNoDuplicates -HistorySavePath -HistorySaveStyle -HistorySearchBackward -HistorySearchCaseSensitive -HistorySearchCursorMovesToEnd -host.Name -Int32 -KillWord -MaximumHistoryCount -MaximumKillRingCount -Microsoft.PowerShell.KeyHandler -ResetTokenColors -ReverseSearchHistory -SaveAtExit -SaveIncrementally -SaveNothing -ScriptBlock -ShowToolTips -TokenClassification -TokenKind -ToString -ValidateAndAcceptLine -ValidationHandler -WordDelimiters -#endregion - -#region src/Microsoft.PowerShell.SDK/README.md Overrides - - src/Microsoft.PowerShell.SDK/README.md -metapackage -project.json -#endregion - -#region src/Modules/README.md Overrides - - src/Modules/README.md -ps1xml -psd1 -psm1 -#endregion - -#region src/powershell/README.md Overrides - - src/powershell/README.md -powershell-unix -#endregion - -#region src/TypeCatalogGen/README.md Overrides - - src/TypeCatalogGen/README.md -TypeCatalogGen -#endregion - -#region test/README.md Overrides - - test/README.md -csharp -fullclr -shebang -#endregion - -#region test/tools/CodeCoverageAutomation/README.md Overrides - - test/tools/CodeCoverageAutomation/README.md -CodeCoverage.zip -Coveralls.exe -Coveralls.io. -Coveralls.net -csmacnz -OpenCover.zip -powershell.version -Start-CodeCoverageRun -tests.zip -v5.0 -v6.0. -#endregion - -#region test/tools/WebListener/README.md Overrides - - test/tools/WebListener/README.md -Auth -NTLM -ResponseHeaders -#endregion + - tools/performance/README.md +Invoke-PerfviewPS +JIT.Regions.xml +PowerShell.Regions.xml +PowerShell.stacktags +PowerShell.wpaProfile +PowerShell.wprp +wpa +wpaProfile + - demos/WindowsPowerShellModules/README.md +2.x. diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1f8c14d26e2c..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ -language: cpp - -git: - depth: 1000 - -matrix: - include: - - os: linux - dist: trusty - sudo: required - - os: osx - osx_image: xcode8.1 - fast_finish: true - -addons: - artifacts: - paths: - - $(ls powershell*{deb,pkg,AppImage,gz} | tr "\n" ":") - - pester-tests.xml - -install: - # Default 2.0.0 Ruby is buggy - # Default bundler version is buggy - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - rvm install ruby-2.3.3; - rvm --default use 2.3.3; - fi - # Ensure that libcurl+openssl is used on macOS for greater feature support. - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - export DYLD_LIBRARY_PATH=/usr/local/opt/curl/lib:/usr/local/opt/openssl/lib:${DYLD_LIBRARY_PATH}; - fi - - pushd tools - - ./install-powershell.sh - - popd - # spellcheck - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - nvm install 6.4.0 && - npm install -g markdown-spellcheck@0.11.0; - fi - - ulimit -n 4096 - - pwsh -File tools/travis.ps1 -Stage Bootstrap - -script: - - pwsh -File tools/travis.ps1 - # spellcheck - # Ignore 'Pester' folder because it's third party - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - mdspell '**/*.md' '!**/Pester/**/*.md' --ignore-numbers --ignore-acronyms --report; - fi - -after_failure: - - pwsh -File tools/travis.ps1 -Stage Failure - -after_success: - - pwsh -File tools/travis.ps1 -Stage Success diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b0c23e31c2d1..117f430270b9 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,11 +1,13 @@ { - // See http://go.microsoft.com/fwlink/?LinkId=827846 + // See https://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ + "ms-azure-devops.azure-pipelines", "ms-vscode.cpptools", "ms-vscode.csharp", "ms-vscode.PowerShell", "twxs.cmake", - "DavidAnson.vscode-markdownlint" + "DavidAnson.vscode-markdownlint", + "vitaliymaz.vscode-svg-previewer" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 792e547d8a5c..bc8c2b8e6174 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,16 +22,16 @@ // Sets the codeformatting options to follow the given indent style in a way that is compatible with PowerShell syntax. For more information about the brace styles please refer to https://github.com/PoshCode/PowerShellPracticeAndStyle/issues/81. "powershell.codeFormatting.preset": "OTBS", - + // Adds a space between a keyword and its associated scriptblock expression. "powershell.codeFormatting.whitespaceBeforeOpenBrace": true, - + // Adds a space between a keyword (if, elseif, while, switch, etc) and its associated conditional expression. "powershell.codeFormatting.whitespaceBeforeOpenParen": true, - + // Adds spaces before and after an operator ('=', '+', '-', etc.). "powershell.codeFormatting.whitespaceAroundOperator": true, - + // Adds a space after a separator (',' and ';'). "powershell.codeFormatting.whitespaceAfterSeparator": true } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4283a9f10eba..b92aaddeb0d6 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -41,19 +41,19 @@ { "label": "Bootstrap", "type": "shell", - "command": "Import-Module ${workspaceFolder}/build.psm1; Start-PSBootstrap", + "command": "Import-Module '${workspaceFolder}/build.psm1'; Start-PSBootstrap", "problemMatcher": [] }, { "label": "Clean Build", "type": "shell", - "command": "Import-Module ${workspaceFolder}/build.psm1; Start-PSBuild -Clean -Output (Join-Path ${workspaceFolder} debug)", + "command": "Import-Module '${workspaceFolder}/build.psm1'; Start-PSBuild -Clean -Output (Join-Path '${workspaceFolder}' debug)", "problemMatcher": "$msCompile" }, { "label": "Build", "type": "shell", - "command": "Import-Module ${workspaceFolder}/build.psm1; Start-PSBuild -Output (Join-Path ${workspaceFolder} debug)", + "command": "Import-Module '${workspaceFolder}/build.psm1'; Start-PSBuild -Output (Join-Path '${workspaceFolder}' debug)", "group": { "kind": "build", "isDefault": true diff --git a/.vsts-ci/install-ps.yml b/.vsts-ci/install-ps.yml new file mode 100644 index 000000000000..72f425511624 --- /dev/null +++ b/.vsts-ci/install-ps.yml @@ -0,0 +1,158 @@ +name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master + - release* + - feature* + paths: + include: + - /tools/install-powershell.sh + - /tools/installpsh-amazonlinux.sh + - /tools/installpsh-debian.sh + - /tools/installpsh-osx.sh + - /tools/installpsh-redhat.sh + - /tools/installpsh-suse.sh + - /tools/install-powershell.ps1 + - /.vsts-ci/install-ps.yml +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - /tools/install-powershell.sh + - /tools/installpsh-amazonlinux.sh + - /tools/installpsh-debian.sh + - /tools/installpsh-osx.sh + - /tools/installpsh-redhat.sh + - /tools/installpsh-suse.sh + - /tools/install-powershell.ps1 + - /.vsts-ci/install-ps.yml + +variables: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + +resources: +- repo: self + clean: true +phases: +- template: templates/install-ps-phase.yml + parameters: + scriptName: sudo ./tools/install-powershell.sh + jobName: InstallPowerShellUbuntu + pool: ubuntu-latest + verification: | + if ([Version]"$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor).$($PSVersionTable.PSVersion.Patch)" -lt [version]"6.2.0") + { + throw "powershell was not upgraded: $($PSVersionTable.PSVersion)" + } + +- template: templates/install-ps-phase.yml + parameters: + scriptName: sudo ./tools/install-powershell.sh + jobName: InstallPowerShellAmazonLinux + pool: ubuntu-latest + container: pshorg/powershellcommunity-test-deps:amazonlinux-2.0 + verification: | + if ([Version]"$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor).$($PSVersionTable.PSVersion.Patch)" -lt [version]"6.2.0") + { + throw "powershell was not upgraded: $($PSVersionTable.PSVersion)" + } + +- template: templates/install-ps-phase.yml + parameters: + scriptName: sudo ./tools/installpsh-amazonlinux.sh + jobName: InstallPSHAmazonLinux + pool: ubuntu-latest + container: pshorg/powershellcommunity-test-deps:amazonlinux-2.0 + verification: | + if ([Version]"$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor).$($PSVersionTable.PSVersion.Patch)" -lt [version]"6.2.0") + { + throw "powershell was not upgraded: $($PSVersionTable.PSVersion)" + } + continueOnError: false + +# TODO: add sudo to script and use image with sudo +- template: templates/install-ps-phase.yml + parameters: + scriptName: ./tools/install-powershell.sh + jobName: InstallPowerShellCentOS + pool: ubuntu-latest + container: mcr.microsoft.com/powershell/test-deps:centos-7 + +- template: templates/install-ps-phase.yml + parameters: + scriptName: ./tools/install-powershell.sh + jobName: InstallPowerShellDebian9 + pool: ubuntu-latest + container: mcr.microsoft.com/powershell/test-deps:debian-9 + + +# VSTS could not find pwsh in: +# mcr.microsoft.com/powershell:opensuse-42.3 +# could not repo locally + +# sudo is not needed on macOS +- template: templates/install-ps-phase.yml + parameters: + scriptName: ./tools/install-powershell.sh + jobName: InstallPowerShellMacOS + pool: macOS-latest + verification: | + if ([Version]"$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor).$($PSVersionTable.PSVersion.Patch)" -lt [version]"6.2.0") + { + # The script does not upgrade on mac os https://github.com/PowerShell/PowerShell/issues/9322 + Write-Warning "powershell was not upgraded: $($PSVersionTable.PSVersion)" + } + +- template: templates/install-ps-phase.yml + parameters: + scriptName: pwsh -c ./tools/install-powershell.ps1 -AddToPath + jobName: InstallPowerShellPS1Ubuntu + pool: ubuntu-latest + +- template: templates/install-ps-phase.yml + parameters: + scriptName: pwsh -c ./tools/install-powershell.ps1 -AddToPath -Daily + jobName: InstallPowerShellPS1UbuntuDaily + pool: ubuntu-latest + verification: | + Write-Verbose $PSVersionTable.PSVersion -verbose + if ([Version]"$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor).$($PSVersionTable.PSVersion.Patch)" -lt [version]"7.0.0") + { + throw "powershell was not upgraded: $($PSVersionTable.PSVersion)" + } + +- template: templates/install-ps-phase.yml + parameters: + scriptName: pwsh -c ./tools/install-powershell.ps1 -AddToPath -Daily + jobName: InstallPowerShellMacOSDaily + pool: macOS-latest + verification: | + Write-Verbose $PSVersionTable.PSVersion -verbose + if ([Version]"$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor).$($PSVersionTable.PSVersion.Patch)" -lt [version]"7.0.0") + { + throw "powershell was not upgraded: $($PSVersionTable.PSVersion)" + } + +- template: templates/install-ps-phase.yml + parameters: + scriptName: | + pwsh -c ./tools/install-powershell.ps1 -AddToPath -Daily + jobName: InstallPowerShellWindowsDaily + pool: windows-latest + verification: | + $newVersion = &$env:LOCALAPPDATA\Microsoft\powershell-daily\pwsh -v + $newVersion -match '^PowerShell ((\d*\.\d*\.\d*)(-\w*(\.\d*)?)?){1}' + $versionOnly = $Matches[2] + Write-verbose "$newVersion; versionOnly: $versionOnly" -verbose + if ([Version]$versionOnly -lt [version]"7.0.0") + { + throw "powershell was not upgraded: $newVersion" + } diff --git a/.vsts-ci/linux.yml b/.vsts-ci/linux.yml new file mode 100644 index 000000000000..5218a20cf9c5 --- /dev/null +++ b/.vsts-ci/linux.yml @@ -0,0 +1,97 @@ +name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /tools/releaseBuild/**/* + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /tools/releaseBuild/**/* + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml + +variables: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + +resources: +- repo: self + clean: true +jobs: +- template: templates/ci-build.yml + parameters: + pool: Hosted Ubuntu 1604 + jobName: linux_build + displayName: linux Build + +- template: templates/nix-test.yml + parameters: + name: Linux + pool: Hosted Ubuntu 1604 + purpose: UnelevatedPesterTests + tagSet: CI + parentJobs: + - linux_build + +- template: templates/nix-test.yml + parameters: + name: Linux + pool: Hosted Ubuntu 1604 + purpose: ElevatedPesterTests + tagSet: CI + parentJobs: + - linux_build + +- template: templates/nix-test.yml + parameters: + name: Linux + pool: Hosted Ubuntu 1604 + purpose: UnelevatedPesterTests + tagSet: Others + parentJobs: + - linux_build + +- template: templates/nix-test.yml + parameters: + name: Linux + pool: Hosted Ubuntu 1604 + purpose: ElevatedPesterTests + tagSet: Others + parentJobs: + - linux_build + +- template: templates/verify-xunit.yml + parameters: + pool: Hosted Ubuntu 1604 + parentJobs: + - linux_build + +- job: CodeCovTestPackage + displayName: CodeCoverage and Test Packages + steps: + - powershell: | + Import-Module .\tools\ci.psm1 + New-CodeCoverageAndTestPackage + displayName: CodeCoverage and Test Package diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml new file mode 100644 index 000000000000..1df0bcf61118 --- /dev/null +++ b/.vsts-ci/mac.yml @@ -0,0 +1,91 @@ +name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /tools/releaseBuild/**/* + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /tools/releaseBuild/**/* + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml + +variables: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + # Turn off Homebrew analytics + HOMEBREW_NO_ANALYTICS: 1 + +resources: +- repo: self + clean: true +jobs: +- template: templates/ci-build.yml + parameters: + pool: Hosted macOS + jobName: mac_build + displayName: macOS Build + +- template: templates/nix-test.yml + parameters: + purpose: UnelevatedPesterTests + tagSet: CI + parentJobs: + - mac_build + +- template: templates/nix-test.yml + parameters: + purpose: ElevatedPesterTests + tagSet: CI + parentJobs: + - mac_build + +- template: templates/nix-test.yml + parameters: + purpose: UnelevatedPesterTests + tagSet: Others + parentJobs: + - mac_build + +- template: templates/nix-test.yml + parameters: + purpose: ElevatedPesterTests + tagSet: Others + parentJobs: + - mac_build + +- template: templates/verify-xunit.yml + parameters: + pool: 'Hosted macOS' + parentJobs: + - mac_build + +- job: CodeCovTestPackage + displayName: CodeCoverage and Test Packages + steps: + - powershell: | + Import-Module .\tools\ci.psm1 + New-CodeCoverageAndTestPackage + displayName: CodeCoverage and Test Package diff --git a/.vsts-ci/misc-analysis.yml b/.vsts-ci/misc-analysis.yml new file mode 100644 index 000000000000..d9e7aa46e989 --- /dev/null +++ b/.vsts-ci/misc-analysis.yml @@ -0,0 +1,70 @@ +name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master + - release* + - feature* + +pr: + branches: + include: + - master + - release* + - feature* + +resources: +- repo: self + clean: true +jobs: +- template: templates/credscan.yml + +- job: Linux_CI + + displayName: Markdown and Common Tests + + pool: + name: Hosted Ubuntu 1604 + steps: + - powershell: | + Get-ChildItem -Path env: + displayName: Capture environment + condition: succeededOrFailed() + + - powershell: | + Install-module pester -Scope CurrentUser -Force + displayName: Install Pester + condition: succeededOrFailed() + + - bash: | + curl -o- --progress-bar -L https://yarnpkg.com/install.sh | bash + displayName: Bootstrap Yarn + condition: succeededOrFailed() + + - bash: | + sudo yarn global add markdown-spellcheck@0.11.0 + displayName: Install mdspell + condition: succeededOrFailed() + + - powershell: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" + displayName: Set Build Name for Non-PR + condition: ne(variables['Build.Reason'], 'PullRequest') + + - bash: | + mdspell '**/*.md' '!**/Pester/**/*.md' --ignore-numbers --ignore-acronyms --report --en-us; + displayName: Test Spelling in Markdown + condition: succeededOrFailed() + + - powershell: | + Import-module ./build.psm1 + $path = Join-Path -Path $pwd -ChildPath './commonTestResults.xml' + $results = invoke-pester -Script ./test/common -OutputFile $path -OutputFormat NUnitXml -PassThru + Write-Host "##vso[results.publish type=NUnit;mergeResults=true;runTitle=Common Tests;publishRunAttachments=true;resultFiles=$path;]" + if($results.TotalCount -eq 0 -or $results.FailedCount -gt 0) + { + throw "Markdown tests failed" + } + displayName: Run Common Tests + condition: succeededOrFailed() diff --git a/.vsts-ci/templates/ci-build.yml b/.vsts-ci/templates/ci-build.yml new file mode 100644 index 000000000000..8eb6fc9fb265 --- /dev/null +++ b/.vsts-ci/templates/ci-build.yml @@ -0,0 +1,44 @@ +parameters: + pool: 'Hosted VS2017' + jobName: 'win_build' + displayName: Windows Build + +jobs: +- job: ${{ parameters.jobName }} + pool: + name: ${{ parameters.pool }} + + displayName: ${{ parameters.displayName }} + + steps: + - powershell: | + Get-ChildItem -Path env: + displayName: Capture environment + condition: succeededOrFailed() + + - powershell: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" + displayName: Set Build Name for Non-PR + condition: ne(variables['Build.Reason'], 'PullRequest') + + - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml + + - powershell: | + [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + displayName: Bootstrap + condition: succeededOrFailed() + + - powershell: | + Import-Module .\tools\ci.psm1 + Invoke-CIBuild + displayName: Build + condition: succeeded() + + - powershell: | + Import-Module .\tools\ci.psm1 + Restore-PSOptions + Invoke-CIxUnit -SkipFailing + displayName: xUnit Tests + condition: succeeded() + continueOnError: true diff --git a/.vsts-ci/templates/credscan.yml b/.vsts-ci/templates/credscan.yml new file mode 100644 index 000000000000..859500797fa8 --- /dev/null +++ b/.vsts-ci/templates/credscan.yml @@ -0,0 +1,28 @@ +parameters: + pool: 'Hosted VS2017' + jobName: 'credscan' + displayName: Secret Scan + +jobs: +- job: ${{ parameters.jobName }} + pool: + name: ${{ parameters.pool }} + + displayName: ${{ parameters.displayName }} + + steps: + - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@2 + displayName: 'Scan for secrets' + inputs: + suppressionsFile: tools/credScan/suppress.json + debugMode: false + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 + displayName: 'Publish Secret Scan Logs to Build Artifacts' + continueOnError: true + + - task: securedevelopmentteam.vss-secure-development-tools.build-task-postanalysis.PostAnalysis@1 + displayName: 'Check for failures' + inputs: + CredScan: true + ToolLogsNotFoundAction: Error diff --git a/.vsts-ci/templates/install-ps-phase.yml b/.vsts-ci/templates/install-ps-phase.yml new file mode 100644 index 000000000000..62b7553f832e --- /dev/null +++ b/.vsts-ci/templates/install-ps-phase.yml @@ -0,0 +1,42 @@ +parameters: + pool: 'ubuntu-latest' + jobName: 'none' + scriptName: '' + container: '' + verification: '' + continueOnError: false + +jobs: + +- job: ${{ parameters.jobName }} + variables: + scriptName: ${{ parameters.scriptName }} + + ${{ if ne(parameters.container, '') }}: + container: ${{ parameters.container }} + + pool: + vmImage: ${{ parameters.pool }} + + displayName: ${{ parameters.jobName }} + + steps: + - pwsh: | + Get-ChildItem -Path env: + displayName: Capture environment + condition: succeededOrFailed() + + - powershell: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" + displayName: Set Build Name for Non-PR + condition: ne(variables['Build.Reason'], 'PullRequest') + + - bash: | + $(scriptName) + displayName: Run Script - $(scriptName) + condition: succeededOrFailed() + continueOnError: ${{ parameters.continueOnError }} + + - ${{ if ne(parameters.verification, '') }}: + - pwsh: ${{ parameters.verification }} + displayName: Verification + continueOnError: ${{ parameters.continueOnError }} diff --git a/.vsts-ci/templates/nanoserver.yml b/.vsts-ci/templates/nanoserver.yml new file mode 100644 index 000000000000..28e108e96712 --- /dev/null +++ b/.vsts-ci/templates/nanoserver.yml @@ -0,0 +1,61 @@ +parameters: + vmImage: 'win1803' + jobName: 'Nanoserver_Tests' + continueOnError: false + +jobs: + +- job: ${{ parameters.jobName }} + variables: + scriptName: ${{ parameters.scriptName }} + + pool: + vmImage: ${{ parameters.vmImage }} + + displayName: ${{ parameters.jobName }} + + steps: + - script: | + set + displayName: Capture environment + condition: succeededOrFailed() + + - task: DownloadBuildArtifacts@0 + displayName: 'Download build artifacts' + inputs: + downloadType: specific + itemPattern: | + build/**/* + downloadPath: '$(System.ArtifactsDirectory)' + + - pwsh: | + Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse + displayName: 'Capture artifacts directory' + continueOnError: true + + - pwsh: | + Install-module pester -Scope CurrentUser -Force + displayName: 'Install Pester' + continueOnError: true + + - pwsh: | + Import-Module .\tools\ci.psm1 + Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' + $options = (Get-PSOptions) + $path = split-path -path $options.Output + Write-Verbose "Path: '$path'" -Verbose + $rootPath = split-Path -path $path + Expand-Archive -Path '$(System.ArtifactsDirectory)\build\build.zip' -DestinationPath $rootPath -Force + Invoke-Pester -Path ./test/nanoserver -OutputFormat NUnitXml -OutputFile ./test-nanoserver.xml + displayName: Test + condition: succeeded() + + - task: PublishTestResults@2 + condition: succeededOrFailed() + displayName: Publish Nanoserver Test Results **\test*.xml + inputs: + testRunner: NUnit + testResultsFiles: '**\test*.xml' + testRunTitle: nanoserver + mergeTestResults: true + failTaskOnFailedTests: true diff --git a/.vsts-ci/templates/nix-test.yml b/.vsts-ci/templates/nix-test.yml new file mode 100644 index 000000000000..b93e336a2890 --- /dev/null +++ b/.vsts-ci/templates/nix-test.yml @@ -0,0 +1,72 @@ +parameters: + pool: 'Hosted macOS' + parentJobs: [] + purpose: '' + tagSet: 'CI' + name: 'mac' + +jobs: +- job: ${{ parameters.name }}_test_${{ parameters.purpose }}_${{ parameters.tagSet }} + dependsOn: + ${{ parameters.parentJobs }} + pool: + name: ${{ parameters.pool }} + + displayName: ${{ parameters.name }} Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} + + steps: + - pwsh: | + Get-ChildItem -Path env: + displayName: Capture environment + condition: succeededOrFailed() + + - task: DownloadBuildArtifacts@0 + displayName: 'Download build artifacts' + inputs: + downloadType: specific + itemPattern: | + build/**/* + downloadPath: '$(System.ArtifactsDirectory)' + + - pwsh: | + Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse + displayName: 'Capture artifacts directory' + continueOnError: true + + - pwsh: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + displayName: Bootstrap + condition: succeededOrFailed() + + - task: ExtractFiles@1 + displayName: 'Extract build zip' + inputs: + archiveFilePatterns: '$(System.ArtifactsDirectory)/build/build.zip' + destinationFolder: '$(System.ArtifactsDirectory)/bins' + + - bash: | + find "$(System.ArtifactsDirectory)/bins" -type d -exec chmod +rwx {} \; + find "$(System.ArtifactsDirectory)/bins" -type f -exec chmod +rw {} \; + displayName: 'Fix permissions' + continueOnError: true + + - pwsh: | + Get-ChildItem "$(System.ArtifactsDirectory)\bins\*" -Recurse -ErrorAction SilentlyContinue + displayName: 'Capture extracted build zip' + continueOnError: true + + - pwsh: | + Import-Module .\tools\ci.psm1 + Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' + $options = (Get-PSOptions) + $rootPath = '$(System.ArtifactsDirectory)\bins' + $originalRootPath = Split-Path -path $options.Output + $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) + $pwshPath = Join-Path -path $path -ChildPath 'pwsh' + chmod a+x $pwshPath + $options.Output = $pwshPath + Set-PSOptions $options + Invoke-CITest -Purpose '${{ parameters.purpose }}' -TagSet '${{ parameters.tagSet }}' + displayName: Test + condition: succeeded() diff --git a/.vsts-ci/templates/verify-xunit.yml b/.vsts-ci/templates/verify-xunit.yml new file mode 100644 index 000000000000..03f89ce30ee7 --- /dev/null +++ b/.vsts-ci/templates/verify-xunit.yml @@ -0,0 +1,33 @@ +parameters: + parentJobs: [] + pool: 'Hosted VS2017' + jobName: 'xunit_verify' + +jobs: +- job: verify_xunit + displayName: Verify xUnit Results + pool: + name: ${{ parameters.pool }} + dependsOn: + ${{ parameters.parentJobs }} + steps: + - task: DownloadBuildArtifacts@0 + displayName: 'Download build artifacts' + inputs: + downloadType: specific + itemPattern: | + xunit/**/* + downloadPath: '$(System.ArtifactsDirectory)' + + - powershell: | + dir "$(System.ArtifactsDirectory)\*" -Recurse + displayName: 'Capture artifacts directory' + continueOnError: true + + - powershell: | + Import-Module .\tools\ci.psm1 + $xUnitTestResultsFile = "$(System.ArtifactsDirectory)\xunit\xUnitTestResults.xml" + + Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile + displayName: Test + condition: succeeded() diff --git a/.vsts-ci/templates/windows-packaging.yml b/.vsts-ci/templates/windows-packaging.yml new file mode 100644 index 000000000000..df422b812d51 --- /dev/null +++ b/.vsts-ci/templates/windows-packaging.yml @@ -0,0 +1,34 @@ +parameters: + pool: 'Hosted VS2017' + jobName: 'win_packaging' + parentJobs: [] + +jobs: +- job: ${{ parameters.jobName }} + dependsOn: + ${{ parameters.parentJobs }} + pool: + name: ${{ parameters.pool }} + + displayName: Windows Packaging + + steps: + - powershell: | + Get-ChildItem -Path env: + displayName: Capture environment + condition: succeededOrFailed() + + - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml + + - powershell: | + [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 + Import-Module .\tools\ci.psm1 + Invoke-CIInstall + displayName: Bootstrap + condition: succeededOrFailed() + + - powershell: | + Import-Module .\tools\ci.psm1 + New-CodeCoverageAndTestPackage + Invoke-CIFinish -NuGetKey $(NUGET_KEY) + displayName: Build and Test Package diff --git a/.vsts-ci/templates/windows-test.yml b/.vsts-ci/templates/windows-test.yml new file mode 100644 index 000000000000..fefa39b98dc1 --- /dev/null +++ b/.vsts-ci/templates/windows-test.yml @@ -0,0 +1,51 @@ +parameters: + pool: 'Hosted VS2017' + parentJobs: [] + purpose: '' + tagSet: 'CI' + +jobs: +- job: win_test_${{ parameters.purpose }}_${{ parameters.tagSet }} + dependsOn: + ${{ parameters.parentJobs }} + pool: + name: ${{ parameters.pool }} + + displayName: Windows Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} + + steps: + - pwsh: | + Get-ChildItem -Path env: + displayName: Capture environment + condition: succeededOrFailed() + + - task: DownloadBuildArtifacts@0 + displayName: 'Download build artifacts' + inputs: + downloadType: specific + itemPattern: | + build/**/* + downloadPath: '$(System.ArtifactsDirectory)' + + - pwsh: | + Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse + displayName: 'Capture artifacts directory' + continueOnError: true + + # must be run frow Windows PowerShell + - powershell: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall + displayName: Bootstrap + condition: succeededOrFailed() + + - pwsh: | + Import-Module .\tools\ci.psm1 + Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' + $options = (Get-PSOptions) + $path = split-path -path $options.Output + $rootPath = split-Path -path $path + Expand-Archive -Path '$(System.ArtifactsDirectory)\build\build.zip' -DestinationPath $rootPath -Force + Invoke-CITest -Purpose '${{ parameters.purpose }}' -TagSet '${{ parameters.tagSet }}' + displayName: Test + condition: succeeded() diff --git a/.vsts-ci/windows-daily.yml b/.vsts-ci/windows-daily.yml new file mode 100644 index 000000000000..65390776c1fc --- /dev/null +++ b/.vsts-ci/windows-daily.yml @@ -0,0 +1,80 @@ +name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml + +variables: + GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + +resources: +- repo: self + clean: true + +stages: +- stage: BuildWin + displayName: Build for Windows + jobs: + - template: templates/ci-build.yml + +- stage: TestWin + displayName: Test for Windows + jobs: + - template: templates/windows-test.yml + parameters: + purpose: UnelevatedPesterTests + tagSet: CI + + - template: templates/windows-test.yml + parameters: + purpose: ElevatedPesterTests + tagSet: CI + + - template: templates/windows-test.yml + parameters: + purpose: UnelevatedPesterTests + tagSet: Others + + - template: templates/windows-test.yml + parameters: + purpose: ElevatedPesterTests + tagSet: Others + + - template: templates/verify-xunit.yml + parameters: + pool: 'Hosted VS2017' + +- stage: PackagingWin + displayName: Packaging for Windows + jobs: + # Unlike daily builds, we do not upload nuget package to MyGet so we do not wait on tests to finish. + - template: templates/windows-packaging.yml + diff --git a/.vsts-ci/windows.yml b/.vsts-ci/windows.yml new file mode 100644 index 000000000000..2881a6a4fb00 --- /dev/null +++ b/.vsts-ci/windows.yml @@ -0,0 +1,83 @@ +name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) +trigger: + # Batch merge builds together while a merge build is running + batch: true + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - /.vsts-ci/misc-analysis.yml + - /.github/ISSUE_TEMPLATE/* + - /.dependabot/config.yml + +variables: + GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + +resources: +- repo: self + clean: true + +stages: +- stage: BuildWin + displayName: Build for Windows + jobs: + - template: templates/ci-build.yml + +- stage: TestWin + displayName: Test for Windows + jobs: + - template: templates/windows-test.yml + parameters: + purpose: UnelevatedPesterTests + tagSet: CI + + - template: templates/windows-test.yml + parameters: + purpose: ElevatedPesterTests + tagSet: CI + + - template: templates/windows-test.yml + parameters: + purpose: UnelevatedPesterTests + tagSet: Others + + - template: templates/windows-test.yml + parameters: + purpose: ElevatedPesterTests + tagSet: Others + + - template: templates/verify-xunit.yml + parameters: + pool: 'Hosted VS2017' + + - template: templates/nanoserver.yml + +- stage: PackagingWin + displayName: Packaging for Windows + dependsOn: [] # by specifying an empty array, this stage doesn't depend on the stage before it + jobs: + # Unlike daily builds, we do not upload nuget package to MyGet so we do not wait on tests to finish. + - template: templates/windows-packaging.yml + diff --git a/CHANGELOG.md b/CHANGELOG.md index 959bb6521ec0..a356d830a0ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,2034 @@ # Changelog +## v7.0.0-preview.3 - 08/20/2019 + +### Breaking Changes + +- Remove `kill` alias for `Stop-Process` cmdlet on Unix (#10098) (Thanks @iSazonov!) +- Support for starting PowerShell as a login shell (`pwsh -Login` / `pwsh -l`) support (#10050) + +### Engine Updates and Fixes + +- Additional Telemetry - implementation of [`RFC0036`](https://github.com/PowerShell/PowerShell-RFC/pull/158) (#10336) +- Implement `ForEach-Object -Parallel` as an experimental feature (#10229) +- Skip `JumpList` on `NanoServer` and `IoT` (#10164) +- Make `Get-DscResource` work with class based resources (#10350) +- Fix `#requires -version` for `pwsh` 7 to include `6.1` and `6.2` in `PSCompatibleVersions` (#9943) (Thanks @bgelens!) +- Add dispose of `_runspaceDebugCompleteEvent` event object. (#10323) +- Fix performance regression from disabling debugger in system lockdown mode (#10269) +- Special case the `posix` locale in `WildcardPattern` (#10186) +- Use `Platform.IsWindowsDesktop` instead of checking both NanoServer and IoT (#10205) + +### General Cmdlet Updates and Fixes + +- Enable Experimental Features by default on Preview builds (#10228) +- Enable `-sta` and `-mta` switches for `pwsh` (`-sta` is required for `GUIs`) (#10061) +- Make breakpoints display better over PowerShell remoting (#10339) (Thanks @KirkMunro!) +- Add support for `AppX` reparse points (#10331) +- Make module name matching for `get-module -FullyQualifiedName` case insensitive (#10329) +- Expose `PreRelease` label in `PSModuleInfo` formatter (#10316) +- Add `-Raw` switch to `Select-String` which allows returning only the string that was matched (#9901) (Thanks @Jawz84!) + +- ### Performance + +- Reduce allocations in `MakePath()` method (#10027) (Thanks @iSazonov!) +- Remove extra check that the system dll exists (#10244) (Thanks @iSazonov!) +- Avoid boxing when passing value type arguments to `PSTraceSource.WriteLine` (#10052) (Thanks @iSazonov!) +- Reduce allocations in `Escape()` and `Unescape()` (#10041) (Thanks @iSazonov!) + +### Code Cleanup + +- Add the license header to `nanoserver.tests.ps1` (#10171) +- Mark `-parallel` and `-throttlelimit` reserved for `foreach` and `switch` statements (#10328) (Thanks @KirkMunro!) +- Deprecate workflow debugging code (#10321) (Thanks @KirkMunro!) +- Fix style issues in `InternalCommands.cs` (#10352) (Thanks @iSazonov!) +- Deprecate internal `HelpCategory.Workflow` enumeration (#10319) (Thanks @KirkMunro!) +- Update `Microsoft.PowerShell.CoreCLR.Eventing` to resolve conflict with `System.Diagnostics.EventLog` (#10305) +- Don't collect process start time as it's not being used on `consolehost` startup (#10294) +- .NET Core 3.0 now aborts the thread for us. Remove the `ThreadAbortException` code (#10230) (Thanks @iSazonov!) +- Use `nameof()` in `LocationGlobber` and `PathInfo` (#10200) (Thanks @iSazonov!) + +### Tools + +- Fix Hungarian prefix `my` (#9976) (Thanks @RDIL!) +- Fix spelling error in issue template (#10256) +- Quote arguments in `.vscode/tasks.json` in case of spaces (#10204) (Thanks @msftrncs!) + +### Tests + +- Remove `markdownlint` tests due to security issues (#10163) +- Add tests for `WildcardPattern.Escape()` and `Unescape()` (#10090) (Thanks @iSazonov!) +- Cleanup Docker release testing (#10310) (Thanks @RDIL!) + +### Build and Packaging Improvements + +- Update `Microsoft.Management.Infrastructure` version to `2.0.0-preview.2` (#10366) +- Move to `.NET Core 3.0 preview.8` (#10351) (#10227) (Thanks @bergmeister!) +- Bump `NJsonSchema` from `10.0.21` to `10.0.22` (#10364) +- Add `Microsoft.PowerShell.CoreCLR.Eventing.dll` to exception list for build fix (#10337) +- Bump `Microsoft.CodeAnalysis.CSharp` from `3.1.0` to `3.2.1` (#10273) (#10330) +- Revert the temporary AzDevOps artifact workaround (#10260) +- Fix macOS build break (#10207) + +### Documentation and Help Content + +- Update docs for `7.0.0-preview.2` release (#10160) (#10176) +- `PSSA` also includes formatting (#10172) +- Refactor security policy documentation so that they appear in the Security policy tab of GitHub (#9905) (Thanks @bergmeister!) +- Add tooling section to PR template (#10144) +- Update `README.md` and `metadata.json` for next releases (#10087) +- Update DotNet Support links (#10145) +- Update our language on our policy applying to security issues (#10304) +- Update dead links from `powershell.com` (#10297) +- Create `Distribution_Request` issue template (#10253) +- Fix: Removed dependency file with `Dependabot` (#10212) (Thanks @RDIL!) + +## v7.0.0-preview.2 - 07/17/2019 + +### Breaking Changes + +- Cleanup workflow - remove `PSProxyJob` (#10083) (Thanks @iSazonov!) +- Disable `Enter-PSHostProcess` cmdlet when system in lock down mode (Internal 9168) + +### Engine Updates and Fixes + +- Consider `DBNull.Value` and `NullString.Value` the same as `$null` when comparing with `$null` and casting to bool (#9794) (Thanks @vexx32!) +- Allow methods to be named after keywords (#9812) (Thanks @vexx32!) +- Create `JumpList` in `STA` thread as some `COM` `APIs` are strictly `STA` only to avoid sporadic `CLR` crashes (#9928) (#10057) (Thanks @bergmeister!) +- Skip `JumpList` on `NanoServer` and `IoT` (#10164) +- Display `COM` method signature with argument names (#9858) (Thanks @nbkalex!) +- Use the original precision (prior-dotnet-core-3) for double/float-to-string conversion (#9893) +- `Import-DscResource` should allow to overwrite DSC built-in resources. (#9879) +- Add ability to pass `InitialSessionState` to the `ConsoleShell.Start` (#9802) (Thanks @asrosent!) +- Have console host not enter command prompt mode when using `Read-Host -Prompt` (#9743) +- Fix use of `Start-Process http://bing.com` (#9793) +- Support negative numbers in `-split` operator (#8960) (Thanks @ece-jacob-scott!) + +### General Cmdlet Updates and Fixes + +- Support DSC compilation on Linux. (#9834) +- Add alias for Service `StartType` (#9940) (Thanks @NeoBeum!) +- Add `-SecurityDescriptorSddl` parameter to `Set-Service` (#8626) (Thanks @kvprasoon!) +- Fix auto-download of files when enumerating files from a `OneDrive` folder (#9895) +- Set request headers when request body is empty in Web Cmdlets (#10034) (Thanks @markekraus!) +- Fix wrong comparison in `CertificateProvider` (#9987) (Thanks @iSazonov!) +- Sync docs changes into the embedded help for `pwsh` (#9952) +- Display Duration when displaying `HistoryInfo` (#9751) (Thanks @rkeithhill!) +- Update console startup and help `url` for PowerShell docs (#9775) +- Make `UseAbbreviationExpansion` and `TempDrive` official features (#9872) +- Fix `Get-ChildItem -Path` with wildcard `char` (#9257) (Thanks @kwkam!) + +### Performance + +- Add another fast path to `WildcardPattern.IsMatch` for patterns that only have an asterisk in the end (#10054) (Thanks @iSazonov!) +- Move some of the creations of `WildcardPattern` in outer loop to avoid unnecessary allocation (#10053) (Thanks @iSazonov!) +- Make `Foreach-Object` 2 times faster by reducing unnecessary allocations and boxing (#10047) +- Use a static cache for `PSVersionInfo.PSVersion` to avoid casting `SemanticVersion` to `Version` every time accessing that property (#10028) +- Reduce allocations in `NavigationCmdletProvider.NormalizePath()` (#10038) (Thanks @iSazonov!) +- Add fast path for wildcard patterns that contains no wildcard characters (#10020) +- Avoid `Assembly.GetName()` in `ClrFacade.GetAssemblies(string)` to reduce allocations of `CultureInfo` objects (#10024) (Thanks @iSazonov!) +- Avoid the `int[]` and `int[,]` allocation when tokenizing line comments and matching wildcard pattern (#10009) + +### Tools + +- Update change log generation tool to deal with private commits (#10096) +- Update `Start-PSBuild -Clean` logic of `git clean` to ignore locked files from `VS2019` (#10071) (Thanks @bergmeister!) +- Indent fix in `markdown-link.tests.ps1` (#10049) (Thanks @RDIL!) +- `Start-PSBuild -Clean` does not remove all untracked files (#10022) (Thanks @vexx32!) +- Add module to support Pester tests for automating debugger commands (`stepInto`, `stepOut`, etc.), along with basic tests (#9825) (Thanks @KirkMunro!) +- Remove `markdownlint` tests due to security issues (#10163) + +### Code Cleanup + +- Cleanup `CompiledScriptBlock.cs` (#9735) (Thanks @vexx32!) +- Cleanup workflow code (#9638) (Thanks @iSazonov!) +- Use `AddOrUpdate()` instead of `Remove` then `Add` to register runspace (#10007) (Thanks @iSazonov!) +- Suppress `PossibleIncorrectUsageOfAssignmentOperator` rule violation by adding extra parenthesis (#9460) (Thanks @xtqqczze!) +- Use `AddRange` in `GetModules()` (#9975) (Thanks @iSazonov!) +- Code cleanup: use `IndexOf(char)` overload (#9722) (Thanks @iSazonov!) +- Move `consts` and methods to single `CharExtensions` class (#9992) (Thanks @iSazonov!) +- Cleanup: Use `EndsWith(char)` and `StartsWith(char)` (#9994) (Thanks @iSazonov!) +- Remove `LCIDToLocaleName` `P/Invoke` from `GetComputerInfoCommand` (#9716) (Thanks @iSazonov!) +- Cleanup Parser tests (#9792) (Thanks @vexx32!) +- Remove `EtwActivity` empty constructor and make minor style fixes (#9958) (Thanks @RDIL!) +- Fix style issues from last commits (#9937) (Thanks @iSazonov!) +- Remove dead code about `IsTransparentProxy` (#9966) +- Fix minor typos in code comments (#9917) (Thanks @RDIL!) +- Style fixes for `CimAsyncOperations` (#9945) (Thanks @RDIL!) +- Fix minor `CodeFactor` style issues in `ModuleCmdletBase` (#9915) (Thanks @RDIL!) +- Clean up the use of `SetProfileRoot` and `StartProfile` in ConsoleHost (#9931) +- Fix minor style issues come from last commits (#9640) (Thanks @iSazonov!) +- Improve whitespace for Parser tests (#9806) (Thanks @vexx32!) +- Use new `string.ConCat()` in `Process.cs` (#9720) (Thanks @iSazonov!) +- Code Cleanup: Tidy up `scriptblock.cs` (#9732) (Thanks @vexx32!) + +### Tests + +- Mark `Set-Service` tests with password as `Pending` (#10146) +- Fix test password generation rule to meet Windows complexity requirements (#10143) +- Add test for `New-Item -Force` (#9971) (Thanks @robdy!) +- Fix gulp versions (#9916) (Thanks @RDIL!) +- Indentation fixes in `ci.psm1` (#9947) (Thanks @RDIL!) +- Remove some `Travis-CI` references (#9919) (Thanks @RDIL!) +- Improve release testing Docker images (#9942) (Thanks @RDIL!) +- Use `yarn` to install global tools (#9904) (Thanks @RDIL!) +- Attempt to work around the zip download issue in Azure DevOps Windows CI (#9911) +- Update PowerShell SDK version for hosting tests (Internal 9185) + +### Build and Packaging Improvements + +- Update the target framework for reference assemblies to `netcoreapp3.0` (#9747) +- Pin version of `netDumbster` to `2.0.0.4` (#9748) +- Fix daily `CodeCoverageAndTest` build by explicitly calling `Start-PSBootStrap` (#9724) +- Split the `fxdependent` package on Windows into two packages (#10134) +- Bump `System.Data.SqlClient` (#10109) +- Bump `System.Security.AccessControl` (#10100) +- Add performance tag to change log command (Internal) +- Upgrade .Net Core 3 SDK from `preview5` to `preview6` and related out of band `Nuget` packages from `2.1` to `3.0-preview6` (#9888) (Thanks @bergmeister!) +- Add to `/etc/shells` on macOS (#10066) +- Bump `Markdig.Signed` from `0.17.0` to `0.17.1` (#10062) +- Update copyright symbol for `NuGet` packages (#9936) +- Download latest version `(6.2.0)` of `PSDesiredStateConfiguration` `nuget` package. (#9932) +- Add automated `RPM` signing to release build (#10013) +- Bump `ThreadJob` from `1.1.2` to `2.0.1` in `/src/Modules` (#10003) +- Bump `PowerShellGet` from `2.1.4` to `2.2` in /src/Modules (#9933) (#10085) +- Bump `PackageManagement` from `1.4` to `1.4.3` in `/src/Modules` (#9820) (#9918) (#10084) +- Update to use `TSAv2` (#9914) +- Bump `NJsonSchema` from `9.14.1` to `10.0.21` (#9805) (#9843) (#9854) (#9862) (#9875) (#9885) (#9954) (#10017) +- Bump `System.Net.Http.WinHttpHandler` from `4.5.3` to `4.5.4` (#9786) +- Bump `Microsoft.ApplicationInsights` from `2.9.1` to `2.10.0` (#9757) +- Increase timeout of NuGet job to workaround build timeout (#9772) + +### Documentation and Help Content + +- Change log `6.1.4` (#9759) +- Change log for release `6.2.1` (#9760) +- Add quick steps for adding docs to cmdlets (#9978) +- Update readme `gitter` badge (#9920) (Thanks @RDIL!) +- Update `README` and `metadata.json` for `7.0.0-preview.1` release (#9767) + +## v7.0.0-preview.1 - 05/30/2019 + +### Breaking Changes + +- Disable the debugger when in system lock-down mode (#9645) +- Fix `Get-Module -FullyQualifiedName` option to work with paths (#9101) (Thanks @pougetat!) +- Fix `-NoEnumerate` behavior in `Write-Output` (#9069) (Thanks @vexx32!) +- Make command searcher treat wildcard as literal if target exists for execution (#9202) + +### Engine Updates and Fixes + +- Port PowerShell to .NET Core 3.0 (#9597) +- Make sure we always return an object in command searcher (#9623) +- Support line continuance with pipe at the start of a line (#8938) (Thanks @KirkMunro!) +- Add support for `ValidateRangeKind` to `ParameterMetadata.GetProxyAttributeData` (#9059) (Thanks @indented-automation!) +- Allow passing just a dash as an argument to a file via pwsh (#9479) +- Fix tab completion for functions (#9383) +- Reduce string allocation in console output code (#6882) (Thanks @iSazonov!) +- Fixing test run crash by not passing script block to the callback (#9298) +- Add Binary Parsing Support & Refactor `TryGetNumberValue` & `ScanNumberHelper` (#7993) (Thanks @vexx32!) +- Add PowerShell remoting enable/disable cmdlet warning messages (#9203) +- Add `xsd` for `cdxml` (#9177) +- Improve formatting performance by having better primitives on `PSObject` (#8785) (Thanks @powercode!) +- Improve type inference of array literals and foreach statement variables (#8100) (Thanks @SeeminglyScience!) +- Fix for `FormatTable` remote deserialization regression (#9116) +- Get `MethodInfo` from .NET public type with explicit parameter types (#9029) (Thanks @iSazonov!) +- Add retry logic to the operation that updates `powershell.config.json` (#8779) (Thanks @iSazonov!) +- Update the task-based `async` APIs added to PowerShell to return a Task object directly (#9079) +- Add 5 `InvokeAsync` overloads and `StopAsync` to the `PowerShell` type (#8056) (Thanks @KirkMunro!) +- Remove unused cached types (#9015) + +### General Cmdlet Updates and Fixes + +- Fix use of unicode ellipsis in `XML` for truncating error messages (#9589) +- Improve error message in FileSystemProvider when removing a folder containing hidden or read only files (#9551) (Thanks @iSazonov!) +- Enable recursion into `OneDrive` by not treating placeholders as symlinks (#9509) +- Change `MatchType` for `EnumerationOptions` to be `Win32` making this consistent with Windows PowerShell (#9529) +- Add Support for null Usernames in Web Cmdlet Basic Auth (#9536) (Thanks @markekraus!) +- Fix null reference when `Microsoft.PowerShell.Utility` is loaded as a `snapin` in hosting scenarios (#9404) +- Update width of `DateTime` to accommodate change in Japan `DateTime` format with new era starting 5/1/19 (#9503) +- Fix `Get-Runspace` runspace object format Type column (#9438) +- Return correct casing of filesystem path during normalization (#9250) +- Move warning message to `EndProcessing` so it only shows up once (#9385) +- Fix the platform check in `CimDSCParser.cs` (#9338) +- New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) +- Fix help paging issues on macOS/Linux and with custom pager that takes arguments (#9033) (Thanks @rkeithhill!) +- Add `QuoteFields` parameter to `ConvertTo-Csv` and `Export-Csv` (#9132) (Thanks @iSazonov!) +- Fix progress for Get-ComputerInfo (#9236) (Thanks @powercode!) +- Add `ItemSeparator` and `AltItemSeparator` properties in `ProviderInfo` (#8587) (Thanks @renehernandez!) +- Add timestamp to `pshost` trace listener (#9230) +- Implement `Get-Random -Count` without specifying an `InputObject` list (#9111) (Thanks @pougetat!) +- Enable `SecureString` cmdlets for non-Windows (#9199) +- Add Obsolete message to `Send-MailMessage` (#9178) +- Fix `Restart-Computer` to work on `localhost` when WinRM is not present (#9160) +- Make `Start-Job` throw terminating exception when `-RunAs32` is specified in 64-bit pwsh (#9143) +- Make `Start-Job` throw terminating error when PowerShell is being hosted (#9128) +- Made `-Subject` parameter of `Send-MailMessage` command no longer mandatory. (#8961) (Thanks @ece-jacob-scott!) +- Make `New-ModuleManifest` consistent with `Update-ModuleManifest` (#9104) (Thanks @pougetat!) +- Add support for empty `NoteProperty` in `Group-Object` (#9109) (Thanks @iSazonov!) +- Remove `Hardlink` from `Mode` property in default file system format (#8789) (Thanks @powercode!) +- Fixing issue with help progress with `Get-Help` not calling `Completed` (#8788) (Thanks @powercode!) +- Allow `Test-ModuleManifest` to work when `RootModule` has no file extension (#8687) (Thanks @pougetat!) +- Add `UseQuotes` parameter to `Export-Csv` and `ConvertTo-Csv` cmdlets (#8951) (Thanks @iSazonov!) +- Update version for `PowerShell.Native` and hosting tests (#8983) +- Refactor shuffle in `Get-Random` to save a full iteration of the objects. (#8969) (Thanks @st0le!) +- Suggest `-Id pid` for `Get-Process pid` (#8959) (Thanks @MohiTheFish!) + +### Code Cleanup + +- `Attributes.cs` - Style / Formatting Fixes (#9625) (Thanks @vexx32!) +- Remove Workflow from `PSSessionType` (#9618) (Thanks @iSazonov!) +- Update use of "PowerShell Core" to just "PowerShell" (#9513) +- Use `IPGlobalProperties` on all platforms for getting host name (#9530) (Thanks @iSazonov!) +- Remove `IsSymLink()` P/Invoke on Unix (#9534) (Thanks @iSazonov!) +- Cleanup unused P/Invokes on Unix (#9531) (Thanks @iSazonov!) +- Update use of `Windows PowerShell` to just `PowerShell` (#9508) +- Cleanup: sort `usings` (#9490) (Thanks @iSazonov!) +- Cleanup `Export-Command` from `AssemblyInfo` (#9455) (Thanks @iSazonov!) +- Run CodeFormatter for `System.Management.Automation` (#9402) (Thanks @iSazonov!) +- Run CodeFormatter with `BraceNewLine`,`UsingLocation`,`FormatDocument`,`NewLineAbove` rules (#9393) (Thanks @iSazonov!) +- Run CodeFormatter for `WSMan.Management` (#9400) (Thanks @iSazonov!) +- Run CodeFormatter for `WSMan.Runtime` (#9401) (Thanks @iSazonov!) +- Run CodeFormatter for `Security` module (#9399) (Thanks @iSazonov!) +- Run CodeFormatter for `MarkdownRender` (#9398) (Thanks @iSazonov!) +- Run CodeFormatter for `Eventing` (#9394) (Thanks @iSazonov!) +- Use `Environment.NewLine` for new lines in `ConsoleHost` code (#9392) (Thanks @iSazonov!) +- Run CodeFormatter for Diagnostics module (#9378) (Thanks @iSazonov!) +- Run CodeFormatter for `Microsoft.PowerShell.Commands.Management` (#9377) (Thanks @iSazonov!) +- Run CodeFormatter for Utility module (#9376) (Thanks @iSazonov!) +- Style: Match file name casings of C# source files for Utility commands (#9329) (Thanks @ThreeFive-O!) +- Update repo for Ubuntu 14.04 EOL (#9324) +- Cleanup: sort `usings` (#9283) (Thanks @iSazonov!) +- Fix StyleCop Hungarian Notation (#9281) (Thanks @iSazonov!) +- Style: Update StyleCop rules (#8500) +- Enhance the P/Invoke code for `LookupAccountSid` in `Process.cs` (#9197) (Thanks @iSazonov!) +- Fix coding style for `NewModuleManifestCommand` (#9134) (Thanks @pougetat!) +- Remove unused method `CredUIPromptForCredential` from `HostUtilities.cs` (#9220) (Thanks @iSazonov!) +- Remove non-existent paths from `.csproj` files (#9214) (Thanks @ThreeFive-O!) +- Typo in new parameter set (#9205) +- Minor `FileSystemProvider` cleanup (#9182) (Thanks @RDIL!) +- Cleanup style issues in `CoreAdapter` and `MshObject` (#9190) (Thanks @iSazonov!) +- Minor cleanups in `Process.cs` (#9195) (Thanks @iSazonov!) +- Refactor `ReadConsole` P/Invoke in `ConsoleHost` (#9165) (Thanks @iSazonov!) +- Clean up `Get-Random` cmdlet (#9133) (Thanks @pougetat!) +- Fix to not pass `StringBuilder` by reference (`out` or `ref`) in P/Invoke (#9066) (Thanks @iSazonov!) +- Update AppVeyor comments in `Implicit.Remoting.Tests.ps1` (#9020) (Thanks @RDIL!) +- Remove AppImage from tools (#9100) (Thanks @Geweldig!) +- Using supported syntax for restoring warnings - Visual Studio 2019 complains about enable. (#9107) (Thanks @powercode!) +- Use `Type.EmptyTypes` and `Array.Empty()` to replace our custom code of the same functionality (#9042) (Thanks @iSazonov!) +- Rename private methods in `MshCommandRuntime.cs` (#9074) (Thanks @vexx32!) +- Cleanup & update `ErrorRecord` class code style (#9021) (Thanks @vexx32!) +- Remove unused cached types from `CachedReflectionInfo` (#9019) (Thanks @iSazonov!) +- Fix CodeFactor brace style issues in `FileSystemProvider` (#8992) (Thanks @RDIL!) +- Use `List.AddRange` to optimize `-Split` (#9001) (Thanks @iSazonov!) +- Remove Arch Linux Dockerfile (#8990) (Thanks @RDIL!) +- Cleanup `dllimport` (#8847) (Thanks @iSazonov!) + +### Tools + +- Convert custom attribute `ValidatePathNotInSettings` to function (#9406) +- Create `DependaBot` `config.yml` (#9368) +- Add more users to failures detection and fix alias for static analysis (#9292) +- Make `install-powershell.ps1` work on Windows Server 2012 R2 (#9271) +- Enable `PoshChan` for getting and automatic retrieval of test failures for a PR (#9232) +- Fix capitalization cases for `PoshChan` (#9188) (Thanks @RDIL!) +- Update to new format for `PoshChan` settings and allow all users access to reminders (#9198) +- Fix settings to use dashes instead of underscore (#9167) +- Fix `AzDevOps` context names and add all PowerShell team members (#9164) +- Add settings for `PoshChan` (#9162) +- Adding `CmdletsToExport` and `AliasesToExport` to test module manifests. (#9108) (Thanks @powercode!) +- Delete Docker manifest creation script (#9076) (Thanks @RDIL!) +- Make install scripts more consistent over different operating systems (#9071) (Thanks @Geweldig!) +- Comment cleanup in `releaseTools.psm1` (#9064) (Thanks @RDIL!) +- Fix duplicate recommendation of Azure DevOps extension for Visual Studio Code (#9032) (Thanks @ThreeFive-O!) +- Code coverage artifacts (#8993) + +### Tests + +- Update version tests to use `NextReleaseVersion` from `metadata.json` (#9646) +- Convert Windows CI to stages (#9607) +- Multiple test fixes and improved logging for fragile tests (#9569) +- Add unit and feature tests for `Send-MailMessage` (#9213) (Thanks @ThreeFive-O!) +- Update to Pester `4.8.0` (#9510) +- Ensure `Wait-UntilTrue` returns `$true` in Pester tests (#9458) (Thanks @xtqqczze!) +- Adding tests for `Remove-Module` (#9276) (Thanks @pougetat!) +- Allow CI to run on branches with this name pattern: `feature*` (#9415) +- Mark tests in macOS CI which use `AppleScript` as pending/inconclusive (#9352) +- Reduce time for stack overflow test (#9302) +- Added more tests for `Import-Alias` by file regarding parsing difficult aliases strings (#9247) (Thanks @SytzeAndr!) +- Move from `npm` to `Yarn` for markdown tests (#9312) (Thanks @RDIL!) +- Only search for functions in Constrained Language help tests (#9301) +- Fix skipping of tests in `RemoteSession.Basic.Tests.ps1` (#9304) +- Make sure non-Windows CI fails when a test fails (#9303) +- Update tests to account for when `$PSHOME` is read only (#9279) +- Add tests for command globbing (#9180) +- Fix tab completion test to handle multiple matches (#8891) +- Refactor macOS CI so that tests run in parallel (#9056) +- Fix `Enter-PSHostProcess` tests flakiness (#9007) +- Add source for `Install-Package` to install `netDumbster` (#9081) +- Style fixes for `Select-Xml` tests (#9037) (Thanks @ThreeFive-O!) +- Enable cross-platform `Send-MailMessage` tests for CI (#8859) (Thanks @ThreeFive-O!) +- Added `RequireSudoOnUnix` tags to `PowerShellGet` tests and remove pending parameter (#8954) (Thanks @RDIL!) +- Style fixes for `ConvertTo-Xml` tests (#9036) (Thanks @ThreeFive-O!) +- Align name schemes for test files (#9034) (Thanks @ThreeFive-O!) +- Pending `NamedPipeConnectionInfo` test (#9003) (Thanks @iSazonov!) +- Add test for `-WhatIf` for `New-FileCatalog` (#8966) (Thanks @mjanko5!) + +### Build and Packaging Improvements + +- Fix the PowerShell version number in MSI packages (Internal 8547) +- Add cleanup before building test package (Internal 8529) +- Update version for SDK tests and `Microsoft.PowerShell.Native` package (Internal 8512) +- Update the target framework for reference assemblies to `netcoreapp3.0` (Internal 8510) +- Fix syncing modules from PowerShell gallery by normalizing version numbers (Internal 8504) +- Add `tsaVersion` property as `TsaV1` for compliance build phase (#9176) +- Add ability to cross compile (#9374) +- Add `AcessToken` variable to jobs that perform signing (#9351) +- Add CI for `install-powershell.sh` and Amazon Linux (#9314) +- Add component detection to all jobs (#8964) +- Add Preview assets for `MSIX` (#9375) +- Add secret scanning to CI (#9249) +- Build test packages for `windows`, `linux-x64`, `linux-arm`, `linux-arm64` and `macOS` (#9476) +- Bump `gulp` from `4.0.0` to `4.0.2` (#9441, #9544) +- Bump `Markdig.Signed` from `0.15.7` to `0.17.0` (#8981, #9579) +- Bump `Microsoft.CodeAnalysis.CSharp` from `2.10.0` to `3.1.0` (#9277, 9653) +- Bump `Microsoft.PowerShell.Native` from `6.2.0-rc.1` to `6.2.0` (#9200) +- Bump `Microsoft.Windows.Compatibility` from `2.0.1` to `2.1.1` (#9605) +- Bump `Newtonsoft.Json` from `12.0.1` to `12.0.2` (#9431, #9434) +- Bump `NJsonSchema` from `9.13.19` to `9.14.1` (#9044, #9136, #9166, #9172, #9184, #9196, #9265, #9349, #9388, #9421, #9429, #9478, #9523, #9616) +- Bump `PackageManagement` from `1.3.1` to `1.4` (#9567, #9650) +- Bump `PowerShellGet` from `2.0.4` to `2.1.4` in /src/Modules (#9110, #9145, #9600, #9691) +- Bump `PSReadLine` from `2.0.0-beta3` to `2.0.0-beta4` (#9554) +- Bump `SelfSignedCertificate` (#9055) +- Bump `System.Data.SqlClient` from `4.6.0` to `4.6.1` (#9601) +- Bump `System.Net.Http.WinHttpHandler` from `4.5.2` to `4.5.3` (#9333) +- Bump `Microsoft.PowerShell.Archive` from `1.2.2.0` to `1.2.3.0` (#9593) +- Check to be sure that the test result file has actual results before uploading (#9253) +- Clean up static analysis config (#9113) (Thanks @RDIL!) +- Create `codecoverage` and test packages for non-Windows (#9373) +- Create test package for macOS on release builds (#9344) +- Disable Homebrew analytics in macOS Azure DevOps builds (#9130) (Thanks @RDIL!) +- Enable building of `MSIX` package (#9289) +- Enable building on Kali Linux (#9471) +- Fix artifact Download issue in release build (#9095) +- Fix build order in `windows-daily` build (#9275) +- Fix dependencies of NuGet build to wait on `DEB` uploads to finish (#9118) +- Fix `MSI` Upgrade failure for preview builds (#9013) +- Fix publishing daily `nupkg` to MyGet (#9269) +- Fix the failed test and update `Publish-TestResults` to make Azure DevOps fail the task when any tests failed (#9457) +- Fix variable name in `windows-daily.yml` (#9274) +- Fixed Dockerfile syntax highlighting (#8991) (Thanks @RDIL!) +- Make `CodeCoverage` configuration build portable symbol files (#9346) +- Make Linux CI parallel (#9209) +- Move artifacts to artifact staging directory before uploading (#9273) +- Performance improvements for release build (#9179) +- Preserve user shortcuts pinned to TaskBar during MSI upgrade (#9305) (Thanks @bergmeister!) +- Publish global tool packages to `pwshtool` blob and bug fixes (#9163) +- Publish test package on release builds (#9063) +- Publish windows daily build to MyGet (#9288) +- Remove appveyor references from packaging tools (#9117) (Thanks @RDIL!) +- Remove code from `CI.psm1` to optionally run Feature tests (#9212) (Thanks @RDIL!) +- Remove duplicate `PoliCheck` task and pin to specific version (#9297) +- Run `Start-PSBootStrap` in Code Coverage build to install .NET SDK (#9690) +- Switch from `BMP` to `PNG` for graphical `MSI` installer assets (#9606) +- Translate Skipped the test results into something Azure DevOps does NOT understand (#9124) +- Update Markdown test dependencies (#9075) (Thanks @RDIL!) +- Update UML to represent SDK and Global tool builds (#8997) +- Use IL assemblies for NuGet packages to reduce size (#9171) + +### Documentation and Help Content + +- Add checkbox to PR checklist for experimental feature use (#9619) (Thanks @KirkMunro!) +- Updating committee membership (#9577) (Thanks @HemantMahawar!) +- Update `CODEOWNERS` file to reduce noise (#9547) +- add download link to `raspbian64` to readme (#9520) +- Update `Support_Question.md` (#9218) (Thanks @vexx32!) +- Fix version of `PowerShellGet` in changelog (#9335) +- Update release process template to clarify that most tasks are coordinated by the release pipeline (#9238) +- Fix several problems in `WritingPesterTests` guideline (#9078) (Thanks @ThreeFive-O!) +- Update `ChangeLog` for `6.2.0` (#9245) +- Update docs for `v6.2.0` (#9229) +- Update `feature-request` issue template to move instructions into comments. (#9187) (Thanks @mklement0!) +- Update link to Contributing guide to new `PowerShell-Doc` repo (#9090) (Thanks @iSazonov!) +- Correct punctuation in `README.md` (#9045) (Thanks @yashrajbharti!) +- Update Docker `README.md` (#9010) (Thanks @RDIL!) +- Update release process issue template (#9051) (Thanks @RDIL!) +- Documentation Cleanup (#8851) (Thanks @RDIL!) +- Update docs for `6.2.0-rc.1` release (#9022) +- Update release template (#8996) + +## v6.2.2 - 07/16/2019 + +### Breaking Changes + +- Disable `Enter-PSHostProcess` cmdlet when system in lock down mode (Internal 8969) + +### Engine Updates and Fixes + +- Create `JumpList` in STA thread as some COM APIs are strictly STA only to avoid sporadic CLR crashes (#10057, #9928) (Thanks @bergmeister!) + +### Build and Packaging Improvements + +- Update DotNet SDK and runtime framework version (Internal 9082, 9088, 9092) +- Make `Hashtable` case insensitivity test use current culture rather than shell to set culture (Internal 8529) +- Add automated RPM signing to release build (#10013) +- Update copyright symbol for NuGet packages (#9936) +- Bump `Microsoft.ApplicationInsights` from `2.9.1` to `2.10.0` (#9757) +- Switch from BMP to PNG for graphical MSI installer assets (#9606) +- Bump `System.Net.Http.WinHttpHandler` from `4.5.3` to `4.5.4` (#9789) +- Enable building of MSIX package (#9289, #9715) + +## v6.2.1 - 05/21/2019 + +### Engine Updates and Fixes + +- Re-enable tab completion for functions (#9383) +- Disable debugger in System Lock down mode (Internal 8428) + +### Code Cleanup + +- Update repo for Ubuntu 14.04 EOL (#9324) + +### Tests + +- Fix skipping of tests in `RemoteSession.Basic.Tests.ps1` (#9304) +- Update tests to account for when `$PSHOME` is read only (#9279) +- Mark tests in macOS CI which use `applescript` as pending/inconclusive (#9352) +- Make sure non-Windows CI fails when a test fails (#9303) + +### Build and Packaging Improvements + +- Partially revert "Fix the failed test and update `Publish-TestResults` to make `AzDO` fail the task when any tests failed (#9457)" +- Bump `Markdig.Signed` from `0.16.0` to `0.17.0` (#9595) +- Bump `Microsoft.PowerShell.Archive` from `1.2.2.0` to `1.2.3.0` in `/src/Modules` (#9594) +- Enable building on Kali Linux (#9471) +- Fix the failed test and update `Publish-TestResults` to make `AzDO` fail the task when any tests failed (#9457) +- Add Preview assets for `msix` (#9375) +- Create code coverage and test packages for non-windows (#9373) +- Fix publishing daily `nupkg` to MyGet (#9269) +- Bump `PackageManagement` from `1.3.1` to `1.3.2` in `/src/Modules` (#9568) +- Bump `NJsonSchema` from `9.13.27` to `9.13.37` (#9524) +- Bump `gulp` from `4.0.0` to `4.0.2` in `/test/common/markdown` (#9443) +- Bump `Newtonsoft.Json` from `12.0.1` to `12.0.2` (#9433) +- Bump `System.Net.Http.WinHttpHandler` from `4.5.2` to `4.5.3` (#9367) +- Add `AccessToken` variable to jobs that perform signing (#9351) +- Create test package for macOS on release builds (#9344) +- Add component detection to all jobs (#8964) +- Move artifacts to artifact staging directory before uploading (#9273) + +## v6.2.0 - 03/28/2019 + +### Breaking Changes + +- Fix `-NoEnumerate` behavior in `Write-Output` to be consistent with Windows PowerShell (#9069) (Thanks @vexx32!) + +### Engine Updates and Fixes + +- Add PowerShell remoting enable/disable cmdlet warning messages (#9203) +- Fix for `FormatTable` remote deserialization regression (#9116) +- Update the task-based `async` APIs added to PowerShell to return a Task object directly (#9079) +- Add 5 `InvokeAsync` overloads and `StopAsync` to the `PowerShell` type (#8056) (Thanks @KirkMunro!) + +### General Cmdlet Updates and Fixes + +- Enable `SecureString` cmdlets for non-Windows by storing the plain text (#9199) +- Add Obsolete message to `Send-MailMessage` (#9178) +- Fix `Restart-Computer` to work on `localhost` when WinRM is not present (#9160) +- Make `Start-Job` throw terminating error when PowerShell is being hosted (#9128) +- Update version for `PowerShell.Native` and hosting tests (#8983) + +### Tools + +- Adding `CmdletsToExport` and `AliasesToExport` to test module manifests. (#9108) (Thanks @powercode!) +- Comment cleanup in `releaseTools.psm1` (#9064) (Thanks @RDIL!) + +### Tests + +- Fix `Enter-PSHostProcess` tests flakiness (#9007) +- Add tests for command globbing (#9180) +- Add source for `Install-package` to install `netDumbster` (#9081) (Thanks @Geweldig!) +- Fix tab completion test to handle multiple matches (#8891) +- Refactor macOS and Linux CI so that tests run in parallel (#9056, #9209) +- Added `RequireSudoOnUnix` tags to `PowerShellGet` tests and remove `-pending` parameter (#8954) (Thanks @RDIL!) +- Pending `NamedPipeConnectionInfo` test (#9003) (Thanks @iSazonov!) +- Add test for `-WhatIf` for `New-FileCatalog` (#8966) (Thanks @mjanko5!) + +### Build and Packaging Improvements + +- Performance improvements for release build (#9179) +- Add `tsaVersion` property as `TsaV1` for compliance build phase (#9176) +- Publish global tool packages to `pwshtool` blob and bug fixes (#9163) +- Translate Skipped test results into something Azure DevOps does **not** understand (#9124) +- Disable Homebrew analytics in macOS VSTS builds (#9130) (Thanks @RDIL!) +- Remove AppVeyor references from packaging tools (#9117) (Thanks @RDIL!) +- Fixed Dockerfile syntax highlighting (#8991) (Thanks @RDIL!) +- Fix dependencies of NuGet build to wait on DEB uploads to finish (#9118) +- Fix artifact download issue in release build (#9095) +- Publish test package on release builds (#9063) +- Bump `Microsoft.PowerShell.Native` from `6.2.0-rc.1` to `6.2.0` (#9200) +- Bump `NJsonSchema` from `9.13.19` to `9.13.27` (#9044, #9136, #9166, #9172, #9184 #9196) +- Bump `PowerShellGet` from `2.0.4` to `2.1.2` in /src/Modules (#9110, #9145) +- Bump `SelfSignedCertificate` in `/test/tools/Modules` (#9055) + +### Documentation and Help Content + +- Update docs for `6.2.0-rc.1` release (#9022) + +## v6.2.0-rc.1 - 2019-03-05 + +### Breaking Changes + +- Make `Join-String -InputObject 1,2,3` result equal to `1,2,3 | Join-String` result (#8611) (Thanks @sethvs!) + +### Engine Updates and Fixes + +- Improve check for developer mode by checking minimum required build number (#8749) +- Simplify the declaration of new experimental features (#8726) +- Remove AMSI uninitialized assert and replace with call to uninitialized (#8713) +- Port Security bypass fixes from 6.1.3 (#8915) +- Enable discovering modules that have names same as a culture (e.g. `Az`) (#8777) +- Flatten interface hierarchy when generating properties that implement interface properties (#8382) (Thanks @IISResetMe!) +- Don't use Win32 native APIs on non-Windows for cryptography of secure string over remoting (#8746) +- Allow `.exe` files to be used as IL binary modules (#7281) +- Remove unused cached types (#9015) + +### Experimental Features + +- Add the experimental feature for creating `Temp:\` drive when `FileSystemProvider` initializes (#8696) +- Move `CommandNotFoundException` suggestion to an experimental feature (#8805) + +### General Cmdlet Updates and Fixes + +- Correctly Report impact level when `SupportsShouldProcess` is not set to 'true' (#8209) (Thanks @vexx32!) +- Fix Request Charset Issues in Web Cmdlets (#8742) (Thanks @markekraus!) +- Refactor `ConvertTo-Json` to expose `JsonObject.ConvertToJson` as a public API (#8682) +- Add `-CustomPipeName` to `pwsh` and `Enter-PSHostProcess` (#8889) +- Add configurable maximum depth in `ConvertFrom-Json` with `-Depth` (#8199) (Thanks @louistio!) +- Enable creating relative symbolic links on Windows with `New-Item` (#8783) +- Parse numeric strings as numbers again during conversions (#8681) (Thanks @vexx32!) +- Expose file attributes of `OneDrive` placeholders (#8745) (Thanks @sba923!) +- Enable `Write-Information` to accept `$null` (#8774) +- Adding parameter `ReplyTo` to `Send-MailMessage` (#8727) (Thanks @replicaJunction!) +- Fix `Get-Help` `PSTypeName` issue with `-Parameter` when only one parameter is declared (#8754) (Thanks @pougetat!) + +### Code Cleanup + +- Use HTTPS in URLs where available (#8622) (Thanks @xtqqczze!) +- Update code to use single method to check if path is UNC (#8680) +- Fix typo: `aganist` ➜ `against` (#8943) (Thanks @lupino3!) +- Use the `OperationCancellationException` to replace the `StoppingException` in `ConvertToJson` (#8920) +- Fix style issues in CSV cmdlets (#8894) (Thanks @iSazonov!) +- Fix `LGTM` issues (#8843) (Thanks @iSazonov!) +- Fix length check in `PSSnapinQualifiedName.GetInstance()` (#8837) (Thanks @hvitved!) +- Reduce string allocations when formatting file system objects. (#8831) (Thanks @powercode!) +- Fix many instances of CodeFactor style issue `A single-line comment must not be followed by a blank line` (#8825) (Thanks @RDIL!) +- Refactor `appveyor.psm1` to `ci.psm1` (#8733, #8854, #8709, #8756, #8867) (Thanks @RDIL!) +- Refactor `travis.ps1` into `ci.psm1` (#8822, #8888) (Thanks @RDIL!) +- Fix Markdown lint issues (#8929) +- Fix code-of-conduct linting (#8896) (Thanks @RDIL!) + +### Tools + +- Fix broken reference (#8753) (Thanks @RDIL!) +- Remove `GitKracken` files from `.gitignore` (#8743) (Thanks @RDIL!) +- Update path of `test\xUnit\xUnit.tests.csproj` in `PowerShell.sln` (#8730) (Thanks @markekraus!) +- Ignore files added by `SelfSignedCertificate` (#8728) (Thanks @markekraus!) +- Build Global tool for PowerShell and SDK container (#8984) +- Add Experimental Features to change log creation (#8827) +- Remove unneeded `Invoke-Expression` on unvalidated input (#8826) +- Update CLA pull request labeling info (#8820) (Thanks @RDIL!) +- Update some info in `md-link-checks` (#8757) (Thanks @RDIL!) + +### Tests + +- Fix `Enter-PSHostProcess` test to wait until runspace is ready before attempting to enter (#8725) +- Package validation tests updates (#8714) +- Make xUnit tests run sequentially to avoid race conditions caused by manipulating `powershell.config.json` in tests (#8945) +- Use verbatim string literals for paths (#8937) (Thanks @iSazonov!) +- Parallelize the Windows CI to enable us to run all tests all the time (#8868) +- Fixes for Scheduled release build (#8887) +- Remove references to uninitialized variable (#8849) +- Remove directory causing static analysis failure (#8812) +- Update Pester version to 4.4.4 (#8739) +- Change xUnit Runspace tests to run sequentially (#8796) +- Fix cleanup config files for the csharp xUnit tests (#8761) (Thanks @iSazonov!) +- Moved `fxdependent-dotnetsdk-latest/Dockerfile` (#8738) + +### Build and Packaging Improvements + +- Make every `csproj` files have its own folder (#8750) +- Update packaging script to build reference assembly targeting `netcoreapp2.1` and use actual `.csproj` files (#8729) +- Generate and deploy reference assembly for `Microsoft.PowerShell.Commands.Utility.dll` (#8716) +- Make test file result names unique (#8979) +- Add variable to control the version of the signing task we use (#8982) +- Publish test and code coverage artifacts for daily builds (#8955) +- Integrate building NuGet package in the coordinated build (#8947) +- Support release branches based on the forward slash separator (#8903) +- Port DotNet fixes from 6.1.3 (#8914) +- Start tracking release build information in an azure storage table (#8850) +- Make license a link in the MSI (#8846) +- Use `-ErrorAction Ignore` instead of `SilentlyContinue` with `Get-Command` in build.psm1 (#8832) +- Add `binskim` to coordinated build and increase timeout (#8834) +- Fix daily CI builds to publish tar package as artifacts (#8775) +- Add instrumentation for `Start-PSPackage` (#8811) +- Fix passing credential to the `SyncGalleryToAzArtifacts.psm1` script (#8808) +- Move Final artifacts from coordinated build to `finalResults` folder (#8806) +- Refactor coordinated release build (#8804) +- Add compliance to Coordinated build (#8798) +- Switch to 1.11 of FPM to fix FPM install issue (#8797) +- Update the coordinated build with framework dependent package for dotnet SDK (#8773) +- Fix MSI upgrade failure for preview builds (#9013) +- Build(deps): Bump `Microsoft.ApplicationInsights` from `2.8.1` to `2.9.1` (#8807,#8848) +- Build(deps): Bump `Microsoft.PowerShell.Native` (#8712) +- Build(deps): Bump `NJsonSchema` from `9.13.15` to `9.13.19` (#8732, #8747, #8881, #8952) +- Build(deps): Bump `PackageManagement` from `1.2.4` to `1.3.1` (#8800) +- Build(deps): Bump `XunitXml.TestLogger` from `2.0.0` to `2.1.26` (#8731) +- Build(deps): Bump `Markdig.Signed` from `0.15.7` to `0.16.0` (#8981) + +### Documentation and Help Content + +- Updating README.md for supported openSUSE version and updating link to OS versions supported by CoreFx (#8701) (Thanks @stknohg!) +- Add complete XML docs for `ConvertToJsonContext` constructors (#8737) +- Update README.md for ARM to include both 32-bit and 64-bit PS package links (#8677) (Thanks @slide!) +- Update issue templates with new supported values (#8718) (Thanks @RDIL!) +- Update maintainer docs about the CLA PR labels (#8734) (Thanks @RDIL!) +- Add Andrew to the maintainer list (#8722) +- Update release process template (#8711) +- Change label in doc issue template (#8895) (Thanks @iSazonov!) +- Update the `dir -recurse` example (#8939) (Thanks @vmsilvamolina!) +- Update CHANGELOG for release `6.1.3` (#8918) +- Update stable version to `6.1.3` (#8902) +- Fix broken link (#8905) +- Update Coding Guidelines (#8844) (Thanks @iSazonov!) +- Update governance documentation (#8776) (Thanks @RDIL!) +- Fix broken python method (#8821) (Thanks @RDIL!) +- Changing docs issue template to new docs repo location (#8818) +- Fix spelling in `releaseTool/README.md` (#8810) +- Update GitHub templates (#8792) (Thanks @iSazonov!) +- Fix broken link in `FAQs.md` (#8803) +- Updated `basics.md` to add a link for showing example for installing git on all package managers (#8735) (Thanks @RDIL!) +- Update `README.md` for `preview.4` (#8772) + +## v6.2.0-preview.4 - 2019-01-28 + +### Breaking Changes + +- Add `-Stable` to `Sort-Object` and related tests (#7862) (Thanks @KirkMunro!) +- Improve `Start-Sleep` cmdlet to accept fractional seconds (#8537) (Thanks @Prototyyppi!) +- Change hashtable to use `OrdinalIgnoreCase` to be case-insensitive in all Cultures (#8566) +- Fix `LiteralPath` in `Import-Csv` to bind to `Get-ChildItem` output (#8277) (Thanks @iSazonov!) + +### Engine Updates and Fixes + +- Allow user-specified underlying type for enums (#8329) (Thanks @IISResetMe!) +- Handle case where AppLocker test script fails to delete (#8627) +- Update `CommandNotFound` fuzzy suggestion to only return unique results (#8640) +- Add support to show suggestions on `CommandNotFound` exception (#8458) +- Make `S.M.A.PowerShell.GetSteppablePipeline` method public (#8055) (Thanks @KirkMunro!) +- Add `S.M.A.PowerShell.Create` method overload with Runspace argument (#8057) (Thanks @KirkMunro!) +- Fix mistake on deserialization (#8502) +- Fix formatting of header of table when center aligned (#8497) +- Add `-RepeatHeader` to `Format-Table` to enable repeating header for each screen full (#8481) +- Fix `Debug-Runspace` for Unix platforms and properly enable Windows identity impersonation code (#8451) +- Reset output attributes if column had `ESC` char when using `Format-Table`; Replace `...` with unicode ellipsis (#8326) + +### Experimental Features + +- Add the experimental feature `PSUseAbbreviationExpansion` to support tab completion on abbreviated command names (#8109) + +### General Cmdlet Updates and Fixes + +- Fix code page parsing issue in `Invoke-RestMethod` (#8694) (Thanks @markekraus!) +- Fix `Expect 100-continue` issue with Web Cmdlets (#8679) (Thanks @markekraus!) +- Allow 'name' as an alias key for 'label' in `ConvertTo-Html`, allow the 'width' entry to be an integer (#8426) (Thanks @mklement0!) +- Resolve `:PAGER` if its path contains spaces (#8571) (Thanks @pougetat!) +- Add support enum and char types in `Format-Hex` cmdlet (#8191) (Thanks @iSazonov!) +- Change `Get-Help` cmdlet `-Parameter` parameter so it accepts string arrays (#8454) (Thanks @sethvs!) +- Fix `FixupFileName` to not load resolved assembly during module discovery (#8634) +- Change `Clear-Host` back to using `$RAWUI` and `clear` to work over remoting (#8609) +- Fix `LiteralPath` in `Import-Csv` to bind to `Get-ChildItem` output (#8277) (Thanks @iSazonov!) +- Make scriptblock based calculated properties work again in `ConvertTo-Html` (#8427) (Thanks @mklement0!) +- Fix `Join-String` cmdlet `FormatString` parameter logic (#8449) (Thanks @sethvs!) +- Allow Windows users in developer mode to create symlinks without elevation (#8534) +- `Help` function should only pass content to pager if content was found (#8528) +- Change `Clear-Host` to simply called `[console]::clear` and remove `clear` alias from Unix (#8603) +- `help` function shouldn't use pager for `AliasHelpInfo` (#8552) +- Fix XML nesting bug in `CustomSerializer.WriteMemberInfoCollection()` (#8476) (Thanks @IISResetMe!) +- Add `-UseMinimalHeader` to `Start-Transcript` to minimize transcript header (#8402) (Thanks @lukexjeremy!) + +### Code Cleanup + +- Remove the no longer used `RunspaceConfigurationEntry` types (#8424) +- Remove unneeded catch/throw from `mkdir` and `oss` functions (#8425) +- Remove comments after closing brackets (#8344) (Thanks @Meir017!) +- Cleanup `Format-Hex` (#8683) (Thanks @vexx32!) +- Delete `appveyor.yml` (#8639) (Thanks @RDIL!) +- Revise use of `Start-Sleep` cmdlet (#8633) (Thanks @xtqqczze!) +- Style: Change first char to upper in summary comments (#8597) (Thanks @iSazonov!) +- Style: Use the type aliases `char` and `bool` instead of `Char` and `Boolean` (#8572) (Thanks @iSazonov!) +- Style: Use the type alias `string` instead of `String` in places that are appropriate (#8573) (Thanks @iSazonov!) +- Correctly capitalize the `ForEach` operator in `*.ps1` (#8583) (Thanks @xtqqczze!) +- Remove unnecessary trim of passed-in command line in interactive debugging (#8594) +- Style: Add a space after "//" in comments and remove unneeded comments after "}" (#8576) (Thanks @iSazonov!) +- Style: Add the ending period to the XML document texts (#8577) (Thanks @iSazonov!) +- Avoid use of `mkdir` alias in `*.ps1` and `*.psm1` (#8582) (Thanks @xtqqczze!) +- Regularize redirection operator spacing in `*.ps1` and `*.psm1` (#8581) (Thanks @xtqqczze!) +- Style: Change 'String.' to 'string.' (#8568) (Thanks @iSazonov!) +- Style: Replace `String.IsNullOrEmpty` with `string.IsNullOrEmpty` (#8557) (Thanks @iSazonov!) +- Fix typo in AMSI test (#8561) (Thanks @iSazonov!) +- Style: Convert to upper first char in `` and `` doc tags (#8556) (Thanks @iSazonov!) +- Style: Add period before `` and `` doc tags (#8553) (Thanks @iSazonov!) +- Remove use of cmdlet aliases from `.\test\powershell` (#8546) (Thanks @xtqqczze!) +- Style: Remove extra spaces after `` and before `` docs tags (#8547) (Thanks @iSazonov!) +- Style: Remove preceding spaces from C# `preprocessor-type` keywords (#8540) (Thanks @xtqqczze!) +- Style: remove ` ` (#8538) (Thanks @iSazonov!) +- Style: Add period before returns doc tag (#8535) (Thanks @iSazonov!) +- Style: Change `Object[]` to `object[]` (#8526) (Thanks @iSazonov!) +- Style: Change `Object` to `object` (#8522) (Thanks @iSazonov!) +- Style: Change `UInt64?` to `ulong?` (#8527) (Thanks @iSazonov!) +- Style: Change `Byte{}` to `byte[]` (#8525) (Thanks @iSazonov!) +- Code cleanup: Add space after closing brace where needed (#8530) +- Style: Change `System.Boolean` to `bool` (#8521) (Thanks @iSazonov!) +- Change `String` to `string` for simple references (#8519) +- Change `Int32` to `int` for simple references in variable declaration (#8518) +- Style: Member access symbols should be followed with member name (#8517) +- Style: Remove extra space before colon in named parameters (#8504) +- Style: Use the shorthand of the `nullable` type (#8501) +- Remove empty lines; correct space on closing square brackets, negative signs, and generic brackets (#8508) +- Remove space after new keyword in implicitly typed array allocation (#8505) +- The static keyword should be right after access modifier (#8506) +- Remove comments after closing bracket (#8503) +- Remove space character after `'!'` (#8507) +- Style: Remove extra space before colon in named parameters (#8504) + +### Tools + +- Recommend Azure DevOps extension inside VS-Code for better `YAML` editing. (#8403) (Thanks @bergmeister!) +- `-AddToPath` re-implementation in `install-powershell.ps1` (#8081) (Thanks @glachancecmaisonneuve!) +- Change the feed `URL` to feed name due to changes in `AzDevOps` (#8664) +- Batch merge builds together while a merge build is running (#8668) +- Fix grammar in stale bot message (#8660) (Thanks @RDIL!) +- Add macOS files to `.gitignore` (#8456) (Thanks @RDIL!) +- Name the spelling yaml something more appropriate (#8601) (Thanks @RDIL!) +- Add script to create `icns` files. (#7456) (Thanks @thezim!) +- Pass `nugetkey` as parameter (#8461) +- Add `gitkracken` files to `gitignore` (#8434) (Thanks @RDIL!) +- Create release process issue template (#8417) +- Support for `linuxmint` in `installpsh-debian.sh` (#8440) (Thanks @DarwinJS!) +- Enable `install-powershell.ps1` to use `MSI` (#8418) + +### Tests + +- Remove broken `HelpUri` from `CimTest` (#8688) (Thanks @xtqqczze!) +- Remove appveyor environment checks (#8669) (Thanks @RDIL!) +- Adding tests for `PSDiagnostics Module` (#8431) (Thanks @kvprasoon!) +- Increase diagnose-ability of Link Checker failures (#8667) +- Fix broken urls (#8653) +- Update fuzzy test to fix daily build (#8629) +- Create link check task (#8471) (Thanks @RDIL!) +- Add Tests for `ConfirmImpact` Ratings (#8214) (Thanks @vexx32!) +- Fix style issues in xUnit tests (#8465) (Thanks @iSazonov!) +- Move `xUnit` tests in new folder (#8356) (Thanks @iSazonov!) +- Fix environment variable test and add missing null check in `CommandHelpProvider` (#8408) +- Remove `dotnet` dependency to start WebListener (#8390) + +### Build and Packaging Improvements + +- Update Third Party Notices (#8415) +- Adding yaml for Windows Release builds (#8374) +- Bump `NJsonSchema` from `9.13.1` to `9.13.2` (#8422) +- Do not ship fullclr binaries of `PackageManagement` (#8700) (Thanks @bergmeister!) +- Fix the build for `fxdependent` build for `dotnet sdk` (#8670) +- Add Windows build to universal release build YAML (#8695) +- Remove `Debian 8` references as it is EOL (#8678) +- Build(deps): Bump `NJsonSchema` from `9.13.14` to `9.13.15` (#8671) +- Build package build using ubuntu 18.04 image (#8666) +- Fix a typo in `packaging.psm1` (#8647) (Thanks @sethvs!) +- Add function to create a framework dependent package `dotnet-sdk` containers (#8644) +- Build(deps): Bump `NJsonSchema` from `9.13.13` to `9.13.14` (#8648) +- Build(deps): Bump `PowerShellGet` from `2.0.3` to `2.0.4` (#8649) +- Fix installing `fpm` and `ronn` in macOS CI by avoid installing docs for them (#8656) +- Build(deps): Bump `Markdig.Signed` from `0.15.6` to `0.15.7` (#8637) +- Build(deps): Bump `System.Security.Cryptography.Pkcs` from `4.5.1` to `4.5.2` (#8614) +- Build(deps): Bump `System.Net.Http.WinHttpHandler` from `4.5.1` to `4.5.2` (#8615) +- Build(deps): Bump `NJsonSchema` from `9.13.11` to `9.13.13` (#8616) +- Build(deps): Bump `System.Text.Encoding.CodePages` from `4.5.0` to `4.5.1` (#8613) +- Enable install of Preview MSI release side-by-side with Stable release (#8513) +- Get macOS to publish daily build to nugetfeed (#8464) +- Build(deps): Bump `Markdig.Signed` from `0.15.5` to `0.15.6` (#8558) +- Build(deps): Bump `NJsonSchema` from `9.13.10` to `9.13.11` (#8569) +- Remove duplicate `Open Here` context menu item upgrading to newer Preview release (#8496) +- Bump `NJsonSchema` from `9.13.9` to `9.13.10` (#8511) +- Bump `NJsonSchema` from `9.13.7` to `9.13.9` (#8498) +- Bump `NJsonSchema` from `9.13.4` to `9.13.7` (#8493) +- Bump `NJsonSchema` from `9.13.3` to `9.13.4` (#8462) +- Fix daily NuGet publishing (#8460) +- Bump `NJsonSchema` from `9.13.2` to `9.13.3` (#8457) +- Bump `Markdig.Signed` from `0.15.4` to `0.15.5` (#8444) + +### Documentation and Help Content + +- Remove unused `AppVeyor` links from `README.md` (#8685) (Thanks @RDIL!) +- Update `README.md` (#8684) +- Update Package Management license to MIT (#8676) (Thanks @RDIL!) +- Create Support File (#8618) (Thanks @RDIL!) +- Update git clone URL (#8673) (Thanks @RDIL!) +- docs(contributing): add link check information (#8659) (Thanks @RDIL!) +- Update License and Third Party Notice (#8646) +- Update README, `metadata.json` and changelog for release `6.1.2` (#8658) +- Fix typo in `README.md` (#8642) (Thanks @MarkTiedemann!) +- Fix some typos in the README (#8623) (Thanks @RDIL!) +- Remove `en-us` from `docs.microsoft.com` URL (#8628) (Thanks @xtqqczze!) +- Update examples for hosting PSCore and remove old outdated examples (#8472) (Thanks @bergmeister!) +- Update the pull request template (#8624) (Thanks @RDIL!) +- Contributing guidelines: Remove references to Travis CI and AppVeyor (#8617) (Thanks @RDIL!) +- Update code coverage analysis document (#8543) (Thanks @xtqqczze!) +- Remove `en-us` from our doc links (#8602) +- Document `First-time-issue` and `Hackathon`/`Hacktoberfest` labels (#8575) +- Updated linux build link (#8579) (Thanks @jwmoss!) +- Update contributing guidelines doc to run spellchecking in English (#8473) (Thanks @RDIL!) +- Updating links to point to new VS Code docs (#8468) + +## v6.2.0-preview.3 - 2018-12-10 + +### Breaking Changes + +- `Get-ExperimentalFeature` no longer has `-ListAvailable` switch (#8318) +- `Debug` parameter now sets `DebugPreference` to `Continue` instead of `Inquire` (#8195) (Thanks @KirkMunro!) + +### Engine Updates and Fixes + +- Improve PowerShell startup time by 24% (#8341) (#8396) +- Remove extra newlines from formatting which resulted in unnecessary double newlines (#8247) +- Add `Enable-ExperimentalFeature` and `Disable-ExperimentalFeature` cmdlets (#8318) +- Fix `Export-ModuleMember` bug for a `ScriptBlock` having no context (#8363) +- Fix race condition to access `powershell.config.json` (#8249) (Thanks @iSazonov!) +- Add `SkipCA` and `SkipCN` check requirement to WinRM/OMI HTTPS connection (#8279) +- Add fix for `Start-Job` initialization script which should not be executed as trusted in system lockdown (#8284) + +### General Cmdlet Updates and Fixes + +- Add `Enable-ExperimentalFeature` and `Disable-ExperimentalFeature` cmdlets (#8318) +- Add cmdlet `Join-String` for creating text from pipeline input (#7660) (Thanks @powercode!) +- Expose all cmdlets from `PSDiagnostics` if `logman.exe` is available (#8366) +- Fix `Get-Help` for advanced functions with MAML help content (#8353) +- Conditionally mark getter/setter implementations as virtual in generated classes (#8303) (Thanks @IISResetMe!) +- Fix for `PSDrive` creation with a UNC path with a trailing backslash or forward slash when combined with `-Persist` (#8305) (Thanks @kvprasoon!) +- Remove `Persist` parameter from `New-PSDrive` on non-Windows platform (#8291) (Thanks @lukexjeremy!) +- `Test-Path`: Return `$false` when given an empty or `$null` `-Path`/`-LiteralPath` value (#8080) (Thanks @vexx32!) +- Token calculation fix for `Get-Help` executed on `ScriptBlock` for comment help. (#8238) (Thanks @hubuk!) +- Support `Get-PSHostProcessInfo` and `Enter-PSHostProcess` on Unix platforms (#8232) + +### Code Cleanup + +- Update `resgen`, `typegen` to use .Net Core 2.1 (#8369) (Thanks @bergmeister!) +- Change `Newtonsoft` deserializing bug comment to link to the new issue (#8377) (Thanks @louistio!) +- Cleanup `#if !CORECLR` code (#8337) (Thanks @iSazonov!) +- Cleanup `UpdatableHelpSystem` and enable XSD validation on MAML help content (#8335) (Thanks @iSazonov!) +- Remove old `customPSSnapInType` parameter from `PSSnapInInfo()` (#8333) (Thanks @iSazonov!) +- Cleanup `#if CORECLR` from some files (#8332) (Thanks @iSazonov!) +- Cleanup `AssemblyInfo` (#8190) (Thanks @iSazonov!) +- Fix `GetLocationCommand` output type parameter set and style issues (#8324) (Thanks @Meir017!) + +### Tools + +- Remove `dependabot` attribution and generate changelog sections using `CL-*` labels (#8386) + +### Tests + +- Update folder path for storing optimization profile and add test to validate loaded assemblies and libraries on startup (#8406) +- Fix an intermittent failure in macOS logging tests (#8385) +- Created a `csproj` to pin test modules and updated `build.psm1` accordingly (#8350) +- Update help content for `TabCompletion` tests only if it does not exist (#8355) +- Skip `Enter-PSHostProcess` tests on `AppVeyor` due to `PSReadline` issue (#8317) + +### Build and Packaging Improvements + +- Remove `AmazonLinux` Dockerfile (#8271) (Thanks @kiazhi!) +- Make `install-powershell.sh` auto-detect if it should use `wget` or `curl` (#8225) (Thanks @DarwinJS!) +- Bump `NJsonSchema` from `9.12.2` to `9.13.1` (#8319) (#8328) (#8412) (#8371) (#8384) +- Bump `Microsoft.PowerShell.Native` from `6.2.0-preview.2` to `6.2.0-preview.3` (#8411) +- Update the name of the artifact to be unique per artifact (#8405) +- Create unified release build for macOS and Linux packages (#8399) +- Add Linux `ARM64` build support (#8016) (Thanks @slide!) +- Update the timeout of CI builds (#8398) +- Bump `PackageManagement` from `1.2.2` to `1.2.4` in `/src/Modules` (#8320) (#8383) +- Bump `Newtonsoft.Json` from `11.0.2` to `12.0.1` (#8348) +- Enable pipeline to sync `PSGallery` modules to `AzArtifacts` feed (#8316) +- Build Alpine `tar.gz` package in release builds (#8340) +- Publish test package to `AppVeyor` daily build (#8273) +- Bump `Microsoft.CodeAnalysis.CSharp` from `2.9.0` to `2.10.0` (#8294) +- Bump `PowerShellGet` from `2.0.1` to `2.0.3` in `/src/Modules` (#8321) +- Enable `Open Here` context menu on Windows to work with root of a drive (#8287) +- Bump `System.Data.SqlClient` from `4.5.1` to `4.6.0` (#8266) + +### Documentation and Help Content + +- Merge `changelogs` from `6.1.1` and `6.0.5` into master (#8283) +- Remove all reference to `AppVeyor` and `Travis CI` from docs (#8376) +- Change default issue template to use different categories (#8203) + +## v6.2.0-preview.2 - 2018-11-15 + +### Breaking Changes + +- Honor `-OutputFormat` if specified in non-interactive, redirected, encoded command used with `pwsh` (#8115) +- Load assembly from module base path before trying to load from the `GAC` (#8073) +- Remove tilde from Linux preview packages (#8244) +- Move processing of `-WorkingDirectory` before processing of profiles (#8079) + +### Known Issues + +- PowerShell WSMan remoting does not work on Debian 9 due to missing symbolic links. + For more information and a workaround see issue [#7598](https://github.com/PowerShell/PowerShell/issues/7598) + +### Engine Updates and Fixes + +- Enable case-insensitive tab completion for files and folders on case-sensitive filesystem (#8128) +- Experimental feature: Implicit remoting batching performance improvements (#8038) +- Add a path for checking `ZoneInformation` without throwing an exception (#8025) (Thanks @powercode!) +- Fix [CVE-2018-8256](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8256), + issues with expanding `ZIP` files with relative paths (#8252) +- Fix [CVE-2018-8415](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8415), + issue logging when the `scriptblock` has a null character (#8253) +- Make `PSVersionInfo.PSVersion` and `PSVersionInfo.PSEdition` public (#8054) (Thanks @KirkMunro!) +- Enable distinct `ModuleAnalysisCache` files for each installation of `pwsh` (#8174) +- Consolidation of all Windows PowerShell work ported to PowerShell Core (#8257) +- Fix incorrect name check when auto-loading required modules (#8218) +- Adding verbose output for experimental implicit remoting batching feature (#8166) +- Add Type Inference for `$_ / $PSItem in catch{ }` blocks (#8020) (Thanks @vexx32!) +- Fix static method invocation type inference (#8018) (Thanks @SeeminglyScience!) + +### General Cmdlet Updates and Fixes + +- Reduce allocations in `Get-Content` cmdlet (#8103) (Thanks @iSazonov!) +- Enable `Set-Location -LiteralPath` to work with folders named `-` and `+` (#8089) +- Enable `Add-Content` to share read access with other tools while writing content (#8091) +- Add new `Offset` and `Count` parameters to `Format-Hex` and refactor the cmdlet (#7877) (Thanks @iSazonov!) +- Add `-Name`, `-NoUserOverrides` and `-ListAvailable` parameters to `Get-Culture` cmdlet (#7702) (Thanks @iSazonov!) +- Allow dynamic parameter to be returned even if path does not match any provider (#7957) +- Style fixes in `Format-Hex` (#8083) (Thanks @iSazonov!) +- Fix logic to rely on PowerShell major and minor version instead of build number to determine whether to output `formatdata` (#8063) +- Fix `Rename-Item -Path` with wildcard `char` (#7398) (Thanks @kwkam!) +- When using `Start-Transcript` and file exists, empty file rather than deleting (#8131) (Thanks @paalbra!) +- Error message enhancement for `Clear-Content` cmdlet when targeting a directory (#8134) (Thanks @kvprasoon!) +- Make `Select-String` faster by not doing extra work (#7673) (Thanks @powercode!) +- Remove `ShouldProcess` from `Format-Hex` (#8178) + +### Code Cleanup + +- Remove clone of command-line arguments array (#7910) (Thanks @iSazonov!) +- Use `DefaultPathSeparator` `char` instead of `DefaultPathSeparatorString` (#8082) (Thanks @iSazonov!) +- Replace `StringComparision.CurrentCulture` with `StringComparision.Ordinal` (#8068) (Thanks @iSazonov!) +- Fix typo in `-icontains` description from `incase sensitive` to `case insensitive` (#7840) (Thanks @StingyJack!) +- Refactor module version/`GUID` comparison logic (#7125) + +### Tools + +- Update `installpsh-amazonlinux.sh` for container specific issues (#7907) (Thanks @DarwinJS!) +- Update the `codeowners` file (#8017) + +### Tests + +- Filter the `TestPackage` artifact upload by name to avoid other `ZIP` files being uploaded (#8116) +- Adding `fxdependent` PowerShell package tests (#7830) +- Fix Windows Feature tests running in Azure DevOps (#8220) +- Create `$PROFILE` if it does not exist for `-WorkingDirectory` processing test (#8152) +- Add test coverage for additional `Get-Module` parameters (#8137) (Thanks @KevinMarquette!) +- Fix conflict with `Get-AdlStoreChildItem` from `az` module in tab completion tests (#8167) +- Fix static secret in code (#8186) + +### Build and Packaging Improvements + +- Bump `xunit.runner.visualstudio` from `2.4.0` to `2.4.1` (#8139) +- Bump `xunit` from `2.4.0` to `2.4.1` (#8140) +- Bump `Microsoft.ApplicationInsights` from `2.8.0` to `2.8.1` (#8104) +- Bump `NJsonSchema` from `9.11.1` to `9.12.1` (#8183, #8248) +- Fix `Start-PSBuild -Output` (#7504) (Thanks @kwkam!) +- Adding `YML` for Linux builds (#8168) +- Publish test package at `AGENT_WORKFOLDER` if `TEMP` is not available (#8108) +- Fix `psmodulerestore` path when built in Visual Studio Code (#8075) +- Use approved verb instead of `Generate-CrossGenAssembly` (#8151) (Thanks @kvprasoon!) +- Add path filters to CI `YAML` (#8222) +- Update `SignType` in `signing.xml` (#8223) +- Update metadata for `6.0.5` and `6.1.1` releases (#8259) +- Port changes to allow Azure DevOps NuGet feeds for Mac build (Internal 5818) +- Update version for dependencies (Internal 5822) +- Add code to use private NuGet feeds when running in internal CI system (#8187) +- Add title to `Open Here` window for `MSI` installer (#8164) +- Remove build and documentation references to `git` submodules (#8177) (Thanks @andschwa!) +- Add function to create a new `nuget.config` file (#8170) +- Update macOS release build to create the `nuget.config` (#8185) +- Workaround for accessing Azure Artifacts (#8188) +- Fix script path for `PowerShellPackageVsts.ps1` (#8189) +- `Microsoft.PowerShell.Native` now has `MUSL` binaries for Alpine. + +### Documentation and Help Content + +- Fix grammar in `README.md` (#8059) (Thanks @daviddreher2!) +- Update `powershell-beginners-guide.md` to add alias for `Clear-Host` (#7912) (Thanks @aavdberg!) +- Add Microsoft Docs link to FAQ (#8133) (Thanks @vongrippen!) +- Added updated photo of Visual Studio Code due to new version of Code (#8084) (Thanks @lassehastrup!) +- Update `license.rtf` to only have major version (#8127) +- Updated Pester Syntax in Writing Tests Guide (#8039) (Thanks @markwragg!) +- Remove duplicate parts from license file (#8143) (Thanks @azkarmoulana!) +- Fix spellings in `CHANGELOG.md` (#8062) +- Update license RTF to 6.2 (#8065) +- Combine notes about `ITuple` changes in Change Log (#8077) (Thanks @Jocapear!) +- Correct typos in `powershell-beginners-guide.md` (#8088) (Thanks @nycjan!) +- Added `Learn Windows PowerShell in a Month of Lunches` as recommended reading (#8067) (Thanks @tobvil!) +- Update `README.md` for `v6.1.1` (#8255) +- Fix some typos (#8206) (Thanks @jeis2497052!) +- Promote `HTTPS` (#8160) (Thanks @RDIL!) +- Simple grammatical correction in `README.md` file (#7978) (Thanks @iGotenz!) +- Update URLs to use `HTTPS` instead of `HTTP` in the documentation (#8165) (Thanks @RDIL!) +- Remove #7633 from `v6.2.0-preview.1` `CHANGELOG.md` updates. (#8101) (Thanks @stknohg!) + +## v6.2.0-preview.1 - 2018-10-18 + +### Breaking Changes + +- Do not add `PATHEXT` environment variable on Unix (#7697) (Thanks @iSazonov!) + +### Known Issues + +- Remoting on Windows IOT ARM platforms has an issue loading modules. See [#8053](https://github.com/PowerShell/PowerShell/issues/8053) + +### Engine Updates and Fixes + +- Add C# style type accelerators and suffixes for `ushort`, `uint`, `ulong`, and `short` literals (#7813) (Thanks @vexx32!) +- Create inferred types for `Select-Object`, `Group-Object`, `PSObject` and `Hashtable` (#7231) (Thanks @powercode!) +- Fix .NET adapter to be able to get members from `System.IntPtr` (#7808) +- Fix .NET adapter to not throw when fails to create a `PSMethod` due to `ByRef-like` type (#7788) +- Support calling method with `ByRef-like` type parameters (#7721) +- Fix perf issue in provider by using `Refresh()` to update the status rather than instantiating `ServiceController` which has a significant perf degradation from .NET Framework (#7680) +- Update PowerShell to handle the case where the Windows PowerShell module path is already in the environment's `PSModulePath` (#7727) +- Ensure the `SSHClientSessionTransportManager` stream writer and reader fields are cleared after dispose. (#7746) +- Add unified attribute for completion for `Encoding` parameter. (#7732) (Thanks @ThreeFive-O!) +- Add support for Byte Literals (#7901) (Thanks @vexx32!) +- Fix Property and `ScriptBlock` expressions in `EntrySelectedBy` tags within custom controls (#7913) (Thanks @SeeminglyScience!) +- Fix `BeginInvoke`/`EndInvoke` to return results when `Stop` or `BeginStop`/`EndStop` was called previously (#7917) +- Allow root node of `format.ps1xml` to have attributes that are ignored (#7987) +- Use non-virtual call to invoke 'family or assembly' methods on base class from PowerShell class (#7622) (#7624) (Thanks @yurko7!) +- Make the parameter to `ImportPSModule` use `params` so that it is easier to call (#7933) (Thanks @iSazonov!) + +### General Cmdlet Updates and Fixes + +- Add `EscapeHandling` parameter in `ConvertTo-Json` cmdlet (#7775) (Thanks @iSazonov!) +- Make `Add-Type` open source files with `FileAccess.Read` and `FileShare.Read` explicitly (#7915) (Thanks @IISResetMe!) +- No longer skips a column without name if double quote delimiter is used in `Import-Csv` (#7899) (Thanks @Topping!) +- Add support for `cd +` (#7206) (Thanks @bergmeister!) +- Allow numeric Ids and name of registered code pages in `-Encoding` parameters (#7636) (Thanks @iSazonov!) +- Remove extra space in `LastWriteTime` format (#7810) (Thanks @iSazonov!) +- Fix `Enter-PSSession -ContainerId` for the latest Windows (#7883) +- `Get/Add-Content` throws improved error when targeting a container (#7823) (Thanks @kvprasoon!) +- Ensure `NestedModules` property gets populated by `Test-ModuleManifest` (#7859) +- Add `%F` case to `Get-Date -UFormat` (#7630) (Thanks @britishben!) +- Fix file blocking issue with web cmdlets (#7676) (Thanks @Claustn!) +- Improve error message on non-Windows when importing `clixml` with `securestring` (#7997) +- Add prompt to the use of less in the function 'help' to instruct user how to quit (#7998) +- Fix `Set-Service -Status Stopped` to stop services with dependencies (#5525) (Thanks @zhenggu!) + +### Code Cleanup + +- Use `nameof()` in bound `parameters.contains key()` (#7908) (Thanks @iSazonov!) +- Cleanup all native code from repository (#7892) +- Add `XSDs` for Format and `Types.ps1xml` files (#7832) (Thanks @felixfbecker!) +- Remove unused commented out code (#7935) (Thanks @vpondala!) +- Add `.editorconfig` (#7357) (Thanks @iSazonov!) +- Remove unused stopwatch (#7878) +- Clean up `MshObject.cs` and `MshMemberInfo.cs` (#7446) +- Add `TimeToLive` and `Hops` aliases to `MaxHops` parameter of `Test-Connection` cmdlet. (#7850) (Thanks @sethvs!) +- Fix a typo in `Credential.cs` (#7696) (Thanks @sethvs!) +- Remove workaround on VSTS that is no longer needed (#7666) +- Improve code style of `Send-MailMessage` cmdlet (#7723) (Thanks @ThreeFive-O!) +- Cleanup `FileSystemProvider` from runtime checks (#7655) (Thanks @iSazonov!) +- Remove extra spaces in error messages in `Modules.resx` (#7662) (Thanks @sethvs!) +- Remove empty XML comment lines (missed in #7401) (#7641) (Thanks @kvprasoon!) +- Remove `Suspend-Job` and `Resume-Job` cmdlets from compilation (#7650) + +### Tools + +- Fix syntax error in `installpwsh-amazonlinux.sh` (#7905) (Thanks @DarwinJS!) +- Add tools for PowerShell perf analysis (#7595) (Thanks @lzybkr!) +- Started using [Dependabot](https://dependabot.com) to create PRs to update package and module versions + +### Tests + +- Add test for `$error[0]` tab completion (#7924) (Thanks @iSazonov!) +- Replace test certificates with self-signed certificate generating command (#7875) +- Standardize Pester syntax in `ReplaceOperator.Tests.ps1` (#7963) (Thanks @sethvs!) +- Updating `ModulePath.Tests` for `fxdependent` package (#7772) +- Add tests for `Import-Module -Force` (#7491) +- Updates to Docker package tests (#7667) +- Updating test gallery URL in `PackageManagement` tests (#7879) +- Add version checking tests for `Import-Module` (#7499) +- Update Markdown tests (#7838) +- Change locale of `mdspell` to `en-US` (#7671) +- Test changes needed for running in a container (#7869) +- Add daily build non-windows platforms (#7683) +- Remove workaround on VSTS that is no longer needed (#7666) +- Fix module specification `hashtable` in `ModuleSpecification.Tests.ps1` (#7663) (Thanks @sethvs!) +- Use `dotnet test` since the `dotnet xunit` test runner has been deprecated (#7980) (Thanks @bergmeister!) +- Fix pipeline test where `SmtpServer` key was set wrong in pipeline object (#7745) (Thanks @ThreeFive-O!) +- Change API to get host name to match cmdlet which is more reliable in Azure DevOps Pipelines `Hosted Windows VS2017` (#8003) +- Disable `travis-ci` (#7766) +- Make artifact upload only occur for non-PR builds (#7657) +- Change logic for downloading zip files based on job id (#7653) +- Add missing dependency for hosting xUnit tests + +### Build and Packaging Improvements + +- Change default of `Start-PSBuild` to include `-PSModuleRestore` (#7881) +- Specify verb, `pwsh`, for shell context menu to avoid overriding the default verb (#7932) (Thanks @bergmeister!) +- Converting aliases to cmdlets in `build.psm1` (#7964) (Thanks @kvprasoon!) +- Add dependencies for SUSE (#7938) (Thanks @Jellyfrog!) +- Wait for package manager not to be locked (#7817) +- Make `Start-PSPackage` give better message about how to fix `files.wxs` (#7841) +- Bump to .NET Core `2.1.5` with SDK `2.1.403` and latest packages (#7646, #7834, #7922, #7936) (Thanks @iSazonov!) +- Bump `Markdig.Signed` NuGet package from `0.15.3` to `0.15.4` (#7960) (Thanks @bergmeister!) +- Bump `Microsoft.ApplicationInsights` from `2.7.2` to `2.8.0` (#8002) +- Bump `Microsoft.PowerShell.Native` from `6.1.0-rc.1` to `6.1.0` (#7861) +- Bump `NJsonSchema` from `9.10.71` to `9.11.1` (#7705, #7764, #7990) +- Bump `PackageManagement` from `1.1.7.2` to `1.2.2` in /src/Modules (#8014, #8029) +- Bump `Pester` to use latest version (#8015) +- Bump `PowerShellGet` to `2.0.0` (#7831) +- Bump `PSReadLine` to `2.0.0-beta3` (#7711) +- Bump `Xunit.SkippableFact` from `1.3.6` to `1.3.12` (#7972) +- Make Windows MSI uninstallation shortcut remove work when more than one version is installed (#7701) (Thanks @bergmeister!) +- Update Docker files to use MCR (#7726) +- Update `metadata.json` in preparation for `6.1` release (#7741) +- Build and package framework dependent package (#7729) +- Make sure MSI build works when not preview (#7752) +- Remove `PDBs` from `fxdependent` package (#8006) +- Improve debugging of NuGet package generation and add type to filtering + +### Documentation and Help Content + +- Replace ambiguous `hang` term (#7902, #7931) (Thanks @iSazonov!) +- Updating incorrect example of `PowerShell.Create()` (#7926) (Thanks @1RedOne!) +- Update `governance.md` (#7927) (Thanks @tommymaynard!) +- Add `cURL` to the Bash users list in `README.md` (#7948) (Thanks @vmsilvamolina!) +- Optimize image assets used in documentation (#7874) (Thanks @RDIL!) +- Update build badges (#7792) +- Remove packaging, building and installation scripts for Ubuntu 17.10 (#7773) +- Remove badges for master build as it reflects last PR which is not actionable from the `README` file (#7816) +- Improve Markdown formatting of beginners guide (#7684) (Thanks @fbehrens!) +- Fix the `Basic cookbooks` link (#7934) (Thanks @vmsilvamolina!) +- Update version for PowerShell release `6.1.0` (#7751) +- Add VSTS CI build badges for master branch to `README.md` (#7691) (Thanks @bergmeister!) +- Add a paragraph on `files.wxs` updating (#7695) (Thanks @iSazonov!) +- Update `CONTRIBUTION.md` about adding an empty line after the copyright header (#7706) (Thanks @iSazonov!) +- Update docs about .NET Core version `2.0` to be about version `2.x` (#7467) (Thanks @bergmeister!) + +## 6.1.5 - 2019-07-16 + +### Breaking changes + +- Disable `Enter-PSHostProcess` cmdlet when system in lock down mode (Internal 8968) + +### Build and Packaging Improvements + +- Update DotNet SDK and runtime framework version (Internal 9087) +- Add automated RPM signing to release build (#10013) +- Update copyright symbol for NuGet packages (#9936) +- Bump `System.Net.Http.WinHttpHandler` from `4.5.3` to `4.5.4` (#9790) +- Integrate building NuGet package in the coordinated build (#8947) (#9708) +- Bump `Newtonsoft.Json` (#9662) + +## 6.1.4 - 2019-05-21 + +### Build and Packaging Improvements + +- Disable debugger in System Lock down mode (Internal 8430) +- Port changes for release automation to `6.1` (Internal 8402) +- Fix `MSI` `WIX` generation (#9013) (Internal 8385) +- Update `Microsoft.PowerShell.Archive` version (Internal 8380) +- Update package version in hosting test (Internal 8374) +- Bump to `dotnet` `2.1.11` release +- Remove update build table logic from release build (Internal 8364) +- Add `AccessToken` variable to jobs that perform signing (#9351) +- Support release branches based on the forward slash separator (#8903) + +## 6.1.3 - 2019-02-14 + +### Engine Updates and Fixes + +- Add security mitigation for 6.1.3 release (Internal 6561) + +### Tools + +- Change the feed URL to feed name due to changes in Azure DevOps (#8664) + +### Tests + +- Updating test gallery URL in PackageManagement tests (#7879) + +### Build and Packaging Improvements + +- Get PowerShellGet tests working (#7831) +- Start tracking release build information in an azure storage table (#8850) +- Remove `PDBs` from `fxdependent` package (#8006) +- Make every `csproj` files have its own folder (#8750) +- Update packaging script to build reference assembly targeting `netcoreapp2.1` and use actual `.csproj` files (#8729) +- Move Final artifacts from coordinated build to `finalResults` folder (#8806) +- Refactor Unified Release Build (#8804) +- Add compliance to Coordinated build (#8798) +- Switch to 1.11 of FPM to fix FPM install issue (#8797) +- Update the coordinated build with framework dependent package for dotnet SDK (#8773) +- Add Windows build to coordinated release build YAML (#8695) +- Build package build using Ubuntu 18.04 image (#8666) +- Adding `yml` for Windows Release builds (#8374) +- Update `SignType` in `signing.xml` (#8223) +- Update DotNet SDK and Runtime version (Internal 7004) +- Add `binskim` to coordinated build and increase timeout (#8834) + +## v6.1.2 - 2019-01-15 + +### Tests + +- Fix test failures (Internal 6310) + +### Build and Packaging Improvements + +- Moved the cleanup logic to `Restore-PSModuleToBuild` (Internal 6442) +- Update dependency versions (Internal 6421) +- Create unified release build for macOS and Linux packages (#8399) +- Build Alpine `tar.gz` package in release builds (Internal 6027) + +### Documentation and Help Content + +- Update version for README, Alpine docker file and hosting tests (Internal 6438) + +## v6.1.1 - 2018-11-13 + +### Engine Updates and Fixes + +- Fix issue with logging the null character in `ScriptBlock` logging (Internal 5607) +- Consolidation of all Windows PowerShell work ported to 6.1 (Internal 5233) + +### General Cmdlet Updates and Fixes + +- Use `ZipFile` and `ExtractToDirectory` APIs to extract zip file (Internal 5608) + +## v6.0.5 - 2018-11-13 + +### Engine updates and fixes + +- Fix issue with logging the null character in `ScriptBlock` logging (Internal 5605) + +### General cmdlet updates and fixes + +- Use `ZipFile` and `ExtractToDirectory` APIs to extract zip file (Internal 4802) + +### Build and Packaging Improvements + +- Update `SignType` in `signing.xml` (Internal 5721) +- Port changes to pull PowerShell Gallery modules from Modules `csproj` (Internal 5713) +- Port macOS Release build changes changes from GitHub (#8189, #8188, #8185) +- Fix script path for `PowerShellPackageVsts.ps1` (#8189) +- Workaround for accessing `AzDevOps` Artifacts (#8188) +- Bump various packages to latest patch version (Internal 5675) +- Update PowerShell SDK NuGet various metadata description (Internal 4527, 4510, 4505) + +## v6.0.4 - 2018-08-10 + +### Build and Packaging Improvements + +- Update the Archive module version (Internal 5671) +- Update to .NET Core `2.1.5` with SDK `2.1.403` (#7936) (Thanks @iSazonov!) +- Disable package major upgrade tests for release branch (Internal 5209) +- Bump versions for dependencies (Internal 5612) +- Port changes to allow `AzDevOps` NuGet feeds for macOS build (Internal 5716) +- Port macOS changes from GitHub (#8189, #8188, #8185) +- Add function to create a new `nuget.config` file (#8170) +- Updated `wxs` file to match published packages (Internal 5660) + +### Tests + +- Change API to match cmdlet which is more reliable in `AzDevOps` Pipelines Windows (#8003) +- Fix conflict with `Get-AdlStoreChildItem` from `az` module in tab completion tests (#8167) + +## v6.1.0 - 2018-09-13 + +### Engine Updates and Fixes + +- Enable indexing operations on `System.Tuple` and `System.ValueTuple` (#7633) (Thanks @SeeminglyScience!) +- Use non-virtual call to invoke 'family or assembly' methods on base class from PowerShell class (#7624) (Thanks @yurko7!) +- Handle operations with `ByRef-like` types gracefully in PowerShell (#7533) +- Make the `-settingfile` flag on `pwsh` work for `ScriptBlock` logging on windows (#7631) +- Ensure the `SSHClientSessionTransportManager` stream writer and reader fields are cleared after disposing (#7746) +- Add `LocationChangedAction` handler to support the Windows Compatibility module (#7552) + +### General Cmdlet Updates and Fixes + +- Fix `Set-Service -Status Stopped` to stop services with dependencies (#5525) (Thanks @zhenggu!) +- Add the `Duration` property to `HistoryInfo` (#5208) (Thanks @powercode!) +- Fix null reference in `ConvertFrom-Markdown` when the markdown content is empty (#7463) +- Fix file blocking issue with WebCmdlets (#7676) (Thanks @Claustn!) +- Fix performance issue in `WSMan` provider by using `Refresh()` to update the status rather than instantiating `ServiceController` (#7680) + +### Code Cleanup + +- Remove `Suspend-Job` and `Resume-Job` cmdlets from compilation on Unix platforms (#7650) +- Remove extra spaces in error messages in `Modules.resx` (#7662) (Thanks @sethvs!) +- Cleanup the platform runtime checks from `FileSystemProvider` (#7655) (Thanks @iSazonov!) +- Improve code style of `Send-MailMessage` cmdlet (#7723) (Thanks @ThreeFive-O!) + +### Tools + +- Add tools for PowerShell performance analysis (#7595) (Thanks @lzybkr!) +- Update code coverage module to download zip files based on job ID (#7653) + +### Tests + +- Update test which assumes all previews have the name preview in the version (#7625) +- Update Pester syntax in `Set-Location` test (#7615) (Thanks @iSazonov!) +- Add `ScriptBlock` logging test for Linux and macOS (#7599) (#7586) +- Add tests to report when package references are out of date (#7661) +- Fix `ModuleSpecification.Tests.ps1` (#7663) (Thanks @sethvs!) +- Updates Docker package tests (#7667) + +### Build and Packaging Improvements + +- Update to the latest package references, dotnet core SDK and framework (#7646) (Thanks @iSazonov!) +- Make the artifact upload only occur for non-PR builds (#7657) +- Change to not upload artifacts during pull request due to missing VSTS feature (#7588) +- Remove workaround on VSTS that is no longer needed (#7666) +- Update docker files to use MCR (#7656) +- Add symbolic links for `libssl` and `libcrypto` to Debian 9 build to make remoting work (#7609) +- Simplify the `StartupInfo` type used in Jumplist creation for faster `P/Invoke` (#7580) (Thanks @powercode!) +- Add VSTS CI for Windows (#7536) +- Update the version of `PowerShellGet` module to `1.6.7` (#7564) +- update the version of `PSReadLine` module to `2.0.0-beta3` (#7711) +- Make sure MSI build works for non-preview builds (#7752) +- Build and package framework dependent package (#7729) +- Change locale of `mdspell` to `en-US` (#7671) +- Add daily build on non-windows platforms (#7683) +- Fix Windows MSI to remove the `Uninstall` shortcut during an uninstall when more than one version is installed (#7701) (Thanks @bergmeister!) +- Fix docker image names for release build (#7726) + +### Documentation and Help Content + +- Update the version of .NET Core in docs (#7467) (Thanks @bergmeister!) +- Fix links in `README.md` (#7619) (Thanks @iSazonov!) +- Add VSTS CI build badges for master branch to `README.md` (#7691) (Thanks @bergmeister!) +- Add a paragraph in `CONTRIBUTING.md` about updating `files.wxs` (#7695) (Thanks @iSazonov!) + +## v6.1.0-rc.1 - 2018-08-22 + +### Engine Updates and Fixes + +- Fix to not duplicate the `System32` module path when starting `pwsh` from `pwsh` (#7414) +- Fix sequence point update for `switch/if/for/while/do-while/do-until` statements (#7305) +- Set the cursor to the place where a user hits tab key (#7299) +- Adding `LanguagePrimitives.TryCompare` to provide faster comparisons (#7438) (Thanks @powercode!) +- Improving performance of `LanguagePrimitives.TryConvertTo` (#7418) (Thanks @powercode!) +- Set `PowerShellVersion` to `3.0` for built-in modules to make Windows PowerShell work when starting from PowerShell Core (#7365) +- Avoid extra unnecessary allocations in `PSMemberInfoInternalCollection` (#7435) (Thanks @iSazonov!) +- Enforce the `CompatiblePSEditions` check for modules from the legacy `System32` module path (#7183) +- Make sure that `SettingFile` argument is parsed before we load the settings (#7449) +- Default to `DefaultConsoleWidth` when DotNet says `WindowWidth` is 0 (#7465) + +### General Cmdlet Updates and Fixes + +- Fix parameter name in the `Get-Variable` cmdlet error message (#7384) (Thanks @sethvs!) +- Fix `Move-Item -Path` with wildcard character (#7397) (Thanks @kwkam!) +- Ignore `Newtonsoft.Json` metadata properties in `ConvertFrom-Json` (#7308) (Thanks @louistio!) +- Fix several issues in Markdown cmdlets (#7329) +- Add support for parsing Link Header with variable whitespace (#7322) +- Change parameter order in `Get-Help` and help in order to get first `-Full` and + then `-Functionality` when using Get-Help `-Fu` followed by pressing tab and help `-Fu` followed by pressing tab (#7370) (Thanks @sethvs!) +- Add support for passing files and Markdown directly to `Show-Markdown` (#7354) +- Add `-SkipIndex` parameter to `Select-Object` (#7483) (Thanks @powercode!) +- Improve performance of `Import-CSV` up to 10 times (#7413) (Thanks @powercode!) +- Update `Enable-PSRemoting` so configuration name is unique for Preview releases (#7202) +- Improve performance on JSON to PSObject conversion (#7482) (Thanks @powercode!) +- Fix error message for `Add-Type` when `-AssemblyName` with wildcard is not found (#7444) +- Make native globbing on Unix return an absolute path when it is given an absolute path (#7106) +- Improve the performance of `Group-Object` (#7410) (Thanks @powercode!) +- Remove one unneeded verbose output from `ConvertTo-Json` (#7487) (Thanks @devblackops!) +- Enable `Get-ChildItem` to produce `Mode` property even if cannot determine if hard link (#7355) + +### Code Cleanup + +- Remove empty XML comment lines (#7401) (Thanks @iSazonov!) +- Cleanup Docker files (#7328) +- Correct the comment for `WSManReceiveDataResult.Unmarshal` (#7364) +- Format Utility `csproj` with updated `codeformatter` (#7263) (Thanks @iSazonov!) +- Bulk update format for files in Management folder with `codeformatter` (#7346) (Thanks @iSazonov!) +- Cleanup: replace `Utils.FileExists()/DirectoryExists()/ItemExists()` with DotNet methods (#7129) (Thanks @iSazonov!) +- Update `Utils.IsComObject` to use `Marshal.IsComObject` since CAS is no longer supported in DotNet Core (#7344) +- Fix some style issues in engine code (#7246) (Thanks @iSazonov!) + +### Test + +- Use `-BeExactly` and `-HaveCount` instead of `-Be` in `BugFix.Tests.ps1` (#7386) (Thanks @sethvs!) +- Use `-BeExactly` and `-HaveCount` instead of `-Be` in `TabCompletion.Tests.ps1` (#7380) (Thanks @sethvs!) +- Update CI scripts to support running tests for experimental features (#7419) +- Use `-HaveCount` instead of `-Be` in `Where-Object.Tests.ps1` (#7379) (Thanks @sethvs!) +- Fix ThreadJob tests so that they will run more reliably (#7360) +- Make logging tests for macOS pending (#7433) + +### Build and Packaging Improvements + +- Update Build script owners (#7321) +- Make `MUSL` NuGet package optional (#7316) +- Enable `pwsh-preview` to work on Windows (#7345) +- Fix SDK dependencies +- Add back the `powershell-core` NuGet source for hosting tests +- Fix typo in environment checker (#7547 & #7549) +- Only remove the revision if it is `0` from module version when restoring modules (#7538) +- Update `WCF` and `NJsonSchema` NuGet packages to latest released patch version (#7411) (Thanks @bergmeister!) +- Add Linux and macOS VSTS CI (#7490, #7527, #7535, #7515 & #7516) +- Updated ThreadJob to version `1.1.2` (#7522) +- Add xUnit project to `PowerShell.sln` and make it runnable from within VisualStudio (#7254) (Thanks @bergmeister!) +- Update NuGet packaging code for the new markdown assembly (#7431) +- Update version of modules shipped with PowerShell (#7531) +- Retry restore on failure (#7544 & #7550) +- Update `PowerShellGet` version +- Update NuGet package metadata (#7517) +- Update reference to use packages from `NuGet.org` (#7525) +- `Start-DevPowerShell`: add `-Configuration` and handle `-ArgumentList` more properly (#7300) (Thanks @jazzdelightsme!) +- Add preview icon to macOS launcher (#7448) (Thanks @thezim!) +- Add `Microsoft.PowerShell.MarkdownRender` to `signing.xml` (#7472) +- Fix building on RedHat Enterprise Linux (#7489) +- Build: Also search PATH for `rcedit` (#7503) (Thanks @kwkam!) +- Save modules to un-versioned folder to enable servicing (#7518 & #7523) +- Fix macOS launcher app to allow release and preview versions (#7306) (Thanks @thezim!) + +### Documentation and Help Content + +- Fix docs comments in utility folder (#7192) (Thanks @iSazonov!) +- Fix a typo in `issue-management.md` (#7393) (Thanks @alexandair!) +- Fix casing of `GitHub` in `best-practice.md` (#7392) (Thanks @alexandair!) +- Fix typos in `docs/maintainers/README.md` (#7390) (Thanks @alexandair!) +- Add maintainer's best practice document and update maintainer list (#7311) +- Update Docker link to `PowerShell-Docker` (#7351) (Thanks @JoshuaCooper!) +- Add `Snapcraft` to spelling dictionary (#7318) +- Update `README.md` and `metadata.json` for release `v6.0.4` (#7497) +- Add `Former Repository Maintainers` section in `maintainers/README.md` (#7475) +- Update the `HelpUri` for `Get-ExperimentalFeature` (#7466) + +## v6.1.0-preview.4 - 2018-07-19 + +### Breaking Changes + +- Remove the `VisualBasic` support from Add-Type (#7284) +- Update PowerShell Direct to try `pwsh` then fallback to `powershell` (#7241) +- Make pwsh able to start in a directory with wildcards in the name (#7240) +- Update `Enable-PSRemoting` so configuration name is unique for Preview releases (#7202) +- Enforce the `CompatiblePSEditions` check for modules from the legacy `System32` module path (#7183) + +### Engine Updates and Fixes + +- Add support to experimental features (#7242) +- Fix error when using `Get-ChildItem c:` (#7033) (Thanks @sethvs!) +- Add location history for `Set-Location` to enable `cd -` scenario (issue #2188) (#5051) (Thanks @bergmeister!) +- Fix padding for right aligned column in table formatting (#7136) +- Fix a performance regression to the `-replace` operator after adding `ScriptBlock` support (#7135) +- Fix tab expansion for `Get-Process` on macOS (#7176) +- When using PSRP, if we receive text instead of XML, output it as error to help troubleshoot (#7168) +- Fix trimming of whitespace when table is wrapped (#7184) +- Modified the `Group-Object -AsHashTable` to use the base object of `PSObject` as the key for the `Hashtable` (#7123) +- Add back ADSI and WMI type accelerators (#7085) +- Add `CompatiblePSEditions` to PowerShell Core built-in modules (#7083) +- Make `Start-Process -ArgumentList` to accept `@()` or `$null` (#6597) +- Avoid calling native APIs to check for existence of FileSystem items (#6929) (Thanks @iSazonov!) +- Add copy environment variables from `ProcessStartInfo` to key/pair array used in creating SSH process (#7070) +- Add markdown rendering feature assemblies to the trusted assembly list (#7280) +- Don't fail if `SaferPolicy` API is not available on Windows 10 IoT or NanoServer (#7075) +- Fix conditions for transcription of `Write-Information` command. (#6917) (Thanks @hubuk!) +- Fix a parsing error when `break` and `continue` are used in a switch statement in a finally block (#7273) +- Fix prompt string to be platform agnostic and keep its trailing spaces (#7255) +- Make progress panel display correctly on UNIX when the user is typing. (#6972) +- Revert change to have `SetLocation()` treat wildcarded path as literal if it exists (#7101) +- Make `Select-Object`/`ForEach-Object`/`Where-Object` see dynamic properties (#6898) (Thanks @jazzdelightsme!) +- Fix class searcher to ignore hidden properties (#7188) +- Update remote prompt when using SSH to show username if different (#7191) +- Remove `SemanticVersion` from `knowntypes` list in serialization code to enable interop between Windows PowerShell and PowerShell Core (#7016) +- Add more information to job process failure error (#7251) +- Use .Net Core `File.Delete()` method to remove symbolic links and alternate streams (#7017) (Thanks @iSazonov!) +- Enable `UseShellExecute` on all platforms (#7198) +- Methods with return type `[object]` should return `null` for an empty result (#7138) + +### General Cmdlet Updates and Fixes + +- Add Markdown rendering cmdlets (#6926) +- `Send-MailMessage`: Update all parameters to support `ValueFromPipelineByPropertyName`. (#6911) (Thanks @sethvs!) +- Allow Basic Auth over HTTPS (#6890) +- Add `ThreadJob` module package and tests (#7169) +- Fix Windows Event Log channel isolation semantics (#6956) (Thanks @Robo210!) +- Make `Measure-Object` handle `scriptblock` properties. (#6934) +- Added functionality to retry in `Invoke-RestMethod` and `Invoke-WebRequest`. (#5760) +- Add type inference for `Select-Object` command (#7171) (Thanks @powercode!) +- Add `-AllStats` Switch parameter for `Measure-Object` cmdlet (#7220) (Thanks @kvprasoon!) + +### Code Cleanup + +- Remove unneeded code that forces ARM platforms to run PowerShell in CL mode (#7046) +- Bulk update code base to put `null` on the right-hand-side of a comparison expression (#6949) (Thanks @iSazonov!) +- Remove `MapSecurityZoneWithUrlmon` method and related code (#7103) +- Cleanup: remove the unneeded type `RemotingCommandUtils` (#7029) +- Remove unneeded "Windows-Full" modules (#7030) +- CodeFactor code style cleanup: replace literal empty strings with `string.Empty` (#6950) (Thanks @iSazonov!) +- Remove dummy comments in Utility module files (#7224) (Thanks @iSazonov!) +- Use empty array for Functions/Cmdlets/`AliasesToExport` to follow the best practice (#7108) +- Refactor module code related to `Get-Module -ListAvailable` (#7145) +- Refactor module specification logic (#7126) + +### Test + +- Add tests for module specifications (#7140) +- Update test string for better clarity in `Send-MailMessage.Tests.ps1` (#7195) (Thanks @sethvs!) +- Add test to verify filesystem provider isn't used when accessing root path in `PSDrive` (#7173) +- Fix to address `ThreadJob` tests reliability and speed (#7270) +- Add additional checks for test that passes inconsistently (#7051) + +### Build and Packaging Improvements + +- `install-powershell.sh` filter pre-releases (when available), `params` documentation (#6849) (Thanks @DarwinJS!) +- Fedora 28 was released, Fedora 26 and 25 went end of life. (#7079) (Thanks @adelton!) +- Disambiguate icon on Windows for preview builds/installers to use `Powershell_av_colors` and + make daily build use `Powershell_avatar` instead (#7086) (Thanks @bergmeister!) +- Update to build for Alpine (#7139) +- Update build and packaging modules for Alpine (#7149) +- Add ability to install previews side-by-side with production releases (#7194) (Thanks @DarwinJS!) +- Enable NuGet Package Registration for compliance (#7053) +- Fix the preview macOS package link (#7061) +- Remove PSReadLine from then `PowerShell.sln` file (#7137) +- Fix the file `PowerShell.sln` that was corrupted by accident (#7288) +- Fix the encoding of `PowerShell.sln` to be `utf-8` (#7289) +- Make sure all references to the Package ID for previews packages is powershell-preview (#7066) +- Update `internals.md` with the latest build changes (#7058) +- When installing using MSI, set the working directory of the shortcut to the user home directory (#7072) +- Move to dotnet core 2.1.1 (#7161) (Thanks @iSazonov!) +- Update to latest package references, runtime framework, and SDK (#7272) +- AppVeyor build matrix: more efficient build job split to reduce total time by another 5 minutes (#7021) (Thanks @bergmeister!) +- Build: Fix the source location of `PowerShell.Core.Instrumentation.dll` (#7226) +- Add Andrew to the default reviewers of the build related files (#7019) +- Build: Fix a check to avoid null argument in case `vcvarsall.bat` is absent (#7218) (Thanks @PetSerAl!) +- Update `releaseTag` in `tools/metadata.json` (#7214) +- Update `Start-PSPester` to make it more user friendly (#7210) (Thanks @bergmeister!) +- Make `Start-PSBuild -Clean` not prompt due to locked files when Visual Studio is open by excluding `sqlite3` folder and use `-x` instead of `-X` option on `git clean` (#7235) (Thanks @bergmeister!) + +### Documentation and Help Content + +- Fix typos in `DOCSMIGRATION.md` (#7094) (Thanks @alexandair!) +- Add instructions to update Homebrew formula for the preview version PowerShell (#7067) (Thanks @vors!) +- Merge Third Party Notices and License updates (#7203) +- Update third party notices (#7042) +- Fix Markdown and spelling errors in `CHANGELOG.md` (#7064) +- Fix `New-TemporaryFile` online help URI (#6608) +- Fix links to PowerShell install docs (#7001) (Thanks @jokajak!) +- Update links that contain `en-us` culture (#7013) (Thanks @bergmeister!) +- Update docs for `ArgumentCompleterAttribute` class (#7227) (Thanks @Meir017!) +- Fix the name of a `Register-EngineEvent` test (#7222) (Thanks @alexjordan6!) +- Update README files for native code for migration (#7248) +- Comment about dynamic members for the `DotNetAdapter`, `GetMember` and `GetMembers` (#7087) +- Update the PowerShell executable location in building guide docs (#7205) (Thanks @louistio!) + +## v6.1.0-preview.3 - 2018-06-07 + +### Breaking Changes + +- Clean up uses of `CommandTypes.Workflow` and `WorkflowInfo` (#6708) +- Disallow Basic Auth over HTTP in PowerShell Remoting on Unix (#6787) +- Change packaging to differentiate only between major versions and previews (#6968) +- Enhance and refactor `Add-Type` cmdlet (#6141) (Thanks @iSazonov!) + - A few error strings were removed and thus the corresponding fully qualified error ids are no longer in use. + +### Engine Updates and Fixes + +- Fix crash when terminal is reset (#6777) +- Fix a module-loading regression that caused an infinite loop (#6843) +- Further improve `PSMethod` to `Delegate` conversion (#6851) +- Blacklist `System.Windows.Forms` from loading to prevent a crash (#6822) +- Fix `Format-Table` where rows were being trimmed unnecessarily if there's only one row of headers (#6772) +- Fix `SetDate` function in `libpsl-native` to avoid corrupting memory during `P/Invoke` (#6881) +- Fix tab completions for hash table (#6839) (Thanks @iSazonov!) +- Fix parser to continue parsing key-value pairs after an `If-Statement` value in a `HashExpression` (#7002) +- Add error handling for `#requires` in an interactive session (#6469) + +### General Cmdlet Updates and Fixes + +- Improve parameter validation in `ExportCsvHelper` (#6816) (Thanks @sethvs!) +- Quote `Multipart` form-data field names (#6782) (Thanks @markekraus!) +- Fix Web Cmdlets for .NET Core 2.1 (#6806) (Thanks @markekraus!) +- Fix `Set-Location DriveName:` to restore current working directory in the drive (#6774) (Thanks @mcbobke!) +- Add the alias `-lp` for `-LiteralPath` parameters #6732 (#6770) (Thanks @kvprasoon!) +- Remove `more` function and move the `$env:PAGER` capability into the `help` function (#6059) (Thanks @iSazonov!) +- Add line break to the error message for `Set-ExecutionPolicy` (#6803) (Thanks @wesholton84!) + +### Code Cleanup + +- Clean up `#if SILVERLIGHT` (#6907) (Thanks @iSazonov!) +- Clean up the unused method `NonWindowsGetDomainName()` (#6948) (Thanks @iSazonov!) +- Clean up FileSystem provider (#6909) (Thanks @iSazonov!) + +### Test + +- Add tests for PowerShell hosting API to verify MyGet packages (#6737) +- Remove Web Cmdlets tests using proxy environment variables (#6808) (Thanks @iSazonov!) +- Enable Web Cmdlets tests for greater platform support (#6836) (Thanks @markekraus!) +- Convert `ShouldBeErrorId` to `Should -Throw -ErrorId` in PowerShell tests (#6682) +- Fix CIM cmdlets tests (#6755) (Thanks @sethvs!) +- Add tests for PowerShell classes inheriting from abstract .NET classes (#6752) +- Fix `Select-Object.Tests.ps1` which previously failed intermittently on Unix platforms. (#6747) +- Update docker package tests to fix error on OpenSUSE 42 (#6783) +- Fix test and infrastructure that block code coverage runs (#6790) +- Update Tests `Isfile` to correct response for `"/"` (#6754) (Thanks @Patochun!) +- Improve code coverage in `Export-Csv.Tests.ps1` (#6795) (Thanks @sethvs!) +- Change `-Quiet` parameter of `Invoke-Pester` to `-Show None` in `OpenCover.psm1` (#6798) (Thanks @sethvs!) +- Replace `Dbg.Assert` with `if () throw` in `CSVCommands.cs` (#6910) (Thanks @sethvs!) +- Fix xUnit test `GetTempFileName` (#6943) (Thanks @iSazonov!) + +### Build and Packaging Improvements + +- Add Windows Compatibility Pack 2.0.0 to PowerShell Core and adopt the official .NET Core 2.1 (#6958) +- Add Jumplist 'Run as Administrator' to Taskbar on Windows (#6913, #6985) (Thanks @bergmeister!) +- Use AppVeyor matrix for faster Pull Request builds (#6945) (Thanks @bergmeister!) +- Fix `build.psm1` to not add tool path to $PATH twice (#6834) +- Add script to create a container manifest (#6735) +- Fix docker manifest creation script to work with more complex tags and with repeated use (#6852) +- Add functions to merge Pester and xUnit logs (#6854) +- Enable generating full symbols for the Windows debug build (#6853) +- Add functions into `build.psm1` to save and restore `PSOptions` between different sessions. (#6884) +- Update signing XML based on new signing guidelines (#6893) +- Update the release docker files to allow specifying the version of to-be-installed PowerShell and the version of image to use (#6835) +- Updates docker files for Fedora 27 and Kali Linux (#6819) +- Change packaging to support Ubuntu 17.10 and 18.04 (#6769) +- Update `Get-ChangeLog` to make it more accurate (#6764) +- Fix comparison to see if sudo test is needed in `install-*.sh` (#6771) (Thanks @bjh7242!) +- Packaging: Add registry keys to support library folder background for explorer context menu (#6784) (Thanks @bergmeister!) +- Skip `dotnet-cli` initialization and stop caching the `dotnet` folder for Travis CI (#7007) +- Skip compiling the non-supported cmdlets on Unix in `System.Management.Automation.dll` to fix the crash in Unix debug build (#6939) +- Use `PSReadLine` 2.0.0-beta2 from PSGallery (#6998) +- Update `PSRP` Linux NuGet package version to 1.4.2-* (#6711) +- Add path cleanup utility `Reset-PWSHSystemPath.ps1` (#6892) (Thanks @DarwinJS!) +- Add logic to create signing XML for NuGet packages (#6921) +- Add and config the `Settings.StyleCop` file (#6930, #6986) (Thanks @iSazonov!) +- Fix the double curly bracket typo in a docker file (#6960) (Thanks @adelton!) +- Remove dependencies on `libcurl` and `libunwind` in packaging to match the .NET Core behavior (#6964) (Thanks @qmfrederik!) +- Make the docker build fail when the curl operation fails. (#6961) (Thanks @adelton!) + +### Documentation and Help Content + +- Update installation doc about Raspbian (#6859) +- Add code coverage report generation instructions (#6515) +- Migrate docs from PowerShell repository to Docs repository (#6899) +- Fix broken links due to migrating GitHub docs on Installation, Known Issues and Breaking Changes to `docs.microsoft.com` (#6981) (Thanks @bergmeister!) +- Update documentation on how to write tests verifying errors conditions (#6687) +- Fix preview download links in `README.md` (#6762) + +## v6.1.0-preview.2 - 2018-04-27 + +### Breaking Changes + +- Remove support for file to opt-out of telemetry, only support environment variable (#6601) +- Simplify the installation paths the MSI uses (#6442) + +### Engine Updates and Fixes + +- Fix running `pwsh` produced from `dotnet build` (#6549) +- Remove the `FullCLR-only` symbol-info related code from `EventManager.cs` (#6563) +- Improve `PSMethod-to-Delegate` conversion (#6570) +- Fix `PsUtils.GetManModule()` to avoid infinite loop when there was no main module (#6358) +- Fix error in windows environment provider when the environment variable has duplicates that differ only by case (#6489) (Thanks @mklement0!) +- Make sure that the width of the header is at least the size of the label (or property name) (#6487) +- Enable `[Environment]::OSVersion` to return current OS rather than compatible version (#6457) +- Change the `SaveError` method in Parser to use `nameof` for error ids (#6498) +- Fix error when `Format-Wide -AutoSize | Out-String` is called (#6491) (Thanks @stknohg!) +- Make `LanguagePrimitive.GetEnumerable` treat `DataTable` as Enumerable (#6511) +- Fix formatting of tables where headers span multiple rows (#6504) +- Improve performance of parsing `RegexOption` for `-split` by using `if` branches (#6605) (Thanks @iSazonov!) +- Enable specifying `sshd` subsystem to use via `-Subsystem` (#6603) +- Add some optimizations in formatting subsystem (#6678) (Thanks @iSazonov!) +- Throw better parsing error when statements should be put in named block (#6434) +- Use `Unregister-Event` to remove an event subscriber when removing `PSEdit` function (#6449) +- Make the `PSISERemoteSessionOpenFile` a support event (#6582) +- Add `-WorkingDirectory` parameter to `pwsh` (#6612) +- Support importing module paths that end in trailing directory separator (#6602) +- Formatting: Use cache for dash padding strings for tables (#6625) (Thanks @iSazonov!) +- Port Windows PowerShell AppLocker and DeviceGuard `UMCI` application white listing support (#6133) +- Reduce allocations in `TableWriter` (#6648) (Thanks @iSazonov!) + +### General Cmdlet Updates and Fixes + +- Add `-Resume` Feature to WebCmdlets (#6447) (Thanks @markekraus!) +- Support `user@host:port` syntax for `SSH` transport (#6558) +- Add ported `Test-Connection` cmdlet (#5328) (Thanks @iSazonov!) +- Added line break to Access-Denied error message (#6607) +- Some fixes in `Get-Date -UFormat` (#6542) (Thanks @iSazonov!) +- Added check for existence of Location HTTP header before using it (#6560) (Thanks @ffeldhaus!) +- Enable `Update-Help` to save help content in user scope by default (#6352) +- Update `Enable-PSRemoting` to create PowerShell.6 endpoint and version specific endpoint (#6519, #6630) +- Update error message that `Disconnect-PSSession` is only supported with `WSMan` (#6689) +- Make `Export-FormatData` print pretty XML output (#6691) (Thanks @iSazonov!) +- Add `-AsArray` parameter to `ConvertoTo-Json` command (#6438) +- Add `Test-Json` cmdlet (`NJsonSchema`) (#5229) (Thanks @iSazonov!) +- Correct a typo in comment for `Invoke-WebRequest` (#6700) (Thanks @gabrielsroka!) +- Re-order `UFormat` options in `Get-Date` (#6627) (Thanks @iSazonov!) +- Add the parameter `-Not` to `Where-Object` (#6464) (Thanks @SimonWahlin!) + +### Code Cleanup + +- Engine: Fix several code cleanup issues (#6552, #6609) +- Clean up workflow logic in the module loading component (#6523) +- Engine: Clean up unneeded `GetTypeInfo()` calls (#6613, #6636, #6633, #6635, #6634) + +### Test + +- Fix line ending in `DefaultCommands.Tests.ps1` from `CRLF` to `LF` (#6553) +- Use new Pester parameter syntax in tests (#6490, #6574, #6535, #6536, #6488, #6366, #6351, #6349, #6256, #6250) (Thanks @KevinMarquette, @sethvs, @bergmeister!) +- Fix `Copy.Item.Tests.ps1` (#6596) (Thanks @sethvs!) +- Fix typos or formatting in some test files (#6595, #6593, #6594, #6592, #6591) (Thanks @sethvs!) +- Add missing `Start-WebListener` to WebCmdlets tests (#6604) (Thanks @markekraus!) +- Update Dockerfile test to use Ubuntu 17.10 as the base image (#6503) +- Add PowerShell logging tests for macOS and Linux (#6025) +- Add tests for `Format-Table -Wrap` (#6670) (Thanks @iSazonov!) +- Reformat `Format-Table` tests (#6657) (Thanks @iSazonov!) +- Add new reliable tests for `Get-Date -UFormat` (#6614) (Thanks @iSazonov!) + +### Build and Packaging Improvements + +- Use C# latest language in `.csproj` files (#6559) (Thanks @iSazonov!) +- Update `installpsh-.sh` installers to handle "preview" in version number (#6573) (Thanks @DarwinJS!) +- Enable `PowerShell.sln` to work in VisualStudio (#6546) +- Remove duplicate `Restore-PSPackage` (#6544) +- Use `-WorkingDirectory` parameter to handle context menu when path contains single quotes (#6660) (Thanks @bergmeister!) +- Make `-CI` not depend on `-PSModuleRestore` in `Start-PSBuild` (#6450) +- Restore for official Linux arm builds (#6455) +- Fix error about setting readonly variable in `install-powershell.sh` (#6617) +- Make release macOS build work better (#6619, #6610) +- MSI: add function to generate a `MSP` package (#6445) + +### Documentation and Help Content + +- Doc: Update Ubuntu source creation commands to use `curl -o` (#6510) (Thanks @M-D-M!) +- Update stale bot message (#6462) (Thanks @iSazonov!) +- Remove extraneous SSH and install docs from the 'demos' folder (#6628) + +## v6.1.0-preview.1 - 2018-03-23 + +### Breaking Changes + +- Throw terminating error in `New-TemporaryFile` and make it not rely on the presence of the `TEMP` environment variable (#6182) (Thanks @bergmeister!) +- Remove the unnecessary `AddTypeCommandBase` class from `Add-Type` (#5407) (Thanks @iSazonov!) +- Remove unsupported members from the enum `Language` in `Add-Type` (#5829) (Thanks @iSazonov!) +- Fix range operator to work better with character ranges (#5732) (Thanks @iSazonov!) + +### Engine Updates and Fixes + +- Fix `ValidateSet` with generator in a module (#5702) +- Update `SAL` annotation and fix warnings (#5617) +- Add `ForEach` and `Where` methods to `PSCustomobject` (#5756) (Thanks @iSazonov!) +- Add `Count` and `Length` properties to `PSCustomobject` (#5745) (Thanks @iSazonov!) +- Make minor fixes in compiler to properly handle void type expression (#5764) +- Logging: Fix the escaped characters when generating `.resx` file from PowerShell `ETW` manifest. (#5892) +- Remove `PSv2` only code from `Types_Ps1Xml.cs` and `HostUtilities.cs` (#5907) (Thanks @iSazonov!) +- Enable passing arrays to `pwsh -EncodedArguments` on debug builds. (#5836) +- Logging: Handle path that contains spaces in `RegisterManifest.ps1` (#5859) (Thanks @tandasat!) +- Add `-settingsfile` to `pwsh` to support loading a custom powershell config file. (#5920) +- Return better error for `pwsh -WindowStyle` on unsupported platforms. (#5975) (Thanks @thezim!) +- Enable conversions from `PSMethod` to `Delegate` (#5287) (Thanks @powercode!) +- Minor code clean-up changes in tab completion code (#5737) (Thanks @kwkam!) +- Add lambda support to `-replace` operator (#6029) (Thanks @IISResetMe!) +- Fix retrieval of environment variables on Windows in cases where variable names differ only by case. (#6320) +- Fix the `NullRefException` when using `-PipelineVariable` with `DynamicParam` block (#6433) +- Add `NullReference` checks to two code paths related to `PseudoParameterBinder` (#5738) (Thanks @kwkam!) +- Fix `PropertyOnlyAdapter` to allow calling base methods (#6394) +- Improve table view for `Certs` and `Signatures` by adding `EnhancedKeyUsageList` and `StatusMessage` (#6123) +- Fix the filtering of analytic events on Unix platforms. (#6086) +- Update copyright and license headers (#6134) +- Set pipeline thread stack size to 10MB (#6224) (Thanks @iSazonov!) + +### General Cmdlet Updates and Fixes + +- Fix the `NullRefException` in `Enter-PSHostProcess` (#5995) +- Merge and Sort `BasicHtmlWebResponseObject` and `ContentHelper` in Web Cmdlets (#5720) (Thanks @markekraus!) +- Encoding for `New-ModuleManifest` on all platforms should be `UTF-8 NoBOM` (#5923) +- Make `Set-Location` use path with wildcard characters as literal if it exists (#5839) +- Combine Web Cmdlets partial class files (#5612) (Thanks @markekraus!) +- Change `Microsoft.PowerShell.Commands.SetDateCommand.SystemTime` to `struct`. (#6006) (Thanks @stknohg!) +- Add Simplified `multipart/form-data` support to Web Cmdlets through `-Form` parameter (#5972) (Thanks @markekraus!) +- Make a relative redirect URI absolute when `Authorization` header present (#6325) (Thanks @markekraus!) +- Make relation-link handling in Web Cmdlets case-insensitive (#6338) +- Make `Get-ChildItem -LiteralPath` accept `Include` or `Exclude` filter (#5462) +- Stop `ConvertTo-Json` when `Ctrl+c` is hit (#6392) +- Make `Resolve-Path -Relative` return useful path when `$PWD` and `-Path` is on different drive (#5740) (Thanks @kwkam!) +- Correct the `%c`, `%l`, `%k`, `%s` and `%j` formats in `Get-Date -UFormat` (#4805) (Thanks @iSazonov!) +- Add standard deviation implementation on `Measure-Object` (#6238) (Thanks @CloudyDino!) +- Make `Get-ChildItem /* -file` include `` as search directory (#5431) +- Enable setting `PSSession` Name when using `SSHTransport` and add `Transport` property (#5954) +- Add `Path` alias to `-FilePath` parameters and others for several commands (#5817) (Thanks @KevinMarquette!) +- Add the parameter `-Password` to `Get-PfxCertificate` (#6113) (Thanks @maybe-hello-world!) +- Don't add trailing spaces to last column when using `Format-Table` (#5568) +- Fix table alignment and padding. (#6230) +- Add `-SkipHeaderValidation` Support to `ContentType` on Web Cmdlets (#6018) (Thanks @markekraus!) +- Add common aliases for all `write-*` commands default message parameter (#5816) (Thanks @KevinMarquette!) +- Make `UTF-8` the default encoding for `application/json` (#6109) (Thanks @markekraus!) +- Enable `$env:PAGER` to work correctly if arguments are used (#6144) + +### Test + +- Convert Web Cmdlets test to `one-true-brace-style` formatting (#5716) (Thanks @markekraus!) +- Add a test for `IValidateSetValuesGenerator` in a module (#5830) (Thanks @iSazonov!) +- Fix function to test for docker OS due to change to use `linuxkit` for macOS (#5843) +- Replace `HttpListener` tests with `WebListener` (#5806, #5840, #5872) (Thanks @markekraus!) +- Stop `HttpListener` from running in Web Cmdlets tests (#5921) (Thanks @markekraus!) +- Fix `PSVersion` in `PSSessionConfiguration` tests (#5554) (Thanks @iSazonov!) +- Update test framework to support Pester v4 (#6064) +- Update tests to use Pester v4 Syntax. (#6294, #6257, #6306, #6304, #6298) +- Add negative tests for `Copy-Item` over remote sessions (#6231) +- Markdown test: Use strict in JavaScript (#6328) +- Add tests for `Get-Process` about the `-Module` and `-FileVersion` parameters (#6272) +- Add test for the `OsLocalDateTime` property of `Get-ComputerInfo`. (#6253) +- Change `Get-FileHash` tests to use raw bytes (#6430) +- Remove `runas.exe` from tests as we have tags to control this behavior (#6432) +- Refactor the `Get-Content` tests to use `-TestCases`. (#6082) +- Use `RequireAdminOnWindows` tag in `Set-Date` tests (#6034) (Thanks @stknohg!) +- Remove `-TimeOutSec` from non timeout related tests (#6055) (Thanks @markekraus!) +- Add verbosity and more accurate timeout implementation for `Start-WebListener` (#6013) (Thanks @markekraus!) +- Skip tests that use `ExecutionPolicy` cmdlets on Unix (#6021) +- Change Web Cmdlet tests to use `127.0.0.1` instead of `Localhost` (#6069) (Thanks @markekraus!) +- Fix `Start-PSPester` to include or exclude `RequireSudoOnUnix` tag smartly on Unix (#6241) +- Fix the terse output on Windows for test runs without admin privilege (#6252) +- Add `RequireSudoOnUnix` tag for `Get-Help` tests. (#6223) +- Add tests for `*-Item` Cmdlets in function provider (#6172) +- Support running tests in root privilege on Linux. (#6145) + +### Build and Packaging Improvements + +- Add option to add explorer shell context menu in Windows installer (#5774) (Thanks @bergmeister!) +- Make the explorer shell context menu registry entries platform specific to allow side by side of `x86` and `x64`. (#5824) (Thanks @bergmeister!) +- Fix start menu folder clash of shortcut when `x86` and `x64` are both installed by appending ` (x86)` for `x86` installation. (#5826) (Thanks @bergmeister!) +- Reduce image file sizes using lossless compression with `imgbot` (#5808) (Thanks @bergmeister!) +- Windows installer: Allow `Launch PowerShell` checkbox to be toggled using the space bar. (#5792) (Thanks @bergmeister!) +- Fix release packaging build (#6459) +- Fail `AppVeyor` Build if `MSI` does not build (#5755) (Thanks @bergmeister!) +- Cleanup temporarily created `WiX` files after compilation to be able to have a clean re-build (#5757) (Thanks @bergmeister!) +- Fix `install-powershell.ps1` for running during window setup (#5727) +- Start using `Travis-CI` cache (#6003) +- Fix build, packaging and installation scripts for `SLES` (#5918) (Thanks @tomconte!) +- Update recommended `WiX` toolset link to be generic to `WiX 3.x` but mention that latest version of 3.11 has to be taken (#5926) (Thanks @bergmeister!) +- Add service point manager call in `Install-PowerShell.ps1` to force `TLS1.2`. (#6310) (Thanks @DarqueWarrior!) +- Add `-Restore` when build `win-arm` and `win-arm64` (#6353) +- Make sure package verification failure fails the `AppVeyor` build (#6337) +- Specify the runtime when running `dotnet restore` in `Start-PSBuild` (#6345) +- Rename `log` and `logerror` to `Write-Log [$message] [-error]` (#6333) +- Make Linux packages use correct version scheme for preview releases (#6318) +- Add support for Debian in `installpsh-debian.sh` (#6314) (Thanks @Pawamoy!) +- MSI: Make preview builds to install Side by side with release builds (#6301) +- Add `TLS1.2` workaround for code coverage script (#6299) +- Cleanup after Powershell install for `CentOS` and `Fedora` Docker images (#6264) (Thanks @strawgate!) +- MSI: Update the environment variable PATH with proper value (#6441) +- MSI: Remove the version from the product name (#6415) +- Support non-GitHub commits in the change log generation script (#6389) +- Fix secret and JavaScript compliance issues (#6408) +- Remove `AppVeyor` specific cmdlet from `Start-NativeExecution` (#6263) +- Restore modules from the `NuGet` package cache by using `dotnet restore` (#6111) +- CI Build: Use `TRAVIS_PULL_REQUEST_SHA` to accurately get the commit message (#6024) +- Use `TLS1.2` on Windows during `Start-PSBootstrap` (#6235) (Thanks @CallmeJoeBob!) +- Use `TLS1.2` in `Start-PSBootStrap` without breaking `HTTPS` (#6236) (Thanks @markekraus!) +- Add options to enable `PSRemoting` and register Windows Event Logging Manifest to MSI installer (#5999) (Thanks @bergmeister!) + +### Documentation and Help Content + +- Separate macOS from Linux install instructions. (#5823) (Thanks @thezim!) +- Show usage (short) help if command line parameter is wrong (#5780) (Thanks @iSazonov!) +- Add the breaking changes doc for 6.0.0 release. (#5620) (Thanks @maertendMSFT!) +- Remove DockerFile for Fedora 25 and add DockerFile for Fedora 27 (#5984) (Thanks @seemethere!) +- Add a missing step to prepare the build environment on Mac. (#5901) (Thanks @zackJKnight!) +- Update `BREAKINGCHANGES.md` to include WebCmdlets breaking changes (#5852) (Thanks @markekraus!) +- Fix typos in `BREAKINGCHANGES.md` (#5913) (Thanks @brianbunke!) +- Update `macos.md` to use `brew cask upgrade` for upgrading powershell (#5875) (Thanks @timothywlewis!) +- Add verification step to macOS install docs (#5860) (Thanks @rpalo!) +- Fix links in macOS install docs (#5861) (Thanks @kanjibates!) +- Update docs with test guidelines with the `RequireSudoOnUnix` tag. (#6274) +- Add `Alpine` Linux support (#6367) (Thanks @kasper3!) +- Update to Governance doc to reflect current working model (#6323) +- Add guidance on adding copyright and license header to new source files (#6140) +- Fix the command to build type catalog in `internals.md` (#6084) (Thanks @ppadmavilasom!) +- Fix `Pull Request Process` dead link (#6066) (Thanks @IISResetMe!) +- Update processes to allow for coordinated vulnerability disclosure (#6042) +- Rework Windows Start menu folder name (#5891) (Thanks @Stanzilla!) +- Update `Raspbian` installation instructions to create `symlink` for `pwsh` (#6122) +- Fix various places that still refer to old versions of `pwsh` (#6179) (Thanks @bergmeister!) +- Correct a Linux installation typo (#6219) (Thanks @mababio!) +- Change synopsis of `install-powershell.ps1` to reflect that it works cross-platform (#5465) (Thanks @bergmeister!) + +## v6.0.2 - 2018-03-15 + +### Engine updates and fixes + +- Update PowerShell to use `2.0.6` dotnet core runtime and packages (#6403) + - This change addresses this vulnerability: [Microsoft Security Advisory `CVE-2018-0875`: Hash Collision can cause Denial of Service](https://github.com/PowerShell/Announcements/issues/4) + +### Build and Packaging Improvements + +- Add Ubuntu build without `AppImage` (#6380) +- Add scripts to set and or update the release tag in `VSTS` (#6107) +- Fix `DSC` Configuration compilation (#6225) +- Fix errors in `Start-PSBootStrap` during release builds (#6159) +- Fix spelling failures in `CI` (#6191) +- Use PowerShell `windowsservercore` Docker image for release builds (#6226) +- Use `ADD` instead of `Invoke-WebRequest` in `nanoserver` Docker file (#6255) +- When doing daily/test build in a non-release branch use the branch name as the preview name (#6355) +- Add Environment Variable override of telemetry (#6063) (Thanks @diddledan!) +- Build: Remove two unneeded lines from `Invoke-AppveyorFinish` (#6344) +- MSI: Refactor `New-MsiPackage` into `packaging.psm1` + and various fixes to enable patching + (#5871, #6221, #6254, #6303, #6356, #6208, #6334, #6379, #6094, #6192) +- MSI: Use `HKLM` instead of `HKCU` registry keys since the current installation scope is per-machine. (#5915) (Thanks @bergmeister!) + +## v6.0.1 - 2018-01-25 + +### Engine updates and fixes + +- Update PowerShell to use `2.0.5` dotnet core runtime and packages. (#5903, #5961) (Thanks @iSazonov!) + +### Build and Packaging Improvements + +- Re-release of `v6.0.0` as `v6.0.1` due to issues upgrading from pre-release versions + +### Test + +- Update regular expression to validate `GitCommitId` in `$PSVersionTable` to not require a pre-release tag (#5893) + +## v6.0.0 - 2018-01-10 + +### Breaking changes + +- Remove `sc` alias which conflicts with `sc.exe` (#5827) +- Separate group policy settings and enable policy controlled logging in PowerShell Core (#5791) + +### Engine updates and fixes + +- Handle `DLLImport` failure of `libpsrpclient` in PowerShell Remoting on Unix platforms (#5622) + +### Test + +- Replace `lee.io` Tests with `WebListener` (#5709) (Thanks @markekraus!) +- Update the docker based release package tests due to the removal of `Pester` module and other issues (#5692) +- Replace Remaining `HttpBin.org` Tests with `WebListener` (#5665) (Thanks @markekraus!) + +### Build and Packaging Improvements + +- Update x86 and x64 `MSI` packages to not overwrite each other (#5812) (Thanks @bergmeister!) +- Update `Restore-PSPester` to include the fix for nested describe errors (#5771) +- Automate the generation of release change log draft (#5712) + +### Documentation and Help Content + +- Updated help Uri to point to latest help content for `Microsoft.PowerShell.Core` module (#5820) +- Update the installation doc for `Raspberry-Pi` about supported devices (#5773) +- Fix a typo and a Markdown linting error in the Pull Request Template (#5807) (Thanks @markekraus!) +- Update submodule documentation for pester removal (#5786) (Thanks @bergmeister!) +- Change `Github` to `GitHub` in `CONTRIBUTING.md` (#5697) (Thanks @stuntguy3000!) +- Fix incorrect release date on the changelog (#5698) (Thanks @SwarfegaGit!) +- Add instructions to deploy `win-arm` build on Windows IoT (#5682) + ## v6.0.0-rc.2 - 2017-12-14 ### Breaking changes @@ -468,7 +2497,7 @@ work is required for Microsoft to continue to sign and release packages from the ### Breaking change -* Make invalid argument error messages for -File and -Command consistent and make exit codes consistent with Unix standards (#4573) +* Make invalid argument error messages for `-File` and `-Command` consistent and make exit codes consistent with Unix standards (#4573) ### Engine updates and fixes @@ -561,7 +2590,7 @@ To read more about this, check out [this blog post](https://blogs.msdn.microsoft * Add support for `Invoke-Item -Path `. (#4262) * Fix `ConvertTo-Html` output when using a single column header. (#4276) * Fix output of `Length` for `FileInfo` when using `Format-List`. (#4437) -* Fix an issue in implicit remoting where restricted sessions couldn't use `Get-FormatData –PowerShellVersion`. (#4222) +* Fix an issue in implicit remoting where restricted sessions couldn't use `Get-FormatData �PowerShellVersion`. (#4222) * Fix an issue where `Register-PSSessionConfiguration` fails if `SessionConfig` folder doesn't exist. (#4271) ### Installer updates @@ -664,10 +2693,12 @@ For more information on this, we invite you to read [this blog post explaining P Even if the module isn't owned by the PowerShell Team, please tell us what works and what doesn't by leaving a comment in [issue #4062][issue-4062]! (#3981) - Enhance type inference in tab completion based on runtime variable values. (#2744) (Thanks to @powercode!) This enables tab completion in situations like: + ```powershell $p = Get-Process $p | Foreach-Object Prio ``` + - Add `GitCommitId` to PowerShell Core banner. Now you don't have to run `$PSVersionTable` as soon as you start PowerShell to get the version! (#3916) (Thanks to @iSazonov!) - Fix a bug in tab completion to make `native.exe --` call into native completer. (#3633) (Thanks to @powercode!) @@ -701,7 +2732,7 @@ For more information on this, we invite you to read [this blog post explaining P - Once the pipeline is running as a job, all of the standard `*-Job` cmdlets can be used to manage the job. - Variables (ignoring process-specific variables) used in the pipeline are automatically copied to the job so `Copy-Item $foo $bar &` just works. - The job is also run in the current directory instead of the user's home directory. -- For more information about PowerShell jobs, see [about_Jobs](https://msdn.microsoft.com/en-us/powershell/reference/6/about/about_jobs). +- For more information about PowerShell jobs, see [about_Jobs](https://msdn.microsoft.com/powershell/reference/6/about/about_jobs). ### Engine updates and fixes @@ -746,7 +2777,7 @@ Many modules and cmdlets that didn't work in the past may now work on .NET Core, If you want to opt-out of this telemetry, simply delete `$PSHome\DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY`. Even before the first run of Powershell, deleting this file will bypass all telemetry. -In the future, we plan on also enabling a configuration value for whatever is approved as part of [RFC0015](https://github.com/PowerShell/PowerShell-RFC/blob/master/1-Draft/RFC0015-PowerShell-StartupConfig.md). +In the future, we plan on also enabling a configuration value for whatever is approved as part of [RFC0015](https://github.com/PowerShell/PowerShell-RFC/blob/master/X-Rejected/RFC0015-PowerShell-StartupConfig.md). We also plan on exposing this telemetry data (as well as whatever insights we leverage from the telemetry) in [our community dashboard](https://blogs.msdn.microsoft.com/powershell/2017/01/31/powershell-open-source-community-dashboard/). If you have any questions or comments about our telemetry, please file an issue. @@ -850,9 +2881,9 @@ We made a number of fixes to the progress bar rendering and the `ProgressRecord` - Add the `-TimeOut` parameter to `Test-Connection`. (#2492) - Add `ShouldProcess` support to `New-FileCatalog` and `Test-FileCatalog` (fixes `-WhatIf` and `-Confirm`). (#3074) (Thanks to @iSazonov!) - Fix `Test-ModuleManifest` to normalize paths correctly before validating. - - This fixes some problems when using `Publish-Module` on non-Windows platforms. (#3097) + - This fixes some problems when using `Publish-Module` on non-Windows platforms. (#3097) - Remove the `AliasProperty "Count"` defined for `System.Array`. - - This removes the extraneous `Count` property on some `ConvertFrom-Json` output. (#3231) (Thanks to @PetSerAl!) + - This removes the extraneous `Count` property on some `ConvertFrom-Json` output. (#3231) (Thanks to @PetSerAl!) - Port `Import-PowerShellDatafile` from PowerShell script to C#. (#2750) (Thanks to @powercode!) - Add `-CustomMethod` parameter to web cmdlets to allow for non-standard method verbs. (#3142) (Thanks to @Lee303!) - Fix web cmdlets to include the HTTP response in the exception when the response status code is not success. (#3201) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index dddfa22df2ad..90768d1293e5 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -3,6 +3,6 @@ This project has adopted the [Microsoft Open Source Code of Conduct][conduct-code]. For more information see the [Code of Conduct FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any additional questions or comments. -[conduct-code]: http://opensource.microsoft.com/codeofconduct/ -[conduct-FAQ]: http://opensource.microsoft.com/codeofconduct/faq/ +[conduct-code]: https://opensource.microsoft.com/codeofconduct/ +[conduct-FAQ]: https://opensource.microsoft.com/codeofconduct/faq/ [conduct-email]: mailto:opencode@microsoft.com diff --git a/LICENSE.txt b/LICENSE.txt index f2618346d7bd..f8b2ee434814 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,8 +2,6 @@ PowerShell 6.0 Copyright (c) Microsoft Corporation. All rights reserved. -All rights reserved. - MIT License Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/PowerShell.Common.props b/PowerShell.Common.props index a9ac37f96752..f8c90bf678b2 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -62,6 +62,8 @@ Tracking Issue https://github.com/dotnet/sdk/issues/1557 --> $(PSCoreBuildVersion) + ..\..\assets\Powershell_av_colors.ico + ..\..\assets\Powershell_black.ico @@ -89,16 +91,17 @@ - PowerShell Core + PowerShell Microsoft Corporation (c) Microsoft Corporation. All rights reserved. - netcoreapp2.0 - 2.0.4 + netcoreapp3.0 + 8.0 true true true + true en-US true @@ -107,4 +110,45 @@ true + + $(DefineConstants);CORECLR + true + + + + + $(DefineConstants);UNIX + + + + + portable + + + + + true + + + + + true + + full + + + + + + false + portable + + + + + + portable + diff --git a/PowerShell-Win.sln b/PowerShell.sln similarity index 74% rename from PowerShell-Win.sln rename to PowerShell.sln index 35a5c99e93dc..b164361d7d2e 100644 --- a/PowerShell-Win.sln +++ b/PowerShell.sln @@ -1,34 +1,47 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 +# Visual Studio Version 16 +# https://github.com/dotnet/project-system/blob/master/docs/opening-with-new-project-system.md#project-type-guids VisualStudioVersion = 15.0.26730.12 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "powershell-win-core", "src\powershell-win-core\powershell-win-core.csproj", "{8359D422-E0C4-4A0D-94EB-3C9DD16B7932}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "powershell-win-core", "src\powershell-win-core\powershell-win-core.csproj", "{8359D422-E0C4-4A0D-94EB-3C9DD16B7932}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Management.Automation", "src\System.Management.Automation\System.Management.Automation.csproj", "{AF660EE7-0183-4B79-A93F-221B6AC1C24B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Management.Automation", "src\System.Management.Automation\System.Management.Automation.csproj", "{AF660EE7-0183-4B79-A93F-221B6AC1C24B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.Commands.Utility", "src\Microsoft.PowerShell.Commands.Utility\Microsoft.PowerShell.Commands.Utility.csproj", "{EAB203E1-2A68-4166-BE54-5C44DE825229}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.Commands.Utility", "src\Microsoft.PowerShell.Commands.Utility\Microsoft.PowerShell.Commands.Utility.csproj", "{EAB203E1-2A68-4166-BE54-5C44DE825229}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.CoreCLR.Eventing", "src\Microsoft.PowerShell.CoreCLR.Eventing\Microsoft.PowerShell.CoreCLR.Eventing.csproj", "{981D3972-343D-4E17-935B-037E1C622771}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.CoreCLR.Eventing", "src\Microsoft.PowerShell.CoreCLR.Eventing\Microsoft.PowerShell.CoreCLR.Eventing.csproj", "{981D3972-343D-4E17-935B-037E1C622771}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.ConsoleHost", "src\Microsoft.PowerShell.ConsoleHost\Microsoft.PowerShell.ConsoleHost.csproj", "{8FFE645D-F0C9-4220-9A88-83062ED211D2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.ConsoleHost", "src\Microsoft.PowerShell.ConsoleHost\Microsoft.PowerShell.ConsoleHost.csproj", "{8FFE645D-F0C9-4220-9A88-83062ED211D2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.Commands.Management", "src\Microsoft.PowerShell.Commands.Management\Microsoft.PowerShell.Commands.Management.csproj", "{FCE53A5E-5FAC-48BE-BAD8-2110040B5C2E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.Commands.Management", "src\Microsoft.PowerShell.Commands.Management\Microsoft.PowerShell.Commands.Management.csproj", "{FCE53A5E-5FAC-48BE-BAD8-2110040B5C2E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.SDK", "src\Microsoft.PowerShell.SDK\Microsoft.PowerShell.SDK.csproj", "{4BC19063-1F66-467B-87DE-80449C72BCD6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.SDK", "src\Microsoft.PowerShell.SDK\Microsoft.PowerShell.SDK.csproj", "{4BC19063-1F66-467B-87DE-80449C72BCD6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Management.Infrastructure.CimCmdlets", "src\Microsoft.Management.Infrastructure.CimCmdlets\Microsoft.Management.Infrastructure.CimCmdlets.csproj", "{131A8527-92D7-468F-822D-5354229A865C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Management.Infrastructure.CimCmdlets", "src\Microsoft.Management.Infrastructure.CimCmdlets\Microsoft.Management.Infrastructure.CimCmdlets.csproj", "{131A8527-92D7-468F-822D-5354229A865C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.Commands.Diagnostics", "src\Microsoft.PowerShell.Commands.Diagnostics\Microsoft.PowerShell.Commands.Diagnostics.csproj", "{439A24FC-8E0A-48B6-8227-44C297311F49}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.Commands.Diagnostics", "src\Microsoft.PowerShell.Commands.Diagnostics\Microsoft.PowerShell.Commands.Diagnostics.csproj", "{439A24FC-8E0A-48B6-8227-44C297311F49}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.PSReadLine", "src\Microsoft.PowerShell.PSReadLine\Microsoft.PowerShell.PSReadLine.csproj", "{07BFD271-8992-4F34-9091-6CFC3E224A24}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.WSMan.Management", "src\Microsoft.WSMan.Management\Microsoft.WSMan.Management.csproj", "{8F63D134-E413-4181-936D-D82F3F5F1D85}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.WSMan.Management", "src\Microsoft.WSMan.Management\Microsoft.WSMan.Management.csproj", "{8F63D134-E413-4181-936D-D82F3F5F1D85}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.Security", "src\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.csproj", "{C4F81816-C87A-4ABF-8A37-24AC16A0A6CF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.Security", "src\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.csproj", "{C4F81816-C87A-4ABF-8A37-24AC16A0A6CF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.WSMan.Runtime", "src\Microsoft.WSMan.Runtime\Microsoft.WSMan.Runtime.csproj", "{D9CCCB67-4EBE-4854-AB52-C0129DC5BAE4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.WSMan.Runtime", "src\Microsoft.WSMan.Runtime\Microsoft.WSMan.Runtime.csproj", "{D9CCCB67-4EBE-4854-AB52-C0129DC5BAE4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "powershell-unix", "src\powershell-unix\powershell-unix.csproj", "{73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerShell.MarkdownRender", "src\Microsoft.PowerShell.MarkdownRender\Microsoft.PowerShell.MarkdownRender.csproj", "{43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnit.tests", "test\xUnit\xUnit.tests.csproj", "{08704934-9764-48CE-86DB-BCF0A1CF7899}" +EndProject +# Configuration mapping comment +# All global configurations must be mapped to project configurations +# +# 4BC19063-1F66-467B-87DE-80449C72BCD6 - Microsoft.PowerShell.SDK +# 8359D422-E0C4-4A0D-94EB-3C9DD16B7932 - PowerShell-Win +# Linux is invalid and mapped to Release +# +# 73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690 - powershell-unix +# Only Linux is valid, all configurations mapped to Linux Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CodeCoverage|Any CPU = CodeCoverage|Any CPU @@ -41,8 +54,8 @@ Global {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Linux|Any CPU.ActiveCfg = Linux|Any CPU - {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Linux|Any CPU.Build.0 = Linux|Any CPU + {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Linux|Any CPU.ActiveCfg = Release|Any CPU + {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Linux|Any CPU.Build.0 = Release|Any CPU {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Release|Any CPU.ActiveCfg = Release|Any CPU {8359D422-E0C4-4A0D-94EB-3C9DD16B7932}.Release|Any CPU.Build.0 = Release|Any CPU {AF660EE7-0183-4B79-A93F-221B6AC1C24B}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU @@ -109,14 +122,6 @@ Global {439A24FC-8E0A-48B6-8227-44C297311F49}.Linux|Any CPU.Build.0 = Linux|Any CPU {439A24FC-8E0A-48B6-8227-44C297311F49}.Release|Any CPU.ActiveCfg = Release|Any CPU {439A24FC-8E0A-48B6-8227-44C297311F49}.Release|Any CPU.Build.0 = Release|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.Linux|Any CPU.ActiveCfg = Linux|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.Linux|Any CPU.Build.0 = Linux|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.Release|Any CPU.ActiveCfg = Release|Any CPU - {07BFD271-8992-4F34-9091-6CFC3E224A24}.Release|Any CPU.Build.0 = Release|Any CPU {8F63D134-E413-4181-936D-D82F3F5F1D85}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU {8F63D134-E413-4181-936D-D82F3F5F1D85}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU {8F63D134-E413-4181-936D-D82F3F5F1D85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -141,6 +146,30 @@ Global {D9CCCB67-4EBE-4854-AB52-C0129DC5BAE4}.Linux|Any CPU.Build.0 = Linux|Any CPU {D9CCCB67-4EBE-4854-AB52-C0129DC5BAE4}.Release|Any CPU.ActiveCfg = Release|Any CPU {D9CCCB67-4EBE-4854-AB52-C0129DC5BAE4}.Release|Any CPU.Build.0 = Release|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.Linux|Any CPU.ActiveCfg = Linux|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.Linux|Any CPU.Build.0 = Linux|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.Release|Any CPU.Build.0 = Release|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU + {73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.Linux|Any CPU.ActiveCfg = Linux|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.Linux|Any CPU.Build.0 = Linux|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43D4F8DA-A7DE-494B-81B0-BDE3CFD7B1F1}.Release|Any CPU.Build.0 = Release|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.Linux|Any CPU.ActiveCfg = Linux|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.Linux|Any CPU.Build.0 = Linux|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08704934-9764-48CE-86DB-BCF0A1CF7899}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index d4f512c0eab4..b5d72f90d1be 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,12 @@ PowerShell Core is a cross-platform (Windows, Linux, and macOS) automation and c for dealing with structured data (e.g. JSON, CSV, XML, etc.), REST APIs, and object models. It includes a command-line shell, an associated scripting language and a framework for processing cmdlets. -[logo]: https://raw.githubusercontent.com/PowerShell/PowerShell/master/assets/Powershell_black_64.png +[logo]: https://raw.githubusercontent.com/PowerShell/PowerShell/master/assets/ps_black_64.svg?sanitize=true -## Windows PowerShell vs PowerShell Core +## Windows PowerShell vs. PowerShell Core -Although this repo started as a fork of the Windows PowerShell code base, changes made in this repo do not make their way back to Windows PowerShell 5.1 automatically. -This also means that issues tracked here are only for PowerShell Core 6.0. +Although this repository started as a fork of the Windows PowerShell code base, changes made in this repository do not make their way back to Windows PowerShell 5.1 automatically. +This also means that issues tracked here are only for PowerShell Core 6. Windows PowerShell specific issues should be opened on [UserVoice][]. [UserVoice]: https://windowsserver.uservoice.com/forums/301869-powershell @@ -25,82 +25,93 @@ If you are new to PowerShell and would like to learn more, we recommend reviewin You can download and install a PowerShell package for any of the following platforms. -| Supported Platform | Downloads | How to Install | -| -------------------------------------------| ------------------------| ----------------------------- | -| [Windows (x64)][corefx-win] | [.msi][rl-windows-64] | [Instructions][in-windows] | -| [Windows (x86)][corefx-win] | [.msi][rl-windows-86] | [Instructions][in-windows] | -| [Ubuntu 17.04][corefx-linux] | [.deb][rl-ubuntu17] | [Instructions][in-ubuntu17] | -| [Ubuntu 16.04][corefx-linux] | [.deb][rl-ubuntu16] | [Instructions][in-ubuntu16] | -| [Ubuntu 14.04][corefx-linux] | [.deb][rl-ubuntu14] | [Instructions][in-ubuntu14] | -| [Debian 8.7+][corefx-linux] | [.deb][rl-debian8] | [Instructions][in-deb8] | -| [Debian 9][corefx-linux] | [.deb][rl-debian9] | [Instructions][in-deb9] | -| [CentOS 7][corefx-linux] | [.rpm][rl-centos] | [Instructions][in-centos] | -| [Red Hat Enterprise Linux 7][corefx-linux] | [.rpm][rl-centos] | [Instructions][in-rhel7] | -| [OpenSUSE 42.2][corefx-linux] | [.rpm][rl-centos] | [Instructions][in-opensuse422]| -| [Fedora 25][corefx-linux] | [.rpm][rl-centos] | [Instructions][in-fedora25] | -| [Fedora 26][corefx-linux] | [.rpm][rl-centos] | [Instructions][in-fedora26] | -| [macOS 10.12+][corefx-macos] | [.pkg][rl-macos] | [Instructions][in-macos] | -| Docker | | [Instructions][in-docker] | +| Supported Platform | Downloads (stable) | Downloads (preview) | How to Install | +| -------------------------------------------| ------------------------| ----------------------| ------------------------------| +| [Windows (x64)][corefx-win] | [.msi][rl-windows-64] | [.msi][pv-windows-64] | [Instructions][in-windows] | +| [Windows (x86)][corefx-win] | [.msi][rl-windows-86] | [.msi][pv-windows-86] | [Instructions][in-windows] | +| [Ubuntu 18.04][corefx-linux] | [.deb][rl-ubuntu18] | [.deb][pv-ubuntu18] | [Instructions][in-ubuntu18] | +| [Ubuntu 16.04][corefx-linux] | [.deb][rl-ubuntu16] | [.deb][pv-ubuntu16] | [Instructions][in-ubuntu16] | +| [Debian 9][corefx-linux] | [.deb][rl-debian9] | [.deb][pv-debian9] | [Instructions][in-deb9] | +| [CentOS 7][corefx-linux] | [.rpm][rl-centos] | [.rpm][pv-centos] | [Instructions][in-centos] | +| [Red Hat Enterprise Linux 7][corefx-linux] | [.rpm][rl-centos] | [.rpm][pv-centos] | [Instructions][in-rhel7] | +| [openSUSE 42.3][corefx-linux] | [.rpm][rl-centos] | [.rpm][pv-centos] | [Instructions][in-opensuse] | +| [Fedora 28][corefx-linux] | [.rpm][rl-centos] | [.rpm][pv-centos] | [Instructions][in-fedora] | +| [macOS 10.12+][corefx-macos] | [.pkg][rl-macos] | [.pkg][pv-macos] | [Instructions][in-macos] | +| Docker | | | [Instructions][in-docker] | You can download and install a PowerShell package for any of the following platforms, **which are supported by the community.** -| Platform | Downloads | How to Install | -| -------------------------| ------------------------| ----------------------------- | -| Arch Linux | | [Instructions][in-archlinux] | -| Kali Linux | [.deb][rl-ubuntu16] | [Instructions][in-kali] | -| Many Linux distributions | [.AppImage][rl-ai] | [Instructions][in-appimage] | +| Platform | Downloads (stable) | Downloads (preview) | How to Install | +| -------------------------| ------------------------| ----------------------------- | ------------------------------| +| Arch Linux | | | [Instructions][in-archlinux] | +| Kali Linux | [.deb][rl-ubuntu16] | [.deb][pv-ubuntu16] | [Instructions][in-kali] | +| Many Linux distributions | [Snapcraft][rl-snap] | [Snapcraft][pv-snap] | | You can also download the PowerShell binary archives for Windows, macOS and Linux. -| Platform | Downloads | How to Install | -| ------------------------------------| ------------------------------------------------ | ------------------------------ | -| Windows | [32-bit][rl-winx86-zip]/[64-bit][rl-winx64-zip] | [Instructions][in-windows-zip] | -| macOS | [64-bit][rl-macos-tar] | [Instructions][in-tar] | -| Linux | [64-bit][rl-linux-tar] | [Instructions][in-tar] | -| Windows (arm) **Experimental** | [32-bit][rl-winarm]/[64-bit][rl-winarm64] | [Instructions][in-windows-zip] | -| Raspbian (Stretch) **Experimental** | [.tgz][rl-raspbian] | [Instructions][in-raspbian] | - -[rl-windows-64]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-win-x64.msi -[rl-windows-86]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-win-x86.msi -[rl-ubuntu17]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell_6.0.0-rc.2-1.ubuntu.17.04_amd64.deb -[rl-ubuntu16]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell_6.0.0-rc.2-1.ubuntu.16.04_amd64.deb -[rl-ubuntu14]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell_6.0.0-rc.2-1.ubuntu.14.04_amd64.deb -[rl-debian8]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell_6.0.0-rc.2-1.debian.8_amd64.deb -[rl-debian9]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell_6.0.0-rc.2-1.debian.9_amd64.deb -[rl-centos]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -[rl-ai]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-x86_64.AppImage -[rl-macos]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-osx.10.12-x64.pkg -[rl-winarm]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-win-arm32.zip -[rl-winarm64]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-win-arm64.zip -[rl-winx86-zip]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-win-x86.zip -[rl-winx64-zip]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-win-x64.zip -[rl-macos-tar]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-osx-x64.tar.gz -[rl-linux-tar]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-linux-x64.tar.gz -[rl-raspbian]: https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-linux-arm32.tar.gz - -[installation]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation -[in-windows]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/windows.md#msi -[in-ubuntu14]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#ubuntu-1404 -[in-ubuntu16]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#ubuntu-1604 -[in-ubuntu17]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#ubuntu-1704 -[in-deb8]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#debian-8 -[in-deb9]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#debian-9 -[in-centos]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#centos-7 -[in-rhel7]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#red-hat-enterprise-linux-rhel-7 -[in-opensuse422]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#opensuse-422 -[in-fedora25]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#fedora-25 -[in-fedora26]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#fedora-26 -[in-archlinux]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#arch-linux -[in-appimage]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#linux-appimage -[in-macos]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#macos-1012 -[in-docker]: https://github.com/PowerShell/PowerShell/tree/master/docker -[in-kali]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#kali -[in-windows-zip]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/windows.md#zip -[in-tar]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#binary-archives -[in-raspbian]: https://github.com/PowerShell/PowerShell/tree/master/docs/installation/linux.md#raspbian -[corefx-win]:https://github.com/dotnet/core/blob/master/release-notes/2.0/2.0-supported-os.md#windows -[corefx-linux]:https://github.com/dotnet/core/blob/master/release-notes/2.0/2.0-supported-os.md#linux -[corefx-macos]:https://github.com/dotnet/core/blob/master/release-notes/2.0/2.0-supported-os.md#macos +| Platform | Downloads (stable) | Downloads (preview) | How to Install | +| ------------------------------------| ------------------------------------------------ | ------------------------------------------------| -----------------------------------------------| +| Windows | [32-bit][rl-winx86-zip]/[64-bit][rl-winx64-zip] | [32-bit][pv-winx86-zip]/[64-bit][pv-winx64-zip] | [Instructions][in-windows-zip] | +| macOS | [64-bit][rl-macos-tar] | [64-bit][pv-macos-tar] | [Instructions][in-tar-macos] | +| Linux | [64-bit][rl-linux-tar] | [64-bit][pv-linux-tar] | [Instructions][in-tar-linux] | +| Windows (arm) **Experimental** | [32-bit][rl-winarm]/[64-bit][rl-winarm64] | [32-bit][pv-winarm]/[64-bit][pv-winarm64] | [Instructions][in-arm] | +| Raspbian (Stretch) **Experimental** | [32-bit][rl-raspbian]/[64-bit][rl-raspbian64] | [32-bit][pv-arm32]/[64-bit][pv-arm64] | [Instructions][in-raspbian] | + +[rl-windows-64]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/PowerShell-6.2.2-win-x64.msi +[rl-windows-86]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/PowerShell-6.2.2-win-x86.msi +[rl-ubuntu18]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell_6.2.2-1.ubuntu.18.04_amd64.deb +[rl-ubuntu16]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell_6.2.2-1.ubuntu.16.04_amd64.deb +[rl-debian9]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell_6.2.2-1.debian.9_amd64.deb +[rl-centos]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-1.rhel.7.x86_64.rpm +[rl-macos]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-osx-x64.pkg +[rl-winarm]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/PowerShell-6.2.2-win-arm32.zip +[rl-winarm64]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/PowerShell-6.2.2-win-arm64.zip +[rl-winx86-zip]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/PowerShell-6.2.2-win-x86.zip +[rl-winx64-zip]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/PowerShell-6.2.2-win-x64.zip +[rl-macos-tar]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-osx-x64.tar.gz +[rl-linux-tar]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-linux-x64.tar.gz +[rl-raspbian]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-linux-arm32.tar.gz +[rl-raspbian64]: https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-linux-arm64.tar.gz +[rl-snap]: https://snapcraft.io/powershell + +[pv-windows-64]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/PowerShell-7.0.0-preview.3-win-x64.msi +[pv-windows-86]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/PowerShell-7.0.0-preview.3-win-x86.msi +[pv-ubuntu18]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-preview_7.0.0-preview.3-1.ubuntu.18.04_amd64.deb +[pv-ubuntu16]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-preview_7.0.0-preview.3-1.ubuntu.16.04_amd64.deb +[pv-debian9]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-preview_7.0.0-preview.3-1.debian.9_amd64.deb +[pv-centos]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-preview-7.0.0_preview.3-1.rhel.7.x86_64.rpm +[pv-macos]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-7.0.0-preview.3-osx-x64.pkg +[pv-winarm]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/PowerShell-7.0.0-preview.3-win-arm32.zip +[pv-winarm64]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/PowerShell-7.0.0-preview.3-win-arm64.zip +[pv-winx86-zip]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/PowerShell-7.0.0-preview.3-win-x86.zip +[pv-winx64-zip]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/PowerShell-7.0.0-preview.3-win-x64.zip +[pv-macos-tar]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-7.0.0-preview.3-osx-x64.tar.gz +[pv-linux-tar]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-7.0.0-preview.3-linux-x64.tar.gz +[pv-arm32]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-7.0.0-preview.3-linux-arm32.tar.gz +[pv-arm64]: https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-preview.3/powershell-7.0.0-preview.3-linux-arm64.tar.gz +[pv-snap]: https://snapcraft.io/powershell-preview + +[in-windows]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-windows?view=powershell-6 +[in-ubuntu14]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#ubuntu-1404 +[in-ubuntu16]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#ubuntu-1604 +[in-ubuntu18]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#ubuntu-1804 +[in-deb9]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#debian-9 +[in-centos]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#centos-7 +[in-rhel7]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#red-hat-enterprise-linux-rhel-7 +[in-opensuse]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#opensuse +[in-fedora]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#fedora +[in-archlinux]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#arch-linux +[in-macos]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-macos?view=powershell-6 +[in-docker]: https://github.com/PowerShell/PowerShell-Docker +[in-kali]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#kali +[in-windows-zip]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-windows?view=powershell-6#zip +[in-tar-linux]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#binary-archives +[in-tar-macos]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-macos?view=powershell-6#binary-archives +[in-raspbian]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6#raspbian +[in-arm]: https://docs.microsoft.com/powershell/scripting/setup/powershell-core-on-arm?view=powershell-6 +[corefx-win]:https://github.com/dotnet/core/blob/master/release-notes/3.0/3.0-supported-os.md#windows +[corefx-linux]:https://github.com/dotnet/core/blob/master/release-notes/3.0/3.0-supported-os.md#linux +[corefx-macos]:https://github.com/dotnet/core/blob/master/release-notes/3.0/3.0-supported-os.md#macos To install a specific version, visit [releases](https://github.com/PowerShell/PowerShell/releases). @@ -116,15 +127,15 @@ Want to chat with other members of the PowerShell community? We have a Gitter Room which you can join below. -[![Join the chat at https://gitter.im/PowerShell/PowerShell](https://badges.gitter.im/PowerShell/PowerShell.svg)](https://gitter.im/PowerShell/PowerShell?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat](https://img.shields.io/static/v1.svg?label=chat&message=on%20gitter&color=informational&logo=gitter)](https://gitter.im/PowerShell/PowerShell?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -There is also the community driven PowerShell Slack Team which you can sign up for at [Slack Sign up]. +There is also the community driven PowerShell Slack Team which you can sign up for at [Slack]. -[Slack Sign up]: http://slack.poshcode.org +[Slack]: http://slack.poshcode.org ## Add-ons and libraries -[Awesome PowerShell](https://github.com/janikvonrotz/awesome-powershell) is a great curated list of add-ons and resources. +[Awesome PowerShell](https://github.com/janikvonrotz/awesome-powershell) has a great curated list of add-ons and resources. ## Building the Repository @@ -134,17 +145,11 @@ There is also the community driven PowerShell Slack Team which you can sign up f If you have any problems building, please consult the developer [FAQ][]. -### Build status of master branches - -| AppVeyor (Windows) | Travis CI (Linux / macOS) | -|--------------------------|--------------------------| -| [![av-image][]][av-site] | [![tv-image][]][tv-site] | - ### Build status of nightly builds -| AppVeyor (Windows) | Travis CI (Linux) | Travis CI (macOS) | Code Coverage Status | -|--------------------------|-------------------|-------------------|----------------------| -| [![av-nightly-image][]][av-nightly-site] | [![linux-nightly-image][]][tv-site] | [![macOS-nightly-image][]][tv-site] | [![cc-image][]][cc-site] | +| Azure CI (Windows) | Azure CI (Linux) | Azure CI (macOS) | Code Coverage Status | CodeFactor Grade | +|:-----------------------------------------|:-----------------------------------------------|:-----------------------------------------------|:-------------------------|:-------------------------| +| [![windows-nightly-image][]][windows-nightly-site] | [![linux-nightly-image][]][linux-nightly-site] | [![macOS-nightly-image][]][macos-nightly-site] | [![cc-image][]][cc-site] | [![cf-image][]][cf-site] | [bd-linux]: https://github.com/PowerShell/PowerShell/tree/master/docs/building/linux.md [bd-windows]: https://github.com/PowerShell/PowerShell/tree/master/docs/building/windows-core.md @@ -152,31 +157,31 @@ If you have any problems building, please consult the developer [FAQ][]. [FAQ]: https://github.com/PowerShell/PowerShell/tree/master/docs/FAQ.md -[tv-image]: https://travis-ci.org/PowerShell/PowerShell.svg?branch=master -[tv-site]: https://travis-ci.org/PowerShell/PowerShell/branches -[av-image]: https://ci.appveyor.com/api/projects/status/nsng9iobwa895f98/branch/master?svg=true -[av-site]: https://ci.appveyor.com/project/PowerShell/powershell -[linux-nightly-image]: https://jimtru1979.blob.core.windows.net/badges/DailyBuildStatus.Linux.svg -[macOS-nightly-image]: https://jimtru1979.blob.core.windows.net/badges/DailyBuildStatus.OSX.svg -[av-nightly-image]: https://ci.appveyor.com/api/projects/status/46yd4jogtm2jodcq?svg=true -[av-nightly-site]: https://ci.appveyor.com/project/PowerShell/powershell-f975h +[az-windows-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-windows?branchName=master +[az-windows-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=19 +[az-linux-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-linux?branchName=master +[az-linux-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=17 +[az-macos-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-macos?branchName=master +[az-macos-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=14 +[az-spell-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-static-analysis?branchName=master +[az-spell-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=22 +[windows-nightly-site]: https://powershell.visualstudio.com/PowerShell/_build/latest?definitionId=32 +[linux-nightly-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=23 +[macos-nightly-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=24 +[windows-nightly-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-Windows-daily +[linux-nightly-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-linux-daily?branchName=master +[macOS-nightly-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-macos-daily?branchName=master [cc-site]: https://codecov.io/gh/PowerShell/PowerShell [cc-image]: https://codecov.io/gh/PowerShell/PowerShell/branch/master/graph/badge.svg +[cf-site]: https://www.codefactor.io/repository/github/powershell/powershell +[cf-image]: https://www.codefactor.io/repository/github/powershell/powershell/badge ## Downloading the Source Code -The PowerShell repository has a number of other repositories embedded as submodules. - -To make things easy, you can just clone recursively: +You can just clone the repository: ```sh -git clone --recursive https://github.com/PowerShell/PowerShell.git -``` - -If you already cloned but forgot to use `--recursive`, you can update submodules manually: - -```sh -git submodule update --init +git clone https://github.com/PowerShell/PowerShell.git ``` See [working with the PowerShell repository](https://github.com/PowerShell/PowerShell/tree/master/docs/git) for more information. @@ -184,18 +189,18 @@ See [working with the PowerShell repository](https://github.com/PowerShell/Power ## Developing and Contributing Please see the [Contribution Guide][] for how to develop and contribute. - -If you have any problems, please consult the [known issues][], developer [FAQ][], and [GitHub issues][]. -If you do not see your problem captured, please file a [new issue][] and follow the provided template. If you are developing .NET Core C# applications targeting PowerShell Core, please [check out our FAQ][] to learn more about the PowerShell SDK NuGet package. -Also make sure to check out our [PowerShell-RFC repository](https://github.com/powershell/powershell-rfc) for request-for-comments (RFC) documents to submit and give comments on proposed and future designs. +Also, make sure to check out our [PowerShell-RFC repository](https://github.com/powershell/powershell-rfc) for request-for-comments (RFC) documents to submit and give comments on proposed and future designs. +[Contribution Guide]: https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md [check out our FAQ]: https://github.com/PowerShell/PowerShell/tree/master/docs/FAQ.md#where-do-i-get-the-powershell-core-sdk-package -[Contribution Guide]: https://github.com/PowerShell/PowerShell/tree/master/.github/CONTRIBUTING.md -[known issues]: https://github.com/PowerShell/PowerShell/tree/master/docs/KNOWNISSUES.md -[GitHub issues]: https://github.com/PowerShell/PowerShell/issues -[new issue]:https://github.com/PowerShell/PowerShell/issues/new + +## Support + +For support, please see the [Support Section][]. + +[Support Section]: https://github.com/PowerShell/PowerShell/tree/master/.github/SUPPORT.md ## Legal and Licensing @@ -205,16 +210,16 @@ PowerShell is licensed under the [MIT license][]. ### Windows Docker Files and Images -License: By requesting and using the Container OS Image for Windows containers, you acknowledge, understand, and consent to the Supplemental License Terms available on Docker hub: +License: By requesting and using the Container OS Image for Windows containers, you acknowledge, understand, and consent to the Supplemental License Terms available on Docker Hub: -- [Window Server Core](https://hub.docker.com/r/microsoft/windowsservercore/) +- [Windows Server Core](https://hub.docker.com/r/microsoft/windowsservercore/) - [Nano Server](https://hub.docker.com/r/microsoft/nanoserver/) ### Telemetry -By default, PowerShell collects the OS description and the version of PowerShell (equivalent to `$PSVersionTable.OS` and `$PSVersionTable.GitCommitId`) using [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/). -To opt-out of sending telemetry, delete the file `DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY` before starting PowerShell from the installed location. -The telemetry we collect fall under the [Microsoft Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement/). +By default, PowerShell collects the OS description and the version of PowerShell (equivalent to `$PSVersionTable.OS` and `$PSVersionTable.GitCommitId`) using [Application Insights](https://azure.microsoft.com/services/application-insights/). +To opt-out of sending telemetry, create an environment variable called `POWERSHELL_TELEMETRY_OPTOUT` set to a value of `1` before starting PowerShell from the installed location. +The telemetry we collect falls under the [Microsoft Privacy Statement](https://privacy.microsoft.com/privacystatement/). ## Governance @@ -227,7 +232,7 @@ Governance policy for PowerShell project is described [here][]. This project has adopted the [Microsoft Open Source Code of Conduct][conduct-code]. For more information see the [Code of Conduct FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any additional questions or comments. -[conduct-code]: http://opensource.microsoft.com/codeofconduct/ -[conduct-FAQ]: http://opensource.microsoft.com/codeofconduct/faq/ +[conduct-code]: https://opensource.microsoft.com/codeofconduct/ +[conduct-FAQ]: https://opensource.microsoft.com/codeofconduct/faq/ [conduct-email]: mailto:opencode@microsoft.com -[conduct-md]: https://github.com/PowerShell/PowerShell/tree/master/./CODE_OF_CONDUCT.md +[conduct-md]: https://github.com/PowerShell/PowerShell/tree/master/CODE_OF_CONDUCT.md diff --git a/Settings.StyleCop b/Settings.StyleCop new file mode 100644 index 000000000000..eae7b6275660 --- /dev/null +++ b/Settings.StyleCop @@ -0,0 +1,214 @@ + + + + + + + False + + + + + False + + + + + + False + + + + + + False + + + + + + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + True + + + + + True + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + True + True + + + + + + + False + + + + + + False + + + + + + False + + + + + + False + + + + + + as + at + by + do + go + if + in + is + it + no + of + on + or + to + n + r + l + i + io + fs + lp + dw + h + rs + ps + op + my + sb + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + False + + + + + + + + + + + False + + + + + + False + + + + + + + diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 971899c4e05f..6fb08e23244d 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -1,9 +1,1980 @@ +THIRD PARTY SOFTWARE NOTICES AND INFORMATION -THIRD-PARTY SOFTWARE NOTICES AND INFORMATION Do Not Translate or Localize -The software is based on or incorporates material from the projects listed below (collectively, “Third Party Code”). Microsoft is not the original author of the Third Party Code. The original copyright notice and license, under which Microsoft received such Third Party Code, are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise. +This software incorporates material from third parties. +Microsoft makes certain open source code available at http://3rdpartysource.microsoft.com, +or you may send a check or money order for US $5.00, including the product name, +the open source component name, and version number, to: +Source Code Compliance Team +Microsoft Corporation +One Microsoft Way +Redmond, WA 98052 +USA + +Notwithstanding any other terms, you may reverse engineer this software to the extent +required to debug changes to any libraries licensed under the GNU Lesser General Public License. + + +------------------------------------------------------------------- + +Markdig.Signed 0.15.6 - BSD-2-Clause + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.Platforms 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.Platforms 2.1.1 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.Platforms 2.1.2 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.Targets 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.Targets 2.0.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.Win32.Registry 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.Win32.Registry.AccessControl 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.Win32.SystemEvents 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.Windows.Compatibility 2.0.1 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.CodeDom 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Collections.Immutable 1.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ComponentModel.Composition 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Configuration.ConfigurationManager 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Data.DataSetExtensions 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Data.Odbc 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Diagnostics.DiagnosticSource 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Diagnostics.EventLog 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Diagnostics.PerformanceCounter 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.DirectoryServices 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.DirectoryServices.AccountManagement 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.DirectoryServices.Protocols 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Drawing.Common 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.IO.FileSystem.AccessControl 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.IO.Packaging 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.IO.Pipes.AccessControl 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.IO.Ports 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Management 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Net.Http.WinHttpHandler 4.5.2 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Private.ServiceModel 4.5.3 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Reflection.DispatchProxy 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Reflection.Metadata 1.6.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Runtime.Caching 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Runtime.CompilerServices.Unsafe 4.5.2 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Security.AccessControl 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Security.Cryptography.Cng 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Security.Cryptography.Pkcs 4.5.2 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Security.Cryptography.ProtectedData 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Security.Cryptography.Xml 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Security.Permissions 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Security.Principal.Windows 4.5.1 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ServiceModel.Duplex 4.5.3 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ServiceModel.Http 4.5.3 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ServiceModel.NetTcp 4.5.3 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ServiceModel.Primitives 4.5.3 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ServiceModel.Security 4.5.3 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ServiceModel.Syndication 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.ServiceProcess.ServiceController 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Text.Encoding.CodePages 4.5.1 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Text.Encodings.Web 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +System.Threading.AccessControl 4.5.0 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.ApplicationInsights 2.8.1 - MIT + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +NJsonSchema 9.12.2 - MIT + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Newtonsoft.Json 11.0.2 - MIT + +The MIT License (MIT) + +Copyright (c) 2007 James Newton-King + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +NETStandard.Library 2.0.3 - MIT + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.App 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.App 2.1.5 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.DotNetAppHost 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.DotNetAppHost 2.1.5 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.DotNetHostPolicy 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.DotNetHostPolicy 2.1.5 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.DotNetHostResolver 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Microsoft.NETCore.DotNetHostResolver 2.1.5 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +runtime.win-x64.Microsoft.NETCore.App 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +runtime.win-x64.Microsoft.NETCore.DotNetAppHost 2.1.0 - MIT + +The MIT License (MIT) + +Copyright (c) 2015 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +------------------------------------------------------------------- + +------------------------------------------------------------------- + +Additional - --------------------------------------------- File: PSReadLine @@ -18,13 +1989,13 @@ All rights reserved. BSD License Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -37,8 +2008,6 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ---------------------------------------------- File: Hashtables from ConvertFrom-json ---------------------------------------------- @@ -47,7 +2016,7 @@ http://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-hav Copyright (c) 2015 Dave Wyatt. All rights reserved. -All rights reserved. +All rights reserved. MIT License @@ -57,12 +2026,11 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------------------------------------------------- -File: PackageManagement +PackageManagement ------------------------------------------------- -Copyright (c) Microsoft Corporation. +Copyright (c) Microsoft Corporation. All rights reserved. @@ -76,3 +2044,35 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +-------------------------------------------------------- +• NuGet.Common +• NuGet.Configuration +• NuGet.DependencyResolver.Core +• NuGet.Frameworks +• NuGet.LibraryModel +• NuGet.Packaging +• NuGet.Packaging.Core +• NuGet.Packaging.Core.Types +• NuGet.ProjectModel +• NuGet.Protocol.Core.Types +• NuGet.Protocol.Core.v3 +• NuGet.Repositories +• NuGet.RuntimeModel +• NuGet.Versioning +---------------------------------------------------------- + +Copyright (c) .NET Foundation. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +these files except in compliance with the License. You may obtain a copy of the +License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. + +------------------------------------------------------------------- diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index f5072d90eab2..000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,28 +0,0 @@ -# version is set in tools\appveyor.psm1 - Invoke-AppVeyorInstall - -image: Visual Studio 2017 - -# cache version - netcoreapp.2.0.4 -cache: - - '%LocalAppData%\Microsoft\dotnet -> appveyor.yml' - - '%HOMEDRIVE%%HOMEPATH%\.nuget\packages -> appveyor.yml' - -nuget: - project_feed: true - -install: - - git submodule update --init - - ps: Import-Module .\tools\Appveyor.psm1 - - ps: Invoke-AppveyorInstall - -build_script: - - ps: Invoke-AppveyorBuild - -test_script: - - ps: Invoke-AppveyorTest - -after_test: - - ps: Invoke-AppVeyorAfterTest - -on_finish: - - ps: Invoke-AppveyorFinish diff --git a/assets/AppImageThirdPartyNotices.txt b/assets/AppImageThirdPartyNotices.txt index 0eaf1e0cd585..d492e7c3b539 100644 --- a/assets/AppImageThirdPartyNotices.txt +++ b/assets/AppImageThirdPartyNotices.txt @@ -87,7 +87,7 @@ property of their respective owners. # provided under other licenses, as set forth below. # # The BSD License - # http://opensource.org/licenses/bsd-license.php + # https://opensource.org/licenses/bsd-license.php # Copyright (C) 2006-2008, Google Inc. # # All rights reserved. @@ -289,7 +289,7 @@ property of their respective owners. # Copyright (c) 2013 International Business Machines Corporation # and others. All Rights Reserved. # - # Project: http://code.google.com/p/lao-dictionary/ + # Project: https://code.google.com/p/lao-dictionary/ # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt # (copied below) @@ -440,7 +440,7 @@ XZ Utils Licensing naturally it is not legally required. Here is an example of a good notice to put into "about box" or into documentation: - This software includes code from XZ Utils . + This software includes code from XZ Utils . The following license texts are included in the following files: - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1 diff --git a/assets/AppxManifest.xml b/assets/AppxManifest.xml new file mode 100644 index 000000000000..d24bfd4a7ec9 --- /dev/null +++ b/assets/AppxManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + PowerShell 7 + Microsoft Corporation + assets\StoreLogo.png + disabled + disabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/Powershell-preview.icns b/assets/Powershell-preview.icns new file mode 100644 index 000000000000..a0ed0c4bc2c3 Binary files /dev/null and b/assets/Powershell-preview.icns differ diff --git a/assets/Powershell_256.png b/assets/Powershell_256.png index 8767330b82d9..0f51af844e4a 100644 Binary files a/assets/Powershell_256.png and b/assets/Powershell_256.png differ diff --git a/assets/Product.wxs b/assets/Product.wxs index ed98172a4a00..f0fc38f0f513 100644 --- a/assets/Product.wxs +++ b/assets/Product.wxs @@ -5,47 +5,98 @@ - + + + + + + + + + + + + - - - - - - - + + + + + + - + - + - - - - + + + + - + + + + + + + + + + + Installed AND NOT UPGRADINGPRODUCTCODE + + + + + + + - - - - - - - + + + + + + - @@ -56,7 +107,7 @@ 1 - LAUNCHAPPONEXIT + LAUNCHAPPONEXIT=1 @@ -67,14 +118,15 @@ - + - + + @@ -101,33 +153,203 @@ - + - - - + + + + + + + - - - + + + ADD_PATH=1 + + + + + ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + + + + + + + + + + + + + + + + + + + + + The application is distributed under the MIT license.]]> + + + Please review the ThirdPartyNotices.txt]]> + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + "1"]]> + + NOT Installed + Installed AND PATCH + + 1 + 1 + + 1 + 1 + NOT WIXUI_DONTVALIDATEPATH + "1"]]> + WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1" + 1 + 1 + 1 + + NOT Installed + Installed AND NOT PATCH + Installed AND PATCH + + 1 + + 1 + 1 + 1 + + + + + + diff --git a/assets/Square150x150Logo-Preview.png b/assets/Square150x150Logo-Preview.png new file mode 100644 index 000000000000..e206cf8064f4 Binary files /dev/null and b/assets/Square150x150Logo-Preview.png differ diff --git a/assets/Square150x150Logo.png b/assets/Square150x150Logo.png new file mode 100644 index 000000000000..bba1843f1206 Binary files /dev/null and b/assets/Square150x150Logo.png differ diff --git a/assets/Square44x44Logo-Preview.png b/assets/Square44x44Logo-Preview.png new file mode 100644 index 000000000000..df150a063b99 Binary files /dev/null and b/assets/Square44x44Logo-Preview.png differ diff --git a/assets/Square44x44Logo.png b/assets/Square44x44Logo.png new file mode 100644 index 000000000000..16b1f6dd160c Binary files /dev/null and b/assets/Square44x44Logo.png differ diff --git a/assets/Square44x44Logo.targetsize-48-Preview.png b/assets/Square44x44Logo.targetsize-48-Preview.png new file mode 100644 index 000000000000..df150a063b99 Binary files /dev/null and b/assets/Square44x44Logo.targetsize-48-Preview.png differ diff --git a/assets/Square44x44Logo.targetsize-48.png b/assets/Square44x44Logo.targetsize-48.png new file mode 100644 index 000000000000..16b1f6dd160c Binary files /dev/null and b/assets/Square44x44Logo.targetsize-48.png differ diff --git a/assets/Square44x44Logo.targetsize-48_altform-unplated-Preview.png b/assets/Square44x44Logo.targetsize-48_altform-unplated-Preview.png new file mode 100644 index 000000000000..df150a063b99 Binary files /dev/null and b/assets/Square44x44Logo.targetsize-48_altform-unplated-Preview.png differ diff --git a/assets/Square44x44Logo.targetsize-48_altform-unplated.png b/assets/Square44x44Logo.targetsize-48_altform-unplated.png new file mode 100644 index 000000000000..16b1f6dd160c Binary files /dev/null and b/assets/Square44x44Logo.targetsize-48_altform-unplated.png differ diff --git a/assets/StoreLogo-Preview.png b/assets/StoreLogo-Preview.png new file mode 100644 index 000000000000..8c1fa58568fa Binary files /dev/null and b/assets/StoreLogo-Preview.png differ diff --git a/assets/StoreLogo.png b/assets/StoreLogo.png new file mode 100644 index 000000000000..afd20a3d9d4d Binary files /dev/null and b/assets/StoreLogo.png differ diff --git a/assets/WixUIBannerBmp.bmp b/assets/WixUIBannerBmp.bmp deleted file mode 100644 index 92248d4a5248..000000000000 Binary files a/assets/WixUIBannerBmp.bmp and /dev/null differ diff --git a/assets/WixUIBannerBmp.png b/assets/WixUIBannerBmp.png new file mode 100644 index 000000000000..2a1922c1d7c8 Binary files /dev/null and b/assets/WixUIBannerBmp.png differ diff --git a/assets/WixUIDialogBmp.bmp b/assets/WixUIDialogBmp.bmp deleted file mode 100644 index 81e8546d5721..000000000000 Binary files a/assets/WixUIDialogBmp.bmp and /dev/null differ diff --git a/assets/WixUIDialogBmp.png b/assets/WixUIDialogBmp.png new file mode 100644 index 000000000000..57cf3734c176 Binary files /dev/null and b/assets/WixUIDialogBmp.png differ diff --git a/assets/WixUIInfoIco.bmp b/assets/WixUIInfoIco.bmp deleted file mode 100644 index af892ffe8879..000000000000 Binary files a/assets/WixUIInfoIco.bmp and /dev/null differ diff --git a/assets/WixUIInfoIco.png b/assets/WixUIInfoIco.png new file mode 100644 index 000000000000..cb705d5f33f1 Binary files /dev/null and b/assets/WixUIInfoIco.png differ diff --git a/assets/additionalAttributions.txt b/assets/additionalAttributions.txt new file mode 100644 index 000000000000..d244bad6877a --- /dev/null +++ b/assets/additionalAttributions.txt @@ -0,0 +1,110 @@ +## Used to generate a new TPN +## Copy this into the additional attributions fields +## Copy everything below here, but do not include this line + +--------------------------------------------- +File: PSReadLine +--------------------------------------------- + +https://github.com/lzybkr/PSReadLine + +Copyright (c) 2013, Jason Shirk + +All rights reserved. + +BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------- +File: Hashtables from ConvertFrom-json +---------------------------------------------- + +https://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-have-different-type-from-powershells-built-in-h + +Copyright (c) 2015 Dave Wyatt. All rights reserved. + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------- +PackageManagement +------------------------------------------------- + +Copyright (c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the Software), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +-------------------------------------------------------- +• NuGet.Common +• NuGet.Configuration +• NuGet.DependencyResolver.Core +• NuGet.Frameworks +• NuGet.LibraryModel +• NuGet.Packaging +• NuGet.Packaging.Core +• NuGet.Packaging.Core.Types +• NuGet.ProjectModel +• NuGet.Protocol.Core.Types +• NuGet.Protocol.Core.v3 +• NuGet.Repositories +• NuGet.RuntimeModel +• NuGet.Versioning +---------------------------------------------------------- + +Copyright (c) .NET Foundation. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +these files except in compliance with the License. You may obtain a copy of the +License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. diff --git a/assets/files.wxs b/assets/files.wxs new file mode 100644 index 000000000000..78984cd748aa --- /dev/null +++ b/assets/files.wxs @@ -0,0 +1,3893 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/license.rtf b/assets/license.rtf index 0e507920b40e..0129ec54408d 100644 --- a/assets/license.rtf +++ b/assets/license.rtf @@ -1,1248 +1,389 @@ -{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31506\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;} -{\f3\fbidi \froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f10\fbidi \fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;} -{\f11\fbidi \froman\fcharset128\fprq1{\*\panose 02020609040205080304}MS Mincho{\*\falt \'82\'6c\'82\'72 \'96\'be\'92\'a9};}{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;} -{\f39\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f40\fbidi \fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Tahoma;}{\f41\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0603020202020204}Trebuchet MS;} -{\f42\fbidi \fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Segoe UI;}{\f43\fbidi \froman\fcharset128\fprq1{\*\panose 02020609040205080304}@MS Mincho;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} -{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;} -{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} -{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;} -{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f44\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f45\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} -{\f47\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f48\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f49\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f50\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\f51\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f52\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f64\fbidi \fmodern\fcharset238\fprq1 Courier New CE;}{\f65\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;} -{\f67\fbidi \fmodern\fcharset161\fprq1 Courier New Greek;}{\f68\fbidi \fmodern\fcharset162\fprq1 Courier New Tur;}{\f69\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f70\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);} -{\f71\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f72\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);}{\f434\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f435\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;} -{\f437\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f438\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f439\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f440\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);} -{\f441\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f442\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f444\fbidi \fswiss\fcharset238\fprq2 Tahoma CE;}{\f445\fbidi \fswiss\fcharset204\fprq2 Tahoma Cyr;} -{\f447\fbidi \fswiss\fcharset161\fprq2 Tahoma Greek;}{\f448\fbidi \fswiss\fcharset162\fprq2 Tahoma Tur;}{\f449\fbidi \fswiss\fcharset177\fprq2 Tahoma (Hebrew);}{\f450\fbidi \fswiss\fcharset178\fprq2 Tahoma (Arabic);} -{\f451\fbidi \fswiss\fcharset186\fprq2 Tahoma Baltic;}{\f452\fbidi \fswiss\fcharset163\fprq2 Tahoma (Vietnamese);}{\f453\fbidi \fswiss\fcharset222\fprq2 Tahoma (Thai);}{\f454\fbidi \fswiss\fcharset238\fprq2 Trebuchet MS CE;} -{\f455\fbidi \fswiss\fcharset204\fprq2 Trebuchet MS Cyr;}{\f457\fbidi \fswiss\fcharset161\fprq2 Trebuchet MS Greek;}{\f458\fbidi \fswiss\fcharset162\fprq2 Trebuchet MS Tur;}{\f461\fbidi \fswiss\fcharset186\fprq2 Trebuchet MS Baltic;} -{\f464\fbidi \fswiss\fcharset238\fprq2 Segoe UI CE;}{\f465\fbidi \fswiss\fcharset204\fprq2 Segoe UI Cyr;}{\f467\fbidi \fswiss\fcharset161\fprq2 Segoe UI Greek;}{\f468\fbidi \fswiss\fcharset162\fprq2 Segoe UI Tur;} -{\f469\fbidi \fswiss\fcharset177\fprq2 Segoe UI (Hebrew);}{\f470\fbidi \fswiss\fcharset178\fprq2 Segoe UI (Arabic);}{\f471\fbidi \fswiss\fcharset186\fprq2 Segoe UI Baltic;}{\f472\fbidi \fswiss\fcharset163\fprq2 Segoe UI (Vietnamese);} -{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} -{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} -{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} -{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} -{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;} -{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);} -{\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);}{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);} -{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} -{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} -{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} -{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} -{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} -{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} -{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;} -{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;} -{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} -{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}} -{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; -\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red51\green51\blue51;}{\*\defchp \f31506\fs22 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1 -\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 -\ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\s1\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext1 \slink22 \sqformat \styrsid7813854 heading 1;}{ -\s2\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext2 \slink23 \sqformat \styrsid7813854 heading 2;}{\s3\ql \fi-357\li1077\ri0\sb120\sa120\widctlpar\tx1077\jclisttab\tx1440\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl2\outlinelevel2\adjustright\rin0\lin1077\itap0 \rtlch\fcs1 -\af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext3 \slink24 \sqformat \styrsid7813854 heading 3;}{\s4\ql \fi-358\li1435\ri0\sb120\sa120\widctlpar -\jclisttab\tx1437\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl3\outlinelevel3\adjustright\rin0\lin1435\itap0 \rtlch\fcs1 \af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext4 \slink25 \sqformat \styrsid7813854 heading 4;}{\s5\ql \fi-357\li1792\ri0\sb120\sa120\widctlpar\tx1792\jclisttab\tx2155\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl4\outlinelevel4\adjustright\rin0\lin1792\itap0 \rtlch\fcs1 -\af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext5 \slink26 \sqformat \styrsid7813854 heading 5;}{\s6\ql \fi-357\li2149\ri0\sb120\sa120\widctlpar -\jclisttab\tx2152\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl5\outlinelevel5\adjustright\rin0\lin2149\itap0 \rtlch\fcs1 \af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext6 \slink27 \sqformat \styrsid7813854 heading 6;}{\s7\ql \fi-357\li2506\ri0\sb120\sa120\widctlpar\jclisttab\tx2509\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl6\outlinelevel6\adjustright\rin0\lin2506\itap0 \rtlch\fcs1 -\af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext7 \slink28 \sqformat \styrsid7813854 heading 7;}{\s8\ql \fi-357\li2863\ri0\sb120\sa120\widctlpar -\jclisttab\tx2866\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl7\outlinelevel7\adjustright\rin0\lin2863\itap0 \rtlch\fcs1 \af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext8 \slink29 \sqformat \styrsid7813854 heading 8;}{\s9\ql \fi-358\li3221\ri0\sb120\sa120\widctlpar\jclisttab\tx3223\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl8\outlinelevel8\adjustright\rin0\lin3221\itap0 \rtlch\fcs1 -\af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext9 \slink30 \sqformat \styrsid7813854 heading 9;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 -Default Paragraph Font;}{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv -\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused -Normal Table;}{\s15\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext15 \ssemihidden \sunhideused \styrsid3804850 Normal (Web);}{\s16\ql \li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af39\afs22\alang1025 \ltrch\fcs0 -\f39\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext16 \sqformat \spriority34 \styrsid6173475 List Paragraph;}{\s17\ql \li0\ri0\widctlpar -\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af2\afs20\alang1025 \ltrch\fcs0 -\f2\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext17 \slink18 \ssemihidden \sunhideused \styrsid6573559 HTML Preformatted;}{\*\cs18 \additive \rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20 -\sbasedon10 \slink17 \slocked \ssemihidden \styrsid6573559 HTML Preformatted Char;}{\*\cs19 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf1 \sbasedon10 \sunhideused \styrsid7092439 Hyperlink;}{\*\cs20 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 -\sbasedon10 \spriority0 \styrsid7092439 spelle;}{\*\cs21 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \sbasedon10 \spriority0 \styrsid7092439 grame;}{\*\cs22 \additive \rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \fs19\loch\f40\hich\af40\dbch\af11 -\sbasedon10 \slink1 \slocked \styrsid7813854 Heading 1 Char;}{\*\cs23 \additive \rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \fs19\loch\f40\hich\af40\dbch\af11 \sbasedon10 \slink2 \slocked \styrsid7813854 Heading 2 Char;}{\*\cs24 \additive \rtlch\fcs1 -\af40\afs19 \ltrch\fcs0 \b\fs19\loch\f40\hich\af40\dbch\af11 \sbasedon10 \slink3 \slocked \styrsid7813854 Heading 3 Char;}{\*\cs25 \additive \rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \b\fs19\loch\f40\hich\af40\dbch\af11 -\sbasedon10 \slink4 \slocked \styrsid7813854 Heading 4 Char;}{\*\cs26 \additive \rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \b\fs19\loch\f40\hich\af40\dbch\af11 \sbasedon10 \slink5 \slocked \styrsid7813854 Heading 5 Char;}{\*\cs27 \additive \rtlch\fcs1 -\af40\afs19 \ltrch\fcs0 \b\fs19\loch\f40\hich\af40\dbch\af11 \sbasedon10 \slink6 \slocked \styrsid7813854 Heading 6 Char;}{\*\cs28 \additive \rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \b\fs19\loch\f40\hich\af40\dbch\af11 -\sbasedon10 \slink7 \slocked \styrsid7813854 Heading 7 Char;}{\*\cs29 \additive \rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \b\fs19\loch\f40\hich\af40\dbch\af11 \sbasedon10 \slink8 \slocked \styrsid7813854 Heading 8 Char;}{\*\cs30 \additive \rtlch\fcs1 -\af40\afs19 \ltrch\fcs0 \b\fs19\loch\f40\hich\af40\dbch\af11 \sbasedon10 \slink9 \slocked \styrsid7813854 Heading 9 Char;}{\s31\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\af40\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext31 \styrsid7813854 Body 1;}{ -\s32\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af40\afs28\alang1025 \ltrch\fcs0 \fs28\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext0 \styrsid7813854 Heading EULA;}{\s33\ql \li0\ri0\sb120\sa120\widctlpar\brdrb\brdrs\brdrw10\brsp20 \wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af40\afs28\alang1025 \ltrch\fcs0 -\fs28\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \styrsid7813854 Heading Software Title;}{\s34\ql \li0\ri0\sb120\sa120\widctlpar\brdrt\brdrs\brdrw10\brsp20 -\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\f40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext34 \styrsid7813854 -Preamble Border Above;}}{\*\listtable{\list\listtemplateid412752146\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} -\f3\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 -\fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 -\fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 -\fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 } -{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel -\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23 -\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid256596791}{\list\listtemplateid-234466468 -\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23 -\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative -\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0 -\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0 -{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid268852893}{\list\listtemplateid2071779370\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative -\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0 -{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 -\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers -;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} -\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid472724034}{\list\listtemplateid837583652\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 -\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers -;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} -\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} -\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 -\fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 -\fi-360\li6480\lin6480 }{\listname ;}\listid678236712}{\list\listtemplateid468190476\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} -\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} -\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} -\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 -\fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 -\fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 -\fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 } -{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname -;}\listid696808916}{\list\listtemplateid256027766\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} -\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 -\fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 -\fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 -\fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 } -{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel -\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23 -\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid833446968}{\list\listtemplateid812297174 -{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 \fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace0\levelindent0{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'03(\'03);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;} -\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 -\hres0\chhres0 \fi-360\li2517\lin2517 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 } -{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 }{\listname ;}\listid888110291}{\list\listtemplateid812297174{\listlevel\levelnfc4 -\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 \fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'03(\'03);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;} -\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 -\hres0\chhres0 \fi-360\li2517\lin2517 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 } -{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 }{\listname ;}\listid1282881056}{\list\listtemplateid827650700\listhybrid{\listlevel -\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative -\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0 -{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid1470391773}{\list\listtemplateid-1331279738\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} -\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 -\fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 } -{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid1543639483}{\list\listtemplateid812297174{\listlevel\levelnfc4\levelnfcn4 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 \fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 -{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'03);}{\levelnumbers -\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 -\hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2517\lin2517 } -{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 }{\listlevel\levelnfc4\levelnfcn4\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 }{\listname ;}\listid1670060985}{\list\listtemplateid-1676387632{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab\ai0\af40\afs20 \ltrch\fcs0 \b\i0\f40\fs20\fbias0\hres0\chhres0 \fi-357\li357\jclisttab\tx360\lin357 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\b\i0\f3\fs20\fbias0\hres0\chhres0 \fi-363\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace0\levelindent0{\leveltext\'02\'02.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab\ai0\af40\afs20 \ltrch\fcs0 \b\i0\f40\fs20\fbias0\hres0\chhres0 \s3\fi-357\li1077\jclisttab\tx1440\lin1077 }{\listlevel\levelnfc3\levelnfcn3\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'03.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af41\afs20 \ltrch\fcs0 \b0\i0\strike0\f41\fs20\ulnone\fbias0\hres0\chhres0 \s4\fi-358\li1435\jclisttab\tx1437\lin1435 }{\listlevel\levelnfc1\levelnfcn1 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'04.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af41\afs20 \ltrch\fcs0 \b0\i0\strike0\f41\fs20\ulnone\fbias0\hres0\chhres0 \s5\fi-357\li1792\jclisttab\tx2155\lin1792 } -{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'05.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af41\afs20 \ltrch\fcs0 \b0\i0\f41\fs20\fbias0\hres0\chhres0 \s6\fi-357\li2149 -\jclisttab\tx2152\lin2149 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af41\afs20 \ltrch\fcs0 \b0\i0\f41\fs20\fbias0\hres0\chhres0 -\s7\fi-357\li2506\jclisttab\tx2509\lin2506 }{\listlevel\levelnfc255\levelnfcn255\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02i.;}{\levelnumbers;}\rtlch\fcs1 \ab0\ai0\af41\afs20 \ltrch\fcs0 -\b0\i0\f41\fs20\fbias0\hres0\chhres0 \s8\fi-357\li2863\jclisttab\tx2866\lin2863 }{\listlevel\levelnfc255\levelnfcn255\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02A.;}{\levelnumbers;}\rtlch\fcs1 \ab0\ai0\af41\afs20 -\ltrch\fcs0 \b0\i0\f41\fs20\fbias0\hres0\chhres0 \s9\fi-358\li3221\jclisttab\tx3223\lin3221 }{\listname ;}\listid1743720866}{\list\listtemplateid-646571904\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0 -\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 -\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers -;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} -\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid2003921709}{\list\listtemplateid1067461628\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 -\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers -;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} -\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} -\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 -\fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 -\fi-360\li6480\lin6480 }{\listname ;}\listid2022782249}{\list\listtemplateid1736062262\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} -\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} -\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} -\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 -\fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 -\fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 -\fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 } -{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname -;}\listid2055036124}{\list\listtemplateid812297174{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 -\fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel -\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'03);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2517\lin2517 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;} -\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 -\hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 } -{\listname ;}\listid2106000387}}{\*\listoverridetable{\listoverride\listid256596791\listoverridecount0\ls1}{\listoverride\listid1543639483\listoverridecount0\ls2}{\listoverride\listid268852893\listoverridecount0\ls3}{\listoverride\listid678236712 -\listoverridecount0\ls4}{\listoverride\listid2022782249\listoverridecount0\ls5}{\listoverride\listid472724034\listoverridecount0\ls6}{\listoverride\listid1470391773\listoverridecount0\ls7}{\listoverride\listid2003921709\listoverridecount0\ls8} -{\listoverride\listid2055036124\listoverridecount0\ls9}{\listoverride\listid696808916\listoverridecount0\ls10}{\listoverride\listid833446968\listoverridecount0\ls11}{\listoverride\listid1743720866\listoverridecount0\ls12}{\listoverride\listid1670060985 -\listoverridecount0\ls13}{\listoverride\listid1282881056\listoverridecount0\ls14}{\listoverride\listid888110291\listoverridecount0\ls15}{\listoverride\listid2106000387\listoverridecount0\ls16}}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0 -\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp10\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li300\ri300\sb300\sa300}{\pgp\ipgp0\itap0\li0\ri0 -\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}{\*\rsidtbl \rsid93983\rsid217518\rsid1984289\rsid3804850\rsid5845909\rsid6173475\rsid6573559\rsid7092439\rsid7813854\rsid8005660\rsid8394862 -\rsid10169937\rsid10363382\rsid10624128\rsid13960513\rsid14557619\rsid16084641}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author Duane Okamoto (CELA)} -{\operator Raghu Shantha}{\creatim\yr2016\mo8\dy12\hr14\min30}{\revtim\yr2016\mo8\dy12\hr14\min30}{\version2}{\edmins1}{\nofpages15}{\nofwords5899}{\nofchars33626}{\*\company Microsoft IT}{\nofcharsws39447}{\vern19}}{\*\xmlnstbl {\xmlns1 http://schemas.mi -crosoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect -\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen -\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1 -\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct -\asianbrkrule\rsidroot3804850\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0 -{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang -{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang -{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} -\pard\plain \ltrpar\s15\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid3804850 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \b\f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid93983\charrsid93983 PowerShell 6.0}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \b\f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 Copyright (c) Microsoft Corporation}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 All rights reserved.\~}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 MIT License}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following cond -itions:}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.}{\rtlch\fcs1 -\af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRA -NTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid3804850 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs20\ul\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid10363382 IMPORTANT NOTICE}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid10363382 -: THE SOFTWARE ALSO CONTAINS THIRD PARTY AND OTHER }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid10624128 PROPRIETARY }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 -\f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid10363382 SOFTWARE THAT ARE GOVERNED BY SEPARATE LICENSE TERMS. BY ACCEPTING THE LICENSE TERMS ABOVE, -YOU ALSO ACCEPT THE LICENSE TERMS GOVERNING THE THIRD PARTY AND OTHER SOFTWARE, WHICH ARE SET FORTH BELOW: -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 The following components }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid16084641 listed }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 -\f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 are governed by }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid16084641 the license terms that follow }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 -\f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 the component}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid16084641 (s) name}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 -\f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 : -\par }\pard \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6173475 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 --------------------------------------}{ -\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid10363382 ----------------}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 -\par }\pard \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid14557619 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 Libmi.so -\par }\pard \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6173475 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 --------------------------------------}{ -\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid10363382 ----------------}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 -\par }\pard \ltrpar\s15\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid3804850 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 -Copyright (c) Microsoft Corporation -\par }\pard \ltrpar\s15\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6173475 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 -All rights reserved.\~}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 MIT License}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated docu -mentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Soft -ware is furnished to do so, subject to the following conditions:}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.}{\rtlch\fcs1 -\af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475\charrsid93983 THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, E -XPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 -\par }\pard \ltrpar\s15\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid14557619 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619 -The following components are governed by the MIT license, a copy of which appears below the list of components: -\par }\pard \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid14557619 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619 ------------------------------------------------------- -\par Newtonsoft.Json -\par ------------------------------------------------------ -\par }\pard \ltrpar\s15\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid14557619 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619 -Copyright (c) 2007 James Newton-King -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 All rights reserved.\~}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 MIT License}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies o -f the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.}{\rtlch\fcs1 -\af2\afs20 \ltrch\fcs0 \f2\fs20\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619\charrsid93983 THE SOFTWAR -E IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 -\f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid14557619 -\par }\pard \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6573559 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6573559 ---------------------------------------------------------- -\par Libuv v.1.9.0 -\par --------------------------------------------------------- -\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6573559 \rtlch\fcs1 -\af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid10169937 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 https://raw.githubusercontent.com/aspnet/libuv-package/dev/content/License.txt -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\insrsid6573559 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 This software is licensed to you by Microsoft Corporation under the original terms of the copyright holder provided below: -\par -\par ========================================= -\par -\par libuv is part of the Node project: http://nodejs.org/ -\par libuv may be distributed alone under Node's license: -\par -\par ==== -\par -\par Copyright Joyent, Inc. and other Node contributors. All rights reserved. -\par -\par Permission is hereby granted, free of charge, to any person obtaining a copy -\par of this software and associated documentation files (the "Software"), to -\par deal in the Software without restriction, including without limitation the -\par rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -\par sell copies of the Software, and to permit persons to whom the Software is -\par furnished to do so, subject to the following conditions: -\par -\par The above copyright notice and this permission notice shall be included in -\par all copies or substantial portions of the Software. -\par -\par THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -\par IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -\par FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -\par AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -\par LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -\par FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -\par IN THE SOFTWARE. -\par -\par ==== -\par -\par This license applies to all parts of libuv that are not externally -\par maintained libraries. -\par -\par The externally maintained libraries used by libuv are: -\par -\par - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. -\par -\par - inet_pton and inet_ntop implementations, contained in src/inet.c, are -\par }\pard \ltrpar\ql \li450\ri0\widctlpar\tx450\tx1530\tx2700\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin450\itap0\pararsid6573559 {\rtlch\fcs1 -\af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 copyright the Internet Systems Consortium, Inc., and licensed under the ISC license. -\par }\pard \ltrpar\ql \li0\ri0\widctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6573559 {\rtlch\fcs1 -\af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 -\par - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three -\par clause BSD license. -\par -\par - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile -\par Communications AB. Three clause BSD license. -\par -\par }\pard \ltrpar\ql \fi-450\li450\ri0\widctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin450\itap0\pararsid6573559 { -\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement -\par }\pard \ltrpar\ql \li0\ri0\widctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6573559 {\rtlch\fcs1 -\af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 n\'b0 289016). Three clause BSD license. -\par -\par ========================================= -\par }\pard\plain \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6573559 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs18 -\ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6573559 -\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid10169937 -\par }\pard \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid10169937 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6573559 ---------------------------------------------------}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid10169937 --}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6573559 -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard\plain \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls11\adjustright\rin0\lin720\itap0\pararsid10169937 \rtlch\fcs1 \af39\afs22\alang1025 \ltrch\fcs0 \f39\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs18 -\ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 dotnet-test-xunit 2.2.0-preview2-build1029 -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\fs18\insrsid16084641\charrsid10169937 xunit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}xunit.abstractions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}xunit.assert -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}xunit.core -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}xunit.extensibility.core -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}xunit.extensibility.execution -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}xunit.runner.reporters -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid16084641\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}xunit.runner.utility -\par }\pard\plain \ltrpar\ql \li0\ri0\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439 ---------------------------------------------------}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid10169937 -}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439 -\par }\pard \ltrpar\ql \li0\ri0\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid10169937 {\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid10169937 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid16084641 https://www.nuget.org/packages -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid10169937 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 Copyright 2015 Outercurve Foundation -\par }\pard \ltrpar\ql \li0\ri0\widctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid10169937 {\rtlch\fcs1 -\af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 -\par }\pard \ltrpar\ql \li0\ri0\widctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6573559 {\rtlch\fcs1 -\af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid6573559\charrsid6573559 Licensed under the Apache License, Version 2.0 (the "License"); -\par you may not use this file except in compliance with the License. -\par You may obtain a copy of the License at -\par -\par http://www.apache.org/licenses/LICENSE-2.0 -\par -\par Unless required by applicable law or agreed to in writing, software -\par distributed under the License is distributed on an "AS IS" BASIS, -\par WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -\par See the License for the specific language governing permissions and -\par limitations under the License.}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid6573559 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid7092439 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid6573559 -\par }\pard\plain \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs20 -\ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid7092439 --------------------------------------------------}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6573559 -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard\plain \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls10\adjustright\rin0\lin720\itap0\pararsid10169937 \rtlch\fcs1 \af39\afs22\alang1025 \ltrch\fcs0 \f39\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs18 -\ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 Microsoft.CodeAnalysis.Analyzers -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.CodeAnalysis.Common -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.CodeAnalysis.CSharp -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.CodeAnalysis.VisualBasic -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.CSharp -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.DiaSymReader -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.DiaSymReader.Native -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.DotNet.Cli.Utils -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.DotNet.InternalAbstractions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.DotNet.ProjectModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.Extensions.DependencyModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.Extensions.Testing.Abstractions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.App -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.DotNetHost -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.DotNetHostPolicy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.DotNetHostResolver -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Jit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Platforms -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Portable.Compatibility -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Runtime -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Runtime.CoreCLR -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Runtime.Native -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Targets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.NETCore.Windows.ApiSets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.VisualBasic -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.Win32.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls9\adjustright\rin0\lin720\itap0\pararsid10169937 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 Microsoft.Win32.Registry -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.Win32.Registry.AccessControl -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NETStandard.Library -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Collections -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Diagnostics.Tools -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Diagnostics.Tracing -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Globalization -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Globalization.Calendars -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.IO -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Reflection -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Reflection.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Reflection.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Resources.ResourceManager -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Runtime -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Runtime.Handles -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Runtime.InteropServices -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Text.Encoding -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Text.Encoding.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Threading.Tasks -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.any.System.Threading.Timer -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.Microsoft.NETCore.DotNetHost -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.Microsoft.NETCore.DotNetHostPolicy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.Microsoft.NETCore.DotNetHostResolver -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.Microsoft.NETCore.Jit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.Microsoft.NETCore.Runtime.CoreCLR -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.runtime.native.System -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.runtime.native.System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.runtime.native.System.Net.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.runtime.native.System.Net.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.debian.8-x64.runtime.native.System.Security.Cryptography -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.native.System -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.native.System.Data.SqlClient.sni -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.native.System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.native.System.Net.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.native.System.Net.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.native.System.Security.Cryptography -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.Microsoft.NETCore.DotNetHost -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.Microsoft.NETCore.DotNetHostPolicy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.Microsoft.NETCore.DotNetHostResolver -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.Microsoft.NETCore.Jit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.Microsoft.NETCore.Runtime.CoreCLR -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.runtime.native.System -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.runtime.native.System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.runtime.native.System.Net.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.runtime.native.System.Net.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.Microsoft.NETCore.DotNetHost -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.Microsoft.NETCore.DotNetHostPolicy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.Microsoft.NETCore.DotNetHostResolver -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.Microsoft.NETCore.Jit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.Microsoft.NETCore.Runtime.CoreCLR -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.runtime.native.System -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.runtime.native.System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.runtime.native.System.Net.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.runtime.native.System.Net.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.rhel.7-x64.runtime.native.System.Security.Cryptography -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.Microsoft.NETCore.DotNetHost -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.Microsoft.NETCore.DotNetHostPolicy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.Microsoft.NETCore.DotNetHostResolver -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.Microsoft.NETCore.Jit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.Microsoft.NETCore.Runtime.CoreCLR -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.runtime.native.System -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.Microsoft.NETCore.DotNetHost -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.Microsoft.NETCore.DotNetHostPolicy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls8\adjustright\rin0\lin720\itap0\pararsid10169937 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 -runtime.ubuntu.16.04-x64.Microsoft.NETCore.DotNetHostResolver -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.Microsoft.NETCore.Jit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.Microsoft.NETCore.Runtime.CoreCLR -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.runtime.native.System -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.Microsoft.Win32.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.System.Console -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.System.Diagnostics.Debug -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.System.IO.FileSystem -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.System.Net.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.System.Net.Sockets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.System.Private.Uri -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.unix.System.Runtime.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win.Microsoft.Win32.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win.System.Console -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win.System.Diagnostics.Debug -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win.System.IO.FileSystem -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win.System.Net.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win.System.Net.Sockets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win.System.Runtime.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.Microsoft.NETCore.DotNetHost -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.Microsoft.NETCore.DotNetHostPolicy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.Microsoft.NETCore.DotNetHostResolver -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.Microsoft.NETCore.Jit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.Microsoft.NETCore.Runtime.CoreCLR -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.Microsoft.NETCore.Windows.ApiSets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.runtime.native.System.Data.SqlClient.sni -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x64.runtime.native.System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7-x86.runtime.native.System.Data.SqlClient.sni -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win7.System.Private.Uri -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}runtime.win81-x64.Microsoft.NETCore.Windows.ApiSets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.AppContext -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Buffers -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Collections -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Collections.Concurrent -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Collections.Immutable -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Collections.NonGeneric -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Collections.Specialized -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ComponentModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ComponentModel.Annotations -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ComponentModel.EventBasedAsync -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ComponentModel.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ComponentModel.TypeConverter -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Console -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Data.Common -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Data.SqlClient -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.Contracts -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.Debug -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.DiagnosticSource -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.FileVersionInfo -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.Process -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.StackTrace -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.TextWriterTraceListener -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.Tools -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.TraceSource -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Diagnostics.Tracing -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Dynamic.Runtime -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Globalization -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Globalization.Calendars -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Globalization.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.Compression -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.Compression.ZipFile -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.FileSystem -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.FileSystem.AccessControl -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls7\adjustright\rin0\lin720\itap0\pararsid10169937 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 System.IO.FileSystem.DriveInfo -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.FileSystem.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.FileSystem.Watcher -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.MemoryMappedFiles -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.Packaging -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.Pipes -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.IO.UnmanagedMemoryStream -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Linq -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Linq.Expressions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Linq.Parallel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Linq.Queryable -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.Http.WinHttpHandler -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.NameResolution -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.NetworkInformation -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.Ping -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.Requests -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.Sockets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.WebHeaderCollection -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.WebSockets -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Net.WebSockets.Client -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Numerics.Vectors -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ObjectModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Private.DataContractSerialization -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Private.ServiceModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Private.Uri -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.DispatchProxy -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.Emit -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.Emit.ILGeneration -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.Emit.Lightweight -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.Metadata -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Reflection.TypeExtensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Resources.Reader -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls6\adjustright\rin0\lin720\itap0\pararsid10169937 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 System.Resources.ResourceManager -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.CompilerServices.VisualC -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.Handles -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.InteropServices -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.InteropServices.PInvoke -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.InteropServices.RuntimeInformation -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.Loader -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.Numerics -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.Serialization.Json -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.Serialization.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Runtime.Serialization.Xml -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.AccessControl -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Claims -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.Algorithms -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.Cng -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.Csp -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.Encoding -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.OpenSsl -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.Pkcs -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Cryptography.X509Certificates -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Principal -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.Principal.Windows -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Security.SecureString -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ServiceModel.Duplex -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ServiceModel.Http -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ServiceModel.NetTcp -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ServiceModel.Primitives -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls5\adjustright\rin0\lin720\itap0\pararsid10169937 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 System.ServiceModel.Security -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.ServiceProcess.ServiceController -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Text.Encoding -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Text.Encoding.CodePages -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Text.Encoding.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Text.Encodings.Web -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Text.RegularExpressions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.AccessControl -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.Overlapped -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.Tasks -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.Tasks.Dataflow -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.Tasks.Extensions -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.Tasks.Parallel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.Thread -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.ThreadPool -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Threading.Timer -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Xml.ReaderWriter -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Xml.XDocument -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Xml.XmlDocument -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Xml.XmlSerializer -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Xml.XPath -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Xml.XPath.XDocument -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}System.Xml.XPath.XmlDocument -\par }\pard\plain \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs20 -\ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid7092439 ------------------------------------------------------- -\par -\par }\pard\plain \ltrpar\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \ab\af40\afs24 \ltrch\fcs0 \b\f40\fs24\cf1\insrsid7092439\charrsid7092439 MICROSOFT SOFTWARE LICENSE TERMS }{\rtlch\fcs1 \ab\af40\afs28 \ltrch\fcs0 \b\f40\fs28\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs24 \ltrch\fcs0 \b\f40\fs24\cf1\insrsid7092439\charrsid7092439 MICROSOFT .NET LIBRARY }{\rtlch\fcs1 \ab\af40\afs28 \ltrch\fcs0 \b\f40\fs28\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 -These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms -also apply to any Microsoft -\par }\pard \ltrpar\ql \fi-363\li720\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 -\ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 updates,}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 supplements,}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 Internet-based services, and -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 support services -\par }\pard \ltrpar\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 -for this software, unless other terms accompany those items. If so, those terms apply. -\par BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE. -\par IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE PERPETUAL RIGHTS BELOW. -\par }\pard \ltrpar\ql \fi-357\li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 1.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 -\b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 INSTALLATION AND USE RIGHTS. -\par }\pard \ltrpar\ql \fi-363\li720\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 a.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 Installation and Use.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 \~You may install and use any number of copies of the software to design, develop and test your programs. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 b.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 -\~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 Third Party Programs.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 -\b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\cf1\insrsid7092439\charrsid7092439 \~ -The software may include third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 -\b\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 2.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 -\b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 DATA.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 -\af40\afs20 \ltrch\fcs0 \f40\fs20\cf1\insrsid7092439\charrsid7092439 The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to improve our products and services.\~ -You can learn more about data collection and use in the help documentation and the privacy statement at\~ }{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid11493340 - HYPERLINK "http://go.microsoft.com/fwlink/?LinkId=528096&clcid=0x409" \\t "_blank" }}{\fldrslt {\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\ul\cf2\insrsid7092439\charrsid7092439 http://go.microsoft.com/fwlink/?LinkId=528096}{\rtlch\fcs1 \af0\afs24 -\ltrch\fcs0 \f0\fs24\ul\cf1\insrsid7092439\charrsid7092439 }}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\cf1\insrsid7092439\charrsid7092439 -. Your use of the software operates as your consent to these practices. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 3.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 -\f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 -ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-363\li720\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 a.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 DISTRIBUTABLE CODE.\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 The software is comprised of Distributable Code. \'93Distributable Code\'94 is code that you are permitted to distribute in programs you develop if you comply with the terms below. }{\rtlch\fcs1 \ab\af40\afs19 -\ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li1077\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin1077\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 i}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 .}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 -\b\f40\fs20\cf1\insrsid7092439\charrsid7092439 Right to Use and Distribute.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li1434\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin1434\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 -\ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\cf1\insrsid7092439\charrsid7092439 You may copy and distribute the object code form of the software. }{\rtlch\fcs1 \af40\afs19 -\ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs. }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li1077\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin1077\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 ii.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 Distribution Requirements.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 \~}{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 For any Distributable Code you distribute, you must }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li1434\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin1434\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 -\ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\cf1\insrsid7092439\charrsid7092439 add significant primary functionality to it in your programs; }{\rtlch\fcs1 \af40\afs19 -\ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 require distributors and external end users to agree to terms that protect it at least as much as this agreement; }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 display your valid copyright notice on your programs; and }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 indemnify, defend, and hold harmless Microsoft from any claims, including attorneys\rquote fees, related to the distribution or use of your programs. }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li1077\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin1077\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 iii.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 Distribution Restrictions.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 \~}{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 You may not}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 -\ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li1434\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin1434\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 -\ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\cf1\insrsid7092439\charrsid7092439 alter any copyright, trademark or patent notice in the Distributable Code; }{\rtlch\fcs1 -\af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 use Microsoft\rquote s trademarks in your programs\rquote names or in a way that suggests your programs come from or are endorsed by Microsoft; }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 include Distributable Code in malicious, deceptive or unlawful programs; or }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 - modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that }{\rtlch\fcs1 \af40\afs19 -\ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-358\li1792\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin1792\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 -\ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\cf1\insrsid7092439\charrsid7092439 the code be disclosed or distributed in source code form; or }{\rtlch\fcs1 \af40\afs19 -\ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f3\fs20\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 -\f40\fs20\cf1\insrsid7092439\charrsid7092439 others have the right to modify it. }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 4.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 -\b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 SCOPE OF LICENSE.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitt -ed in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 - -\par }\pard \ltrpar\ql \fi-363\li720\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 -\ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 work around any technical limitations in the software; -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation; -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 publish the software for others to copy; -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 rent, lease or lend the software; -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 transfer the software or this agreement to any third party; or -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 use the software for commercial software hosting services. -\par }\pard \ltrpar\ql \fi-357\li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 5.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 -\b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 BACKUP COPY.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 -\af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 You may make one backup copy of the software. You may use it only to reinstall the software. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 -\b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 6.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 -\f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -DOCUMENTATION.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 7.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 -\f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -EXPORT RESTRICTIONS.\~ }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destin -ations, end users and end use. For additional information, see\~ }{\rtlch\fcs1 \af40\afs20 \ltrch\fcs0 \f40\fs20\kerning36\insrsid7092439\charrsid7092439 www.microsoft.com/exporting}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 .}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 8.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 -\f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -SUPPORT SERVICES.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 Because this software is \'93as is,\'94 - we may not provide support services for it. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 9.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 -\f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -ENTIRE AGREEMENT.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 -\b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 10.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 -\f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -APPLICABLE LAW.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-363\li720\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 a.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{ -\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 United States.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 -If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other c -laims, including claims under state consumer protection laws, unfair competition laws, and in tort. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\insrsid7092439\charrsid7092439 b.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 -\~\~\~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 -Outside the United States. If you acquired the software in any other country, the laws of that country apply. -\par }\pard \ltrpar\ql \fi-357\li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 11.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 -\b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 LEGAL EFFECT.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 -\af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of y -our country if the laws of your country do not permit it to do so. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 12.}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 -\f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED \'93AS-IS.\'94 YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONS -UMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMEN -T. -\par }\pard \ltrpar\ql \li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\insrsid7092439\charrsid7092439 FOR AUSTRALIA \endash - YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS. }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-357\li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\f40\fs20\cf1\kerning36\insrsid7092439\charrsid7092439 13.}{ -\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\kerning36\insrsid7092439\charrsid7092439 \~\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 -\b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS -ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. -\par }\pard \ltrpar\ql \li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin357\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 This limitation applies to}{\rtlch\fcs1 -\af0\afs24 \ltrch\fcs0 \f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \fi-363\li720\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 -\ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 - anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 \af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. -\par }\pard \ltrpar\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other d -amages. -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French. }{\rtlch\fcs1 -\af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 Remarque : Ce logiciel \'e9tant distribu\'e9 au Qu\'e9bec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en fran\'e7ais. } -{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 EXON\'c9 -RATION DE GARANTIE.\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 Le logiciel vis\'e9 par une licence est offert \'ab - tel quel \'bb. Toute utilisation de ce logiciel est \'e0 votre seule risque et p\'e9ril. Microsoft n\rquote accorde aucune autre garantie expresse. Vous pouvez b\'e9n\'e9ficier de droits - additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualit\'e9 marchande, d\rquote ad\'e9quation \'e0 - un usage particulier et d\rquote absence de contrefa\'e7on sont exclues. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par LIMITATION DES DOMMAGES-INT\'c9R\'caTS ET EXCLUSION DE RESPONSABILIT\'c9 POUR LES DOMMAGES.\~ }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 Vous}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 -\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement \'e0 - hauteur de 5,00 $ US. Vous ne pouvez pr\'e9tendre \'e0 aucune indemnisation pour les autres dommages, y compris les dommages sp\'e9ciaux, indirects ou accessoires et pertes de b\'e9n\'e9fices. }{\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 -\b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 Cette}{\rtlch\fcs1 -\af0\afs24 \ltrch\fcs0 \f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 limitationconcerne:}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 -\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \li720\ri0\sb120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 -\af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 tout ce qui est reli\'e9 - au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \li720\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f3\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 \'b7}{\rtlch\fcs1 -\af0\afs14 \ltrch\fcs0 \f0\fs14\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 \~\~\~\~\~\~\~\~\~}{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 les r\'e9 -clamations au titre de violation de contrat ou de garantie, ou au titre de responsabilit\'e9 stricte, de n\'e9gligence ou d\rquote une autre faute dans la limite autoris\'e9e par la loi en vigueur. }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 {\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 Elle s\rquote -applique \'e9galement, m\'eame si Microsoft connaissait ou devrait conna\'eetre l\rquote \'e9ventualit\'e9 d\rquote un tel dommage. Si votre pays n\rquote autorise pas l\rquote exclusion ou la limitation de responsabilit\'e9 - pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l\rquote exclusion ci-dessus ne s\rquote appliquera pas \'e0 votre \'e9gard. }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 -\f40\fs19\cf1\insrsid7092439\charrsid7092439 -\par }\pard \ltrpar\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0\pararsid7092439 {\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 EFFET JURIDIQUE. -\~}{\rtlch\fcs1 \ab\af0\afs24 \ltrch\fcs0 \b\f0\fs24\insrsid7092439\charrsid7092439 }{\rtlch\fcs1 \af40\afs19 \ltrch\fcs0 \f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 Le pr\'e9sent contrat d\'e9 -crit certains droits juridiques. Vous pourriez avoir d\rquote autres droits pr\'e9vus par les lois de votre pays. Le pr\'e9sent contrat ne modifie pas les droits que vous conf\'e8rent les lois de votre pays si celles-ci ne le permettent pas. }{ -\rtlch\fcs1 \ab\af40\afs19 \ltrch\fcs0 \b\f40\fs19\cf1\kerning36\insrsid7092439\charrsid7092439 -\par }\pard\plain \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs20 -\ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid7092439 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid16084641 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid7092439 -------------------------------------------------------- -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard\plain \ltrpar -\s16\ql \fi-360\li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls4\adjustright\rin0\lin720\itap0\pararsid10169937 \rtlch\fcs1 \af39\afs22\alang1025 \ltrch\fcs0 \f39\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2 -\ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid10169937 NuGet.Common -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Configuration -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.DependencyResolver.Core -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Frameworks -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.LibraryModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Packaging -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Packaging.Core -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Packaging.Core.Types -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.ProjectModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Protocol.Core.Types -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Protocol.Core.v3 -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Repositories -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.RuntimeModel -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid7092439\charrsid10169937 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}NuGet.Versioning -\par }\pard\plain \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs20 -\ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid7092439 ---------------------------------------------------------- -\par -\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 -\af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\insrsid7092439\charrsid7092439 Copyright (c) .NET Foundation. All rights reserved. -\par -\par Licensed under the Apache License, Version 2.0 (the "License"); you may not use -\par these files except in compliance with the License. You may obtain a copy of the -\par License at -\par -\par http://www.apache.org/licenses/LICENSE-2.0 -\par -\par Unless required by applicable law or agreed to in writing, software distributed -\par under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -\par CONDITIONS OF ANY KIND, either express or implied. See the License for the -\par specific language governing permissions and limitations under the License. -\par }\pard\plain \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7092439 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs18 -\ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid7092439\charrsid7092439 -\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid7092439 -\par }\pard \ltrpar\s15\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6173475 {\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 -----------------------------------------}{ -\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid10363382 ----------------}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs18\cf17\lang9\langfe1033\langnp9\insrsid6173475 -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid6173475\charrsid6173475 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}}\pard\plain \ltrpar -\s16\ql \fi-360\li540\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls2\ilvl2\adjustright\rin0\lin540\itap0\pararsid10363382 \rtlch\fcs1 \af39\afs22\alang1025 \ltrch\fcs0 \f39\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2 -\ltrch\fcs0 \f2\fs18\insrsid6173475\charrsid6173475 Microsoft.Management.Infrastructure.dll -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid6173475\charrsid6173475 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.Management.Infrastructure.Native.dll -\par {\listtext\pard\plain\ltrpar \s16 \rtlch\fcs1 \af2\afs22 \ltrch\fcs0 \f10\fs18\insrsid6173475\charrsid6173475 \loch\af10\dbch\af31506\hich\f10 \'a7\tab}Microsoft.Management.Infrastructure.Unmanaged.dll -\par }\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid10363382 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 -{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\fs18\insrsid10363382 ----------------------------------------------------------}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\fs18\insrsid10363382\charrsid10363382 -\par }\pard\plain \ltrpar\s32\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs28\alang1025 \ltrch\fcs0 -\fs28\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 MICROSOFT SOFTWARE LICENSE TERMS -\par }\pard\plain \ltrpar\s33\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs28\alang1025 \ltrch\fcs0 -\fs28\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\fs24\insrsid7813854\charrsid6843334 \hich\af42\dbch\af11\loch\f42 MANAGEMENT.INFRASTRUCTURE.DLL }{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\fs24\insrsid7813854 -\par }{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\fs24\insrsid7813854\charrsid6843334 \hich\af42\dbch\af11\loch\f42 MANAGEMENT.INFRASTRUCTURE.NATIVE.DLL\hich\af42\dbch\af11\loch\f42 MANAGEMENT.INFRASTRUCTURE.UNMANAGED.DLL -\par }\pard \ltrpar\s33\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7813854 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid11493340 -{\pict{\*\picprop\shplid1025{\sp{\sn shapeType}{\sv 1}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn fillColor}{\sv 10526880}}{\sp{\sn fFilled}{\sv 1}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn alignHR}{\sv 1}}{\sp{\sn dxHeightHR}{\sv 30}} -{\sp{\sn fStandardHR}{\sv 1}}{\sp{\sn fHorizRule}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 1}}}\picscalex1\picscaley1\piccropl0\piccropr0\piccropt0\piccropb0\picw7620\pich7620\picwgoal4320\pichgoal4320\wmetafile8}}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\fs24\insrsid7813854\charrsid6112664 -\par }\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}} -{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang -{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar -\s34\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\lang9\langfe1033\langnp9\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 -These license terms are an agreement between you and Microsoft Corporation (or one of its affiliates). They apply to the software named above and any Microsoft services or software updates (except to the extent su\hich\af42\dbch\af11\loch\f42 -ch services or updates are accompanied by new or }{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 additional terms, in which case those different terms {\*\bkmkstart OLE_LINK84}{\*\bkmkstart OLE_LINK85} -apply prospectively {\*\bkmkend OLE_LINK84}{\*\bkmkend OLE_LINK85}and do not alter your or Microsoft\hich\f42 \rquote \loch\f42 s rights relating to pre-updated software or services}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\lang9\langfe1033\langnp9\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 ). IF YOU COMPLY WITH THESE LICENSE TERMS, YO\hich\af42\dbch\af11\loch\f42 U HAVE THE RIGHTS BELOW. }{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\lang9\langfe1033\langnp9\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854 \hich\af40\dbch\af11\loch\f40 1.\tab}}\pard\plain \ltrpar\s1\ql \fi-357\li357\ri0\sb120\sa120\widctlpar -\jclisttab\tx360\wrapdefault\aspalpha\aspnum\faauto\ls12\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854 \hich\af42\dbch\af11\loch\f42 INSTALLATION AND USE RIGHTS}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\*\bkmkstart OLE_LINK124}{\*\bkmkstart OLE_LINK125}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 a)\tab}}\pard\plain \ltrpar -\s2\ql \fi-360\li717\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls13\outlinelevel1\adjustright\rin0\lin717\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 -\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 General.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 You may install and use any number of copies of the software on your devices. -\par {\*\bkmkend OLE_LINK124}{\*\bkmkend OLE_LINK125}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 b)\tab}}{\rtlch\fcs1 \af42 -\ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 Included Microsoft Applications.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 - The software may include other Microsoft applications. These license terms apply to those included applications, if any, {\*\bkmkstart OLE_LINK80}{\*\bkmkstart OLE_LINK81}unless other license terms are provided with the other Microsoft applications -{\*\bkmkend OLE_LINK80}{\*\bkmkend OLE_LINK81}.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 c)\tab}\hich\af42\dbch\af11\loch\f42 Third Party Software.}{\rtlch\fcs1 \af42 -\ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 The software may include third pa\hich\af42\dbch\af11\loch\f42 -rty applications that are licensed to you under this agreement or under their own terms. License terms, notices, and acknowledgements, if any, for the third party applications may be accessible online at }{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af40 -\ltrch\fcs0 \insrsid11493340 \hich\af40\dbch\af11\loch\f40 HYPERLINK "http://aka.ms/thirdpartynotices" }}{\fldrslt {\rtlch\fcs1 \af42 \ltrch\fcs0 \cs19\f42\ul\cf1\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 http -\hich\af42\dbch\af11\loch\f42 ://aka.ms/thirdpartynotices}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 - or in an accompanying notices file. Even if such applications are governed by other agreements, the disclaimer, limitations on, and exclusions of damages below also apply to the extent allowed by applicable law.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854 \hich\af40\dbch\af11\loch\f40 2.\tab}}\pard\plain \ltrpar\s1\ql \fi-357\li357\ri0\sb120\sa120\widctlpar -\jclisttab\tx360\wrapdefault\aspalpha\aspnum\faauto\ls12\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854 \hich\af42\dbch\af11\loch\f42 TIME-SENSITIVE S\hich\af42\dbch\af11\loch\f42 OFTWARE}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 a)\tab}}\pard\plain \ltrpar -\s2\ql \fi-360\li717\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls14\outlinelevel1\adjustright\rin0\lin717\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 -\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 Period.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 The software is time-sensitive and may stop running on a date that is defined in the software.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 b)\tab}\hich\af42\dbch\af11\loch\f42 Notice.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 You may receive periodic reminder notices of this date through the software.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 c)\tab}\hich\af42\dbch\af11\loch\f42 Access to data.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 You may not be able to access data used in the software when it stops running.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 3.\tab}}\pard\plain \ltrpar\s1\ql \fi-357\li357\ri0\sb120\sa120\widctlpar -\jclisttab\tx360\wrapdefault\aspalpha\aspnum\faauto\ls12\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 PRE-RELEASE SOFTWARE.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 - The software is a pre-release version. It may not operate correctly. It may be different from the commercially released version.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 4.\tab}\hich\af42\dbch\af11\loch\f42 FEEDBACK.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 If you give fee\hich\af42\dbch\af11\loch\f42 -dback about the software to Microsoft, you give to Microsoft, without charge, the right to use, share and commercialize your feedback in any way and for any purpose. You will not give feedback that is subject to a license that requires Microsoft to licens -\hich\af42\dbch\af11\loch\f42 e\hich\af42\dbch\af11\loch\f42 its software or documentation to third parties because Microsoft includes your feedback in them. These rights survive this agreement.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 5.\tab}\hich\af42\dbch\af11\loch\f42 DATA COLLECTION.}{\rtlch\fcs1 \af42 -\ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 The software may collect information about you and your use of the software and send that to Microsoft. \hich\af42\dbch\af11\loch\f42 -Microsoft may use this information to provide services and improve Microsoft\hich\f42 \rquote \loch\f42 -s products and services. Your opt-out rights, if any, are described in the product documentation. Some features in the software may enable collection of data from users of your a\hich\af42\dbch\af11\loch\f42 p\hich\af42\dbch\af11\loch\f42 -plications that access or use the software. If you use these features to enable data collection in your applications, you must comply with applicable law, including getting any required user consent, and maintain a prominent privacy policy that accurately -\hich\af42\dbch\af11\loch\f42 \hich\af42\dbch\af11\loch\f42 informs users about how you use, collect, and share their data. You can learn more about Microsoft\hich\f42 \rquote \loch\f42 -s data collection and use in the product documentation and the Microsoft Privacy Statement}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\delrsid16459130\charrsid6112664 \hich\af42\dbch\af11\loch\f42 }{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 at }{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af40 \ltrch\fcs0 \insrsid11493340 \hich\af40\dbch\af11\loch\f40 HYPERLINK "https://go.microsoft.com/fwlink/?LinkId=521839" }}{\fldrslt { -\rtlch\fcs1 \af42 \ltrch\fcs0 \cs19\f42\ul\cf1\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 https://go.microsoft.com/fwlink/?LinkId=521839}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af42 -\ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 . You agree to comply with all applicable provisions of the Microsoft Privacy Statement.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 6.\tab}\hich\af42\dbch\af11\loch\f42 FONTS.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 While the software is running, you may use its fonts to display and print content. You may only (i) embed fonts in\hich\af42\dbch\af11\loch\f42 - content as permitted by the embedding restrictions in the fonts; and (ii) temporarily download them to a printer or other output device to help print content.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 7.\tab}\hich\af42\dbch\af11\loch\f42 SCOPE OF LICENSE.}{\rtlch\fcs1 \af42 -\ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 The software is licensed, not sold. Microsoft reserves all other rights. Unles\hich\af42\dbch\af11\loch\f42 -s applicable law gives you more rights despite this limitation, you will not (and have no right to):}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 a)\tab}}\pard\plain \ltrpar -\s2\ql \fi-360\li717\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls15\outlinelevel1\adjustright\rin0\lin717\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 -\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 -work around any technical limitations in the software that only allow you to use it in certain ways; -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 b)\tab}\hich\af42\dbch\af11\loch\f42 -reverse engineer, decompile or disassemble the softwar\hich\af42\dbch\af11\loch\f42 e; -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 c)\tab}\hich\af42\dbch\af11\loch\f42 -remove, minimize, block, or modify any notices of Microsoft or its suppliers in the software; -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 d)\tab}\hich\af42\dbch\af11\loch\f42 -use the software in any way that is against the law or to create or propagate malware; or -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 e)\tab}\hich\af42\dbch\af11\loch\f42 -share, publish, distribute, or lend the software, provide the softwar\hich\af42\dbch\af11\loch\f42 e as a stand-alone hosted solution for others to use, or transfer the software or this agreement to any third party. -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 8.\tab}}\pard\plain \ltrpar\s1\ql \fi-357\li357\ri0\sb120\sa120\widctlpar -\jclisttab\tx360\wrapdefault\aspalpha\aspnum\faauto\ls12\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 EXPORT RESTRICTIONS.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 - You must comply with all domestic and international export laws and regulations that apply to the software, which incl\hich\af42\dbch\af11\loch\f42 -ude restrictions on destinations, end users, and end use. For further information on export restrictions, visit }{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af40 \ltrch\fcs0 \insrsid11493340 \hich\af40\dbch\af11\loch\f40 HYPERLINK "http://aka.ms/exporting" -}}{\fldrslt {\rtlch\fcs1 \af42 \ltrch\fcs0 \cs19\f42\ul\cf1\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 http://aka.ms/exporting}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 .}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 9.\tab}\hich\af42\dbch\af11\loch\f42 SUPPORT SERVICES.}{\rtlch\fcs1 \af42 -\ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 Microsoft is not obligated under this agreement to provide an\hich\af42\dbch\af11\loch\f42 \hich\f42 y support services for the software. Any support provided is \'93\loch\f42 -\hich\f42 as is\'94\loch\f42 \hich\f42 , \'93\loch\f42 \hich\f42 with all faults\'94\loch\f42 , and without warranty of any kind.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 10.\tab}\hich\af42\dbch\af11\loch\f42 UPDATES.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 The software may periodically check for updates, and download and install them for you. You may obtain updates only from Mic\hich\af42\dbch\af11\loch\f42 -rosoft or authorized sources. Microsoft may need to update your system to provide you with updates. You agree to receive these automatic updates without any additional notice. Updates may not include or support all existing software features, services, or -\hich\af42\dbch\af11\loch\f42 \hich\af42\dbch\af11\loch\f42 peripheral devices.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 11.\tab}\hich\af42\dbch\af11\loch\f42 ENTIRE AGREEMENT.}{\rtlch\fcs1 \af42 -\ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 This agreement, and any other terms Microsoft may provide for supplements, updates, or third-party applications, is the entire agreement for the software. -\par {\*\bkmkstart OLE_LINK170}{\*\bkmkstart OLE_LINK171}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 12.\tab}}{\rtlch\fcs1 \af42 -\ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 - If you acquired the software in the United States or Canada, the laws of the state or province where you live (or, if a business, where your principal place of business is located) govern the interpretation of this agreement, claims for its breach, and a -\hich\af42\dbch\af11\loch\f42 l\hich\af42\dbch\af11\loch\f42 -l other claims (including consumer protection, unfair competition, and tort claims), regardless of conflict of laws principles. If you acquired the software in any other country, its laws apply. If U.S. federal jurisdiction exists, you and Microsoft conse -\hich\af42\dbch\af11\loch\f42 n\hich\af42\dbch\af11\loch\f42 -t to exclusive jurisdiction and venue in the federal court in King County, Washington for all disputes heard in court. If not, you and Microsoft consent to exclusive jurisdiction and venue in the Superior Court of King County, Washington for all disputes -\hich\af42\dbch\af11\loch\f42 h\hich\af42\dbch\af11\loch\f42 eard in court.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\*\bkmkend OLE_LINK170}{\*\bkmkend OLE_LINK171}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 13.\tab} -\hich\af42\dbch\af11\loch\f42 CONSUMER RIGHTS; REGIONAL VARIATIONS.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 - This agreement describes certain legal rights. You may have other rights, including consumer rights, under the laws of your state, province, or country. Separate and apart from your relationship with Mic\hich\af42\dbch\af11\loch\f42 -rosoft, you may also have rights with respect to the party from which you acquired the software. This agreement does not change those other rights if the laws of your state, province, or country do not permit it to do so. For example, if you acquired the -\hich\af42\dbch\af11\loch\f42 s\hich\af42\dbch\af11\loch\f42 oftware in one of the below regions, or mandatory country law applies, then the following provisions apply to you:}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 a)\tab}}\pard\plain \ltrpar -\s2\ql \fi-360\li717\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ls16\outlinelevel1\adjustright\rin0\lin717\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 -\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 Australia.}{\rtlch\fcs1 \af42 \ltrch\fcs0 -\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is intended to affect those rights. -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 b)\tab}}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\hich\af42\dbch\af11\loch\f42 Canada.}{\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 - If you acquired this software in Canada, you may stop receiving updates by turning off the automatic update feature, disconnecting your device from the Internet (if and when you re-connect to the Internet, however, the software will resume checking -\hich\af42\dbch\af11\loch\f42 for and installing updates), or uninstalling the software. The product documentation, if any, may also specify how to turn off updates for your specific device or software. -\par {\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \b\fs19\loch\af42\hich\af42\dbch\af11\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 c)\tab}}{\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 -\hich\af42\dbch\af11\loch\f42 Germany and Austria. -\par }\pard\plain \ltrpar\ql \fi-360\li1080\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin1080\itap0\pararsid7813854 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 -\f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 i.\tab Warranty. The properly licensed software will perform subs -tantially as described in any Microsoft materials that accompany the software. However, Microsoft gives no contractual guarantee in relation to the licensed software. -\par ii.\tab Limitation of Liability. In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as well as, in case of death or personal or physical injury, Microsoft is liable according to the statutory law. -\par }\pard\plain \ltrpar\s1\ql \li717\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin717\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 -\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 -Subject to the foregoing clause ii., Microsoft will only be liable for slight negligence if Microsoft is in br\hich\af42\dbch\af11\loch\f42 -each of such material contractual obligations, the fulfillment of which facilitate the due performance of this agreement, the breach of which would endanger the purpose of this agreement and the compliance with which a party may constantly trust in (so-ca -\hich\af42\dbch\af11\loch\f42 l\hich\af42\dbch\af11\loch\f42 led "cardinal obligations"). In other cases of slight negligence, Microsoft will not be liable for slight negligence. -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 14.\tab}}\pard \ltrpar\s1\ql \fi-357\li357\ri0\sb120\sa120\widctlpar -\jclisttab\tx360\wrapdefault\aspalpha\aspnum\faauto\ls12\outlinelevel0\adjustright\rin0\lin357\itap0\pararsid7813854 {\rtlch\fcs1 \af42 \ltrch\fcs0 \b\f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 \hich\f42 -DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED \'93\loch\f42 \hich\f42 AS IS.\'94\loch\f42 YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, \hich\af42\dbch\af11\loch\f42 -GUARANTEES, OR CONDITIONS. TO THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. -\par {\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af40\afs20 \ltrch\fcs0 \b\fs20\loch\af40\hich\af40\dbch\af11\insrsid7813854\charrsid6112664 \hich\af40\dbch\af11\loch\f40 15.\tab}\hich\af42\dbch\af11\loch\f42 -LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY \hich\af42\dbch\af11\loch\f42 -BASIS FOR RECOVERING DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIREC -\hich\af42\dbch\af11\loch\f42 T\hich\af42\dbch\af11\loch\f42 OR INCIDENTAL DAMAGES. -\par }\pard\plain \ltrpar\s31\ql \li357\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin357\itap0\pararsid7813854 \rtlch\fcs1 \af40\afs19\alang1025 \ltrch\fcs0 -\b\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 -This limitation applies to (a) anything related to the software, services, content (including code) on third party Internet sites, or third party applications; and (b) {\*\bkmkstart OLE_LINK76}{\*\bkmkstart OLE_LINK77} -claims for breach of contract, warranty, guarantee, or condition\hich\af42\dbch\af11\loch\f42 ; strict liability, negligence, or other tort; or any other claim; in each case to the extent permitted by applicable law.{\*\bkmkend OLE_LINK76} -{\*\bkmkend OLE_LINK77} -\par \hich\af42\dbch\af11\loch\f42 It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion m\hich\af42\dbch\af11\loch\f42 -ay not apply to you because your state, province, or country may not allow the exclusion or limitation of incidental, consequential, or other damages. -\par }\pard\plain \ltrpar\s2\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0\pararsid7813854 \rtlch\fcs1 \ab\af40\afs19\alang1025 \ltrch\fcs0 -\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 -\par }\pard\plain \ltrpar\s31\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7813854 \rtlch\fcs1 \af40\afs19\alang1025 \ltrch\fcs0 -\b\fs19\lang1033\langfe1033\loch\af40\hich\af40\dbch\af11\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 -Please note: As this software is distributed in Canada, some of the clauses in this agreement are provid\hich\af42\dbch\af11\loch\f42 ed below in French. -\par \hich\af42\dbch\af11\loch\f42 \hich\f42 Remarque: Ce logiciel \'e9\loch\f42 \hich\f42 tant distribu\'e9\loch\f42 \hich\f42 au Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en fran\'e7\loch\f42 ais. -\par \hich\af42\dbch\af11\loch\f42 \hich\f42 EXON\'c9\loch\f42 \hich\f42 RATION DE GARANTIE. Le logiciel vis\'e9\loch\f42 \hich\f42 par une licence est offert \'ab\loch\f42 \hich\f42 tel quel \'bb\loch\f42 . Toute utilisation de ce logi -\hich\af42\dbch\af11\loch\f42 \hich\f42 ciel est \'e0\loch\f42 \hich\f42 votre seule risque et p\'e9\loch\f42 ril. Microsoft n\hich\f42 \rquote \loch\f42 \hich\f42 accorde aucune autre garantie expresse. Vous pouvez b\'e9\loch\f42 \hich\f42 n\'e9 -\loch\f42 ficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permis\hich\af42\dbch\af11\loch\f42 e\hich\af42\dbch\af11\loch\f42 \hich\f42 -s par le droit locale, les garanties implicites de qualit\'e9\loch\f42 marchande, d\hich\f42 \rquote \loch\f42 \hich\f42 ad\'e9\loch\f42 \hich\f42 quation \'e0\loch\f42 un usage particulier et d\hich\f42 \rquote \loch\f42 \hich\f42 absence de contrefa -\'e7\loch\f42 on sont exclues. -\par \hich\af42\dbch\af11\loch\f42 \hich\f42 LIMITATION DES DOMMAGES-INT\'c9\loch\f42 \hich\f42 R\'ca\loch\f42 \hich\f42 TS ET EXCLUSION DE RESPONSABILIT\'c9\loch\f42 POUR LES DOMMAGES. Vous pouvez obtenir de Mi\hich\af42\dbch\af11\loch\f42 \hich\f42 -crosoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement \'e0\loch\f42 \hich\f42 hauteur de 5,00 $ US. Vous ne pouvez pr\'e9\loch\f42 \hich\f42 tendre \'e0\loch\f42 \hich\f42 - aucune indemnisation pour les autres dommages, y compris les dommages sp\'e9\loch\f42 ciaux, indirects ou accessoires et pertes de\hich\af42\dbch\af11\loch\f42 \hich\af42\dbch\af11\loch\f42 \hich\f42 b\'e9\loch\f42 \hich\f42 n\'e9\loch\f42 fices. -\par \hich\af42\dbch\af11\loch\f42 Cette limitation concerne: -\par }\pard \ltrpar\s31\ql \fi-360\li360\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin360\itap0\pararsid7813854 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \bullet \tab \hich\af42\dbch\af11\loch\f42 -\hich\f42 tout ce qui est reli\'e9\loch\f42 au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers; et -\par \bullet \tab \hich\af42\dbch\af11\loch\f42 \hich\f42 les r\'e9\loch\f42 clamations au titre de violation de contrat ou de garan\hich\af42\dbch\af11\loch\f42 \hich\f42 tie, ou au titre de responsabilit\'e9\loch\f42 \hich\f42 stricte, de n\'e9\loch\f42 -gligence ou d\hich\f42 \rquote \loch\f42 \hich\f42 une autre faute dans la limite autoris\'e9\loch\f42 e par la loi en vigueur. -\par }\pard \ltrpar\s31\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid7813854 {\rtlch\fcs1 \af42 \ltrch\fcs0 \f42\insrsid7813854\charrsid6112664 \hich\af42\dbch\af11\loch\f42 Elle s\hich\f42 \rquote -\loch\f42 \hich\f42 applique \'e9\loch\f42 \hich\f42 galement, m\'ea\loch\f42 \hich\f42 me si Microsoft connaissait ou devrait conna\'ee\loch\f42 tre l\hich\f42 \rquote \'e9\loch\f42 \hich\f42 ventualit\'e9\loch\f42 d\hich\f42 \rquote \loch\f42 -un tel dommage. Si votre pays n\hich\f42 \rquote \loch\f42 aut\hich\af42\dbch\af11\loch\f42 orise pas l\hich\f42 \rquote \loch\f42 \hich\f42 exclusion ou la limitation de responsabilit\'e9\loch\f42 - pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l\hich\f42 \rquote \loch\f42 exclusion ci-dessus ne s\hich\f42 \rquote \loch\f42 \hich\f42 appliquera pas \'e0\loch\f42 \hich\f42 votre \'e9 -\loch\f42 gard. -\par \hich\af42\dbch\af11\loch\f42 \hich\f42 EFFET JURIDIQUE. Le pr\'e9\loch\f42 sent contrat\hich\af42\dbch\af11\loch\f42 \hich\f42 d\'e9\loch\f42 crit certains droits juridiques. Vous pourriez avoir d\hich\f42 \rquote \loch\f42 \hich\f42 autres droits pr -\'e9\loch\f42 \hich\f42 vus par les lois de votre pays. Le pr\'e9\loch\f42 \hich\f42 sent contrat ne modifie pas les droits que vous conf\'e8\loch\f42 rent les lois de votre pays si celles-ci ne le permettent pas. -\par }\pard\plain \ltrpar\ql \li0\ri0\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid6173475 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid8394862 -\par }{\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid6573559 -\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a -9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad -5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 -b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 -0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 -a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f -c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 -0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 -a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 -6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b -4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b -4757e8d3f729e245eb2b260a0238fd010000ffff0300504b03041400060008000000210007b740aaca0600008f1a0000160000007468656d652f7468656d652f -7468656d65312e786d6cec595b8bdb46147e2ff43f08bd3bbe49be2cf1065bb69336bb49889d943cceda636bb2238dd18c776342a0244f7d2914d2d28706fad6 -87521a68a0a12ffd310b1bdaf447f4cc489667ec71f6420aa1640d8b34face996fce39face48ba7aed51449d239c70c2e2965bbe52721d1c8fd898c4d3967b6f -d82f345c870b148f1165316eb90bccdd6bbb9f7e7215ed881047d801fb98efa0961b0a31db2916f9088611bfc26638866b13964448c069322d8e13740c7e235a -ac944ab5628448ec3a318ac0ededc9848cb033942edddda5f31e85d358703930a2c940bac68685c28e0fcb12c1173ca089738468cb8579c6ec78881f09d7a188 -0bb8d0724beacf2dee5e2da29dcc888a2db69a5d5ffd657699c1f8b0a2e64ca607f9a49ee77bb576ee5f01a8d8c4f5eabd5aaf96fb5300341ac14a532eba4fbf -d3ec74fd0cab81d2438bef6ebd5b2d1b78cd7f758373db973f03af40a97f6f03dfef07104503af4029dedfc07b5ebd1278065e81527c6d035f2fb5bb5eddc02b -5048497cb8812ef9b56ab05c6d0e99307ac30a6ffa5ebf5ec99caf50500d7975c929262c16db6a2d420f59d2078004522448ec88c50c4fd008aa3840941c24c4 -d923d3100a6f8662c661b85429f54b55f82f7f9e3a5211413b1869d6921730e11b43928fc34709998996fb39787535c8e9ebd7274f5f9d3cfdfde4d9b393a7bf -66732b5786dd0d144f75bbb73f7df3cf8b2f9dbf7ffbf1edf36fd3a9d7f15cc7bff9e5ab377ffcf92ef7b0e255284ebf7bf9e6d5cbd3efbffeebe7e716efed04 -1de8f0218930776ee163e72e8b608116fef820b998c5304444b768c7538e622467b1f8ef89d040df5a208a2cb80e36e3783f01a9b101afcf1f1a8407613217c4 -e2f1661819c07dc6688725d628dc947369611ecee3a97df264aee3ee2274649b3b40b191e5de7c061a4b6c2e83101b34ef50140b34c531168ebcc60e31b6acee -0121465cf7c928619c4d84f380381d44ac21199203a39a56463748047959d80842be8dd8ecdf773a8cda56ddc5472612ee0d442de487981a61bc8ee602453697 -4314513de07b48843692834532d2713d2e20d3534c99d31b63ce6d36b71358af96f49b2033f6b4efd345642213410e6d3ef710633ab2cb0e831045331b7640e2 -50c77ec60fa144917387091b7c9f9977883c873ca0786bbaef136ca4fb6c35b8070aab535a1588bc324f2cb9bc8e9951bf83059d20aca4061a80a1eb1189cf14 -f93579f7ff3b7907113dfde1856545ef47d2ed8e8d7c5c50ccdb09b1de4d37d6247c1b6e5db803968cc987afdb5d348fef60b855369bd747d9fe28dbeeff5eb6 -b7ddcfef5fac57fa0cd22db7ade9765d6ddea3ad7bf709a174201614ef71b57de7d095c67d189476eab915e7cf72b3100ee59d0c1318b86982948d9330f10511 -e1204433d8e3975de964ca33d753eecc1887adbf1ab6fa96783a8ff6d9387d642d97e5e3692a1e1c89d578c9cfc7e17143a4e85a7df51896bb576ca7ea717949 -40da5e8484369949a26a21515f0eca20a98773089a85845ad97b61d1b4b06848f7cb546db0006a795660dbe4c066abe5fa1e9880113c55218ac7324f69aa97d9 -55c97c9f99de164ca302600fb1ac8055a69b92ebd6e5c9d5a5a5768e4c1b24b4723349a8c8a81ec64334c65975cad1f3d0b868ae9bab941af46428d47c505a2b -1af5c6bb585c36d760b7ae0d34d69582c6ce71cbad557d2899119ab5dc093cfac3613483dae172bb8be814de9f8d4492def097519659c24517f1300db8129d54 -0d222270e25012b55cb9fc3c0d34561aa2b8952b20081f2cb926c8ca87460e926e26194f267824f4b46b2332d2e929287caa15d6abcafcf26069c9e690ee4138 -3e760ee83cb98ba0c4fc7a5906704c38bc012aa7d11c1378a5990bd9aafed61a5326bbfa3b455543e938a2b310651d4517f314aea43ca7a3cef2186867d99a21 -a05a48b2467830950d560faad14df3ae9172d8da75cf369291d34473d5330d55915dd3ae62c60ccb36b016cbcb35798dd532c4a0697a874fa57b5d729b4bad5b -db27e45d02029ec7cfd275cfd110346aabc90c6a92f1a60c4bcdce46cddeb15ce019d4ced32434d5af2dddaec52def11d6e960f0529d1fecd6ab168626cb7da5 -8ab4faf6a17f9e60070f413cbaf022784e0557a9848f0f09820dd140ed4952d9805be491c86e0d3872e60969b98f4b7edb0b2a7e502835fc5ec1ab7aa542c36f -570b6ddfaf967b7eb9d4ed549e4063116154f6d3ef2e7d780d4517d9d71735bef105265abe69bb32625191a92f2c45455c7d812957b67f81710888cee35aa5df -ac363bb542b3daee17bc6ea7516806b54ea15b0beadd7e37f01bcdfe13d7395260af5d0dbc5aaf51a89583a0e0d54a927ea359a87b954adbabb71b3daffd24db -c6c0ca53f9c86201e155bc76ff050000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f7468656d652f5f72 -656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c08 -2e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd0 -8a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa -4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c0200001300000000000000000000000000000000005b436f -6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b00000000000000000000000000300100005f72 -656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000190200007468656d652f746865 -6d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210007b740aaca0600008f1a00001600000000000000000000000000d60200 -007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b01000027000000000000000000000000 -00d40900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000cf0a00000000} -{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d -617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 -6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 -656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} -{\*\latentstyles\lsdstimax373\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdlocked0 heading 1; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 4; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 7; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 1; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 5; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 8; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 8; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Contemporary; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Elegant;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Professional;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdlocked0 Placeholder Text; -\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2; -\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List; -\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdpriority61 \lsdlocked0 Light List Accent 1; -\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdsemihidden1 \lsdlocked0 Revision; -\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1; -\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdpriority72 \lsdlocked0 Colorful List Accent 1; -\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2; -\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2; -\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2; -\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3; -\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3; -\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4; -\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4; -\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4; -\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5; -\lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; -\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; -\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; -\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; -\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; -\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; -\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; -\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; -\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; -\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; -\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; -\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; -\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; -\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; -\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; -\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; -\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; -\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; -\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; -\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; -\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; -\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; -\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; -\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; -\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; -\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; -\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; -\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; -\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;}}{\*\datastore 0105000002000000180000004d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000 -d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000c051 -85b5e0f4d101feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file +{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;} +{\f3\fbidi \fdecor\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f10\fbidi \fdecor\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;}{\f11\fbidi \fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}MS Mincho{\*\falt ?l?r ??fc};} +{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f42\fbidi \fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Tahoma;} +{\f43\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0603020202020204}Trebuchet MS;}{\f44\fbidi \fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}@MS Mincho;} +{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f45\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\f46\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f48\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f49\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f50\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\f51\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f52\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f53\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f65\fbidi \fmodern\fcharset238\fprq1 Courier New CE;} +{\f66\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;}{\f68\fbidi \fmodern\fcharset161\fprq1 Courier New Greek;}{\f69\fbidi \fmodern\fcharset162\fprq1 Courier New Tur;}{\f70\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);} +{\f71\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);}{\f72\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f73\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);} +{\f157\fbidi \fmodern\fcharset0\fprq1 MS Mincho Western{\*\falt ?l?r ??fc};}{\f155\fbidi \fmodern\fcharset238\fprq1 MS Mincho CE{\*\falt ?l?r ??fc};}{\f156\fbidi \fmodern\fcharset204\fprq1 MS Mincho Cyr{\*\falt ?l?r ??fc};} +{\f158\fbidi \fmodern\fcharset161\fprq1 MS Mincho Greek{\*\falt ?l?r ??fc};}{\f159\fbidi \fmodern\fcharset162\fprq1 MS Mincho Tur{\*\falt ?l?r ??fc};}{\f162\fbidi \fmodern\fcharset186\fprq1 MS Mincho Baltic{\*\falt ?l?r ??fc};} +{\f385\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f386\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f388\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f389\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;} +{\f392\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f393\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f415\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f416\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;} +{\f418\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f419\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f420\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f421\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);} +{\f422\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f423\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f465\fbidi \fswiss\fcharset238\fprq2 Tahoma CE;}{\f466\fbidi \fswiss\fcharset204\fprq2 Tahoma Cyr;} +{\f468\fbidi \fswiss\fcharset161\fprq2 Tahoma Greek;}{\f469\fbidi \fswiss\fcharset162\fprq2 Tahoma Tur;}{\f470\fbidi \fswiss\fcharset177\fprq2 Tahoma (Hebrew);}{\f471\fbidi \fswiss\fcharset178\fprq2 Tahoma (Arabic);} +{\f472\fbidi \fswiss\fcharset186\fprq2 Tahoma Baltic;}{\f473\fbidi \fswiss\fcharset163\fprq2 Tahoma (Vietnamese);}{\f474\fbidi \fswiss\fcharset222\fprq2 Tahoma (Thai);}{\f475\fbidi \fswiss\fcharset238\fprq2 Trebuchet MS CE;} +{\f476\fbidi \fswiss\fcharset204\fprq2 Trebuchet MS Cyr;}{\f478\fbidi \fswiss\fcharset161\fprq2 Trebuchet MS Greek;}{\f479\fbidi \fswiss\fcharset162\fprq2 Trebuchet MS Tur;}{\f482\fbidi \fswiss\fcharset186\fprq2 Trebuchet MS Baltic;} +{\f487\fbidi \fmodern\fcharset0\fprq1 @MS Mincho Western;}{\f485\fbidi \fmodern\fcharset238\fprq1 @MS Mincho CE;}{\f486\fbidi \fmodern\fcharset204\fprq1 @MS Mincho Cyr;}{\f488\fbidi \fmodern\fcharset161\fprq1 @MS Mincho Greek;} +{\f489\fbidi \fmodern\fcharset162\fprq1 @MS Mincho Tur;}{\f492\fbidi \fmodern\fcharset186\fprq1 @MS Mincho Baltic;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;} +{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);}{\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);} +{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} +{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;} +{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;} +{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;} +{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}} +{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; +\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;\red51\green51\blue51;}{\*\defchp \f31506\fs22 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1 +\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 +\f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\s1\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af42\afs19\alang1025 +\ltrch\fcs0 \fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext1 \slink15 \sqformat \styrsid7813854 heading 1;}{ +\s2\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af42\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext2 \slink16 \sqformat \styrsid7813854 heading 2;}{\s3\ql \fi-357\li1077\ri0\sb120\sa120\widctlpar\tx1077\jclisttab\tx1440\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl2\outlinelevel2\adjustright\rin0\lin1077\itap0 \rtlch\fcs1 +\af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext3 \slink17 \sqformat \styrsid7813854 heading 3;}{\s4\ql \fi-358\li1435\ri0\sb120\sa120\widctlpar +\jclisttab\tx1437\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl3\outlinelevel3\adjustright\rin0\lin1435\itap0 \rtlch\fcs1 \af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext4 \slink18 \sqformat \styrsid7813854 heading 4;}{\s5\ql \fi-357\li1792\ri0\sb120\sa120\widctlpar\tx1792\jclisttab\tx2155\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl4\outlinelevel4\adjustright\rin0\lin1792\itap0 \rtlch\fcs1 +\af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext5 \slink19 \sqformat \styrsid7813854 heading 5;}{\s6\ql \fi-357\li2149\ri0\sb120\sa120\widctlpar +\jclisttab\tx2152\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl5\outlinelevel5\adjustright\rin0\lin2149\itap0 \rtlch\fcs1 \af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext6 \slink20 \sqformat \styrsid7813854 heading 6;}{\s7\ql \fi-357\li2506\ri0\sb120\sa120\widctlpar\jclisttab\tx2509\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl6\outlinelevel6\adjustright\rin0\lin2506\itap0 \rtlch\fcs1 +\af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext7 \slink21 \sqformat \styrsid7813854 heading 7;}{\s8\ql \fi-357\li2863\ri0\sb120\sa120\widctlpar +\jclisttab\tx2866\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl7\outlinelevel7\adjustright\rin0\lin2863\itap0 \rtlch\fcs1 \af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext8 \slink22 \sqformat \styrsid7813854 heading 8;}{\s9\ql \fi-358\li3221\ri0\sb120\sa120\widctlpar\jclisttab\tx3223\wrapdefault\aspalpha\aspnum\faauto\ls12\ilvl8\outlinelevel8\adjustright\rin0\lin3221\itap0 \rtlch\fcs1 +\af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext9 \slink23 \sqformat \styrsid7813854 heading 9;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 +Default Paragraph Font;}{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31506\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused +Normal Table;}{\*\cs15 \additive \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 \fs19\loch\f42\hich\af42\dbch\af11 \sbasedon10 \slink1 \slocked \styrsid7813854 Heading 1 Char;}{\*\cs16 \additive \rtlch\fcs1 \ab\af42\afs19 \ltrch\fcs0 +\fs19\loch\f42\hich\af42\dbch\af11 \sbasedon10 \slink2 \slocked \styrsid7813854 Heading 2 Char;}{\*\cs17 \additive \rtlch\fcs1 \af42\afs19 \ltrch\fcs0 \b\fs19\loch\f42\hich\af42\dbch\af11 \sbasedon10 \slink3 \slocked \styrsid7813854 Heading 3 Char;}{\* +\cs18 \additive \rtlch\fcs1 \af42\afs19 \ltrch\fcs0 \b\fs19\loch\f42\hich\af42\dbch\af11 \sbasedon10 \slink4 \slocked \styrsid7813854 Heading 4 Char;}{\*\cs19 \additive \rtlch\fcs1 \af42\afs19 \ltrch\fcs0 \b\fs19\loch\f42\hich\af42\dbch\af11 +\sbasedon10 \slink5 \slocked \styrsid7813854 Heading 5 Char;}{\*\cs20 \additive \rtlch\fcs1 \af42\afs19 \ltrch\fcs0 \b\fs19\loch\f42\hich\af42\dbch\af11 \sbasedon10 \slink6 \slocked \styrsid7813854 Heading 6 Char;}{\*\cs21 \additive \rtlch\fcs1 +\af42\afs19 \ltrch\fcs0 \b\fs19\loch\f42\hich\af42\dbch\af11 \sbasedon10 \slink7 \slocked \styrsid7813854 Heading 7 Char;}{\*\cs22 \additive \rtlch\fcs1 \af42\afs19 \ltrch\fcs0 \b\fs19\loch\f42\hich\af42\dbch\af11 +\sbasedon10 \slink8 \slocked \styrsid7813854 Heading 8 Char;}{\*\cs23 \additive \rtlch\fcs1 \af42\afs19 \ltrch\fcs0 \b\fs19\loch\f42\hich\af42\dbch\af11 \sbasedon10 \slink9 \slocked \styrsid7813854 Heading 9 Char;}{ +\s24\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext24 \sunhideused \styrsid3804850 Normal (Web);}{\s25\ql \li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af37\afs22\alang1025 \ltrch\fcs0 +\f37\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext25 \sqformat \spriority34 \styrsid6173475 List Paragraph;}{\s26\ql \li0\ri0\widctlpar +\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af2\afs20\alang1025 \ltrch\fcs0 +\f2\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext26 \slink27 \ssemihidden \sunhideused \styrsid6573559 HTML Preformatted;}{\*\cs27 \additive \rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20 +\sbasedon10 \slink26 \slocked \ssemihidden \styrsid6573559 HTML Preformatted Char;}{\*\cs28 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf1 \sbasedon10 \sunhideused \styrsid7092439 Hyperlink;}{\*\cs29 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 +\sbasedon10 \spriority0 \styrsid7092439 spelle;}{\*\cs30 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \sbasedon10 \spriority0 \styrsid7092439 grame;}{\s31\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 +\rtlch\fcs1 \af42\afs19\alang1025 \ltrch\fcs0 \b\fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext31 \styrsid7813854 Body 1;}{ +\s32\ql \li0\ri0\sb120\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af42\afs28\alang1025 \ltrch\fcs0 \fs28\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext0 \styrsid7813854 Heading EULA;}{\s33\ql \li0\ri0\sb120\sa120\widctlpar\brdrb\brdrs\brdrw10\brsp20 \wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af42\afs28\alang1025 \ltrch\fcs0 +\fs28\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \styrsid7813854 Heading Software Title;}{\s34\ql \li0\ri0\sb120\sa120\widctlpar\brdrt\brdrs\brdrw10\brsp20 +\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af42\afs19\alang1025 \ltrch\fcs0 \fs19\lang1033\langfe1033\loch\f42\hich\af42\dbch\af11\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext34 \styrsid7813854 +Preamble Border Above;}}{\*\listtable{\list\listtemplateid412752146\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;} +\f3\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 +\fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 +\fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 +\fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid256596791}{\list\listtemplateid-234466468 +\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative +\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0 +\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid268852893}{\list\listtemplateid2071779370\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative +\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers +;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;} +\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid472724034}{\list\listtemplateid837583652\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers +;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;} +\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;} +\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 +\fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 +\fi-360\li6480\lin6480 }{\listname ;}\listid678236712}{\list\listtemplateid468190476\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} +\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;} +\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;} +\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 +\fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 +\fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 +\fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname +;}\listid696808916}{\list\listtemplateid256027766\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;} +\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 +\fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 +\fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 +\fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid833446968}{\list\listtemplateid812297174 +{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 \fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'03(\'03);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;} +\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 +\hres0\chhres0 \fi-360\li2517\lin2517 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 } +{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 }{\listname ;}\listid888110291}{\list\listtemplateid812297174{\listlevel\levelnfc4 +\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 \fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 +\levelindent0{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'03(\'03);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;} +\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 +\hres0\chhres0 \fi-360\li2517\lin2517 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 } +{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 }{\listname ;}\listid1282881056}{\list\listtemplateid827650700\listhybrid{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative +\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid1470391773}{\list\listtemplateid-1331279738\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 +\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;} +\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 +\fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid1543639483}{\list\listtemplateid812297174{\listlevel\levelnfc4\levelnfcn4 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 \fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 +{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'03);}{\levelnumbers +\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 +\hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2517\lin2517 } +{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 }{\listlevel\levelnfc4\levelnfcn4\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 }{\listname ;}\listid1670060985}{\list\listtemplateid-1676387632{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab\ai0\af42\afs20 \ltrch\fcs0 \b\i0\f42\fs20\fbias0\hres0\chhres0 \fi-357\li357\jclisttab\tx360\lin357 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 _;}{\levelnumbers;}\b\i0\f3\fs20\fbias0\hres0\chhres0 \fi-363\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\'02\'02.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab\ai0\af42\afs20 \ltrch\fcs0 \b\i0\f42\fs20\fbias0\hres0\chhres0 \s3\fi-357\li1077\jclisttab\tx1440\lin1077 }{\listlevel\levelnfc3\levelnfcn3\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'03.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af43\afs20 \ltrch\fcs0 \b0\i0\strike0\f43\fs20\ulnone\fbias0\hres0\chhres0 \s4\fi-358\li1435\jclisttab\tx1437\lin1435 }{\listlevel\levelnfc1\levelnfcn1 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'04.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af43\afs20 \ltrch\fcs0 \b0\i0\strike0\f43\fs20\ulnone\fbias0\hres0\chhres0 \s5\fi-357\li1792\jclisttab\tx2155\lin1792 } +{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'05.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af43\afs20 \ltrch\fcs0 \b0\i0\f43\fs20\fbias0\hres0\chhres0 \s6\fi-357\li2149 +\jclisttab\tx2152\lin2149 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af43\afs20 \ltrch\fcs0 \b0\i0\f43\fs20\fbias0\hres0\chhres0 +\s7\fi-357\li2506\jclisttab\tx2509\lin2506 }{\listlevel\levelnfc255\levelnfcn255\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02i.;}{\levelnumbers;}\rtlch\fcs1 \ab0\ai0\af43\afs20 \ltrch\fcs0 +\b0\i0\f43\fs20\fbias0\hres0\chhres0 \s8\fi-357\li2863\jclisttab\tx2866\lin2863 }{\listlevel\levelnfc255\levelnfcn255\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02A.;}{\levelnumbers;}\rtlch\fcs1 \ab0\ai0\af43\afs20 +\ltrch\fcs0 \b0\i0\f43\fs20\fbias0\hres0\chhres0 \s9\fi-358\li3221\jclisttab\tx3223\lin3221 }{\listname ;}\listid1743720866}{\list\listtemplateid-646571904\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0 +\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers +;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;} +\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname ;}\listid2003921709}{\list\listtemplateid1067461628\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers +;}\f2\fbias0\hres0\chhres0 \fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;} +\f10\fbias0\hres0\chhres0 \fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;} +\f3\fbias0\hres0\chhres0 \fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 +\fi-360\li5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 +\fi-360\li6480\lin6480 }{\listname ;}\listid2022782249}{\list\listtemplateid1736062262\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} +\f2\fbias0\hres0\chhres0 \fi-360\li1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;} +\f10\fbias0\hres0\chhres0 \fi-360\li2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;} +\f3\fbias0\hres0\chhres0 \fi-360\li2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 +\fi-360\li3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 +\fi-360\li4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 _;}{\levelnumbers;}\f3\fbias0\hres0\chhres0 +\fi-360\li5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0\hres0\chhres0 \fi-360\li5760\lin5760 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\lvltentative\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 _;}{\levelnumbers;}\f10\fbias0\hres0\chhres0 \fi-360\li6480\lin6480 }{\listname +;}\listid2055036124}{\list\listtemplateid812297174{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \b\hres0\chhres0 +\fi-360\li717\lin717 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1077\lin1077 }{\listlevel +\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'02);}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1437\lin1437 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'03);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li1797\lin1797 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 +\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2157\lin2157 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'03(\'05);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2517\lin2517 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;} +\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li2877\lin2877 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'07.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 +\hres0\chhres0 \fi-360\li3237\lin3237 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \hres0\chhres0 \fi-360\li3597\lin3597 } +{\listname ;}\listid2106000387}}{\*\listoverridetable{\listoverride\listid256596791\listoverridecount0\ls1}{\listoverride\listid1543639483\listoverridecount0\ls2}{\listoverride\listid268852893\listoverridecount0\ls3}{\listoverride\listid678236712 +\listoverridecount0\ls4}{\listoverride\listid2022782249\listoverridecount0\ls5}{\listoverride\listid472724034\listoverridecount0\ls6}{\listoverride\listid1470391773\listoverridecount0\ls7}{\listoverride\listid2003921709\listoverridecount0\ls8} +{\listoverride\listid2055036124\listoverridecount0\ls9}{\listoverride\listid696808916\listoverridecount0\ls10}{\listoverride\listid833446968\listoverridecount0\ls11}{\listoverride\listid1743720866\listoverridecount0\ls12}{\listoverride\listid1670060985 +\listoverridecount0\ls13}{\listoverride\listid1282881056\listoverridecount0\ls14}{\listoverride\listid888110291\listoverridecount0\ls15}{\listoverride\listid2106000387\listoverridecount0\ls16}}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0 +\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp10\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li300\ri300\sb300\sa300}{\pgp\ipgp0\itap0\li0\ri0 +\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}{\*\rsidtbl \rsid93983\rsid217518\rsid1376282\rsid1984289\rsid2438441\rsid3364025\rsid3804850\rsid5786794\rsid5845909\rsid6112664\rsid6173475 +\rsid6573559\rsid6758551\rsid6843334\rsid7092439\rsid7813854\rsid8005660\rsid8394862\rsid10169937\rsid10363382\rsid10624128\rsid10625519\rsid11493340\rsid13960513\rsid14557619\rsid16084641\rsid16459130}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0 +\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author Duane Okamoto (CELA)}{\operator Travis Plunk}{\creatim\yr2016\mo8\dy12\hr14\min30}{\revtim\yr2019\mo1\dy10\hr14\min49}{\version8}{\edmins14}{\nofpages1} +{\nofwords165}{\nofchars947}{\*\company Microsoft IT}{\nofcharsws1110}{\vern2819}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect +\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen +\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1 +\jexpand\viewkind1\viewscale232\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct +\asianbrkrule\rsidroot3804850\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0 +{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang +{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang +{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} +\pard\plain \ltrpar\s24\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid3364025\contextualspace \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \b\f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid2438441 PowerShell 6}{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \b\f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid3804850 + +\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \b\f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid3364025\charrsid93983 +\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 Copyright (c) Microsoft Corporation}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850 +\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid3364025\charrsid93983 +\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 All rights reserved.\~}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850 +\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid3364025\charrsid93983 +\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 MIT License}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850 +\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid3364025\charrsid93983 +\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 Permission is h +ereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:}{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850 + +\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid3364025\charrsid93983 +\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.}{\rtlch\fcs1 +\af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850 +\par }{\rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20\cf19\lang9\langfe1033\langnp9\insrsid3364025\charrsid93983 +\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850\charrsid93983 +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL T +HE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.}{\rtlch\fcs1 +\af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid3804850 +\par }{\rtlch\fcs1 \af2\afs18 \ltrch\fcs0 \f2\fs18\cf19\lang9\langfe1033\langnp9\insrsid6173475 +\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a +9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad +5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 +b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 +0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 +a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f +c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 +0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 +a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 +6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b +4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b +4757e8d3f729e245eb2b260a0238fd010000ffff0300504b03041400060008000000210007b740aaca0600008f1a0000160000007468656d652f7468656d652f +7468656d65312e786d6cec595b8bdb46147e2ff43f08bd3bbe49be2cf1065bb69336bb49889d943cceda636bb2238dd18c776342a0244f7d2914d2d28706fad6 +87521a68a0a12ffd310b1bdaf447f4cc489667ec71f6420aa1640d8b34face996fce39face48ba7aed51449d239c70c2e2965bbe52721d1c8fd898c4d3967b6f +d82f345c870b148f1165316eb90bccdd6bbb9f7e7215ed881047d801fb98efa0961b0a31db2916f9088611bfc26638866b13964448c069322d8e13740c7e235a +ac944ab5628448ec3a318ac0ededc9848cb033942edddda5f31e85d358703930a2c940bac68685c28e0fcb12c1173ca089738468cb8579c6ec78881f09d7a188 +0bb8d0724beacf2dee5e2da29dcc888a2db69a5d5ffd657699c1f8b0a2e64ca607f9a49ee77bb576ee5f01a8d8c4f5eabd5aaf96fb5300341ac14a532eba4fbf +d3ec74fd0cab81d2438bef6ebd5b2d1b78cd7f758373db973f03af40a97f6f03dfef07104503af4029dedfc07b5ebd1278065e81527c6d035f2fb5bb5eddc02b +5048497cb8812ef9b56ab05c6d0e99307ac30a6ffa5ebf5ec99caf50500d7975c929262c16db6a2d420f59d2078004522448ec88c50c4fd008aa3840941c24c4 +d923d3100a6f8662c661b85429f54b55f82f7f9e3a5211413b1869d6921730e11b43928fc34709998996fb39787535c8e9ebd7274f5f9d3cfdfde4d9b393a7bf +66732b5786dd0d144f75bbb73f7df3cf8b2f9dbf7ffbf1edf36fd3a9d7f15cc7bff9e5ab377ffcf92ef7b0e255284ebf7bf9e6d5cbd3efbffeebe7e716efed04 +1de8f0218930776ee163e72e8b608116fef820b998c5304444b768c7538e622467b1f8ef89d040df5a208a2cb80e36e3783f01a9b101afcf1f1a8407613217c4 +e2f1661819c07dc6688725d628dc947369611ecee3a97df264aee3ee2274649b3b40b191e5de7c061a4b6c2e83101b34ef50140b34c531168ebcc60e31b6acee +0121465cf7c928619c4d84f380381d44ac21199203a39a56463748047959d80842be8dd8ecdf773a8cda56ddc5472612ee0d442de487981a61bc8ee602453697 +4314513de07b48843692834532d2713d2e20d3534c99d31b63ce6d36b71358af96f49b2033f6b4efd345642213410e6d3ef710633ab2cb0e831045331b7640e2 +50c77ec60fa144917387091b7c9f9977883c873ca0786bbaef136ca4fb6c35b8070aab535a1588bc324f2cb9bc8e9951bf83059d20aca4061a80a1eb1189cf14 +f93579f7ff3b7907113dfde1856545ef47d2ed8e8d7c5c50ccdb09b1de4d37d6247c1b6e5db803968cc987afdb5d348fef60b855369bd747d9fe28dbeeff5eb6 +b7ddcfef5fac57fa0cd22db7ade9765d6ddea3ad7bf709a174201614ef71b57de7d095c67d189476eab915e7cf72b3100ee59d0c1318b86982948d9330f10511 +e1204433d8e3975de964ca33d753eecc1887adbf1ab6fa96783a8ff6d9387d642d97e5e3692a1e1c89d578c9cfc7e17143a4e85a7df51896bb576ca7ea717949 +40da5e8484369949a26a21515f0eca20a98773089a85845ad97b61d1b4b06848f7cb546db0006a795660dbe4c066abe5fa1e9880113c55218ac7324f69aa97d9 +55c97c9f99de164ca302600fb1ac8055a69b92ebd6e5c9d5a5a5768e4c1b24b4723349a8c8a81ec64334c65975cad1f3d0b868ae9bab941af46428d47c505a2b +1af5c6bb585c36d760b7ae0d34d69582c6ce71cbad557d2899119ab5dc093cfac3613483dae172bb8be814de9f8d4492def097519659c24517f1300db8129d54 +0d222270e25012b55cb9fc3c0d34561aa2b8952b20081f2cb926c8ca87460e926e26194f267824f4b46b2332d2e929287caa15d6abcafcf26069c9e690ee4138 +3e760ee83cb98ba0c4fc7a5906704c38bc012aa7d11c1378a5990bd9aafed61a5326bbfa3b455543e938a2b310651d4517f314aea43ca7a3cef2186867d99a21 +a05a48b2467830950d560faad14df3ae9172d8da75cf369291d34473d5330d55915dd3ae62c60ccb36b016cbcb35798dd532c4a0697a874fa57b5d729b4bad5b +db27e45d02029ec7cfd275cfd110346aabc90c6a92f1a60c4bcdce46cddeb15ce019d4ced32434d5af2dddaec52def11d6e960f0529d1fecd6ab168626cb7da5 +8ab4faf6a17f9e60070f413cbaf022784e0557a9848f0f09820dd140ed4952d9805be491c86e0d3872e60969b98f4b7edb0b2a7e502835fc5ec1ab7aa542c36f +570b6ddfaf967b7eb9d4ed549e4063116154f6d3ef2e7d780d4517d9d71735bef105265abe69bb32625191a92f2c45455c7d812957b67f81710888cee35aa5df +ac363bb542b3daee17bc6ea7516806b54ea15b0beadd7e37f01bcdfe13d7395260af5d0dbc5aaf51a89583a0e0d54a927ea359a87b954adbabb71b3daffd24db +c6c0ca53f9c86201e155bc76ff050000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f7468656d652f5f72 +656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c08 +2e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd0 +8a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa +4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c0200001300000000000000000000000000000000005b436f +6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b00000000000000000000000000300100005f72 +656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000190200007468656d652f746865 +6d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210007b740aaca0600008f1a00001600000000000000000000000000d60200 +007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b01000027000000000000000000000000 +00d40900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000cf0a00000000} +{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d +617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 +6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 +656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} +{\*\latentstyles\lsdstimax375\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdlocked0 heading 1; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 4; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 7; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing; +\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1; +\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading; +\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1; +\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdsemihidden1 \lsdlocked0 Revision;\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph; +\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1; +\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1; +\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2; +\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2; +\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdpriority60 \lsdlocked0 Light Shading Accent 3; +\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3; +\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdpriority70 \lsdlocked0 Dark List Accent 3; +\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdpriority61 \lsdlocked0 Light List Accent 4; +\lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4; +\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdpriority62 \lsdlocked0 Light Grid Accent 5; +\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; +\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; +\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; +\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; +\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; +\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; +\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; +\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; +\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; +\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; +\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; +\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; +\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;}}{\*\datastore }} diff --git a/assets/macDialog.png b/assets/macDialog.png index e2610971a065..432aeca610ef 100644 Binary files a/assets/macDialog.png and b/assets/macDialog.png differ diff --git a/assets/patch-template.wxs b/assets/patch-template.wxs new file mode 100644 index 000000000000..bde47a93f4e3 --- /dev/null +++ b/assets/patch-template.wxs @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/ps_black_32x32.ico b/assets/ps_black_32x32.ico new file mode 100644 index 000000000000..59e83ef8d61d Binary files /dev/null and b/assets/ps_black_32x32.ico differ diff --git a/assets/ps_black_64.svg b/assets/ps_black_64.svg new file mode 100644 index 000000000000..a238b21fee5c --- /dev/null +++ b/assets/ps_black_64.svg @@ -0,0 +1,120 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/assets/pwsh.manifest b/assets/pwsh.manifest new file mode 100644 index 000000000000..428ea9143600 --- /dev/null +++ b/assets/pwsh.manifest @@ -0,0 +1,26 @@ + + + PowerShell 7 + + + + + + + + + + + + + + + + + + + + diff --git a/build.psm1 b/build.psm1 index 0fed7d091dde..ba52d96f764c 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1,8 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + # On Unix paths is separated by colon # On Windows paths is separated by semicolon $script:TestModulePathSeparator = [System.IO.Path]::PathSeparator -$dotnetCLIChannel = "release" +$dotnetCLIChannel = 'preview' # TODO: Change this to 'release' once .Net Core 3.0 goes RTM $dotnetCLIRequiredVersion = $(Get-Content $PSScriptRoot/global.json | ConvertFrom-Json).Sdk.Version # Track if tags have been sync'ed @@ -12,7 +15,7 @@ $tagsUpToDate = $false # When not using a branch in PowerShell/PowerShell, tags will not be fetched automatically # Since code that uses Get-PSCommitID and Get-PSLatestTag assume that tags are fetched, # This function can ensure that tags have been fetched. -# This function is used during the setup phase in tools/appveyor.psm1 and tools/travis.ps1 +# This function is used during the setup phase in tools/ci.psm1 function Sync-PSTags { param( @@ -20,7 +23,7 @@ function Sync-PSTags $AddRemoteIfMissing ) - $PowerShellRemoteUrl = "https://github.com/powershell/powershell.git" + $PowerShellRemoteUrl = "https://github.com/PowerShell/PowerShell.git" $upstreamRemoteDefaultName = 'upstream' $remotes = Start-NativeExecution {git --git-dir="$PSScriptRoot/.git" remote} $upstreamRemote = $null @@ -97,7 +100,7 @@ function Get-PSCommitId function Get-EnvironmentInformation { $environment = @{} - # PowerShell Core will likely not be built on pre-1709 nanoserver + # PowerShell will likely not be built on pre-1709 nanoserver if ($PSVersionTable.ContainsKey("PSEdition") -and "Core" -eq $PSVersionTable.PSEdition) { $environment += @{'IsCoreCLR' = $true} $environment += @{'IsLinux' = $IsLinux} @@ -113,8 +116,7 @@ function Get-EnvironmentInformation if ($Environment.IsWindows) { $environment += @{'IsAdmin' = (New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)} - # Can't use $env:HOME - not available on older systems (e.g. in AppVeyor) - $environment += @{'nugetPackagesRoot' = "${env:HOMEDRIVE}${env:HOMEPATH}\.nuget\packages"} + $environment += @{'nugetPackagesRoot' = "${env:USERPROFILE}\.nuget\packages"} } else { @@ -125,19 +127,22 @@ function Get-EnvironmentInformation $LinuxInfo = Get-Content /etc/os-release -Raw | ConvertFrom-StringData $environment += @{'LinuxInfo' = $LinuxInfo} - $environment += @{'IsDebian' = $LinuxInfo.ID -match 'debian'} - $environment += @{'IsDebian8' = $Environment.IsDebian -and $LinuxInfo.VERSION_ID -match '8'} + $environment += @{'IsDebian' = $LinuxInfo.ID -match 'debian' -or $LinuxInfo.ID -match 'kali'} $environment += @{'IsDebian9' = $Environment.IsDebian -and $LinuxInfo.VERSION_ID -match '9'} $environment += @{'IsUbuntu' = $LinuxInfo.ID -match 'ubuntu'} - $environment += @{'IsUbuntu14' = $Environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '14.04'} $environment += @{'IsUbuntu16' = $Environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '16.04'} - $environment += @{'IsUbuntu17' = $Environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '17.04'} + $environment += @{'IsUbuntu18' = $Environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '18.04'} $environment += @{'IsCentOS' = $LinuxInfo.ID -match 'centos' -and $LinuxInfo.VERSION_ID -match '7'} $environment += @{'IsFedora' = $LinuxInfo.ID -match 'fedora' -and $LinuxInfo.VERSION_ID -ge 24} $environment += @{'IsOpenSUSE' = $LinuxInfo.ID -match 'opensuse'} - $environment += @{'IsOpenSUSE13' = $Environment.IsOpenSUSE -and $LinuxInfo.VERSION_ID -match '13'} + $environment += @{'IsSLES' = $LinuxInfo.ID -match 'sles'} + $environment += @{'IsRedHat' = $LinuxInfo.ID -match 'rhel'} + $environment += @{'IsRedHat7' = $Environment.IsRedHat -and $LinuxInfo.VERSION_ID -match '7' } + $environment += @{'IsOpenSUSE13' = $Environmenst.IsOpenSUSE -and $LinuxInfo.VERSION_ID -match '13'} $environment += @{'IsOpenSUSE42.1' = $Environment.IsOpenSUSE -and $LinuxInfo.VERSION_ID -match '42.1'} - $environment += @{'IsRedHatFamily' = $Environment.IsCentOS -or $Environment.IsFedora -or $Environment.IsOpenSUSE} + $environment += @{'IsRedHatFamily' = $Environment.IsCentOS -or $Environment.IsFedora -or $Environment.IsRedHat} + $environment += @{'IsSUSEFamily' = $Environment.IsSLES -or $Environment.IsOpenSUSE} + $environment += @{'IsAlpine' = $LinuxInfo.ID -match 'alpine'} # Workaround for temporary LD_LIBRARY_PATH hack for Fedora 24 # https://github.com/PowerShell/PowerShell/issues/2511 @@ -145,6 +150,16 @@ function Get-EnvironmentInformation Remove-Item -Force ENV:\LD_LIBRARY_PATH Get-ChildItem ENV: } + + if( -not( + $environment.IsDebian -or + $environment.IsUbuntu -or + $environment.IsRedHatFamily -or + $environment.IsSUSEFamily -or + $environment.IsAlpine) + ) { + throw "The current OS : $($LinuxInfo.ID) is not supported for building PowerShell." + } } return [PSCustomObject] $environment @@ -154,238 +169,46 @@ $Environment = Get-EnvironmentInformation # Autoload (in current session) temporary modules used in our tests $TestModulePath = Join-Path $PSScriptRoot "test/tools/Modules" -if ( $env:PSModulePath -notcontains $TestModulePath ) { +if ( -not $env:PSModulePath.Contains($TestModulePath) ) { $env:PSModulePath = $TestModulePath+$TestModulePathSeparator+$($env:PSModulePath) } -function Test-Win10SDK { - # The Windows 10 SDK is installed to "${env:ProgramFiles(x86)}\Windows Kits\10\bin\x64", - # but the directory may exist even if the SDK has not been installed. - # - # A slightly more robust check is for the mc.exe binary within that directory. - # It is only present if the SDK is installed. - return (Test-Path "${env:ProgramFiles(x86)}\Windows Kits\10\bin\x64\mc.exe") -} - -function Start-BuildNativeWindowsBinaries { +<# + .Synopsis + Tests if a version is preview + .EXAMPLE + Test-IsPreview -version '6.1.0-sometthing' # returns true + Test-IsPreview -version '6.1.0' # returns false +#> +function Test-IsPreview +{ param( - [ValidateSet('Debug', 'Release')] - [string]$Configuration = 'Release', - - # The `x64_arm` syntax is the build environment for VS2017, `x64` means the host is an x64 machine and will use - # the x64 built tool. The `arm` refers to the target architecture when doing cross compilation. - [ValidateSet('x64', 'x86', 'x64_arm64', 'x64_arm')] - [string]$Arch = 'x64', - - [switch]$Clean - ) - - if (-not $Environment.IsWindows) { - Write-Warning -Message "'Start-BuildNativeWindowsBinaries' is only supported on Windows platforms" - return - } - - # cmake is needed to build pwsh.exe - if (-not (precheck 'cmake' $null)) { - throw 'cmake not found. Run "Start-PSBootstrap -BuildWindowsNative". You can also install it from https://chocolatey.org/packages/cmake' - } - - Use-MSBuild - - # mc.exe is Message Compiler for native resources - if (-Not (Test-Win10SDK)) { - throw 'Win 10 SDK not found. Run "Start-PSBootstrap -BuildWindowsNative" or install Microsoft Windows 10 SDK from https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk' - } - - if ($env:VS140COMNTOOLS -ne $null) { - $vcPath = (Get-Item(Join-Path -Path "$env:VS140COMNTOOLS" -ChildPath '../../vc')).FullName - } else { - $vcPath = (Get-ChildItem "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017" -Filter "VC" -Directory -Recurse | Select-Object -First 1).FullName - } - - $atlMfcIncludePath = Join-Path -Path $vcPath -ChildPath 'atlmfc/include' - if (!(Test-Path $atlMfcIncludePath)) { # for VS2017, need to search for it - $atlMfcIncludePath = (Get-ChildItem $vcPath -Filter AtlBase.h -Recurse -File | Select-Object -First 1).DirectoryName - } - - # atlbase.h is included in the pwrshplugin project - if ((Test-Path -Path $atlMfcIncludePath\atlbase.h) -eq $false) { - throw "Could not find Visual Studio include file atlbase.h at $atlMfcIncludePath. Please ensure the optional feature 'Microsoft Foundation Classes for C++' is installed." - } - - # vcvarsall.bat is used to setup environment variables - $vcvarsallbatPath = "$vcPath\vcvarsall.bat" - if (!(Test-Path -Path $vcvarsallbatPath)) { # for VS2017, need to search for it - $vcvarsallbatPath = (Get-ChildItem $vcPath -Filter vcvarsall.bat -Recurse -File | Select-Object -First 1).FullName - } - - if ((Test-Path -Path $vcvarsallbatPath) -eq $false) { - throw "Could not find Visual Studio vcvarsall.bat at $vcvarsallbatPath. Please ensure the optional feature 'Common Tools for Visual C++' is installed." - } - - log "Start building native Windows binaries" - - if ($Clean) { - git clean -fdx - Remove-Item $HOME\source\cmakecache.txt -ErrorAction SilentlyContinue - } - - try { - Push-Location "$PSScriptRoot\src\powershell-native" - - # setup cmakeGenerator - $cmakeGeneratorPlatform = "" - if ($Arch -eq 'x86') { - $cmakeGenerator = 'Visual Studio 15 2017' - $cmakeArch = 'x86' - } elseif ($Arch -eq 'x64_arm') { - $cmakeGenerator = 'Visual Studio 15 2017 ARM' - $cmakeArch = 'arm' - } elseif ($Arch -eq 'x64_arm64') { - $cmakeGenerator = 'Visual Studio 15 2017' - $cmakeArch = 'arm64' - $cmakeGeneratorPlatform = "-A ARM64" - } else { - $cmakeGenerator = 'Visual Studio 15 2017 Win64' - $cmakeArch = 'x64' - } - - # Compile native resources - $currentLocation = Get-Location - @("nativemsh\pwrshplugin") | ForEach-Object { - $nativeResourcesFolder = $_ - Get-ChildItem $nativeResourcesFolder -Filter "*.mc" | ForEach-Object { - $command = @" -cmd.exe /C cd /d "$currentLocation" "&" "$vcvarsallbatPath" "$Arch" "&" mc.exe -o -d -c -U "$($_.FullName)" -h "$currentLocation\$nativeResourcesFolder" -r "$currentLocation\$nativeResourcesFolder" -"@ - log " Executing mc.exe Command: $command" - Start-NativeExecution { Invoke-Expression -Command:$command } - } - } - - # make sure we use version we installed and not from VS - $cmakePath = (Get-Command cmake).Source - # Disabling until I figure out if it is necessary - # $overrideFlags = "-DCMAKE_USER_MAKE_RULES_OVERRIDE=$PSScriptRoot\src\powershell-native\windows-compiler-override.txt" - $overrideFlags = "" - $command = @" -cmd.exe /C cd /d "$currentLocation" "&" "$vcvarsallbatPath" "$Arch" "&" "$cmakePath" "$overrideFlags" -DBUILD_ONECORE=ON -DBUILD_TARGET_ARCH=$cmakeArch -G "$cmakeGenerator" $cmakeGeneratorPlatform "$currentLocation" "&" msbuild ALL_BUILD.vcxproj "/p:Configuration=$Configuration" -"@ - log " Executing Build Command: $command" - Start-NativeExecution { Invoke-Expression -Command:$command } - - # Copy the binaries from the local build directory to the packaging directory - $FilesToCopy = @('pwrshplugin.dll', 'pwrshplugin.pdb') - $dstPath = "$PSScriptRoot\src\powershell-win-core" - $FilesToCopy | ForEach-Object { - $srcPath = [IO.Path]::Combine((Get-Location), "bin", $Configuration, "CoreClr/$_") - - log " Copying $srcPath to $dstPath" - Copy-Item $srcPath $dstPath - } - - # - # Build the ETW manifest resource-only binary - # - $location = "$PSScriptRoot\src\PowerShell.Core.Instrumentation" - Set-Location -Path $location - - Remove-Item $HOME\source\cmakecache.txt -ErrorAction SilentlyContinue - - $command = @" -cmd.exe /C cd /d "$location" "&" "$vcvarsallbatPath" "$Arch" "&" "$cmakePath" "$overrideFlags" -DBUILD_ONECORE=ON -DBUILD_TARGET_ARCH=$cmakeArch -G "$cmakeGenerator" $cmakeGeneratorPlatform "$location" "&" msbuild ALL_BUILD.vcxproj "/p:Configuration=$Configuration" -"@ - log " Executing Build Command for PowerShell.Core.Instrumentation: $command" - Start-NativeExecution { Invoke-Expression -Command:$command } - - # Copy the binary to the packaging directory - # NOTE: No PDB file; it's a resource-only DLL. - # VS2017 puts this in $HOME\source - $srcPath = [IO.Path]::Combine($HOME, "source", $Configuration, 'PowerShell.Core.Instrumentation.dll') - Copy-Item -Path $srcPath -Destination $dstPath - - } finally { - Pop-Location - } -} - -function Start-BuildNativeUnixBinaries { - param ( - [switch] $BuildLinuxArm + [parameter(Mandatory)] + [string] + $Version ) - if (-not $Environment.IsLinux -and -not $Environment.IsMacOS) { - Write-Warning -Message "'Start-BuildNativeUnixBinaries' is only supported on Linux/macOS platforms" - return - } - - if ($BuildLinuxArm -and -not $Environment.IsUbuntu) { - throw "Cross compiling for linux-arm is only supported on Ubuntu environment" - } - - # Verify we have all tools in place to do the build - $precheck = $true - foreach ($Dependency in 'cmake', 'make', 'g++') { - $precheck = $precheck -and (precheck $Dependency "Build dependency '$Dependency' not found. Run 'Start-PSBootstrap'.") - } - - if ($BuildLinuxArm) { - foreach ($Dependency in 'arm-linux-gnueabihf-gcc', 'arm-linux-gnueabihf-g++') { - $precheck = $precheck -and (precheck $Dependency "Build dependency '$Dependency' not found. Run 'Start-PSBootstrap'.") - } - } - - # Abort if any precheck failed - if (-not $precheck) { - return - } - - # Build native components - $Ext = if ($Environment.IsLinux) { - "so" - } elseif ($Environment.IsMacOS) { - "dylib" - } - - $Native = "$PSScriptRoot/src/libpsl-native" - $Lib = "$PSScriptRoot/src/powershell-unix/libpsl-native.$Ext" - log "Start building $Lib" - - git clean -qfdX $Native - - try { - Push-Location $Native - if ($BuildLinuxArm) { - Start-NativeExecution { cmake -DCMAKE_TOOLCHAIN_FILE="./arm.toolchain.cmake" . } - Start-NativeExecution { make -j } - } - else { - Start-NativeExecution { cmake -DCMAKE_BUILD_TYPE=Debug . } - Start-NativeExecution { make -j } - Start-NativeExecution { ctest --verbose } - } - } finally { - Pop-Location - } - - if (-not (Test-Path $Lib)) { - throw "Compilation of $Lib failed" - } + return $Version -like '*-*' } function Start-PSBuild { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName="Default")] param( # When specified this switch will stops running dev powershell # to help avoid compilation error, because file are in use. [switch]$StopDevPowerShell, [switch]$Restore, + # Accept a path to the output directory + # When specified, --output will be passed to dotnet [string]$Output, [switch]$ResGen, [switch]$TypeGen, [switch]$Clean, + [Parameter(ParameterSetName="Legacy")] [switch]$PSModuleRestore, + [Parameter(ParameterSetName="Default")] + [switch]$NoPSModuleRestore, [switch]$CI, # this switch will re-build only System.Management.Automation.dll @@ -395,25 +218,35 @@ function Start-PSBuild { # These runtimes must match those in project.json # We do not use ValidateScript since we want tab completion # If this parameter is not provided it will get determined automatically. - [ValidateSet("win7-x64", - "win7-x86", - "osx.10.12-x64", - "linux-x64", + [ValidateSet("alpine-x64", + "fxdependent", + "fxdependent-win-desktop", "linux-arm", + "linux-arm64", + "linux-x64", + "osx-x64", "win-arm", - "win-arm64")] + "win-arm64", + "win7-x64", + "win7-x86")] [string]$Runtime, - [ValidateSet('Linux', 'Debug', 'Release', 'CodeCoverage', '')] # We might need "Checked" as well + [ValidateSet('Debug', 'Release', 'CodeCoverage', '')] # We might need "Checked" as well [string]$Configuration, [switch]$CrossGen, [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d+)?)?$")] [ValidateNotNullOrEmpty()] - [string]$ReleaseTag + [string]$ReleaseTag, + [switch]$Detailed ) + if ($PsCmdlet.ParameterSetName -eq "Default" -and !$NoPSModuleRestore) + { + $PSModuleRestore = $true + } + if ($Runtime -eq "linux-arm" -and -not $Environment.IsUbuntu) { throw "Cross compiling for linux-arm is only supported on Ubuntu environment" } @@ -421,7 +254,6 @@ function Start-PSBuild { if ("win-arm","win-arm64" -contains $Runtime -and -not $Environment.IsWindows) { throw "Cross compiling for win-arm or win-arm64 is only supported on Windows environment" } - function Stop-DevPowerShell { Get-Process pwsh* | Where-Object { @@ -434,23 +266,17 @@ function Start-PSBuild { } if ($Clean) { - log "Cleaning your working directory. You can also do it with 'git clean -fdX'" + Write-Log "Cleaning your working directory. You can also do it with 'git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3'" Push-Location $PSScriptRoot try { - git clean -fdX - # Extra cleaning is required to delete the CMake temporary files. - # These are not cleaned when using "X" and cause CMake to retain state, leading to - # mis-configured environment issues when switching between x86 and x64 compilation - # environments. - git clean -fdx .\src\powershell-native + # Excluded sqlite3 folder is due to this Roslyn issue: https://github.com/dotnet/roslyn/issues/23060 + # Excluded src/Modules/nuget.config as this is required for release build. + git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3 --exclude src/Modules/nuget.config } finally { Pop-Location } } - # create the telemetry flag file - $null = new-item -force -type file "$psscriptroot/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY" - # Add .NET CLI tools to PATH Find-Dotnet @@ -498,18 +324,27 @@ Fix steps: } # setup arguments - $Arguments = @("publish","/property:GenerateFullPaths=true") - if ($Output) { - $Arguments += "--output", $Output + $Arguments = @("publish","--no-restore","/property:GenerateFullPaths=true") + if ($Output -or $SMAOnly) { + $Arguments += "--output", (Split-Path $Options.Output) + } + + if ($Options.Runtime -like 'win*' -or ($Options.Runtime -like 'fxdependent*' -and $Environment.IsWindows)) { + $Arguments += "/property:IsWindows=true" } - elseif ($SMAOnly) { - $Arguments += "--output", (Split-Path $script:Options.Output) + else { + $Arguments += "/property:IsWindows=false" } $Arguments += "--configuration", $Options.Configuration $Arguments += "--framework", $Options.Framework - if (-not $SMAOnly) { + if ($Detailed.IsPresent) + { + $Arguments += '--verbosity', 'd' + } + + if (-not $SMAOnly -and $Options.Runtime -notlike 'fxdependent*') { # libraries should not have runtime $Arguments += "--runtime", $Options.Runtime } @@ -520,26 +355,12 @@ Fix steps: } # handle Restore - if ($Restore -or -not (Test-Path "$($Options.Top)/obj/project.assets.json")) { - log "Run dotnet restore" - - $srcProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen") - $testProjectDirs = Get-ChildItem "$PSScriptRoot/test/*.csproj" -Recurse | ForEach-Object { [System.IO.Path]::GetDirectoryName($_) } - - $RestoreArguments = @("--verbosity") - if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { - $RestoreArguments += "detailed" - } else { - $RestoreArguments += "quiet" - } - - ($srcProjectDirs + $testProjectDirs) | ForEach-Object { Start-NativeExecution { dotnet restore $_ $RestoreArguments } } - } + Restore-PSPackage -Options $Options -Force:$Restore # handle ResGen # Heuristic to run ResGen on the fresh machine if ($ResGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.ConsoleHost/gen")) { - log "Run ResGen (generating C# bindings for resx files)" + Write-Log "Run ResGen (generating C# bindings for resx files)" Start-ResGen } @@ -547,29 +368,70 @@ Fix steps: # .inc file name must be different for Windows and Linux to allow build on Windows and WSL. $incFileName = "powershell_$($Options.Runtime).inc" if ($TypeGen -or -not (Test-Path "$PSScriptRoot/src/TypeCatalogGen/$incFileName")) { - log "Run TypeGen (generating CorePsTypeCatalog.cs)" + Write-Log "Run TypeGen (generating CorePsTypeCatalog.cs)" Start-TypeGen -IncFileName $incFileName } # Get the folder path where pwsh.exe is located. - $publishPath = Split-Path $Options.Output -Parent + if ((Split-Path $Options.Output -Leaf) -like "pwsh*") { + $publishPath = Split-Path $Options.Output -Parent + } + else { + $publishPath = $Options.Output + } + try { - # Relative paths do not work well if cwd is not changed to project - Push-Location $Options.Top - log "Run dotnet $Arguments from $pwd" - Start-NativeExecution { dotnet $Arguments } - - if ($CrossGen) { - Start-CrossGen -PublishPath $publishPath -Runtime $script:Options.Runtime - log "pwsh.exe with ngen binaries is available at: $($Options.Output)" + + if ($Options.Runtime -notlike 'fxdependent*') { + # Relative paths do not work well if cwd is not changed to project + Push-Location $Options.Top + + if ($Options.Runtime -like 'win-arm*') { + $Arguments += "/property:SDKToUse=Microsoft.NET.Sdk" + } else { + $Arguments += "/property:SDKToUse=Microsoft.NET.Sdk.WindowsDesktop" + } + + Write-Log "Run dotnet $Arguments from $pwd" + Start-NativeExecution { dotnet $Arguments } + Write-Log "PowerShell output: $($Options.Output)" + + if ($CrossGen) { + ## fxdependent package cannot be CrossGen'ed + Start-CrossGen -PublishPath $publishPath -Runtime $script:Options.Runtime + Write-Log "pwsh.exe with ngen binaries is available at: $($Options.Output)" + } + } else { - log "PowerShell output: $($Options.Output)" + $globalToolSrcFolder = Resolve-Path (Join-Path $Options.Top "../Microsoft.PowerShell.GlobalTool.Shim") | Select-Object -ExpandProperty Path + + if ($Options.Runtime -eq 'fxdependent') { + $Arguments += "/property:SDKToUse=Microsoft.NET.Sdk" + } elseif ($Options.Runtime -eq 'fxdependent-win-desktop') { + $Arguments += "/property:SDKToUse=Microsoft.NET.Sdk.WindowsDesktop" + } + + # Relative paths do not work well if cwd is not changed to project + Push-Location $Options.Top + Write-Log "Run dotnet $Arguments from $pwd" + Start-NativeExecution { dotnet $Arguments } + Write-Log "PowerShell output: $($Options.Output)" + + try { + Push-Location $globalToolSrcFolder + $Arguments += "--output", $publishPath + Write-Log "Run dotnet $Arguments from $pwd to build global tool entry point" + Start-NativeExecution { dotnet $Arguments } + } + finally { + Pop-Location + } } } finally { Pop-Location } - # publish netcoreapp2.0 reference assemblies + # publish reference assemblies try { Push-Location "$PSScriptRoot/src/TypeCatalogGen" $refAssemblies = Get-Content -Path $incFileName | Where-Object { $_ -like "*microsoft.netcore.app*" } | ForEach-Object { $_.TrimEnd(';') } @@ -584,55 +446,140 @@ Fix steps: Pop-Location } - if ($Environment.IsRedHatFamily) { + # publish powershell.config.json + $config = @{} + if ($Environment.IsWindows) { + $config = @{ "Microsoft.PowerShell:ExecutionPolicy" = "RemoteSigned" } + } + + if ($ReleaseTag) { + $psVersion = $ReleaseTag + } + else { + $psVersion = git --git-dir="$PSSCriptRoot/.git" describe + } + + # ARM is cross compiled, so we can't run pwsh to enumerate Experimental Features + if ((Test-IsPreview $psVersion) -and -not $Runtime.Contains("arm")) { + $expFeatures = [System.Collections.Generic.List[string]]::new() + & $publishPath\pwsh -noprofile -out XML -command Get-ExperimentalFeature | ForEach-Object { $expFeatures.Add($_.Name) } + $config += @{ ExperimentalFeatures = $expFeatures.ToArray() } + } + + if ($config.Count -gt 0) { + $configPublishPath = Join-Path -Path $publishPath -ChildPath "powershell.config.json" + Set-Content -Path $configPublishPath -Value ($config | ConvertTo-Json) -Force -ErrorAction Stop + } + + if ($Environment.IsRedHatFamily -or $Environment.IsDebian9) { # add two symbolic links to system shared libraries that libmi.so is dependent on to handle # platform specific changes. This is the only set of platforms needed for this currently # as Ubuntu has these specific library files in the platform and macOS builds for itself # against the correct versions. + + if ($Environment.IsDebian9){ + # NOTE: Debian 8 doesn't need these symlinks + $sslTarget = "/usr/lib/x86_64-linux-gnu/libssl.so.1.0.2" + $cryptoTarget = "/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.2" + } + else { #IsRedHatFamily + $sslTarget = "/lib64/libssl.so.10" + $cryptoTarget = "/lib64/libcrypto.so.10" + } + if ( ! (test-path "$publishPath/libssl.so.1.0.0")) { - $null = New-Item -Force -ItemType SymbolicLink -Target "/lib64/libssl.so.10" -Path "$publishPath/libssl.so.1.0.0" -ErrorAction Stop + $null = New-Item -Force -ItemType SymbolicLink -Target $sslTarget -Path "$publishPath/libssl.so.1.0.0" -ErrorAction Stop } if ( ! (test-path "$publishPath/libcrypto.so.1.0.0")) { - $null = New-Item -Force -ItemType SymbolicLink -Target "/lib64/libcrypto.so.10" -Path "$publishPath/libcrypto.so.1.0.0" -ErrorAction Stop + $null = New-Item -Force -ItemType SymbolicLink -Target $cryptoTarget -Path "$publishPath/libcrypto.so.1.0.0" -ErrorAction Stop } } - if ($Environment.IsWindows) { - ## need RCEdit to modify the binaries embedded resources - if (-not (Test-Path "~/.rcedit/rcedit-x64.exe")) { - throw "RCEdit is required to modify pwsh.exe resources, please run 'Start-PSBootStrap' to install" + # download modules from powershell gallery. + # - PowerShellGet, PackageManagement, Microsoft.PowerShell.Archive + if ($PSModuleRestore) { + Restore-PSModuleToBuild -PublishPath $publishPath + } + + # Restore the Pester module + if ($CI) { + Restore-PSPester -Destination (Join-Path $publishPath "Modules") + } +} + +function Restore-PSPackage +{ + param( + [ValidateNotNullOrEmpty()] + [Parameter()] + [string[]] $ProjectDirs, + + [ValidateNotNullOrEmpty()] + [Parameter()] + $Options = (Get-PSOptions -DefaultToNew), + + [switch] $Force + ) + + if (-not $ProjectDirs) + { + $ProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen", "$PSScriptRoot/src/Modules") + + if ($Options.Runtime -like 'fxdependent*') { + $ProjectDirs += "$PSScriptRoot/src/Microsoft.PowerShell.GlobalTool.Shim" } + } + + if ($Force -or (-not (Test-Path "$($Options.Top)/obj/project.assets.json"))) { - $ReleaseVersion = "" - if ($ReleaseTagToUse) { - $ReleaseVersion = $ReleaseTagToUse + $sdkToUse = if (($Options.Runtime -eq 'fxdependent-win-desktop' -or $Options.Runtime -like 'win*')) { # this is fxd or some windows runtime + if ($Options.Runtime -like 'win-arm*') { + 'Microsoft.NET.Sdk' + } else { + 'Microsoft.NET.Sdk.WindowsDesktop' + } } else { - $ReleaseVersion = (Get-PSCommitId -WarningAction SilentlyContinue) -replace '^v' + 'Microsoft.NET.Sdk' } - # in VSCode, depending on where you started it from, the git commit id may be empty so provide a default value - if (!$ReleaseVersion) { - $ReleaseVersion = "6.0.0" - $fileVersion = "6.0.0" + + if ($Options.Runtime -notlike 'fxdependent*') { + $RestoreArguments = @("--runtime", $Options.Runtime, "/property:SDKToUse=$sdkToUse", "--verbosity") } else { - $fileVersion = $ReleaseVersion.Split("-")[0] + $RestoreArguments = @("/property:SDKToUse=$sdkToUse", "--verbosity") } - # in VSCode, the build output folder doesn't include the name of the exe so we have to add it for rcedit - $pwshPath = $Options.Output - if (!$pwshPath.EndsWith("pwsh.exe")) { - $pwshPath = Join-Path $Options.Output "pwsh.exe" + if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { + $RestoreArguments += "detailed" + } else { + $RestoreArguments += "quiet" } - Start-NativeExecution { & "~/.rcedit/rcedit-x64.exe" $pwshPath --set-icon "$PSScriptRoot\assets\Powershell_black.ico" ` - --set-file-version $fileVersion --set-product-version $ReleaseVersion --set-version-string "ProductName" "PowerShell Core 6" ` - --set-requested-execution-level "asInvoker" --set-version-string "LegalCopyright" "(C) Microsoft Corporation. All Rights Reserved." } | Write-Verbose - } + $ProjectDirs | ForEach-Object { + $project = $_ + Write-Log "Run dotnet restore $project $RestoreArguments" + $retryCount = 0 + $maxTries = 5 + while($retryCount -lt $maxTries) + { + try + { + Start-NativeExecution { dotnet restore $project $RestoreArguments } + } + catch + { + Write-Log "Failed to restore $project, retrying..." + $retryCount++ + if($retryCount -ge $maxTries) + { + throw + } + continue + } - # download modules from powershell gallery. - # - PowerShellGet, PackageManagement, Microsoft.PowerShell.Archive - if($PSModuleRestore) - { - Restore-PSModuleToBuild -PublishPath $publishPath -CI:$CI.IsPresent + Write-Log "Done restoring $project" + break + } + } } } @@ -641,40 +588,26 @@ function Restore-PSModuleToBuild param( [Parameter(Mandatory)] [string] - $PublishPath, - [Switch] - $CI + $PublishPath ) - $ProgressPreference = "SilentlyContinue" - log "Restore PowerShell modules to $publishPath" - + Write-Log "Restore PowerShell modules to $publishPath" $modulesDir = Join-Path -Path $publishPath -ChildPath "Modules" + Copy-PSGalleryModules -Destination $modulesDir -CsProjPath "$PSScriptRoot\src\Modules\PSGalleryModules.csproj" - # Restore modules from powershellgallery feed - Restore-PSModule -Destination $modulesDir -Name @( - # PowerShellGet depends on PackageManagement module, so PackageManagement module will be installed with the PowerShellGet module. - 'PowerShellGet' - 'Microsoft.PowerShell.Archive' - ) -SourceLocation "https://www.powershellgallery.com/api/v2/" - - if($CI.IsPresent) - { - Restore-PSPester -Destination $modulesDir - } + # Remove .nupkg.metadata files + Get-ChildItem $PublishPath -Filter '.nupkg.metadata' -Recurse | ForEach-Object { Remove-Item $_.FullName -ErrorAction SilentlyContinue -Force } } function Restore-PSPester { - param - ( + param( [ValidateNotNullOrEmpty()] - [string] - $Destination = ([IO.Path]::Combine((Split-Path (Get-PSOptions -DefaultToNew).Output), "Modules")) + [string] $Destination = ([IO.Path]::Combine((Split-Path (Get-PSOptions -DefaultToNew).Output), "Modules")) ) - - Restore-GitModule -Destination $Destination -Uri 'https://github.com/PowerShell/psl-pester' -Name Pester -CommitSha 'aa243108e7da50a8cf82513b6dd649b653c70b0e' + Save-Module -Name Pester -Path $Destination -Repository PSGallery -RequiredVersion "4.8.0" } + function Compress-TestContent { [CmdletBinding()] param( @@ -692,26 +625,34 @@ function Compress-TestContent { function New-PSOptions { [CmdletBinding()] param( - [ValidateSet("Linux", "Debug", "Release", "CodeCoverage", "")] + [ValidateSet("Debug", "Release", "CodeCoverage", '')] [string]$Configuration, - [ValidateSet("netcoreapp2.0")] - [string]$Framework, + [ValidateSet("netcoreapp3.0")] + [string]$Framework = "netcoreapp3.0", # These are duplicated from Start-PSBuild # We do not use ValidateScript since we want tab completion [ValidateSet("", - "win7-x86", - "win7-x64", - "osx.10.12-x64", - "linux-x64", + "alpine-x64", + "fxdependent", + "fxdependent-win-desktop", "linux-arm", + "linux-arm64", + "linux-x64", + "osx-x64", "win-arm", - "win-arm64")] + "win-arm64", + "win7-x64", + "win7-x86")] [string]$Runtime, [switch]$CrossGen, + # Accept a path to the output directory + # If not null or empty, name of the executable will be appended to + # this path, otherwise, to the default path, and then the full path + # of the output executable will be assigned to the Output property [string]$Output, [switch]$SMAOnly, @@ -722,53 +663,18 @@ function New-PSOptions { # Add .NET CLI tools to PATH Find-Dotnet - $ConfigWarningMsg = "The passed-in Configuration value '{0}' is not supported on '{1}'. Use '{2}' instead." if (-not $Configuration) { - $Configuration = if ($Environment.IsLinux -or $Environment.IsMacOS) { - "Linux" - } elseif ($Environment.IsWindows) { - "Debug" - } - } else { - switch ($Configuration) { - "Linux" { - if ($Environment.IsWindows) { - $Configuration = "Debug" - Write-Warning ($ConfigWarningMsg -f $switch.Current, "Windows", $Configuration) - } - } - "CodeCoverage" { - if(-not $Environment.IsWindows) { - $Configuration = "Linux" - Write-Warning ($ConfigWarningMsg -f $switch.Current, $Environment.LinuxInfo.PRETTY_NAME, $Configuration) - } - } - Default { - if ($Environment.IsLinux -or $Environment.IsMacOS) { - $Configuration = "Linux" - Write-Warning ($ConfigWarningMsg -f $switch.Current, $Environment.LinuxInfo.PRETTY_NAME, $Configuration) - } - } - } + $Configuration = 'Debug' } - Write-Verbose "Using configuration '$Configuration'" - - $PowerShellDir = if ($Configuration -eq 'Linux') { - "powershell-unix" - } else { - "powershell-win-core" - } - $Top = [IO.Path]::Combine($PSScriptRoot, "src", $PowerShellDir) - Write-Verbose "Top project directory is $Top" - if (-not $Framework) { - $Framework = "netcoreapp2.0" - Write-Verbose "Using framework '$Framework'" - } + Write-Verbose "Using configuration '$Configuration'" + Write-Verbose "Using framework '$Framework'" if (-not $Runtime) { if ($Environment.IsLinux) { $Runtime = "linux-x64" + } elseif ($Environment.IsMacOS) { + $Runtime = "osx-x64" } else { $RID = dotnet --info | ForEach-Object { if ($_ -match "RID") { @@ -776,14 +682,10 @@ function New-PSOptions { } } - if ($Environment.IsWindows) { - # We plan to release packages targetting win7-x64 and win7-x86 RIDs, - # which supports all supported windows platforms. - # So we, will change the RID to win7- - $Runtime = $RID -replace "win\d+", "win7" - } else { - $Runtime = $RID - } + # We plan to release packages targetting win7-x64 and win7-x86 RIDs, + # which supports all supported windows platforms. + # So we, will change the RID to win7- + $Runtime = $RID -replace "win\d+", "win7" } if (-not $Runtime) { @@ -793,7 +695,23 @@ function New-PSOptions { } } - $Executable = if ($Environment.IsLinux -or $Environment.IsMacOS) { + $PowerShellDir = if ($Runtime -like 'win*' -or ($Runtime -like 'fxdependent*' -and $Environment.IsWindows)) { + "powershell-win-core" + } else { + "powershell-unix" + } + + $Top = [IO.Path]::Combine($PSScriptRoot, "src", $PowerShellDir) + Write-Verbose "Top project directory is $Top" + + if (-not $Framework) { + $Framework = "netcoreapp2.1" + Write-Verbose "Using framework '$Framework'" + } + + $Executable = if ($Runtime -like 'fxdependent*') { + "pwsh.dll" + } elseif ($Environment.IsLinux -or $Environment.IsMacOS) { "pwsh" } elseif ($Environment.IsWindows) { "pwsh.exe" @@ -801,7 +719,13 @@ function New-PSOptions { # Build the Output path if (!$Output) { - $Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Runtime, "publish", $Executable) + if ($Runtime -like 'fxdependent*') { + $Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, "publish", $Executable) + } else { + $Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Runtime, "publish", $Executable) + } + } else { + $Output = [IO.Path]::Combine($Output, $Executable) } if ($SMAOnly) @@ -824,20 +748,21 @@ function New-PSOptions { $RootInfo['IsValid'] = $true } - return @{ RootInfo = [PSCustomObject]$RootInfo - Top = $Top - Configuration = $Configuration - Framework = $Framework - Runtime = $Runtime - Output = $Output - CrossGen = $CrossGen.IsPresent - PSModuleRestore = $PSModuleRestore.IsPresent } + return New-PSOptionsObject ` + -RootInfo ([PSCustomObject]$RootInfo) ` + -Top $Top ` + -Runtime $Runtime ` + -Crossgen $Crossgen.IsPresent ` + -Configuration $Configuration ` + -PSModuleRestore $PSModuleRestore.IsPresent ` + -Framework $Framework ` + -Output $Output } # Get the Options of the last build function Get-PSOptions { param( - [Parameter(HelpMessage='Defaults to New-PSOption if a build has not ocurred.')] + [Parameter(HelpMessage='Defaults to New-PSOption if a build has not occurred.')] [switch] $DefaultToNew ) @@ -872,7 +797,6 @@ function Get-PSOutput { } } - function Get-PesterTag { param ( [Parameter(Position=0)][string]$testbase = "$PSScriptRoot/test/powershell" ) $alltags = @{} @@ -895,7 +819,7 @@ function Get-PesterTag { } $values = $vAst.FindAll({$args[0] -is "System.Management.Automation.Language.StringConstantExpressionAst"},$true).Value $values | ForEach-Object { - if (@('REQUIREADMINONWINDOWS', 'SLOW') -contains $_) { + if (@('REQUIREADMINONWINDOWS', 'REQUIRESUDOONUNIX', 'SLOW') -contains $_) { # These are valid tags also, but they are not the priority tags } elseif (@('CI', 'FEATURE', 'SCENARIO') -contains $_) { @@ -931,13 +855,17 @@ function Get-PesterTag { function Publish-PSTestTools { [CmdletBinding()] - param() + param( + [string] + $runtime + ) Find-Dotnet $tools = @( @{Path="${PSScriptRoot}/test/tools/TestExe";Output="testexe"} @{Path="${PSScriptRoot}/test/tools/WebListener";Output="WebListener"} + @{Path="${PSScriptRoot}/test/tools/TestService";Output="TestService"} ) $Options = Get-PSOptions -DefaultToNew @@ -947,47 +875,82 @@ function Publish-PSTestTools { { Push-Location $tool.Path try { - dotnet publish --output bin --configuration $Options.Configuration --framework $Options.Framework --runtime $Options.Runtime $toolPath = Join-Path -Path $tool.Path -ChildPath "bin" + $objPath = Join-Path -Path $tool.Path -ChildPath "obj" - if ( $env:PATH -notcontains $toolPath ) { - $env:PATH = $toolPath+$TestModulePathSeparator+$($env:PATH) + if (Test-Path $toolPath) { + Remove-Item -Path $toolPath -Recurse -Force } - } finally { - Pop-Location - } - } + + if (Test-Path $objPath) { + Remove-Item -Path $objPath -Recurse -Force + } + + if (-not $runtime) { + dotnet publish --output bin --configuration $Options.Configuration --framework $Options.Framework --runtime $Options.Runtime + } else { + dotnet publish --output bin --configuration $Options.Configuration --framework $Options.Framework --runtime $runtime + } + + if ( -not $env:PATH.Contains($toolPath) ) { + $env:PATH = $toolPath+$TestModulePathSeparator+$($env:PATH) + } + } finally { + Pop-Location + } + } + + # `dotnet restore` on test project is not called if product projects have been restored unless -Force is specified. + Copy-PSGalleryModules -Destination "${PSScriptRoot}/test/tools/Modules" -CsProjPath "$PSScriptRoot/test/tools/Modules/PSGalleryTestModules.csproj" -Force +} + +function Get-ExperimentalFeatureTests { + $testMetadataFile = Join-Path $PSScriptRoot "test/tools/TestMetadata.json" + $metadata = Get-Content -Path $testMetadataFile -Raw | ConvertFrom-Json | ForEach-Object -MemberName ExperimentalFeatures + $features = $metadata | Get-Member -MemberType NoteProperty | ForEach-Object -MemberName Name + + $featureTests = @{} + foreach ($featureName in $features) { + $featureTests[$featureName] = $metadata.$featureName + } + $featureTests } function Start-PSPester { [CmdletBinding(DefaultParameterSetName='default')] param( + [Parameter(Position=0)] + [string[]]$Path = @("$PSScriptRoot/test/powershell"), [string]$OutputFormat = "NUnitXml", [string]$OutputFile = "pester-tests.xml", [string[]]$ExcludeTag = 'Slow', [string[]]$Tag = @("CI","Feature"), - [string[]]$Path = @("$PSScriptRoot/test/common","$PSScriptRoot/test/powershell"), [switch]$ThrowOnFailure, - [string]$binDir = (Split-Path (Get-PSOptions -DefaultToNew).Output), - [string]$powershell = (Join-Path $binDir 'pwsh'), - [string]$Pester = ([IO.Path]::Combine($binDir, "Modules", "Pester")), + [string]$BinDir = (Split-Path (Get-PSOptions -DefaultToNew).Output), + [string]$powershell = (Join-Path $BinDir 'pwsh'), + [string]$Pester = ([IO.Path]::Combine($BinDir, "Modules", "Pester")), [Parameter(ParameterSetName='Unelevate',Mandatory=$true)] [switch]$Unelevate, [switch]$Quiet, [switch]$Terse, [Parameter(ParameterSetName='PassThru',Mandatory=$true)] [switch]$PassThru, - [switch]$IncludeFailingTest + [Parameter(ParameterSetName='PassThru',HelpMessage='Run commands on Linux with sudo.')] + [switch]$Sudo, + [switch]$IncludeFailingTest, + [switch]$IncludeCommonTests, + [string]$ExperimentalFeatureName, + [Parameter(HelpMessage='Title to publish the results as.')] + [string]$Title = 'PowerShell 7 Tests', + [Parameter(ParameterSetName='Wait', Mandatory=$true, + HelpMessage='Wait for the debugger to attach to PowerShell before Pester starts. Debug builds only!')] + [switch]$Wait, + [switch]$SkipTestToolBuild ) - if (-not (Get-Module -ListAvailable -Name $Pester -ErrorAction SilentlyContinue)) + if (-not (Get-Module -ListAvailable -Name $Pester -ErrorAction SilentlyContinue | Where-Object { $_.Version -ge "4.2" } )) { - Write-Warning @" -Pester module not found. -Restore the module to '$Pester' by running: - Restore-PSPester -"@ - return; + Restore-PSPester } if ($IncludeFailingTest.IsPresent) @@ -995,6 +958,11 @@ Restore the module to '$Pester' by running: $Path += "$PSScriptRoot/tools/failingTests" } + if($IncludeCommonTests.IsPresent) + { + $path = += "$PSScriptRoot/test/common" + } + # we need to do few checks and if user didn't provide $ExcludeTag explicitly, we should alternate the default if ($Unelevate) { @@ -1020,57 +988,83 @@ Restore the module to '$Pester' by running: $ExcludeTag += 'RequireAdminOnWindows' } } + elseif (-not $Environment.IsWindows -and (-not $Sudo.IsPresent)) + { + if (-not $PSBoundParameters.ContainsKey('ExcludeTag')) + { + $ExcludeTag += 'RequireSudoOnUnix' + } + } + elseif (-not $Environment.IsWindows -and $Sudo.IsPresent) + { + if (-not $PSBoundParameters.ContainsKey('Tag')) + { + $Tag = 'RequireSudoOnUnix' + } + } Write-Verbose "Running pester tests at '$path' with tag '$($Tag -join ''', ''')' and ExcludeTag '$($ExcludeTag -join ''', ''')'" -Verbose - Publish-PSTestTools | ForEach-Object {Write-Host $_} + if(!$SkipTestToolBuild.IsPresent) + { + $publishArgs = @{ } + # if we are building for Alpine, we must include the runtime as linux-x64 + # will not build runnable test tools + if ( $Environment.IsAlpine ) { + $publishArgs['runtime'] = 'alpine-x64' + } + Publish-PSTestTools @publishArgs | ForEach-Object {Write-Host $_} + } # All concatenated commands/arguments are suffixed with the delimiter (space) - $Command = "" + + # Disable telemetry for all startups of pwsh in tests + $command = "`$env:POWERSHELL_TELEMETRY_OPTOUT = 'yes';" if ($Terse) { - $Command += "`$ProgressPreference = 'silentlyContinue'; " + $command += "`$ProgressPreference = 'silentlyContinue'; " } # Autoload (in subprocess) temporary modules used in our tests - $Command += '$env:PSModulePath = '+"'$TestModulePath$TestModulePathSeparator'" + '+$($env:PSModulePath);' + $newPathFragment = $TestModulePath + $TestModulePathSeparator + $command += '$env:PSModulePath = '+"'$newPathFragment'" + '+$env:PSModulePath;' # Windows needs the execution policy adjusted if ($Environment.IsWindows) { - $Command += "Set-ExecutionPolicy -Scope Process Unrestricted; " + $command += "Set-ExecutionPolicy -Scope Process Unrestricted; " } - $Command += "Import-Module '$Pester'; " + $command += "Import-Module '$Pester'; " if ($Unelevate) { $outputBufferFilePath = [System.IO.Path]::GetTempFileName() } - $Command += "Invoke-Pester " + $command += "Invoke-Pester " - $Command += "-OutputFormat ${OutputFormat} -OutputFile ${OutputFile} " + $command += "-OutputFormat ${OutputFormat} -OutputFile ${OutputFile} " if ($ExcludeTag -and ($ExcludeTag -ne "")) { - $Command += "-ExcludeTag @('" + (${ExcludeTag} -join "','") + "') " + $command += "-ExcludeTag @('" + (${ExcludeTag} -join "','") + "') " } if ($Tag) { - $Command += "-Tag @('" + (${Tag} -join "','") + "') " + $command += "-Tag @('" + (${Tag} -join "','") + "') " } # sometimes we need to eliminate Pester output, especially when we're # doing a daily build as the log file is too large if ( $Quiet ) { - $Command += "-Quiet " + $command += "-Quiet " } if ( $PassThru ) { - $Command += "-PassThru " + $command += "-PassThru " } - $Command += "'" + ($Path -join "','") + "'" + $command += "'" + ($Path -join "','") + "'" if ($Unelevate) { - $Command += " *> $outputBufferFilePath; '__UNELEVATED_TESTS_THE_END__' >> $outputBufferFilePath" + $command += " *> $outputBufferFilePath; '__UNELEVATED_TESTS_THE_END__' >> $outputBufferFilePath" } - Write-Verbose $Command + Write-Verbose $command $script:nonewline = $true $script:inerror = $false @@ -1092,6 +1086,14 @@ Restore the module to '$Pester' by running: $script:nonewline = $true $script:inerror = $false } + elseif ($trimmedline.StartsWith("Executing script ")) { + # Skip lines where Pester reports that is executing a test script + return + } + elseif ($trimmedline -match "^\d+(\.\d+)?m?s$") { + # Skip the time elapse like '12ms', '1ms', '1.2s' and '12.53s' + return + } else { if ($script:nonewline) { Write-Host "`n" -NoNewline @@ -1115,12 +1117,52 @@ Restore the module to '$Pester' by running: } } + $PSFlags = @("-noprofile") + if (-not [string]::IsNullOrEmpty($ExperimentalFeatureName)) { + $configFile = [System.IO.Path]::GetTempFileName() + $configFile = [System.IO.Path]::ChangeExtension($configFile, ".json") + + ## Create the config.json file to enable the given experimental feature. + ## On Windows, we need to have 'RemoteSigned' declared for ExecutionPolicy because the ExecutionPolicy is 'Restricted' by default. + ## On Unix, ExecutionPolicy is not supported, so we don't need to declare it. + if ($Environment.IsWindows) { + $content = @" +{ + "Microsoft.PowerShell:ExecutionPolicy":"RemoteSigned", + "ExperimentalFeatures": [ + "$ExperimentalFeatureName" + ] +} +"@ + } else { + $content = @" +{ + "ExperimentalFeatures": [ + "$ExperimentalFeatureName" + ] +} +"@ + } + + Set-Content -Path $configFile -Value $content -Encoding Ascii -Force + $PSFlags = @("-settings", $configFile, "-noprofile") + } + + # -Wait is only available on Debug builds + # It is used to allow the debugger to attach before PowerShell + # runs pester in this case + if($Wait.IsPresent){ + $PSFlags += '-wait' + } + # To ensure proper testing, the module path must not be inherited by the spawned process try { $originalModulePath = $env:PSModulePath + $originalTelemetry = $env:POWERSHELL_TELEMETRY_OPTOUT + $env:POWERSHELL_TELEMETRY_OPTOUT = 'yes' if ($Unelevate) { - Start-UnelevatedProcess -process $powershell -arguments @('-noprofile', '-c', $Command) + Start-UnelevatedProcess -process $powershell -arguments ($PSFlags + "-c $Command") $currentLines = 0 while ($true) { @@ -1159,48 +1201,102 @@ Restore the module to '$Pester' by running: $passThruFile = [System.IO.Path]::GetTempFileName() try { - $Command += "|Export-Clixml -Path '$passThruFile' -Force" - if ($Terse) - { - Start-NativeExecution -sb {& $powershell -noprofile -c $Command} | ForEach-Object { Write-Terse $_} + $command += "| Export-Clixml -Path '$passThruFile' -Force" + + $passThruCommand = { & $powershell $PSFlags -c $command } + if ($Sudo.IsPresent) { + # -E says to preserve the environment + $passThruCommand = { & sudo -E $powershell $PSFlags -c $command } } - else + + $writeCommand = { Write-Host $_ } + if ($Terse) { - Start-NativeExecution -sb {& $powershell -noprofile -c $Command} | ForEach-Object { Write-Host $_} + $writeCommand = { Write-Terse $_ } } + + Start-NativeExecution -sb $passThruCommand | ForEach-Object $writeCommand Import-Clixml -Path $passThruFile | Where-Object {$_.TotalCount -is [Int32]} } finally { - Remove-Item $passThruFile -ErrorAction SilentlyContinue + Remove-Item $passThruFile -ErrorAction SilentlyContinue -Force } } else { if ($Terse) { - Start-NativeExecution -sb {& $powershell -noprofile -c $Command} | ForEach-Object { Write-Terse -line $_ } + Start-NativeExecution -sb {& $powershell $PSFlags -c $command} | ForEach-Object { Write-Terse -line $_ } } else { - Start-NativeExecution -sb {& $powershell -noprofile -c $Command} + Start-NativeExecution -sb {& $powershell $PSFlags -c $command} } } } } finally { $env:PSModulePath = $originalModulePath + $env:POWERSHELL_TELEMETRY_OPTOUT = $originalTelemetry if ($Unelevate) { Remove-Item $outputBufferFilePath } } + Publish-TestResults -Path $OutputFile -Title $Title + if($ThrowOnFailure) { Test-PSPesterResults -TestResultsFile $OutputFile } } +function Publish-TestResults +{ + param( + [Parameter(Mandatory)] + [string] + $Title, + + [Parameter(Mandatory)] + [ValidateScript({Test-Path -Path $_})] + [string] + $Path, + + [ValidateSet('NUnit','XUnit')] + [string] + $Type='NUnit' + ) + + # In VSTS publish Test Results + if($env:TF_BUILD) + { + $fileName = Split-Path -Leaf -Path $Path + $tempFilePath = Join-Path ([system.io.path]::GetTempPath()) -ChildPath $fileName + + # NUnit allowed values are: Passed, Failed, Inconclusive or Ignored (the spec says Skipped but it doesn' work with Azure DevOps) + # https://github.com/nunit/docs/wiki/Test-Result-XML-Format + # Azure DevOps Reporting is so messed up for NUnit V2 and doesn't follow their own spec + # https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&tabs=yaml + # So, we will map skipped to the actual value in the NUnit spec and they will ignore all results for tests which were not executed + Get-Content $Path | ForEach-Object { + $_ -replace 'result="Ignored"', 'result="Skipped"' + } | Out-File -FilePath $tempFilePath -Encoding ascii -Force + + # If we attempt to upload a result file which has no test cases in it, then vsts will produce a warning + # so check to be sure we actually have a result file that contains test cases to upload. + # If the the "test-case" count is greater than 0, then we have results. + # Regardless, we want to upload this as an artifact, so this logic doesn't pertain to that. + if ( @(([xml](Get-Content $Path)).SelectNodes(".//test-case")).Count -gt 0 -or $Type -eq 'XUnit' ) { + Write-Host "##vso[results.publish type=$Type;mergeResults=true;runTitle=$Title;publishRunAttachments=true;resultFiles=$tempFilePath;failTaskOnFailedTests=true]" + } + + $resolvedPath = (Resolve-Path -Path $Path).ProviderPath + Write-Host "##vso[artifact.upload containerfolder=testResults;artifactname=testResults]$resolvedPath" + } +} + function script:Start-UnelevatedProcess { param( @@ -1244,12 +1340,12 @@ function Show-PSPesterError throw 'Unknown Show-PSPester parameter set' } - logerror ("Description: " + $description) - logerror ("Name: " + $name) - logerror "message:" - logerror $message - logerror "stack-trace:" - logerror $stackTrace + Write-Log -Error ("Description: " + $description) + Write-Log -Error ("Name: " + $name) + Write-Log -Error "message:" + Write-Log -Error $message + Write-Log -Error "stack-trace:" + Write-Log -Error $stackTrace } @@ -1289,12 +1385,12 @@ function Test-XUnitTestResults $message = $failure.test.failure.message.'#cdata-section' $stackTrace = $failure.test.failure.'stack-trace'.'#cdata-section' - logerror ("Description: " + $description) - logerror ("Name: " + $name) - logerror "message:" - logerror $message - logerror "stack-trace:" - logerror $stackTrace + Write-Log -Error ("Description: " + $description) + Write-Log -Error ("Name: " + $name) + Write-Log -Error "message:" + Write-Log -Error $message + Write-Log -Error "stack-trace:" + Write-Log -Error $stackTrace } throw "$($failedTests.failed) tests failed" @@ -1308,12 +1404,17 @@ function Test-PSPesterResults [CmdletBinding(DefaultParameterSetName='file')] param( [Parameter(ParameterSetName='file')] - [string]$TestResultsFile = "pester-tests.xml", + [string] $TestResultsFile = "pester-tests.xml", + [Parameter(ParameterSetName='file')] - [string]$TestArea = 'test/powershell', - [Parameter(ParameterSetName='PesterPassThruObject',Mandatory)] - [pscustomobject] $ResultObject - ) + [string] $TestArea = 'test/powershell', + + [Parameter(ParameterSetName='PesterPassThruObject', Mandatory)] + [pscustomobject] $ResultObject, + + [Parameter(ParameterSetName='PesterPassThruObject')] + [switch] $CanHaveNoResult + ) if($PSCmdLet.ParameterSetName -eq 'file') { @@ -1325,7 +1426,7 @@ function Test-PSPesterResults $x = [xml](Get-Content -raw $testResultsFile) if ([int]$x.'test-results'.failures -gt 0) { - logerror "TEST FAILURES" + Write-Log -Error "TEST FAILURES" # switch between methods, SelectNode is not available on dotnet core if ( "System.Xml.XmlDocumentXPathExtensions" -as [Type] ) { @@ -1344,13 +1445,13 @@ function Test-PSPesterResults } elseif ($PSCmdLet.ParameterSetName -eq 'PesterPassThruObject') { - if ($ResultObject.TotalCount -le 0) + if ($ResultObject.TotalCount -le 0 -and -not $CanHaveNoResult) { throw 'NO TESTS RUN' } elseif ($ResultObject.FailedCount -gt 0) { - logerror 'TEST FAILURES' + Write-Log -Error 'TEST FAILURES' $ResultObject.TestResult | Where-Object {$_.Passed -eq $false} | ForEach-Object { Show-PSPesterError -testFailureObject $_ @@ -1361,10 +1462,9 @@ function Test-PSPesterResults } } - function Start-PSxUnit { [CmdletBinding()]param( - [string] $TestResultsFile = "XUnitResults.xml" + [string] $xUnitTestResultsFile = "xUnitResults.xml" ) # Add .NET CLI tools to PATH @@ -1375,23 +1475,12 @@ function Start-PSxUnit { throw "PowerShell must be built before running tests!" } - if(Test-Path $TestResultsFile) - { - Remove-Item $TestResultsFile -Force -ErrorAction SilentlyContinue - } - try { - Push-Location $PSScriptRoot/test/csharp + Push-Location $PSScriptRoot/test/xUnit # Path manipulation to obtain test project output directory - dotnet restore - # --fx-version workaround required due to https://github.com/dotnet/cli/issues/7901#issuecomment-343323674 - if($Environment.IsWindows) - { - dotnet xunit --fx-version 2.0.0 -xml $TestResultsFile - } - else + if(-not $Environment.IsWindows) { if($Environment.IsMacOS) { @@ -1410,7 +1499,7 @@ function Start-PSxUnit { if((Test-Path $requiredDependencies) -notcontains $false) { - $options = New-PSOptions + $options = Get-PSOptions -DefaultToNew $Destination = "bin/$($options.configuration)/$($options.framework)" New-Item $Destination -ItemType Directory -Force > $null Copy-Item -Path $requiredDependencies -Destination $Destination -Force @@ -1419,16 +1508,23 @@ function Start-PSxUnit { { throw "Dependencies $requiredDependencies not met." } + } - dotnet xunit --fx-version 2.0.0 -configuration $Options.configuration -xml $TestResultsFile + if (Test-Path $xUnitTestResultsFile) { + Remove-Item $xUnitTestResultsFile -Force -ErrorAction SilentlyContinue } + + # We run the xUnit tests sequentially to avoid race conditions caused by manipulating the config.json file. + # xUnit tests run in parallel by default. To make them run sequentially, we need to define the 'xunit.runner.json' file. + dotnet test --configuration $Options.configuration --test-adapter-path:. "--logger:xunit;LogFilePath=$xUnitTestResultsFile" + + Publish-TestResults -Path $xUnitTestResultsFile -Type 'XUnit' -Title 'Xunit Sequential' } finally { Pop-Location } } - function Install-Dotnet { [CmdletBinding()] param( @@ -1441,7 +1537,8 @@ function Install-Dotnet { # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } - $obtainUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain" + $installObtainUrl = "https://dot.net/v1" + $uninstallObtainUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain" # Install for Linux and OS X if ($Environment.IsLinux -or $Environment.IsMacOS) { @@ -1454,23 +1551,23 @@ function Install-Dotnet { if ($uninstallScript) { Start-NativeExecution { - curl -sO $obtainUrl/uninstall/$uninstallScript + curl -sO $uninstallObtainUrl/uninstall/$uninstallScript Invoke-Expression "$sudo bash ./$uninstallScript" } } else { - Write-Warning "This script only removes prior versions of dotnet for Ubuntu 14.04 and OS X" + Write-Warning "This script only removes prior versions of dotnet for Ubuntu and OS X" } # Install new dotnet 1.1.0 preview packages $installScript = "dotnet-install.sh" Start-NativeExecution { - curl -sO $obtainUrl/$installScript + curl -sO $installObtainUrl/$installScript bash ./$installScript -c $Channel -v $Version } } elseif ($Environment.IsWindows) { Remove-Item -ErrorAction SilentlyContinue -Recurse -Force ~\AppData\Local\Microsoft\dotnet $installScript = "dotnet-install.ps1" - Invoke-WebRequest -Uri $obtainUrl/$installScript -OutFile $installScript + Invoke-WebRequest -Uri $installObtainUrl/$installScript -OutFile $installScript if (-not $Environment.IsCoreCLR) { & ./$installScript -Channel $Channel -Version $Version @@ -1488,8 +1585,6 @@ function Get-RedHatPackageManager { "yum install -y -q" } elseif ($Environment.IsFedora) { "dnf install -y -q" - } elseif ($Environment.IsOpenSUSE) { - "zypper --non-interactive install" } else { throw "Error determining package manager for this distribution." } @@ -1506,12 +1601,11 @@ function Start-PSBootstrap { [string]$Version = $dotnetCLIRequiredVersion, [switch]$Package, [switch]$NoSudo, - [switch]$BuildWindowsNative, [switch]$BuildLinuxArm, [switch]$Force ) - log "Installing PowerShell build dependencies" + Write-Log "Installing PowerShell build dependencies" Push-Location $PSScriptRoot/tools @@ -1521,16 +1615,6 @@ function Start-PSBootstrap { # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } - try { - # Update googletest submodule for linux native cmake - Push-Location $PSScriptRoot - $Submodule = "$PSScriptRoot/src/libpsl-native/test/googletest" - Remove-Item -Path $Submodule -Recurse -Force -ErrorAction SilentlyContinue - git submodule --quiet update --init -- $submodule - } finally { - Pop-Location - } - if ($BuildLinuxArm -and -not $Environment.IsUbuntu) { Write-Error "Cross compiling for linux-arm is only supported on Ubuntu environment" return @@ -1548,16 +1632,25 @@ function Start-PSBootstrap { # .NET Core required runtime libraries $Deps += "libunwind8" - if ($Environment.IsUbuntu14) { $Deps += "libicu52" } - elseif ($Environment.IsUbuntu16) { $Deps += "libicu55" } + if ($Environment.IsUbuntu16) { $Deps += "libicu55" } + elseif ($Environment.IsUbuntu18) { $Deps += "libicu60"} # Packaging tools - if ($Package) { $Deps += "ruby-dev", "groff" } + if ($Package) { $Deps += "ruby-dev", "groff", "libffi-dev" } # Install dependencies - Start-NativeExecution { - Invoke-Expression "$sudo apt-get update -qq" - Invoke-Expression "$sudo apt-get install -y -qq $Deps" + # change the fontend from apt-get to noninteractive + $originalDebianFrontEnd=$env:DEBIAN_FRONTEND + $env:DEBIAN_FRONTEND='noninteractive' + try { + Start-NativeExecution { + Invoke-Expression "$sudo apt-get update -qq" + Invoke-Expression "$sudo apt-get install -y -qq $Deps" + } + } + finally { + # change the apt frontend back to the original + $env:DEBIAN_FRONTEND=$originalDebianFrontEnd } } elseif ($Environment.IsRedHatFamily) { # Build tools @@ -1567,7 +1660,7 @@ function Start-PSBootstrap { $Deps += "libicu", "libunwind" # Packaging tools - if ($Package) { $Deps += "ruby-devel", "rpm-build", "groff" } + if ($Package) { $Deps += "ruby-devel", "rpm-build", "groff", 'libffi-devel' } $PackageManager = Get-RedHatPackageManager @@ -1579,12 +1672,32 @@ function Start-PSBootstrap { $baseCommand = $PackageManager } + # Install dependencies + Start-NativeExecution { + Invoke-Expression "$baseCommand $Deps" + } + } elseif ($Environment.IsSUSEFamily) { + # Build tools + $Deps += "gcc", "cmake", "make" + + # Packaging tools + if ($Package) { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel' } + + $PackageManager = "zypper --non-interactive install" + $baseCommand = "$sudo $PackageManager" + + # On OpenSUSE 13.2 container, sudo does not exist, so don't use it if not needed + if($NoSudo) + { + $baseCommand = $PackageManager + } + # Install dependencies Start-NativeExecution { Invoke-Expression "$baseCommand $Deps" } } elseif ($Environment.IsMacOS) { - precheck 'brew' "Bootstrap dependency 'brew' not found, must install Homebrew! See http://brew.sh/" + precheck 'brew' "Bootstrap dependency 'brew' not found, must install Homebrew! See https://brew.sh/" # Build tools $Deps += "cmake" @@ -1595,17 +1708,25 @@ function Start-PSBootstrap { # Install dependencies # ignore exitcode, because they may be already installed Start-NativeExecution { brew install $Deps } -IgnoreExitcode + } elseif ($Environment.IsAlpine) { + $Deps += 'libunwind', 'libcurl', 'bash', 'cmake', 'clang', 'build-base', 'git', 'curl' - # Install patched version of curl - Start-NativeExecution { brew install curl --with-openssl --with-gssapi } -IgnoreExitcode + Start-NativeExecution { + Invoke-Expression "apk add $Deps" + } } # Install [fpm](https://github.com/jordansissel/fpm) and [ronn](https://github.com/rtomayko/ronn) if ($Package) { try { - # We cannot guess if the user wants to run gem install as root - Start-NativeExecution { gem install fpm -v 1.8.1 } - Start-NativeExecution { gem install ronn } + # We cannot guess if the user wants to run gem install as root on linux and windows, + # but macOs usually requires sudo + $gemsudo = '' + if($Environment.IsMacOS -or $env:TF_BUILD) { + $gemsudo = $sudo + } + Start-NativeExecution ([ScriptBlock]::Create("$gemsudo gem install fpm -v 1.11.0 --no-document")) + Start-NativeExecution ([ScriptBlock]::Create("$gemsudo gem install ronn -v 0.7.3 --no-document")) } catch { Write-Warning "Installation of fpm and ronn gems failed! Must resolve manually." } @@ -1624,155 +1745,31 @@ function Start-PSBootstrap { if(!$dotNetExists -or $dotNetVersion -ne $dotnetCLIRequiredVersion -or $Force.IsPresent) { if($Force.IsPresent) { - log "Installing dotnet due to -Force." + Write-Log "Installing dotnet due to -Force." } elseif(!$dotNetExistis) { - log "dotnet not present. Installing dotnet." + Write-Log "dotnet not present. Installing dotnet." } else { - log "dotnet out of date ($dotNetVersion). Updating dotnet." + Write-Log "dotnet out of date ($dotNetVersion). Updating dotnet." } $DotnetArguments = @{ Channel=$Channel; Version=$Version; NoSudo=$NoSudo } Install-Dotnet @DotnetArguments } else { - log "dotnet is already installed. Skipping installation." + Write-Log "dotnet is already installed. Skipping installation." } # Install Windows dependencies if `-Package` or `-BuildWindowsNative` is specified if ($Environment.IsWindows) { ## The VSCode build task requires 'pwsh.exe' to be found in Path - if (-not (Get-Command -Name pwsh.exe -CommandType Application -ErrorAction SilentlyContinue)) + if (-not (Get-Command -Name pwsh.exe -CommandType Application -ErrorAction Ignore)) { - log "pwsh.exe not found. Install latest PowerShell Core release and add it to Path" + Write-Log "pwsh.exe not found. Install latest PowerShell release and add it to Path" $psInstallFile = [System.IO.Path]::Combine($PSScriptRoot, "tools", "install-powershell.ps1") & $psInstallFile -AddToPath } - - ## need RCEdit to modify the binaries embedded resources - if (-not (Test-Path "~/.rcedit/rcedit-x64.exe")) - { - log "Install RCEdit for modifying exe resources" - $rceditUrl = "https://github.com/electron/rcedit/releases/download/v1.0.0/rcedit-x64.exe" - New-Item -Path "~/.rcedit" -Type Directory -Force > $null - Invoke-WebRequest -OutFile "~/.rcedit/rcedit-x64.exe" -Uri $rceditUrl - } - - if ($BuildWindowsNative) { - log "Install Windows dependencies for building PSRP plugin" - - $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') - $newMachineEnvironmentPath = $machinePath - - $cmakePresent = precheck 'cmake' $null - $sdkPresent = Test-Win10SDK - - # Install chocolatey - $chocolateyPath = "$env:AllUsersProfile\chocolatey\bin" - - if(precheck 'choco' $null) { - log "Chocolatey is already installed. Skipping installation." - } - elseif(($cmakePresent -eq $false) -or ($sdkPresent -eq $false)) { - log "Chocolatey not present. Installing chocolatey." - if ($Force -or $PSCmdlet.ShouldProcess("Install chocolatey via https://chocolatey.org/install.ps1")) { - Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) - if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower()))) { - log "Adding $chocolateyPath to Path environment variable" - $env:Path += ";$chocolateyPath" - $newMachineEnvironmentPath += ";$chocolateyPath" - } else { - log "$chocolateyPath already present in Path environment variable" - } - } else { - Write-Error "Chocolatey is required to install missing dependencies. Please install it from https://chocolatey.org/ manually. Alternatively, install cmake and Windows 10 SDK." - return - } - } else { - log "Skipping installation of chocolatey, cause both cmake and Win 10 SDK are present." - } - - # Install cmake - $cmakePath = "${env:ProgramFiles}\CMake\bin" - if($cmakePresent -and !($force.IsPresent)) { - log "Cmake is already installed. Skipping installation." - } else { - log "Cmake not present or -Force used. Installing cmake." - Start-NativeExecution { choco install cmake -y --version 3.10.0 } - if (-not ($machinePath.ToLower().Contains($cmakePath.ToLower()))) { - log "Adding $cmakePath to Path environment variable" - $env:Path += ";$cmakePath" - $newMachineEnvironmentPath = "$cmakePath;$newMachineEnvironmentPath" - } else { - log "$cmakePath already present in Path environment variable" - } - } - - # Install Windows 10 SDK - $packageName = "windows-sdk-10.0" - - if (-not $sdkPresent) { - log "Windows 10 SDK not present. Installing $packageName." - Start-NativeExecution { choco install windows-sdk-10.0 -y } - } else { - log "Windows 10 SDK present. Skipping installation." - } - - # Update path machine environment variable - if ($newMachineEnvironmentPath -ne $machinePath) { - log "Updating Path machine environment variable" - if ($Force -or $PSCmdlet.ShouldProcess("Update Path machine environment variable to $newMachineEnvironmentPath")) { - [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') - } - } - } - } - } finally { - Pop-Location - } -} - -function Publish-NuGetFeed -{ - param( - [string]$OutputPath = "$PSScriptRoot/nuget-artifacts", - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d+)?)?$")] - [ValidateNotNullOrEmpty()] - [string]$ReleaseTag - ) - - # Add .NET CLI tools to PATH - Find-Dotnet - - ## We update 'project.assets.json' files with new version tag value by 'GetPSCoreVersionFromGit' target. - $TopProject = (New-PSOptions).Top - if ($ReleaseTag) { - $ReleaseTagToUse = $ReleaseTag -Replace '^v' - dotnet restore $TopProject "/property:ReleaseTag=$ReleaseTagToUse" - } else { - dotnet restore $TopProject - } - - try { - Push-Location $PSScriptRoot - @( -'Microsoft.PowerShell.Commands.Management', -'Microsoft.PowerShell.Commands.Utility', -'Microsoft.PowerShell.Commands.Diagnostics', -'Microsoft.PowerShell.ConsoleHost', -'Microsoft.PowerShell.Security', -'System.Management.Automation', -'Microsoft.PowerShell.CoreCLR.Eventing', -'Microsoft.WSMan.Management', -'Microsoft.WSMan.Runtime', -'Microsoft.PowerShell.SDK' - ) | ForEach-Object { - if ($ReleaseTag) { - dotnet pack "src/$_" --output $OutputPath "/property:IncludeSymbols=true;ReleaseTag=$ReleaseTagToUse" - } else { - dotnet pack "src/$_" --output $OutputPath - } } } finally { Pop-Location @@ -1780,16 +1777,25 @@ function Publish-NuGetFeed } function Start-DevPowerShell { + [CmdletBinding(DefaultParameterSetName='ConfigurationParamSet')] param( - [string[]]$ArgumentList = '', + [string[]]$ArgumentList = @(), [switch]$LoadProfile, - [string]$binDir = (Split-Path (New-PSOptions).Output), + [Parameter(ParameterSetName='ConfigurationParamSet')] + [ValidateSet("Debug", "Release", "CodeCoverage", '')] # should match New-PSOptions -Configuration values + [string]$Configuration, + [Parameter(ParameterSetName='BinDirParamSet')] + [string]$BinDir, [switch]$NoNewWindow, [string]$Command, [switch]$KeepPSModulePath ) try { + if (-not $BinDir) { + $BinDir = Split-Path (New-PSOptions -Configuration $Configuration).Output + } + if ((-not $NoNewWindow) -and ($Environment.IsCoreCLR)) { Write-Warning "Start-DevPowerShell -NoNewWindow is currently implied in PowerShellCore edition https://github.com/PowerShell/PowerShell/issues/1543" $NoNewWindow = $true @@ -1810,12 +1816,16 @@ function Start-DevPowerShell { $ArgumentList = $ArgumentList + @("-command $Command") } - $env:DEVPATH = $binDir + $env:DEVPATH = $BinDir + # splatting for the win $startProcessArgs = @{ - FilePath = "$binDir\pwsh" - ArgumentList = "$ArgumentList" + FilePath = "$BinDir\pwsh" + } + + if ($ArgumentList) { + $startProcessArgs.ArgumentList = $ArgumentList } if ($NoNewWindow) { @@ -1848,18 +1858,25 @@ function Start-TypeGen # Add .NET CLI tools to PATH Find-Dotnet + # This custom target depends on 'ResolveAssemblyReferencesDesignTime', whose definition can be found in the sdk folder. + # To find the available properties of '_ReferencesFromRAR' when switching to a new dotnet sdk, follow the steps below: + # 1. create a dummy project using the new dotnet sdk. + # 2. build the dummy project with this command: + # dotnet msbuild .\dummy.csproj /t:ResolveAssemblyReferencesDesignTime /fileLogger /noconsolelogger /v:diag + # 3. search '_ReferencesFromRAR' in the produced 'msbuild.log' file. You will find the properties there. $GetDependenciesTargetPath = "$PSScriptRoot/src/Microsoft.PowerShell.SDK/obj/Microsoft.PowerShell.SDK.csproj.TypeCatalog.targets" $GetDependenciesTargetValue = @' - <_RefAssemblyPath Include="%(_ReferencesFromRAR.ResolvedPath)%3B" Condition=" '%(_ReferencesFromRAR.Type)' == 'assembly' And '%(_ReferencesFromRAR.PackageName)' != 'Microsoft.Management.Infrastructure' " /> + <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> '@ + New-Item -ItemType Directory -Path (Split-Path -Path $GetDependenciesTargetPath -Parent) -Force > $null Set-Content -Path $GetDependenciesTargetPath -Value $GetDependenciesTargetValue -Force -Encoding Ascii Push-Location "$PSScriptRoot/src/Microsoft.PowerShell.SDK" @@ -1894,7 +1911,6 @@ function Start-ResGen } } - function Find-Dotnet() { $originalPath = $env:PATH $dotnetPath = if ($Environment.IsWindows) { "$env:LocalAppData\Microsoft\dotnet" } else { "$env:HOME/.dotnet" } @@ -1952,13 +1968,12 @@ function Convert-TxtResourceToXml } } - function script:Use-MSBuild { # TODO: we probably should require a particular version of msbuild, if we are taking this dependency # msbuild v14 and msbuild v4 behaviors are different for XAML generation $frameworkMsBuildLocation = "${env:SystemRoot}\Microsoft.Net\Framework\v4.0.30319\msbuild" - $msbuild = get-command msbuild -ErrorAction SilentlyContinue + $msbuild = get-command msbuild -ErrorAction Ignore if ($msbuild) { # all good, nothing to do return @@ -1971,21 +1986,29 @@ function script:Use-MSBuild { Set-Alias msbuild $frameworkMsBuildLocation -Scope Script } +function script:Write-Log +{ + param + ( + [Parameter(Position=0, Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $message, -function script:log([string]$message) { - Write-Host -Foreground Green $message - #reset colors for older package to at return to default after error message on a compilation error - [console]::ResetColor() -} - -function script:logerror([string]$message) { - Write-Host -Foreground Red $message + [switch] $error + ) + if ($error) + { + Write-Host -Foreground Red $message + } + else + { + Write-Host -Foreground Green $message + } #reset colors for older package to at return to default after error message on a compilation error [console]::ResetColor() } - function script:precheck([string]$command, [string]$missedMessage) { - $c = Get-Command $command -ErrorAction SilentlyContinue + $c = Get-Command $command -ErrorAction Ignore if (-not $c) { if (-not [string]::IsNullOrEmpty($missedMessage)) { @@ -1999,187 +2022,48 @@ function script:precheck([string]$command, [string]$missedMessage) { # this function wraps native command Execution # for more information, read https://mnaoumov.wordpress.com/2015/01/11/execution-of-external-commands-in-powershell-done-right/ -function script:Start-NativeExecution([scriptblock]$sb, [switch]$IgnoreExitcode) +function script:Start-NativeExecution { + param( + [scriptblock]$sb, + [switch]$IgnoreExitcode, + [switch]$VerboseOutputOnError + ) $backupEAP = $script:ErrorActionPreference $script:ErrorActionPreference = "Continue" try { - & $sb - # note, if $sb doesn't have a native invocation, $LASTEXITCODE will - # point to the obsolete value - if ($LASTEXITCODE -ne 0 -and -not $IgnoreExitcode) { - throw "Execution of {$sb} failed with exit code $LASTEXITCODE" - } - } finally { - $script:ErrorActionPreference = $backupEAP - } -} - -# Builds coming out of this project can have version number as 'a.b.c' OR 'a.b.c-d-f' -# This function converts the above version into major.minor[.build[.revision]] format -function Get-PackageVersionAsMajorMinorBuildRevision -{ - [CmdletBinding()] - param ( - # Version of the Package - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $Version - ) - - Write-Verbose "Extract the version in the form of major.minor[.build[.revision]] for $Version" - $packageVersionTokens = $Version.Split('-') - $packageVersion = ([regex]::matches($Version, "\d+(\.\d+)+"))[0].value - - if (1 -eq $packageVersionTokens.Count) { - # In case the input is of the form a.b.c, add a '0' at the end for revision field - $packageVersion = $packageVersion + '.0' - } elseif (1 -lt $packageVersionTokens.Count) { - # We have all the four fields - $packageBuildTokens = ([regex]::Matches($packageVersionTokens[1], "\d+"))[0].value - - if ($packageBuildTokens) + if($VerboseOutputOnError.IsPresent) { - $packageVersion = $packageVersion + '.' + $packageBuildTokens + $output = & $sb 2>&1 } else { - $packageVersion = $packageVersion + & $sb } - } - - $packageVersion -} - -function New-MSIPackage -{ - [CmdletBinding()] - param ( - - # Name of the Product - [ValidateNotNullOrEmpty()] - [string] $ProductName = 'PowerShell', - - # Suffix of the Name - [string] $ProductNameSuffix, - - # Version of the Product - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $ProductVersion, - - # Product Guid needs to change for every version to support SxS install - [ValidateNotNullOrEmpty()] - [string] $ProductGuid = 'a5249933-73a1-4b10-8a4c-13c98bdc16fe', - - # Source Path to the Product Files - required to package the contents into an MSI - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $ProductSourcePath, - - # File describing the MSI Package creation semantics - [ValidateNotNullOrEmpty()] - [string] $ProductWxsPath = "$PSScriptRoot\assets\Product.wxs", - - # Path to Assets folder containing artifacts such as icons, images - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $AssetsPath, - - # Path to license.rtf file - for the EULA - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $LicenseFilePath, - - # Architecture to use when creating the MSI - [Parameter(Mandatory = $true)] - [ValidateSet("x86", "x64")] - [ValidateNotNullOrEmpty()] - [string] $ProductTargetArchitecture, - # Force overwrite of package - [Switch] $Force - ) - - ## AppVeyor base image might update the version for Wix. Hence, we should - ## not hard code version numbers. - $wixToolsetBinPath = "${env:ProgramFiles(x86)}\WiX Toolset *\bin" - - Write-Verbose "Ensure Wix Toolset is present on the machine @ $wixToolsetBinPath" - if (-not (Test-Path $wixToolsetBinPath)) - { - throw "Wix Toolset is required to create MSI package. Please install it from https://github.com/wixtoolset/wix3/releases/download/wix311rtm/wix311.exe" - } - - ## Get the latest if multiple versions exist. - $wixToolsetBinPath = (Get-ChildItem $wixToolsetBinPath).FullName | Sort-Object -Descending | Select-Object -First 1 - - Write-Verbose "Initialize Wix executables - Heat.exe, Candle.exe, Light.exe" - $wixHeatExePath = Join-Path $wixToolsetBinPath "Heat.exe" - $wixCandleExePath = Join-Path $wixToolsetBinPath "Candle.exe" - $wixLightExePath = Join-Path $wixToolsetBinPath "Light.exe" - - $ProductSemanticVersion = Get-PackageSemanticVersion -Version $ProductVersion - $ProductVersion = Get-PackageVersionAsMajorMinorBuildRevision -Version $ProductVersion - - $assetsInSourcePath = Join-Path $ProductSourcePath 'assets' - New-Item $assetsInSourcePath -type directory -Force | Write-Verbose - - Write-Verbose "Place dependencies such as icons to $assetsInSourcePath" - Copy-Item "$AssetsPath\*.ico" $assetsInSourcePath -Force - - $productVersionWithName = $ProductName + '_' + $ProductVersion - $productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion - - Write-Verbose "Create MSI for Product $productSemanticVersionWithName" - - [Environment]::SetEnvironmentVariable("ProductSourcePath", $ProductSourcePath, "Process") - # These variables are used by Product.wxs in assets directory - [Environment]::SetEnvironmentVariable("ProductName", $ProductName, "Process") - [Environment]::SetEnvironmentVariable("ProductGuid", $ProductGuid, "Process") - [Environment]::SetEnvironmentVariable("ProductVersion", $ProductVersion, "Process") - [Environment]::SetEnvironmentVariable("ProductSemanticVersion", $ProductSemanticVersion, "Process") - [Environment]::SetEnvironmentVariable("ProductVersionWithName", $productVersionWithName, "Process") - [Environment]::SetEnvironmentVariable("ProductTargetArchitecture", $ProductTargetArchitecture, "Process") - $ProductProgFilesDir = "ProgramFiles64Folder" - if ($ProductTargetArchitecture -eq "x86") - { - $ProductProgFilesDir = "ProgramFilesFolder" - } - [Environment]::SetEnvironmentVariable("ProductProgFilesDir", $ProductProgFilesDir, "Process") - - $wixFragmentPath = (Join-path $env:Temp "Fragment.wxs") - $wixObjProductPath = (Join-path $env:Temp "Product.wixobj") - $wixObjFragmentPath = (Join-path $env:Temp "Fragment.wixobj") - - $packageName = $productSemanticVersionWithName - if ($ProductNameSuffix) { - $packageName += "-$ProductNameSuffix" - } - $msiLocationPath = Join-Path $pwd "$packageName.msi" - - if(!$Force.IsPresent -and (Test-Path -Path $msiLocationPath)) - { - Write-Error -Message "Package already exists, use -Force to overwrite, path: $msiLocationPath" -ErrorAction Stop - } - - $WiXHeatLog = & $wixHeatExePath dir $ProductSourcePath -dr $productVersionWithName -cg $productVersionWithName -gg -sfrag -srd -scom -sreg -out $wixFragmentPath -var env.ProductSourcePath -v - $WiXCandleLog = & $wixCandleExePath "$ProductWxsPath" "$wixFragmentPath" -out (Join-Path "$env:Temp" "\\") -ext WixUIExtension -ext WixUtilExtension -arch x64 -v - $WiXLightLog = & $wixLightExePath -out $msiLocationPath $wixObjProductPath $wixObjFragmentPath -ext WixUIExtension -ext WixUtilExtension -dWixUILicenseRtf="$LicenseFilePath" -v + # note, if $sb doesn't have a native invocation, $LASTEXITCODE will + # point to the obsolete value + if ($LASTEXITCODE -ne 0 -and -not $IgnoreExitcode) { + if($VerboseOutputOnError.IsPresent -and $output) + { + $output | Out-String | Write-Verbose -Verbose + } - Remove-Item -ErrorAction SilentlyContinue *.wixpdb -Force + # Get caller location for easier debugging + $caller = Get-PSCallStack -ErrorAction SilentlyContinue + if($caller) + { + $callerLocationParts = $caller[1].Location -split ":\s*line\s*" + $callerFile = $callerLocationParts[0] + $callerLine = $callerLocationParts[1] - if (Test-Path $msiLocationPath) - { - Write-Verbose "You can find the MSI @ $msiLocationPath" -Verbose - $msiLocationPath - } - else - { - $WiXHeatLog | Out-String | Write-Verbose -Verbose - $WiXCandleLog | Out-String | Write-Verbose -Verbose - $WiXLightLog | Out-String | Write-Verbose -Verbose - throw "Failed to create $msiLocationPath" + $errorMessage = "Execution of {$sb} by ${callerFile}: line $callerLine failed with exit code $LASTEXITCODE" + throw $errorMessage + } + throw "Execution of {$sb} failed with exit code $LASTEXITCODE" + } + } finally { + $script:ErrorActionPreference = $backupEAP } } @@ -2192,18 +2076,20 @@ function Start-CrossGen { $PublishPath, [Parameter(Mandatory=$true)] - [ValidateSet("win7-x86", - "win7-x64", - "osx.10.12-x64", - "linux-x64", + [ValidateSet("alpine-x64", "linux-arm", + "linux-arm64", + "linux-x64", + "osx-x64", "win-arm", - "win-arm64")] + "win-arm64", + "win7-x64", + "win7-x86")] [string] $Runtime ) - function Generate-CrossGenAssembly { + function New-CrossGenAssembly { param ( [Parameter(Mandatory= $true)] [ValidateNotNullOrEmpty()] @@ -2259,19 +2145,20 @@ function Start-CrossGen { } } elseif ($Runtime -eq "linux-arm") { throw "crossgen is not available for 'linux-arm'" - } elseif ($Environment.IsLinux) { - "linux-x64" - } elseif ($Environment.IsMacOS) { - "osx-x64" + } else { + $Runtime } if (-not $crossGenRuntime) { throw "crossgen is not available for this platform" } + $dotnetRuntimeVersion = $script:Options.Framework -replace 'netcoreapp' + # Get the CrossGen.exe for the correct runtime with the latest version $crossGenPath = Get-ChildItem $script:Environment.nugetPackagesRoot $crossGenExe -Recurse | ` Where-Object { $_.FullName -match $crossGenRuntime } | ` + Where-Object { $_.FullName -match $dotnetRuntimeVersion } | ` Sort-Object -Property FullName -Descending | ` Select-Object -First 1 | ` ForEach-Object { $_.FullName } @@ -2326,22 +2213,23 @@ function Start-CrossGen { "System.IO.Pipes.dll" "System.Diagnostics.FileVersionInfo.dll" "System.Collections.Specialized.dll" + "Microsoft.ApplicationInsights.dll" ) # Common PowerShell libraries to crossgen $psCoreAssemblyList = @( + "pwsh.dll", "Microsoft.PowerShell.Commands.Utility.dll", "Microsoft.PowerShell.Commands.Management.dll", "Microsoft.PowerShell.Security.dll", - "Microsoft.PowerShell.CoreCLR.Eventing.dll", "Microsoft.PowerShell.ConsoleHost.dll", - "Microsoft.PowerShell.PSReadLine.dll", "System.Management.Automation.dll" ) # Add Windows specific libraries if ($Environment.IsWindows) { $psCoreAssemblyList += @( + "Microsoft.PowerShell.CoreCLR.Eventing.dll", "Microsoft.WSMan.Management.dll", "Microsoft.WSMan.Runtime.dll", "Microsoft.PowerShell.Commands.Diagnostics.dll", @@ -2353,7 +2241,7 @@ function Start-CrossGen { foreach ($assemblyName in $fullAssemblyList) { $assemblyPath = Join-Path $PublishPath $assemblyName - Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath + New-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath } # @@ -2395,154 +2283,571 @@ function Clear-PSRepo } } - -# Install PowerShell modules from a git Repo such as PSL-Pester -function Restore-GitModule +# Install PowerShell modules such as PackageManagement, PowerShellGet +function Copy-PSGalleryModules { [CmdletBinding()] param( [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] - [string]$Name, - - [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] - [string]$Uri, + [string]$CsProjPath, [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] [string]$Destination, - [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] - [string]$CommitSha + [Parameter()] + [switch]$Force ) - log 'Restoring module from git repo:' - log ("Name='{0}', Destination='{1}', Uri='{2}', CommitSha='{3}'" -f $Name, $Destination, $Uri, $CommitSha) - - $clonePath = Join-Path -Path $Destination -ChildPath $Name - if(Test-Path $clonePath) - { - remove-Item -Path $clonePath -recurse -force + if (!$Destination.EndsWith("Modules")) { + throw "Installing to an unexpected location" } - $null = Start-NativeExecution {git clone --quiet $uri $clonePath} + Find-DotNet - Push-location $clonePath - try { - $null = Start-NativeExecution {git checkout --quiet -b desiredCommit $CommitSha} -SuppressOutput + Restore-PSPackage -ProjectDirs (Split-Path $CsProjPath) -Force:$Force.IsPresent - $gitItems = Join-Path -Path $clonePath -ChildPath '.git*' - $ymlItems = Join-Path -Path $clonePath -ChildPath '*.yml' - Get-ChildItem -attributes hidden,normal -Path $gitItems, $ymlItems | Remove-Item -Recurse -Force + $cache = dotnet nuget locals global-packages -l + if ($cache -match "info : global-packages: (.*)") { + $nugetCache = $matches[1] } - finally - { - pop-location + else { + throw "Can't find nuget global cache" + } + + $psGalleryProj = [xml](Get-Content -Raw $CsProjPath) + + foreach ($m in $psGalleryProj.Project.ItemGroup.PackageReference) { + $name = $m.Include + $version = $m.Version + Write-Log "Name='$Name', Version='$version', Destination='$Destination'" + + # Remove the build revision from the src (nuget drops it). + $srcVer = if ($version -match "(\d+.\d+.\d+).0") { + $matches[1] + } elseif ($version -match "^\d+.\d+$") { + # Two digit versions are stored as three digit versions + "$version.0" + } else { + $version + } + + # Nuget seems to always use lowercase in the cache + $src = "$nugetCache/$($name.ToLower())/$srcVer" + $dest = "$Destination/$name" + + Remove-Item -Force -ErrorAction Ignore -Recurse "$Destination/$name" + New-Item -Path $dest -ItemType Directory -Force -ErrorAction Stop > $null + # Exclude files/folders that are not needed. The fullclr folder is coming from the PackageManagement module + $dontCopy = '*.nupkg', '*.nupkg.metadata', '*.nupkg.sha512', '*.nuspec', 'System.Runtime.InteropServices.RuntimeInformation.dll', 'fullclr' + Copy-Item -Exclude $dontCopy -Recurse $src/* $dest -ErrorAction Stop } } -# Install PowerShell modules such as PackageManagement, PowerShellGet -function Restore-PSModule +function Merge-TestLogs { [CmdletBinding()] - param( - [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] - [string[]]$Name, + param ( + [Parameter(Mandatory = $true)] + [ValidateScript({Test-Path $_})] + [string]$XUnitLogPath, - [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] - [string]$Destination, + [Parameter(Mandatory = $true)] + [ValidateScript({Test-Path $_})] + [string[]]$NUnitLogPath, - [string]$SourceLocation="https://powershell.myget.org/F/powershellmodule/api/v2/", + [Parameter()] + [ValidateScript({Test-Path $_})] + [string[]]$AdditionalXUnitLogPath, - [string]$RequiredVersion - ) + [Parameter()] + [string]$OutputLogPath + ) - $needRegister = $true - $RepositoryName = "mygetpsmodule" + # Convert all the NUnit logs into single object + $convertedNUnit = ConvertFrom-PesterLog -logFile $NUnitLogPath - # Check if the PackageManagement works in the base-oS or PowerShellCore - $null = Get-PackageProvider -Name NuGet -ForceBootstrap -Verbose:$VerbosePreference - $null = Get-PackageProvider -Name PowerShellGet -Verbose:$VerbosePreference + $xunit = [xml] (Get-Content $XUnitLogPath -ReadCount 0 -Raw) - # Get the existing registered PowerShellGet repositories - $psrepos = PowerShellGet\Get-PSRepository + $strBld = [System.Text.StringBuilder]::new($xunit.assemblies.InnerXml) - foreach ($repo in $psrepos) + foreach($assembly in $convertedNUnit.assembly) { - if(($repo.SourceLocation -eq $SourceLocation) -or ($repo.SourceLocation.TrimEnd("/") -eq $SourceLocation.TrimEnd("/"))) - { - # found a registered repository that matches the source location - $needRegister = $false - $RepositoryName = $repo.Name - break - } + $strBld.Append($assembly.ToString()) | Out-Null } - if($needRegister) + foreach($path in $AdditionalXUnitLogPath) { - $regVar = PowerShellGet\Get-PSRepository -Name $RepositoryName -ErrorAction SilentlyContinue - if($regVar) - { - PowerShellGet\UnRegister-PSRepository -Name $RepositoryName + $addXunit = [xml] (Get-Content $path -ReadCount 0 -Raw) + $strBld.Append($addXunit.assemblies.InnerXml) | Out-Null + } + + $xunit.assemblies.InnerXml = $strBld.ToString() + $xunit.Save($OutputLogPath) +} + +function ConvertFrom-PesterLog { + [CmdletBinding()] + param ( + [Parameter(ValueFromPipeline = $true, Mandatory = $true, Position = 0)] + [string[]]$Logfile, + [Parameter()][switch]$IncludeEmpty, + [Parameter()][switch]$MultipleLog + ) + <# +Convert our test logs to +xunit schema - top level assemblies +Pester conversion +foreach $r in "test-results"."test-suite".results."test-suite" +assembly + name = $r.Description + config-file = log file (this is the only way we can determine between admin/nonadmin log) + test-framework = Pester + environment = top-level "test-results.environment.platform + run-date = date (doesn't exist in pester except for beginning) + run-time = time + time = +#> + + BEGIN { + # CLASSES + class assemblies { + # attributes + [datetime]$timestamp + # child elements + [System.Collections.Generic.List[testAssembly]]$assembly + assemblies() { + $this.timestamp = [datetime]::now + $this.assembly = [System.Collections.Generic.List[testAssembly]]::new() + } + static [assemblies] op_Addition([assemblies]$ls, [assemblies]$rs) { + $newAssembly = [assemblies]::new() + $newAssembly.assembly.AddRange($ls.assembly) + $newAssembly.assembly.AddRange($rs.assembly) + return $newAssembly + } + [string]ToString() { + $sb = [text.stringbuilder]::new() + $sb.AppendLine('' -f $this.timestamp) + foreach ( $a in $this.assembly ) { + $sb.Append("$a") + } + $sb.AppendLine(""); + return $sb.ToString() + } + # use Write-Output to emit these into the pipeline + [array]GetTests() { + return $this.Assembly.collection.test + } } - log "Registering PSRepository with name: $RepositoryName and sourcelocation: $SourceLocation" - PowerShellGet\Register-PSRepository -Name $RepositoryName -SourceLocation $SourceLocation -ErrorVariable ev -verbose - if($ev) - { - throw ("Failed to register repository '{0}'" -f $RepositoryName) + class testAssembly { + # attributes + [string]$name # path to pester file + [string]${config-file} + [string]${test-framework} # Pester + [string]$environment + [string]${run-date} + [string]${run-time} + [decimal]$time + [int]$total + [int]$passed + [int]$failed + [int]$skipped + [int]$errors + testAssembly ( ) { + $this."config-file" = "no config" + $this."test-framework" = "Pester" + $this.environment = $script:environment + $this."run-date" = $script:rundate + $this."run-time" = $script:runtime + $this.collection = [System.Collections.Generic.List[collection]]::new() + } + # child elements + [error[]]$error + [System.Collections.Generic.List[collection]]$collection + [string]ToString() { + $sb = [System.Text.StringBuilder]::new() + $sb.AppendFormat(' ") + if ( $this.error ) { + $sb.AppendLine(" ") + foreach ( $e in $this.error ) { + $sb.AppendLine($e.ToString()) + } + $sb.AppendLine(" ") + } else { + $sb.AppendLine(" ") + } + foreach ( $col in $this.collection ) { + $sb.AppendLine($col.ToString()) + } + $sb.AppendLine(" ") + return $sb.ToString() + } } - $regVar = PowerShellGet\Get-PSRepository -Name $RepositoryName - if(-not $regVar) - { - throw ("'{0}' is not registered" -f $RepositoryName) + class collection { + # attributes + [string]$name + [decimal]$time + [int]$total + [int]$passed + [int]$failed + [int]$skipped + # child element + [System.Collections.Generic.List[test]]$test + # constructor + collection () { + $this.test = [System.Collections.Generic.List[test]]::new() + } + [string]ToString() { + $sb = [Text.StringBuilder]::new() + if ( $this.test.count -eq 0 ) { + $sb.AppendLine(" ") + } else { + $sb.AppendFormat(' ' + "`n", + $this.total, $this.passed, $this.failed, $this.skipped, [security.securityelement]::escape($this.name), $this.time) + foreach ( $t in $this.test ) { + $sb.AppendLine(" " + $t.ToString()); + } + $sb.Append(" ") + } + return $sb.ToString() + } } - } - log ("Name='{0}', Destination='{1}', Repository='{2}'" -f ($Name -join ','), $Destination, $RepositoryName) + class errors { + [error[]]$error + } + class error { + # attributes + [string]$type + [string]$name + # child elements + [failure]$failure + [string]ToString() { + $sb = [system.text.stringbuilder]::new() + $sb.AppendLine('' -f $this.type, [security.securityelement]::escape($this.Name)) + $sb.AppendLine($this.failure -as [string]) + $sb.AppendLine("") + return $sb.ToString() + } + } - # do not output progress - $ProgressPreference = "SilentlyContinue" - $Name | ForEach-Object { + class cdata { + [string]$text + cdata ( [string]$s ) { $this.text = $s } + [string]ToString() { + return '' + } + } - $command = @{ - Name=$_ - Path = $Destination - Repository =$RepositoryName - } + class failure { + [string]${exception-type} + [cdata]$message + [cdata]${stack-trace} + failure ( [string]$message, [string]$stack ) { + $this."exception-type" = "Pester" + $this.Message = [cdata]::new($message) + $this."stack-trace" = [cdata]::new($stack) + } + [string]ToString() { + $sb = [text.stringbuilder]::new() + $sb.AppendLine(" ") + $sb.AppendLine(" " + ($this.message -as [string]) + "") + $sb.AppendLine(" " + ($this."stack-trace" -as [string]) + "") + $sb.Append(" ") + return $sb.ToString() + } + } - if($RequiredVersion) - { - $command.Add("RequiredVersion", $RequiredVersion) + enum resultenum { + Pass + Fail + Skip + } + + class trait { + # attributes + [string]$name + [string]$value + } + class traits { + [trait[]]$trait + } + class test { + # attributes + [string]$name + [string]$type + [string]$method + [decimal]$time + [resultenum]$result + # child elements + [trait[]]$traits + [failure]$failure + [cdata]$reason # skip reason + [string]ToString() { + $sb = [text.stringbuilder]::new() + $sb.appendformat(' ") + $sb.AppendLine($this.failure -as [string]) + $sb.append(' ') + } else { + $sb.Append("/>") + } + return $sb.ToString() + } } - # pull down the module - log "running save-module $_" - PowerShellGet\Save-Module @command -Force + function convert-pesterlog ( [xml]$x, $logpath, [switch]$includeEmpty ) { + <#$resultMap = @{ + Success = "Pass" + Ignored = "Skip" + Failure = "Fail" + }#> + + $resultMap = @{ + Success = "Pass" + Ignored = "Skip" + Failure = "Fail" + Inconclusive = "Skip" + } - # Remove PSGetModuleInfo.xml file - Find-Module -Name $_ -Repository $RepositoryName -IncludeDependencies | ForEach-Object { - Remove-Item -Path $Destination\$($_.Name)\*\PSGetModuleInfo.xml -Force + $configfile = $logpath + $runtime = $x."test-results".time + $environment = $x."test-results".environment.platform + "-" + $x."test-results".environment."os-version" + $rundate = $x."test-results".date + $suites = $x."test-results"."test-suite".results."test-suite" + $assemblies = [assemblies]::new() + foreach ( $suite in $suites ) { + $tCases = $suite.SelectNodes(".//test-case") + # only create an assembly group if we have tests + if ( $tCases.count -eq 0 -and ! $includeEmpty ) { continue } + $tGroup = $tCases | Group-Object result + $total = $tCases.Count + $asm = [testassembly]::new() + $asm.environment = $environment + $asm."run-date" = $rundate + $asm."run-time" = $runtime + $asm.Name = $suite.name + $asm."config-file" = $configfile + $asm.time = $suite.time + $asm.total = $suite.SelectNodes(".//test-case").Count + $asm.Passed = $tGroup| Where-Object -FilterScript {$_.Name -eq "Success"} | ForEach-Object -Process {$_.Count} + $asm.Failed = $tGroup| Where-Object -FilterScript {$_.Name -eq "Failure"} | ForEach-Object -Process {$_.Count} + $asm.Skipped = $tGroup| Where-Object -FilterScript { $_.Name -eq "Ignored" } | ForEach-Object -Process {$_.Count} + $asm.Skipped += $tGroup| Where-Object -FilterScript { $_.Name -eq "Inconclusive" } | ForEach-Object -Process {$_.Count} + $c = [collection]::new() + $c.passed = $asm.Passed + $c.failed = $asm.failed + $c.skipped = $asm.skipped + $c.total = $asm.total + $c.time = $asm.time + $c.name = $asm.name + foreach ( $tc in $suite.SelectNodes(".//test-case")) { + if ( $tc.result -match "Success|Ignored|Failure" ) { + $t = [test]::new() + $t.name = $tc.Name + $t.time = $tc.time + $t.method = $tc.description # the pester actually puts the name of the "it" as description + $t.type = $suite.results."test-suite".description | Select-Object -First 1 + $t.result = $resultMap[$tc.result] + if ( $tc.failure ) { + $t.failure = [failure]::new($tc.failure.message, $tc.failure."stack-trace") + } + $null = $c.test.Add($t) + } + } + $null = $asm.collection.add($c) + $assemblies.assembly.Add($asm) + } + $assemblies + } + + # convert it to our object model + # a simple conversion + function convert-xunitlog { + param ( $x, $logpath ) + $asms = [assemblies]::new() + $asms.timestamp = $x.assemblies.timestamp + foreach ( $assembly in $x.assemblies.assembly ) { + $asm = [testAssembly]::new() + $asm.environment = $assembly.environment + $asm."test-framework" = $assembly."test-framework" + $asm."run-date" = $assembly."run-date" + $asm."run-time" = $assembly."run-time" + $asm.total = $assembly.total + $asm.passed = $assembly.passed + $asm.failed = $assembly.failed + $asm.skipped = $assembly.skipped + $asm.time = $assembly.time + $asm.name = $assembly.name + foreach ( $coll in $assembly.collection ) { + $c = [collection]::new() + $c.name = $coll.name + $c.total = $coll.total + $c.passed = $coll.passed + $c.failed = $coll.failed + $c.skipped = $coll.skipped + $c.time = $coll.time + foreach ( $t in $coll.test ) { + $test = [test]::new() + $test.name = $t.name + $test.type = $t.type + $test.method = $t.method + $test.time = $t.time + $test.result = $t.result + $c.test.Add($test) + } + $null = $asm.collection.add($c) + } + $null = $asms.assembly.add($asm) + } + $asms } + $Logs = @() } - # Clean up - if($needRegister) - { - $regVar = PowerShellGet\Get-PSRepository -Name $RepositoryName -ErrorAction SilentlyContinue - if($regVar) - { - log "Unregistering PSRepository with name: $RepositoryName" - PowerShellGet\UnRegister-PSRepository -Name $RepositoryName + PROCESS { + #### MAIN #### + foreach ( $log in $Logfile ) { + foreach ( $logpath in (resolve-path $log).path ) { + write-progress "converting file $logpath" + if ( ! $logpath) { throw "Cannot resolve $Logfile" } + $x = [xml](get-content -raw -readcount 0 $logpath) + + if ( $x.psobject.properties['test-results'] ) { + $Logs += convert-pesterlog $x $logpath -includeempty:$includeempty + } elseif ( $x.psobject.properties['assemblies'] ) { + $Logs += convert-xunitlog $x $logpath -includeEmpty:$includeEmpty + } else { + write-error "Cannot determine log type" + } + } + } + } + + END { + if ( $MultipleLog ) { + $Logs + } else { + $combinedLog = $Logs[0] + for ( $i = 1; $i -lt $logs.count; $i++ ) { + $combinedLog += $Logs[$i] + } + $combinedLog } } } +# Save PSOptions to be restored by Restore-PSOptions +function Save-PSOptions { + param( + [ValidateScript({$parent = Split-Path $_;if($parent){Test-Path $parent}else{return $true}})] + [ValidateNotNullOrEmpty()] + [string] + $PSOptionsPath = (Join-Path -Path $PSScriptRoot -ChildPath 'psoptions.json'), + + [ValidateNotNullOrEmpty()] + [object] + $Options = (Get-PSOptions -DefaultToNew) + ) + + $Options | ConvertTo-Json -Depth 3 | Out-File -Encoding utf8 -FilePath $PSOptionsPath +} + +# Restore PSOptions +# Optionally remove the PSOptions file +function Restore-PSOptions { + param( + [ValidateScript({Test-Path $_})] + [string] + $PSOptionsPath = (Join-Path -Path $PSScriptRoot -ChildPath 'psoptions.json'), + [switch] + $Remove + ) + + $options = Get-Content -Path $PSOptionsPath | ConvertFrom-Json + + if($Remove) + { + # Remove PSOptions. + # The file is only used to set the PSOptions. + Remove-Item -Path $psOptionsPath -Force + } + + $newOptions = New-PSOptionsObject ` + -RootInfo $options.RootInfo ` + -Top $options.Top ` + -Runtime $options.Runtime ` + -Crossgen $options.Crossgen ` + -Configuration $options.Configuration ` + -PSModuleRestore $options.PSModuleRestore ` + -Framework $options.Framework ` + -Output $options.Output + + Set-PSOptions -Options $newOptions +} + +function New-PSOptionsObject +{ + param( + [PSCustomObject] + $RootInfo, + + [Parameter(Mandatory)] + [String] + $Top, + + [Parameter(Mandatory)] + [String] + $Runtime, + + [Parameter(Mandatory)] + [Bool] + $CrossGen, + + [Parameter(Mandatory)] + [String] + $Configuration, + + [Parameter(Mandatory)] + [Bool] + $PSModuleRestore, + + [Parameter(Mandatory)] + [String] + $Framework, + + [Parameter(Mandatory)] + [String] + $Output + ) + + return @{ + RootInfo = $RootInfo + Top = $Top + Configuration = $Configuration + Framework = $Framework + Runtime = $Runtime + Output = $Output + CrossGen = $CrossGen + PSModuleRestore = $PSModuleRestore + } +} $script:RESX_TEMPLATE = @' @@ -2667,3 +2972,132 @@ $script:RESX_TEMPLATE = @' {0} '@ + +function Get-UniquePackageFolderName { + param( + [Parameter(Mandatory)] $Root + ) + + $packagePath = Join-Path $Root 'TestPackage' + + $triesLeft = 10 + + while(Test-Path $packagePath) { + $suffix = Get-Random + + # Not using Guid to avoid maxpath problems as in example below. + # Example: 'TestPackage-ba0ae1db-8512-46c5-8b6c-1862d33a2d63\test\powershell\Modules\Microsoft.PowerShell.Security\TestData\CatalogTestData\UserConfigProv\DSCResources\UserConfigProviderModVersion1\UserConfigProviderModVersion1.schema.mof' + $packagePath = Join-Path $Root "TestPackage_$suffix" + $triesLeft-- + + if ($triesLeft -le 0) { + throw "Could find unique folder name for package path" + } + } + + $packagePath +} + +function New-TestPackage +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] $Destination, + [string] $Runtime + ) + + if (Test-Path $Destination -PathType Leaf) + { + throw "Destination: '$Destination' is not a directory or does not exist." + } + else + { + $null = New-Item -Path $Destination -ItemType Directory -Force + Write-Verbose -Message "Creating destination folder: $Destination" + } + + $rootFolder = $env:TEMP + + # In some build agents, typically macOS on AzDevOps, $env:TEMP might not be set. + if (-not $rootFolder -and $env:TF_BUILD) { + $rootFolder = $env:AGENT_WORKFOLDER + } + + Write-Verbose -Verbose "RootFolder: $rootFolder" + $packageRoot = Get-UniquePackageFolderName -Root $rootFolder + + $null = New-Item -ItemType Directory -Path $packageRoot -Force + $packagePath = Join-Path $Destination "TestPackage.zip" + Write-Verbose -Verbose "PackagePath: $packagePath" + + # Build test tools so they are placed in appropriate folders under 'test' then copy to package root. + $null = Publish-PSTestTools -runtime $Runtime + $powerShellTestRoot = Join-Path $PSScriptRoot 'test' + Copy-Item $powerShellTestRoot -Recurse -Destination $packageRoot -Force + Write-Verbose -Message "Copied test directory" + + # Copy assests folder to package root for wix related tests. + $assetsPath = Join-Path $PSScriptRoot 'assets' + Copy-Item $assetsPath -Recurse -Destination $packageRoot -Force + Write-Verbose -Message "Copied assests directory" + + # Create expected folder structure for resx files in package root. + $srcRootForResx = New-Item -Path "$packageRoot/src" -Force -ItemType Directory + + $resourceDirectories = Get-ChildItem -Recurse "$PSScriptRoot/src" -Directory -Filter 'resources' + + $resourceDirectories | ForEach-Object { + $directoryFullName = $_.FullName + + $partToRemove = Join-Path $PSScriptRoot "src" + + $assemblyPart = $directoryFullName.Replace($partToRemove, '') + $assemblyPart = $assemblyPart.TrimStart([io.path]::DirectorySeparatorChar) + $resxDestPath = Join-Path $srcRootForResx $assemblyPart + $null = New-Item -Path $resxDestPath -Force -ItemType Directory + Write-Verbose -Message "Created resx directory : $resxDestPath" + Copy-Item -Path "$directoryFullName\*" -Recurse $resxDestPath -Force + } + + Add-Type -AssemblyName System.IO.Compression.FileSystem + + if(Test-Path $packagePath) + { + Remove-Item -Path $packagePath -Force + } + + [System.IO.Compression.ZipFile]::CreateFromDirectory($packageRoot, $packagePath) +} + +function New-NugetConfigFile +{ + param( + [Parameter(Mandatory=$true)] [string] $NugetFeedUrl, + [Parameter(Mandatory=$true)] [string] $FeedName, + [Parameter(Mandatory=$true)] [string] $UserName, + [Parameter(Mandatory=$true)] [string] $ClearTextPAT, + [Parameter(Mandatory=$true)] [string] $Destination + ) + + $nugetConfigTemplate = @' + + + + + + + + + <[FEEDNAME]> + + + + + +'@ + + $content = $nugetConfigTemplate.Replace('[FEED]', $NugetFeedUrl).Replace('[FEEDNAME]', $FeedName).Replace('[USERNAME]', $UserName).Replace('[PASSWORD]', $ClearTextPAT) + + Set-Content -Path (Join-Path $Destination 'nuget.config') -Value $content -Force +} diff --git a/demos/Apache/Apache/Apache.psm1 b/demos/Apache/Apache/Apache.psm1 index a572561f1034..489502a6d393 100644 --- a/demos/Apache/Apache/Apache.psm1 +++ b/demos/Apache/Apache/Apache.psm1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + #Region utility functions $global:sudocmd = "sudo" @@ -216,7 +219,6 @@ Function Restart-ApacheHTTPServer{ } - Function Get-ApacheModule{ $cmd = GetApacheCmd diff --git a/demos/Apache/apache-demo.ps1 b/demos/Apache/apache-demo.ps1 index 30ada4e97e79..1f5d60587d74 100644 --- a/demos/Apache/apache-demo.ps1 +++ b/demos/Apache/apache-demo.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + Import-Module $PSScriptRoot/Apache/Apache.psm1 #list Apache Modules diff --git a/demos/Azure/Azure-Demo.ps1 b/demos/Azure/Azure-Demo.ps1 index d3688e7ea18c..f75aa3e2d028 100644 --- a/demos/Azure/Azure-Demo.ps1 +++ b/demos/Azure/Azure-Demo.ps1 @@ -1,5 +1,8 @@ -### The techniques used in this demo are documented at -### https://azure.microsoft.com/en-us/documentation/articles/powershell-azure-resource-manager/ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +### The techniques used in this demo are documented at +### https://azure.microsoft.com/documentation/articles/powershell-azure-resource-manager/ ### Import AzureRM.Profile.NetCore.Preview and AzureRM.Resources.NetCore.Preview modules. ### AzureRM.NetCore.Preview is a wrapper module that pulls in these modules diff --git a/demos/DSC/dsc-demo.ps1 b/demos/DSC/dsc-demo.ps1 index 95b694c638ac..f393916408b1 100644 --- a/demos/DSC/dsc-demo.ps1 +++ b/demos/DSC/dsc-demo.ps1 @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. #Get Distro type and set distro-specific variables $OSname = Get-Content "/etc/os-release" |Select-String -Pattern "^Name=" diff --git a/demos/DSC/readme.md b/demos/DSC/readme.md index b1374c7699a7..b849e41b0c8c 100644 --- a/demos/DSC/readme.md +++ b/demos/DSC/readme.md @@ -1,6 +1,6 @@ ## DSC MOF Compilation Demo -[PowerShell Desired State Configuration](https://msdn.microsoft.com/en-us/PowerShell/dsc/overview) is a declarative configuration platform for Windows and Linux. DSC configurations can be authored in PowerShell and compiled into the resultant MOF document. +[PowerShell Desired State Configuration](https://docs.microsoft.com/powershell/dsc/overview) is a declarative configuration platform for Windows and Linux. DSC configurations can be authored in PowerShell and compiled into the resultant MOF document. This demo shows use of PowerShell to author a DSC configuration to set the configuration of an Apache web server. PowerShell scripting is used to assess distro and version-specific properties, such as the service controller and repo manager tools, for use in the configuration. @@ -9,4 +9,4 @@ This demo shows use of PowerShell to author a DSC configuration to set the confi - OMI: >= 1.1.0 [https://www.github.com/microsoft/omi/releases](https://www.github.com/microsoft/omi/releases) - Desired State Configuration for Linux >= 1.1.1-278 [https://github.com/Microsoft/PowerShell-DSC-for-Linux/releases](https://github.com/Microsoft/PowerShell-DSC-for-Linux/releases) -Note: applying the DSC configuration requires privileges. The user must have sudo authorization capabilities. You will be prompted for a sudo password when running the demo. \ No newline at end of file +> Note: applying the DSC configuration requires privileges. The user must have sudo authorization capabilities. You will be prompted for a sudo password when running the demo. diff --git a/demos/Docker-PowerShell/Docker-PowerShell.ps1 b/demos/Docker-PowerShell/Docker-PowerShell.ps1 index 3517e8058829..4639f7ee1d00 100644 --- a/demos/Docker-PowerShell/Docker-PowerShell.ps1 +++ b/demos/Docker-PowerShell/Docker-PowerShell.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + # This is a short example of the Docker-PowerShell module. The same cmdlets may be used to manage both local & remote machines, including both Windows & Linux hosts # The only difference between them is the example container image is pulled & run. @@ -26,4 +29,4 @@ Get-Container | Where-Object State -eq "exited" | Remove-Container Remove-ContainerImage hello-world # And list the container images left on the container host -Get-ContainerImage \ No newline at end of file +Get-ContainerImage diff --git a/demos/SSHRemoting/README.md b/demos/SSHRemoting/README.md deleted file mode 100644 index 2d9f06e3f76b..000000000000 --- a/demos/SSHRemoting/README.md +++ /dev/null @@ -1,221 +0,0 @@ -# PowerShell Remoting Over SSH - -## Overview - -PowerShell remoting normally uses WinRM for connection negotiation and data transport. -SSH was chosen for this remoting implementation since it is now available for both Linux and Windows platforms and allows true multiplatform PowerShell remoting. -However, WinRM also provides a robust hosting model for PowerShell remote sessions which this implementation does not yet do. -And this means that PowerShell remote endpoint configuration and JEA (Just Enough Administration) is not yet supported in this implementation. - -PowerShell SSH remoting lets you do basic PowerShell session remoting between Windows and Linux machines. -This is done by creating a PowerShell hosting process on the target machine as an SSH subsystem. -Eventually this will be changed to a more general hosting model similar to how WinRM works in order to support endpoint configuration and JEA. - -The New-PSSession, Enter-PSSession and Invoke-Command cmdlets now have a new parameter set to facilitate this new remoting connection - -```powershell -[-HostName ] [-UserName ] [-KeyFilePath ] -``` - -This new parameter set will likely change but for now allows you to create SSH PSSessions that you can interact with from the command line or invoke commands and scripts on. -You specify the target machine with the HostName parameter and provide the user name with UserName. -When running the cmdlets interactively at the PowerShell command line you will be prompted for a password. -But you also have the option to use SSH key authentication and provide a private key file path with the KeyFilePath parameter. - -## General setup information - -SSH is required to be installed on all machines. -You should install both client (ssh.exe) and server (sshd.exe) so that you can experiment with remoting to and from the machines. -For Windows you will need to install [Win32 OpenSSH from GitHub](https://github.com/PowerShell/Win32-OpenSSH/releases). -For Linux you will need to install SSH (including sshd server) appropriate to your platform. -You will also need a recent PowerShell build or package from GitHub having the SSH remoting feature. -SSH subsystems is used to establish a PowerShell process on the remote machine and the SSH server will need to be configured for that. -In addition you will need to enable password authentication and optionally key based authentication. - -## Setup on Windows Machine - -1. Install the latest [PowerShell for Windows] build from GitHub - - You can tell if it has the SSH remoting support by looking at the parameter sets for New-PSSession - ```powershell - PS> Get-Command New-PSSession -syntax - New-PSSession [-HostName] [-Name ] [-UserName ] [-KeyFilePath ] [-SSHTransport] [] - ``` -1. Install the latest [Win32 Open SSH] build from GitHub using the [installation] instructions -1. Edit the sshd_config file at the location where you installed Win32 Open SSH - - Make sure password authentication is enabled - ```none - PasswordAuthentication yes - ``` - - Add a PowerShell subsystem entry, replace `c:/program files/powershell/6.0.0/pwsh.exe` with the correct path to the version you want to use - ```none - Subsystem powershell c:/program files/powershell/6.0.0/pwsh.exe -sshs -NoLogo -NoProfile - ``` - - Optionally enable key authentication - ```none - PubkeyAuthentication yes - ``` -1. Restart the sshd service - ```powershell - Restart-Service sshd - ``` -1. Add the path where OpenSSH is installed to your Path Env Variable - - This should be along the lines of `C:\Program Files\OpenSSH\` - - This allows for the ssh.exe to be found - -## Setup on Linux (Ubuntu 14.04) Machine - -1. Install the latest [PowerShell for Linux] build from GitHub -1. Install [Ubuntu SSH] as needed - ```bash - sudo apt install openssh-client - sudo apt install openssh-server - ``` -1. Edit the sshd_config file at location /etc/ssh - - Make sure password authentication is enabled - ```none - PasswordAuthentication yes - ``` - - Add a PowerShell subsystem entry - ```none - Subsystem powershell /usr/bin/pwsh -sshs -NoLogo -NoProfile - ``` - - Optionally enable key authentication - ```none - PubkeyAuthentication yes - ``` -1. Restart the sshd service - ```bash - sudo service sshd restart - ``` - -## Setup on MacOS Machine - -1. Install the latest [PowerShell for MacOS] build - - Make sure SSH Remoting is enabled by following these steps: - + Open `System Preferences` - + Click on `Sharing` - + Check `Remote Login` - Should say `Remote Login: On` - + Allow access to appropriate users -1. Edit the `sshd_config` file at location `/private/etc/ssh/sshd_config` - - Use your favorite editor or - ```bash - sudo nano /private/etc/ssh/sshd_config - ``` - - Make sure password authentication is enabled - ```none - PasswordAuthentication yes - ``` - - Add a PowerShell subsystem entry - ```none - Subsystem powershell /usr/local/bin/powershell -sshs -NoLogo -NoProfile - ``` - - Optionally enable key authentication - ```none - PubkeyAuthentication yes - ``` -1. Restart the sshd service - ```bash - sudo launchctl stop com.openssh.sshd - sudo launchctl start com.openssh.sshd - ``` - -## PowerShell Remoting Example - -The easiest way to test remoting is to just try it on a single machine. -Here I will create a remote session back to the same machine on a Linux box. -Notice that I am using PowerShell cmdlets from a command prompt so we see prompts from SSH asking to verify the host computer as well as password prompts. -You can do the same thing on a Windows machine to ensure remoting is working there and then remote between machines by simply changing the host name. - -```powershell -# -# Linux to Linux -# -PS /home/TestUser> $session = New-PSSession -HostName UbuntuVM1 -UserName TestUser -The authenticity of host 'UbuntuVM1 (9.129.17.107)' cannot be established. -ECDSA key fingerprint is SHA256:2kCbnhT2dUE6WCGgVJ8Hyfu1z2wE4lifaJXLO7QJy0Y. -Are you sure you want to continue connecting (yes/no)? -TestUser@UbuntuVM1s password: - -PS /home/TestUser> $session - - Id Name ComputerName ComputerType State ConfigurationName Availability - -- ---- ------------ ------------ ----- ----------------- ------------ - 1 SSH1 UbuntuVM1 RemoteMachine Opened DefaultShell Available - -PS /home/TestUser> Enter-PSSession $session - -[UbuntuVM1]: PS /home/TestUser> uname -a -Linux TestUser-UbuntuVM1 4.2.0-42-generic 49~14.04.1-Ubuntu SMP Wed Jun 29 20:22:11 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux - -[UbuntuVM1]: PS /home/TestUser> Exit-PSSession - -PS /home/TestUser> Invoke-Command $session -ScriptBlock { Get-Process powershell } - -Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName PSComputerName -------- ------ ----- ----- ------ -- -- ----------- -------------- - 0 0 0 19 3.23 10635 635 powershell UbuntuVM1 - 0 0 0 21 4.92 11033 017 powershell UbuntuVM1 - 0 0 0 20 3.07 11076 076 powershell UbuntuVM1 - - -# -# Linux to Windows -# -PS /home/TestUser> Enter-PSSession -HostName WinVM1 -UserName PTestName -PTestName@WinVM1s password: - -[WinVM1]: PS C:\Users\PTestName\Documents> cmd /c ver - -Microsoft Windows [Version 10.0.10586] - -[WinVM1]: PS C:\Users\PTestName\Documents> - -# -# Windows to Windows -# -C:\Users\PSUser\Documents>pwsh.exe -PowerShell -Copyright (c) Microsoft Corporation. All rights reserved. - -PS C:\Users\PSUser\Documents> $session = New-PSSession -HostName WinVM2 -UserName PSRemoteUser -The authenticity of host 'WinVM2 (10.13.37.3)' can't be established. -ECDSA key fingerprint is SHA256:kSU6slAROyQVMEynVIXAdxSiZpwDBigpAF/TXjjWjmw. -Are you sure you want to continue connecting (yes/no)? -Warning: Permanently added 'WinVM2,10.13.37.3' (ECDSA) to the list of known hosts. -PSRemoteUser@WinVM2's password: -PS C:\Users\PSUser\Documents> $session - - Id Name ComputerName ComputerType State ConfigurationName Availability - -- ---- ------------ ------------ ----- ----------------- ------------ - 1 SSH1 WinVM2 RemoteMachine Opened DefaultShell Available - - -PS C:\Users\PSUser\Documents> Enter-PSSession -Session $session -[WinVM2]: PS C:\Users\PSRemoteUser\Documents> $PSVersionTable - -Name Value ----- ----- -PSEdition Core -PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} -SerializationVersion 1.1.0.1 -BuildVersion 3.0.0.0 -CLRVersion -PSVersion 6.0.0-alpha -WSManStackVersion 3.0 -PSRemotingProtocolVersion 2.3 -GitCommitId v6.0.0-alpha.17 - - -[WinVM2]: PS C:\Users\PSRemoteUser\Documents> -``` - -### Known Issues - -1. sudo command does not work in remote session to Linux machine. - -[PowerShell for Windows]: https://github.com/PowerShell/PowerShell/blob/master/docs/installation/windows.md#msi -[Win32 Open SSH]: https://github.com/PowerShell/Win32-OpenSSH -[installation]: https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH -[PowerShell for Linux]: https://github.com/PowerShell/PowerShell/blob/master/docs/installation/linux.md#ubuntu-1404 -[Ubuntu SSH]: https://help.ubuntu.com/lts/serverguide/openssh-server.html -[PowerShell for MacOS]: https://github.com/PowerShell/PowerShell/blob/master/docs/installation/linux.md#macos-1012 diff --git a/demos/SystemD/SystemD/SystemD.psm1 b/demos/SystemD/SystemD/SystemD.psm1 index 38ea8fd41469..b127a2e51690 100644 --- a/demos/SystemD/SystemD/SystemD.psm1 +++ b/demos/SystemD/SystemD/SystemD.psm1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + Function Get-SystemDJournal { [CmdletBinding()] param ( @@ -15,4 +18,4 @@ Function Get-SystemDJournal { { $Result } -} \ No newline at end of file +} diff --git a/demos/SystemD/journalctl-demo.ps1 b/demos/SystemD/journalctl-demo.ps1 index 7e4fc37831b0..c979a97467be 100644 --- a/demos/SystemD/journalctl-demo.ps1 +++ b/demos/SystemD/journalctl-demo.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + Import-Module $PSScriptRoot/SystemD/SystemD.psm1 #list recent journal events diff --git a/demos/WindowsPowerShellModules/README.md b/demos/WindowsPowerShellModules/README.md index 0867e387ea7f..b8e23cffb401 100644 --- a/demos/WindowsPowerShellModules/README.md +++ b/demos/WindowsPowerShellModules/README.md @@ -5,7 +5,7 @@ Existing Windows PowerShell users are familiar with the large number of modules available, however, they are not necessarily compatible with PowerShell Core. More information regarding compatibility is in a [blog post](https://blogs.msdn.microsoft.com/powershell/2017/07/14/powershell-6-0-roadmap-coreclr-backwards-compatibility-and-more/). -Windows PowerShell 5.1 is based on .Net Framework 4.6.1, while PowerShell Core is based on .Net Core 2.0. +Windows PowerShell 5.1 is based on .Net Framework 4.6.1, while PowerShell Core is based on .Net Core 2.x. Although both adhere to .Net Standard 2.0 and can be compatible, some modules may be using APIs or cmdlets not supported on CoreCLR or using APIs from Windows PowerShell that have been deprecated and removed from PowerShell Core (for example, PSSnapins). ## Importing a Windows PowerShell module diff --git a/demos/crontab/CronTab/CronTab.psd1 b/demos/crontab/CronTab/CronTab.psd1 index 02374b1d7917..df7d81494204 100755 --- a/demos/crontab/CronTab/CronTab.psd1 +++ b/demos/crontab/CronTab/CronTab.psd1 @@ -13,10 +13,10 @@ CompatiblePSEditions = @('Core') GUID = '508bb97f-de2e-482e-aae2-01caec0be8c7' # Author of this module -Author = 'Microsoft' +Author = 'PowerShell' # Company or vendor of this module -CompanyName = 'Unknown' +CompanyName = 'Microsoft Corporation' # Copyright statement for this module Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.' diff --git a/demos/crontab/CronTab/CronTab.psm1 b/demos/crontab/CronTab/CronTab.psm1 index ee90c69f7823..15fedb520703 100644 --- a/demos/crontab/CronTab/CronTab.psm1 +++ b/demos/crontab/CronTab/CronTab.psm1 @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. using namespace System.Collections.Generic using namespace System.Management.Automation diff --git a/demos/crontab/crontab.ps1 b/demos/crontab/crontab.ps1 index f0ef43376aec..72cc084d41e6 100644 --- a/demos/crontab/crontab.ps1 +++ b/demos/crontab/crontab.ps1 @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. Import-Module $PSScriptRoot/CronTab/CronTab.psd1 diff --git a/demos/dsc.ps1 b/demos/dsc.ps1 index 27e09f29e469..8f93dd507c31 100644 --- a/demos/dsc.ps1 +++ b/demos/dsc.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + # DSC MOF Compilation # DSC Configuration() script that: # Defines base configuration users, groups, settings @@ -8,4 +11,4 @@ # Show the .ps1 # Run the .ps1 to generate a MOF # Apply the MOF locally with Start-DSCConfiguration -# Show the newly configured state \ No newline at end of file +# Show the newly configured state diff --git a/demos/install/README.md b/demos/install/README.md deleted file mode 100644 index 94a780644a54..000000000000 --- a/demos/install/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Install demo - -For Windows refer to the [installation instructions](https://github.com/PowerShell/PowerShell/blob/master/docs/installation/windows.md). - -For Linux, using [`install-powershell.sh`](https://github.com/PowerShell/PowerShell/blob/master/tools/install-powershell-readme.md) is the best way to deploy PowerShell bits. diff --git a/demos/powershellget/PowerShellGet.ps1 b/demos/powershellget/PowerShellGet.ps1 index 67032152418f..0dc33f85c465 100644 --- a/demos/powershellget/PowerShellGet.ps1 +++ b/demos/powershellget/PowerShellGet.ps1 @@ -1,4 +1,7 @@ -#region find, install, update, uninstall the PowerShell scripts from an online repository. +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +#region find, install, update, uninstall the PowerShell scripts from an online repository. # Value: equivalent of pypi # List of PowerShellGet commands @@ -74,4 +77,4 @@ Set-PSRepository -Name "myPrivateGallery" -InstallationPolicy "Untrusted" # Remove a private feed Unregister-PSRepository -Name "myPrivateGallery" -#endregion \ No newline at end of file +#endregion diff --git a/demos/python/README.md b/demos/python/README.md index 66ec4862d7a6..d2d1486e2fe6 100644 --- a/demos/python/README.md +++ b/demos/python/README.md @@ -1,8 +1,8 @@ -## PowerShell/Python Interoperation Demo +# PowerShell/Python Interoperation Demo -The "demo_script.ps1" file in this directory walks through a +The `demo_script.ps1` file in this directory walks through a demonstration of basic interoperation between PowerShell and Python including how to use JSON to exchange structured objects between Python and PowerShell. -The other files in this directory are referenced by demo_script.ps1. +The other files in this directory are referenced by `demo_script.ps1`. diff --git a/demos/python/class1.ps1 b/demos/python/class1.ps1 index 16b426a91db4..291677fd9483 100644 --- a/demos/python/class1.ps1 +++ b/demos/python/class1.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + # # Wrap Python script in such a way to make it easy to # consume from PowerShell diff --git a/demos/python/class1.py b/demos/python/class1.py index 23209a9208ad..ad9234494555 100755 --- a/demos/python/class1.py +++ b/demos/python/class1.py @@ -4,7 +4,9 @@ # Define a class with a method that returns JSON class returnsjson: - def method1(this): + def __init__(self): + the_object = self + def method1(self): return json.dumps(['foo', { 'bar': ('baz', None, 1.0, 2), @@ -14,5 +16,4 @@ def method1(this): 1,2,3]) c = returnsjson() -print (c.method1()) - +print(c.method1()) diff --git a/demos/python/demo_script.ps1 b/demos/python/demo_script.ps1 index 0544efe15e50..586e14a2085b 100644 --- a/demos/python/demo_script.ps1 +++ b/demos/python/demo_script.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + # # Demo simple interoperation between PowerShell and Python @@ -55,7 +58,6 @@ cat inline_python.ps1 # and run it ./inline_python - #################################### # cleanup rm hi diff --git a/demos/python/inline_python.ps1 b/demos/python/inline_python.ps1 index c9026304c91f..fdad32a8601a 100644 --- a/demos/python/inline_python.ps1 +++ b/demos/python/inline_python.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + # # An example showing inline Python code in a PowerShell script # diff --git a/demos/rest/rest.ps1 b/demos/rest/rest.ps1 index 59bea0ce0d49..db9867e8d287 100644 --- a/demos/rest/rest.ps1 +++ b/demos/rest/rest.ps1 @@ -1,4 +1,6 @@ - +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + #----------------- function Get-Issue diff --git a/docker/InstallTarballPackage.sh b/docker/InstallTarballPackage.sh index 1bc807a0b92d..08c7923c6ebf 100644 --- a/docker/InstallTarballPackage.sh +++ b/docker/InstallTarballPackage.sh @@ -3,24 +3,21 @@ # Exit on errors set -e -# # Example use: # ./InstallTarballPackage.sh "6.0.0-beta.9" "powershell-6.0.0-beta.9-linux-x64.tar.gz" -# + usage() { echo "usage: $0 " exit 1 } POWERSHELL_VERSION=$1 -if [ ! "$POWERSHELL_VERSION" ] -then +if [ ! "$POWERSHELL_VERSION" ]; then usage fi POWERSHELL_PACKAGE=$2 -if [ ! "$POWERSHELL_PACKAGE" ] -then +if [ ! "$POWERSHELL_PACKAGE" ]; then usage fi @@ -37,7 +34,7 @@ tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/$POWERSHELL_VERSION # Create the symbolic link that points to powershell ln -s /opt/microsoft/powershell/$POWERSHELL_VERSION/pwsh $POWERSHELL_LINKFILE # Add the symbolic link path to /etc/shells -if [ ! -f /etc/shells ] ; then +if [ ! -f /etc/shells ]; then echo $POWERSHELL_LINKFILE > /etc/shells ; else grep -q "^${POWERSHELL_LINKFILE}$" /etc/shells || echo $POWERSHELL_LINKFILE >> /etc/shells ; diff --git a/docker/README.md b/docker/README.md index ebe45dbecda1..b1adf71bde29 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,165 +1,3 @@ # Docker -These DockerFiles enable running PowerShell in a container for each Linux distribution we support. - -This requires an up-to-date version of Docker, such as 1.12. -It also expects you to be able to run Docker without `sudo`. -Please follow [Docker's official instructions][install] to install `docker` correctly. - -[install]: https://docs.docker.com/engine/installation/ - -## Release - -The release containers derive from the official distribution image, -such as `centos:7`, then install dependencies, -and finally install the PowerShell package. - -These containers live at [hub.docker.com/r/microsoft/powershell][docker-release]. - -At about 440 megabytes, they are decently minimal, -with their size being the sum of the base image (200 megabytes) -plus the uncompressed package (120 megabytes), -and about 120 megabytes of .NET Core and bootstrapping dependencies. - -[docker-release]: https://hub.docker.com/r/microsoft/powershell/ - -## Community - -The docker files in the community folder were contributed by the community and are not yet officially supported. - -## Examples - -To run PowerShell from using a container: - -```sh -$ docker run -it microsoft/powershell -Unable to find image 'microsoft/powershell:latest' locally -latest: Pulling from microsoft/powershell -cad964aed91d: Already exists -3a80a22fea63: Already exists -50de990d7957: Already exists -61e032b8f2cb: Already exists -9f03ce1741bf: Already exists -adf6ad28fa0e: Pull complete -10db13a8ca02: Pull complete -75bdb54ff5ae: Pull complete -Digest: sha256:92c79c5fcdaf3027626643aef556344b8b4cbdaccf8443f543303319949c7f3a -Status: Downloaded newer image for microsoft/powershell:latest -PowerShell -Copyright (c) Microsoft Corporation. All rights reserved. - -PS /> Write-Host "Hello, World!" -Hello, World! -``` - -## Building the images - -The images are built with the [`docker image build`](https://docs.docker.com/engine/reference/commandline/image_build/) command. - -### Example - -```sh -PS /powershell/docker> cd ./release/ubuntu16.04/ -PS /powershell/docker/release/ubuntu16.04> docker image build -t ps-ubuntu.16.04 . -Sending build context to Docker daemon 3.072 kB -Step 1/12 : FROM ubuntu:xenial - ---> 7b9b13f7b9c0 -Step 2/12 : LABEL maintainer "PowerShell Team " - ---> Using cache - ---> c6515b7d596f -Step 3/12 : LABEL readme.md "https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" - ---> Using cache - ---> 721306ae4490 -Step 4/12 : LABEL description "This Dockerfile will install the latest release of PS." - ---> Using cache - ---> 80c06f5481d2 -Step 5/12 : RUN apt-get update && apt-get install -y --no-install-recommends apt-utils ca-certificates curl apt-transport-https locales && rm -rf /var/lib/apt/lists/* - ---> Using cache - ---> 2d08e2300fc9 -Step 6/12 : ENV LANG en_US.UTF-8 - ---> Using cache - ---> 6dfc363111c0 -Step 7/12 : ENV LC_ALL $LANG - ---> Using cache - ---> b7ef2cd3a7ed -Step 8/12 : RUN locale-gen $LANG && update-locale - ---> Using cache - ---> e75306ddf3e0 -Step 9/12 : RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - ---> Using cache - ---> f476b7be22a2 -Step 10/12 : RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list | tee /etc/apt/sources.list.d/microsoft.list - ---> Using cache - ---> 909ca8e33a3b -Step 11/12 : RUN apt-get update && apt-get install -y --no-install-recommends powershell - ---> Using cache - ---> f32b54204619 -Step 12/12 : ENTRYPOINT powershell - ---> Using cache - ---> ee667ad86a7b -Successfully built ee667ad86a7b -``` - -### Run the docker image you built - -```sh -PS /powershell/docker/release/ubuntu16.04> docker run -it ps-ubuntu.16.04 powershell -c '$psversiontable' - -Name Value ----- ----- -PSVersion 6.0.0-beta -PSEdition Core -BuildVersion 3.0.0.0 -CLRVersion -GitCommitId v6.0.0-beta.2 -OS Linux 4.9.27-moby #1 SMP Thu May 11 04:01:18 ... -Platform Unix -PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} -PSRemotingProtocolVersion 2.3 -SerializationVersion 1.1.0.1 -WSManStackVersion 3.0 - -``` - -## NanoServer-Insider Release Notes - -Please be sure to use a build from the Windows Insider program, either [Windows Server Insider](https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewserver) or the [Windows 10 Insider](https://insider.windows.com/GettingStarted), -as your Container host before trying to pull this image. Otherwise, pulling this image will **fail**. - -Read more about the changes coming to Nano Server in future releases of Windows Server Insider [here](https://docs.microsoft.com/en-us/windows-server/get-started/nano-in-semi-annual-channel). - -### This is pre-release software - -Windows Server Insider Preview builds may be substantially modified before they are commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here. -Some product features and functionality may require additional hardware or software. These builds are for testing purposes only. Microsoft is not obligated to provide any support services for this preview software. - -For more information see [Using Insider Container Images](https://github.com/Microsoft/Virtualization-Documentation/blob/live/virtualization/windowscontainers/quick-start/Using-Insider-Container-Images.md) -and [Build and run an application with or without .NET Core 2.0 or PowerShell Core 6](https://github.com/Microsoft/Virtualization-Documentation/blob/live/virtualization/windowscontainers/quick-start/Nano-RS3-.NET-Core-and-PS.md). - -### Known Issues - -#### PowerShell Get only works with CurrentUser Scope - -Due to [known issues with the nano-server-insider](https://github.com/Microsoft/Virtualization-Documentation/blob/live/virtualization/windowscontainers/quick-start/Insider-Known-Issues.md#build-16237), -you must specify `-Scope CurrentUser` when using `Install-Module`. Example: - -```PowerShell -Install-Module -Scope CurrentUser -``` - -#### Docker run requires full path - -> **Note:** this is fixed in `10.0.16257.1000` of the NanoServer-Insider build. The powershell version of this should be released soon. - -Due to [an issue with the container not picking up the path](https://github.com/Microsoft/Virtualization-Documentation/blob/live/virtualization/windowscontainers/quick-start/Insider-Known-Issues.md#build-16237), you must specify the path -when running a command on the command line. For example, you would expect to be able to run: - -```PowerShell -PS > docker run -it microsoft/nanoserver-insider-powershell powershell -c '$psversiontable' -``` - -but, in `nanoserver-insider-powershell` you must run: - -```PowerShell -PS > docker run -it microsoft/nanoserver-insider-powershell 'C:\program files\powershell\powershell' -c '$psversiontable' -``` +Dockerfiles to build the Docker images for PowerShell Core have been moved to [PowerShell/PowerShell-Docker](https://github.com/PowerShell/PowerShell-Docker). diff --git a/docker/community/amazonlinux/Dockerfile b/docker/community/amazonlinux/Dockerfile deleted file mode 100644 index 0f01e8837a9e..000000000000 --- a/docker/community/amazonlinux/Dockerfile +++ /dev/null @@ -1,55 +0,0 @@ -# Docker image file that describes an Amazon Linux image with PowerShell installed from PowerShell Release - -FROM amazonlinux:latest - -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG POWERSHELL_PACKAGE=powershell-6.0.0-rc.2-linux-x64.tar.gz -ARG IMAGE_NAME=microsoft/powershell:amazonlinux - -LABEL maintainer="PowerShell Team " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.version=${POWERSHELL_VERSION} \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -# Install dependencies and clean up -RUN yum install -y \ - curl \ - libunwind \ - libicu \ - libcurl \ - openssl \ - libuuid.x86_64 \ - && yum clean all - -# Get the InstallTarballPackage.sh script -ADD https://raw.githubusercontent.com/PowerShell/PowerShell/master/docker/InstallTarballPackage.sh /InstallTarballPackage.sh - -# Add execution permission -RUN chmod +x /InstallTarballPackage.sh - -# Install powershell from tarball package -RUN /InstallTarballPackage.sh $POWERSHELL_VERSION $POWERSHELL_PACKAGE - -# Remove the script -RUN rm -f /InstallTarballPackage.sh - -# Use PowerShell as the default shell -# Use array to avoid Docker prepending /bin/sh -c -CMD [ "pwsh" ] diff --git a/docker/community/archlinux/Dockerfile b/docker/community/archlinux/Dockerfile deleted file mode 100644 index 2ef0f170a8e5..000000000000 --- a/docker/community/archlinux/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -FROM archlinux/base AS build-env - -# Install requirements to bulid package -RUN pacman -Syuq --noconfirm base-devel git - -# makepkg won't run as root, so setup a user and folder to run it. -RUN useradd -m -g wheel build -RUN mkdir /build -RUN chown build:wheel /build -USER build -RUN ls -l -RUN git clone https://aur.archlinux.org/powershell-bin.git /build/powershell-bin -RUN cd /build/powershell-bin; \ - makepkg -s -RUN ls /build/powershell-bin - -FROM archlinux/base - -LABEL maintainer="PowerShell Community " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -COPY --from=build-env /build/powershell-bin/*.xz /powershell-package/ -RUN ls /powershell-package/* -RUN pacman -Syu --noconfirm libunwind; \ - pacman -U --noconfirm /powershell-package/*.xz diff --git a/docker/release/centos7/Dockerfile b/docker/release/centos7/Dockerfile deleted file mode 100644 index fe5333e7647c..000000000000 --- a/docker/release/centos7/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -# Docker image file that describes an Centos7 image with PowerShell installed from Microsoft YUM Repo - -FROM centos:7 - -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG IMAGE_NAME=microsoft/powershell:centos7 - -LABEL maintainer="PowerShell Team " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.version=${POWERSHELL_VERSION} \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -# Install dependencies and clean up -RUN yum install -y \ - curl \ - && yum clean all - -# Download and configure Microsoft Repository config file -RUN curl https://packages.microsoft.com/config/rhel/7/prod.repo | tee /etc/yum.repos.d/microsoft.repo - -# Install latest powershell from Microsoft YUM Repo -RUN yum install -y \ - powershell - -# Use PowerShell as the default shell -# Use array to avoid Docker prepending /bin/sh -c -CMD [ "pwsh" ] diff --git a/docker/release/fedora25/Dockerfile b/docker/release/fedora25/Dockerfile deleted file mode 100644 index 8bc5f4ddc995..000000000000 --- a/docker/release/fedora25/Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -# Docker image file that describes an fedora 25 image with PowerShell installed from Microsoft YUM Repo - -FROM fedora:25 - -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG IMAGE_NAME=microsoft/powershell:fedora25 - -LABEL maintainer="PowerShell Team " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.version=${POWERSHELL_VERSION} \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -# Install dependencies and clean up -RUN dnf install -y \ - curl \ - glibc-locale-source \ - && dnf clean all - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -# Download and configure Microsoft Repository config file -RUN curl https://packages.microsoft.com/config/rhel/7/prod.repo | tee /etc/yum.repos.d/microsoft.repo - -# Install latest powershell from Microsoft YUM Repo -RUN dnf install -y powershell - -# Use array to avoid Docker prepending /bin/sh -c -CMD [ "pwsh" ] diff --git a/docker/release/fedora26/Dockerfile b/docker/release/fedora26/Dockerfile deleted file mode 100644 index 3b3ddeb766c2..000000000000 --- a/docker/release/fedora26/Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -# Docker image file that describes an fedora 25 image with PowerShell installed from Microsoft YUM Repo - -FROM fedora:26 - -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG IMAGE_NAME=microsoft/powershell:fedora26 - -LABEL maintainer="PowerShell Team " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.version=${POWERSHELL_VERSION} \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -# Install dependencies and clean up -RUN dnf install -y \ - curl \ - glibc-locale-source \ - && dnf clean all - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -# Download and configure Microsoft Repository config file -RUN curl https://packages.microsoft.com/config/rhel/7/prod.repo | tee /etc/yum.repos.d/microsoft.repo - -# Install latest powershell from Microsoft YUM Repo -RUN dnf install -y powershell - -# Use array to avoid Docker prepending /bin/sh -c -CMD [ "pwsh" ] diff --git a/docker/release/nanoserver/Dockerfile b/docker/release/nanoserver/Dockerfile deleted file mode 100755 index 186a6b486d9f..000000000000 --- a/docker/release/nanoserver/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -# escape=` -# Args used by from statements must be defined here: -ARG NanoServerVersion=1709 -ARG WindowsServerCoreVersion=latest -ARG WindowsServerCoreRepo=microsoft/windowsservercore -ARG NanoServerRepo=microsoft/nanoserver - -# Use server core as an installer container to extract PowerShell, -# As this is a multi-stage build, this stage will eventually be thrown away -FROM ${WindowsServerCoreRepo}:$WindowsServerCoreVersion AS installer-env - -# Arguments for installing powershell, must be defined in the container they are used -ARG PS_VERSION=6.0.0-rc.2 - -ENV PS_DOWNLOAD_URL https://github.com/PowerShell/PowerShell/releases/download/v$PS_VERSION/PowerShell-$PS_VERSION-win-x64.zip - -SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] - -RUN if (!($env:PS_VERSION -match '^\d+\.\d+\.\d+(-\w+(\.\d+)?)?$' )) {throw ('PS_Version ({0}) must match the regex "^\d+\.\d+\.\d+(-\w+(\.\d+)?)?$"' -f $env:PS_VERSION)} -RUN Invoke-WebRequest $Env:PS_DOWNLOAD_URL -OutFile powershell.zip - -RUN Expand-Archive powershell.zip -DestinationPath \PowerShell - -# Install PowerShell into NanoServer -FROM ${NanoServerRepo}:$NanoServerVersion - -ARG VCS_REF="none" -ARG PS_VERSION=6.0.0-rc.2 -ARG IMAGE_NAME=microsoft/powershell - -LABEL maintainer="PowerShell Team " ` - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" ` - description="This Dockerfile will install the latest release of PS." ` - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" ` - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" ` - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" ` - org.label-schema.name="powershell" ` - org.label-schema.vcs-ref=${VCS_REF} ` - org.label-schema.vendor="PowerShell" ` - org.label-schema.version=${PS_VERSION} ` - org.label-schema.schema-version="1.0" ` - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" ` - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" ` - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" ` - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# Copy Powershell Core from the installer containter -ENV ProgramFiles C:\Program Files -COPY --from=installer-env ["\\PowerShell\\", "$ProgramFiles\\PowerShell"] - -# Persist %PSCORE% ENV variable for user convenience -ENV PSCORE="$ProgramFiles\PowerShell\pwsh.exe" - -# Set the path -RUN setx PATH "%PATH%;%ProgramFiles%\PowerShell" - -CMD ["pwsh.exe"] diff --git a/docker/release/opensuse42.2/Dockerfile b/docker/release/opensuse42.2/Dockerfile deleted file mode 100644 index cbb8fea87c5d..000000000000 --- a/docker/release/opensuse42.2/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -# Docker image file that describes an OpenSUSE 42.2 image with PowerShell installed from PowerShell Release - -FROM opensuse:42.2 - -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG POWERSHELL_PACKAGE=powershell-6.0.0-rc.2-linux-x64.tar.gz -ARG IMAGE_NAME=microsoft/powershell:opensuse42.2 - -LABEL maintainer="PowerShell Team " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.version=${POWERSHELL_VERSION} \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -# Update, Install packages to generate localedef and CURL which is used by RPM -# add the Microsoft key as trusted to install packgages using RPM -# Install PowerShell then clean up -RUN zypper --non-interactive update --skip-interactive \ - && zypper --non-interactive install \ - glibc-locale \ - glibc-i18ndata \ - tar \ - curl \ - libunwind \ - libicu \ - openssl \ - && zypper --non-interactive clean --all - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -# Get the InstallTarballPackage.sh script -ADD https://raw.githubusercontent.com/PowerShell/PowerShell/master/docker/InstallTarballPackage.sh /InstallTarballPackage.sh - -# Add execution permission -RUN chmod +x /InstallTarballPackage.sh - -# Install powershell from tarball package -RUN /InstallTarballPackage.sh $POWERSHELL_VERSION $POWERSHELL_PACKAGE - -# Remove the script -RUN rm -f /InstallTarballPackage.sh - -CMD [ "pwsh" ] diff --git a/docker/release/ubuntu14.04/Dockerfile b/docker/release/ubuntu14.04/Dockerfile deleted file mode 100644 index 6a7da8388f3c..000000000000 --- a/docker/release/ubuntu14.04/Dockerfile +++ /dev/null @@ -1,52 +0,0 @@ -# Docker image file that describes an Ubuntu14.04 image with PowerShell installed from Microsoft APT Repo - -FROM ubuntu:trusty - -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG IMAGE_NAME=microsoft/powershell:ubuntu14.04 - -LABEL maintainer="PowerShell Team " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.version=${POWERSHELL_VERSION} \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN locale-gen $LANG && update-locale - -# Install dependencies and clean up -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - ca-certificates \ - curl \ - apt-transport-https \ - && rm -rf /var/lib/apt/lists/* - -# Import the public repository GPG keys for Microsoft -RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - -# Register the Microsoft Ubuntu 14.04 repository -RUN curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | tee /etc/apt/sources.list.d/microsoft.list - -# Install powershell from Microsoft Repo -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - powershell - -# Use PowerShell as the default shell -# Use array to avoid Docker prepending /bin/sh -c -CMD [ "pwsh" ] diff --git a/docker/release/ubuntu16.04/Dockerfile b/docker/release/ubuntu16.04/Dockerfile deleted file mode 100644 index e38b62fca80e..000000000000 --- a/docker/release/ubuntu16.04/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -# Docker image file that describes an Ubuntu16.04 image with PowerShell installed from Microsoft APT Repo - -FROM ubuntu:xenial - -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG IMAGE_NAME=microsoft/powershell:ubuntu16.04 - -LABEL maintainer="PowerShell Team " \ - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - description="This Dockerfile will install the latest release of PS." \ - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" \ - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" \ - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" \ - org.label-schema.name="powershell" \ - org.label-schema.vendor="PowerShell" \ - org.label-schema.version=${POWERSHELL_VERSION} \ - org.label-schema.schema-version="1.0" \ - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" \ - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" \ - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" \ - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -# Install dependencies and clean up -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - ca-certificates \ - curl \ - apt-transport-https \ - locales\ - && rm -rf /var/lib/apt/lists/* - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN locale-gen $LANG && update-locale - -# Import the public repository GPG keys for Microsoft -RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - -# Register the Microsoft Ubuntu 16.04 repository -RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list | tee /etc/apt/sources.list.d/microsoft.list - -# Install powershell from Microsoft Repo -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - powershell - -# Use PowerShell as the default shell -# Use array to avoid Docker prepending /bin/sh -c -CMD [ "pwsh" ] diff --git a/docker/release/windowsservercore/Dockerfile b/docker/release/windowsservercore/Dockerfile deleted file mode 100644 index 5a90668dbe17..000000000000 --- a/docker/release/windowsservercore/Dockerfile +++ /dev/null @@ -1,61 +0,0 @@ -# escape=` -FROM microsoft/windowsservercore:latest - -ARG POWERSHELL_MSI=https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/PowerShell-6.0.0-rc.2-win-x64.msi -ARG POWERSHELL_VERSION=6.0.0-rc.2 -ARG IMAGE_NAME=microsoft/powershell:windowsservercore - -LABEL maintainer="PowerShell Team " ` - readme.md="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" ` - description="This Dockerfile will install the latest release of PS." ` - org.label-schema.usage="https://github.com/PowerShell/PowerShell/tree/master/docker#run-the-docker-image-you-built" ` - org.label-schema.url="https://github.com/PowerShell/PowerShell/blob/master/docker/README.md" ` - org.label-schema.vcs-url="https://github.com/PowerShell/PowerShell" ` - org.label-schema.name="powershell" ` - org.label-schema.vendor="PowerShell" ` - org.label-schema.version=${POWERSHELL_VERSION} ` - org.label-schema.schema-version="1.0" ` - org.label-schema.docker.cmd="docker run ${IMAGE_NAME} pwsh -c '$psversiontable'" ` - org.label-schema.docker.cmd.devel="docker run ${IMAGE_NAME}" ` - org.label-schema.docker.cmd.test="docker run ${IMAGE_NAME} pwsh -c Invoke-Pester" ` - org.label-schema.docker.cmd.help="docker run ${IMAGE_NAME} pwsh -c Get-Help" - -# TODO: addd LABEL org.label-schema.vcs-ref=${VCS_REF} - -RUN setx /M PATH "%ProgramFiles%\PowerShell\latest;%PATH%" -# Setup PowerShell - Log-to > C:\Docker.log -SHELL ["C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "-command"] -ADD $POWERSHELL_MSI /PowerShell-win-x64.msi - -# Install PowerShell package and clean up -RUN $ErrorActionPreference='Stop'; ` - $ConfirmPreference='None'; ` - $VerbosePreference='Continue'; ` - Start-Transcript -path C:\Dockerfile.log -append -IncludeInvocationHeader ; ` - $PSVersionTable | Write-Output ; ` - $VerInfo = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' ; ` - ('FullBuildString: '+$VerInfo.BuildLabEx) | Write-Output ; ` - ('OperatingSystem: '+$VerInfo.ProductName+' '+$VerInfo.EditionId+' '+$VerInfo.InstallationType) | Write-Output ; ` - [System.IO.FileInfo]$MsiFile = Get-Item -Path ./PowerShell-win-x64.msi ; ` - Start-Process -FilePath msiexec.exe -ArgumentList '-qn','-i c:\PowerShell-win-x64.msi', ` - '-log c:\PowerShell-win-x64.msi.log','-norestart' -wait ; ` - $log=get-content -Path C:\PowerShell-win-x64.msi.log -Last 10 ; ` - if ($log -match 'Installation success or error status: 0') { ` - Remove-Item -Path $MsiFile ; ` - $psexe=Get-Item -Path $Env:ProgramFiles\PowerShell\*\pwsh.exe ; ` - New-Item -Type SymbolicLink -Path $Env:ProgramFiles\PowerShell\ -Name latest -Value $psexe.DirectoryName ` - } else { throw 'Installation failed! See c:\PowerShell-win-x64.msi.log' } ; - -# Verify New pwsh.exe runs -SHELL ["C:\\Program Files\\PowerShell\\latest\\pwsh.exe", "-command"] -RUN Start-Transcript -path C:\Dockerfile.log -append -IncludeInvocationHeader ; ` - $ErrorActionPreference='Stop'; ` - Write-Output $PSVersionTable ; ` - If (-not($PSVersionTable.PSEdition -Match 'Core')) { ` - Throw [String]$('['+$PSVersionTable.PSEdition+'] is not [Core]!') ; ` - } ; - -# Persist %PSCORE% ENV variable for user convenience -ENV PSCORE='"C:\Program Files\PowerShell\latest\pwsh.exe"' - -CMD ["pwsh.exe"] diff --git a/docker/tests/README.md b/docker/tests/README.md index f43ec7b51aa4..716a7d6f62e1 100644 --- a/docker/tests/README.md +++ b/docker/tests/README.md @@ -10,7 +10,7 @@ The tests must be run separately on the Windows and Linux docker daemons. You ca Invoke-Pester ``` -Note: be sure to do this using both the Windows and Linux docker daemon, as the windows. +Note: be sure to do this using both the Windows and Linux docker daemon. ## To test the productions containers diff --git a/docker/tests/Templates/centos7/Dockerfile b/docker/tests/Templates/centos7/Dockerfile index fc755dde23b2..dddf24394459 100644 --- a/docker/tests/Templates/centos7/Dockerfile +++ b/docker/tests/Templates/centos7/Dockerfile @@ -1,9 +1,10 @@ FROM centos:7 -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" # Install dependencies RUN yum install -y \ @@ -16,7 +17,7 @@ ENV LANG en_US.UTF-8 ENV LC_ALL $LANG RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG -RUN curl -L -o powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm $PACKAGELOCATIONSTUB/powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm -RUN yum install -y powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" +RUN curl -L -o $PACKAGENAME $PACKAGELOCATION/$PACKAGENAME \ + && yum install -y $PACKAGENAME +RUN $TESTDOWNLOADCOMMAND +RUN pwsh$PREVIEWSUFFIX -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/debian.8/Dockerfile b/docker/tests/Templates/debian.8/Dockerfile deleted file mode 100644 index 31a599715ce2..000000000000 --- a/docker/tests/Templates/debian.8/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM debian:jessie - -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB - -# Install dependencies -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - ca-certificates \ - curl \ - apt-transport-https \ - locales \ - git - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN locale-gen $LANG && update-locale - -RUN curl -L -o powershell_$PSVERSIONSTUB-1.debian.8_amd64.deb $PACKAGELOCATIONSTUB/powershell_$PSVERSIONSTUB-1.debian.8_amd64.deb -RUN dpkg -i powershell_$PSVERSIONSTUB-1.debian.8_amd64.deb || : -RUN apt-get install -y -f -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" diff --git a/docker/tests/Templates/debian.9/Dockerfile b/docker/tests/Templates/debian.9/Dockerfile index b64d6891aabe..f2de0f8d61fe 100644 --- a/docker/tests/Templates/debian.9/Dockerfile +++ b/docker/tests/Templates/debian.9/Dockerfile @@ -1,9 +1,10 @@ FROM debian:stretch -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" # Install dependencies RUN apt-get update \ @@ -13,15 +14,16 @@ RUN apt-get update \ curl \ apt-transport-https \ locales \ - git + git \ + && apt-get clean # Setup the locale ENV LANG en_US.UTF-8 ENV LC_ALL $LANG RUN locale-gen $LANG && update-locale -RUN curl -L -o powershell_$PSVERSIONSTUB-1.debian.9_amd64.deb $PACKAGELOCATIONSTUB/powershell_$PSVERSIONSTUB-1.debian.9_amd64.deb -RUN dpkg -i powershell_$PSVERSIONSTUB-1.debian.9_amd64.deb || : -RUN apt-get install -y -f -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" +RUN curl -L -o $PACKAGENAME $PACKAGELOCATION/$PACKAGENAME +RUN dpkg -i $PACKAGENAME || : +RUN apt-get install -y -f --no-install-recommends +RUN $TESTDOWNLOADCOMMAND +RUN pwsh$PREVIEWSUFFIX -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fedora25/Dockerfile b/docker/tests/Templates/fedora25/Dockerfile deleted file mode 100644 index c82d129f8936..000000000000 --- a/docker/tests/Templates/fedora25/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM fedora:25 - -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB - -# Install dependencies -RUN dnf install -y \ - curl \ - glibc-locale-source \ - git - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -RUN curl -L -o powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm $PACKAGELOCATIONSTUB/powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm -RUN dnf install -y powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" diff --git a/docker/tests/Templates/fedora26/Dockerfile b/docker/tests/Templates/fedora26/Dockerfile deleted file mode 100644 index d786307b3163..000000000000 --- a/docker/tests/Templates/fedora26/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM fedora:26 - -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB - -# Install dependencies -RUN dnf install -y \ - curl \ - glibc-locale-source \ - compat-openssl10 \ - git - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -RUN curl -L -o powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm $PACKAGELOCATIONSTUB/powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm -RUN dnf install -y powershell-$PSVERSIONSTUBRPM-1.rhel.7.x86_64.rpm -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" diff --git a/docker/tests/Templates/fedora28/Dockerfile b/docker/tests/Templates/fedora28/Dockerfile new file mode 100644 index 000000000000..9c9f958f54dd --- /dev/null +++ b/docker/tests/Templates/fedora28/Dockerfile @@ -0,0 +1,26 @@ +FROM fedora:28 + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN dnf install -y \ + curl \ + glibc-locale-source \ + git \ + compat-openssl10 \ + && dnf upgrade-minimal -y --security \ + && dnf clean all + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG + +RUN curl -L -o $PACKAGENAME $PACKAGELOCATION/$PACKAGENAME +RUN dnf install -y $PACKAGENAME +RUN $TESTDOWNLOADCOMMAND +RUN pwsh$PREVIEWSUFFIX -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fxdependent-centos7/Dockerfile b/docker/tests/Templates/fxdependent-centos7/Dockerfile new file mode 100644 index 000000000000..10cde0cd125e --- /dev/null +++ b/docker/tests/Templates/fxdependent-centos7/Dockerfile @@ -0,0 +1,31 @@ +FROM centos:7 + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN yum install -y \ + glibc-locale-source \ + git + +# Install dotnet-runtime +RUN rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm +RUN yum install -y \ + dotnet-runtime-2.1 + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG + +# Install PowerShell package +ADD $PACKAGELOCATION/$PACKAGENAME . +RUN mkdir -p /opt/microsoft/powershell +RUN tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Download and run tests +RUN $TESTDOWNLOADCOMMAND +RUN dotnet /opt/microsoft/powershell/pwsh.dll -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fxdependent-debian.9/Dockerfile b/docker/tests/Templates/fxdependent-debian.9/Dockerfile new file mode 100644 index 000000000000..2d7beff913bb --- /dev/null +++ b/docker/tests/Templates/fxdependent-debian.9/Dockerfile @@ -0,0 +1,31 @@ +FROM microsoft/dotnet:2.1.7-runtime-stretch-slim + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-utils \ + ca-certificates \ + apt-transport-https \ + locales \ + git \ + && apt-get clean + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN locale-gen $LANG && update-locale + +# Install PowerShell package +ADD $PACKAGELOCATION/$PACKAGENAME . +RUN mkdir -p /opt/microsoft/powershell +RUN tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Download and run tests +RUN $TESTDOWNLOADCOMMAND +RUN dotnet /opt/microsoft/powershell/pwsh.dll -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fxdependent-dotnetsdk-latest/Dockerfile b/docker/tests/Templates/fxdependent-dotnetsdk-latest/Dockerfile new file mode 100644 index 000000000000..cf56e4ec0744 --- /dev/null +++ b/docker/tests/Templates/fxdependent-dotnetsdk-latest/Dockerfile @@ -0,0 +1,31 @@ +FROM microsoft/dotnet:3.0.100-preview-sdk + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-utils \ + ca-certificates \ + apt-transport-https \ + locales \ + git \ + && apt-get clean + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN locale-gen $LANG && update-locale + +# Install PowerShell package +ADD $PACKAGELOCATION/$PACKAGENAME . +RUN mkdir -p /opt/microsoft/powershell \ + && tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Download and run tests +RUN $TESTDOWNLOADCOMMAND +RUN dotnet /opt/microsoft/powershell/pwsh.dll -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fxdependent-fedora28/Dockerfile b/docker/tests/Templates/fxdependent-fedora28/Dockerfile new file mode 100644 index 000000000000..6acb74524465 --- /dev/null +++ b/docker/tests/Templates/fxdependent-fedora28/Dockerfile @@ -0,0 +1,38 @@ +FROM fedora:28 + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN dnf install -y \ + glibc-locale-source \ + git \ + compat-openssl10 \ + && dnf upgrade-minimal -y --security \ + && dnf clean all + +# Install dotnet-runtime +RUN rpm --import https://packages.microsoft.com/keys/microsoft.asc +ADD https://packages.microsoft.com/config/fedora/27/prod.repo . +RUN mv prod.repo /etc/yum.repos.d/microsoft-prod.repo +RUN dnf install -y \ + dotnet-runtime-2.1 \ + && dnf upgrade-minimal -y --security \ + && dnf clean all + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG + +# Install PowerShell package +ADD $PACKAGELOCATION/$PACKAGENAME . +RUN mkdir -p /opt/microsoft/powershell \ + && tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Download and run tests +RUN $TESTDOWNLOADCOMMAND +RUN dotnet /opt/microsoft/powershell/pwsh.dll -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fxdependent-opensuse42.3/Dockerfile b/docker/tests/Templates/fxdependent-opensuse42.3/Dockerfile new file mode 100644 index 000000000000..74b4bc98256a --- /dev/null +++ b/docker/tests/Templates/fxdependent-opensuse42.3/Dockerfile @@ -0,0 +1,41 @@ +FROM opensuse:42.3 + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN zypper --non-interactive update --skip-interactive \ + && zypper --non-interactive install \ + glibc-locale \ + glibc-i18ndata \ + tar \ + libunwind \ + libicu \ + openssl \ + git + +# Install dotnet-runtime +ADD https://packages.microsoft.com/keys/microsoft.asc . +RUN rpmkeys --import microsoft.asc +ADD https://packages.microsoft.com/config/opensuse/42.2/prod.repo . +RUN mv prod.repo /etc/zypp/repos.d/microsoft-prod.repo +RUN zypper --non-interactive update --skip-interactive \ + && zypper --non-interactive install \ + dotnet-runtime-2.1 + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG + +# Install PowerShell package +ADD $PACKAGELOCATION/$PACKAGENAME . +RUN mkdir -p /opt/microsoft/powershell +RUN tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Download and run tests +RUN $TESTDOWNLOADCOMMAND +RUN dotnet /opt/microsoft/powershell/pwsh.dll -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fxdependent-ubuntu16.04/Dockerfile b/docker/tests/Templates/fxdependent-ubuntu16.04/Dockerfile new file mode 100644 index 000000000000..aa976ddb19e9 --- /dev/null +++ b/docker/tests/Templates/fxdependent-ubuntu16.04/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:xenial + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-utils \ + ca-certificates \ + apt-transport-https \ + locales \ + git \ + && apt-get clean + +# Install dotnet-runtime +ADD https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb . +RUN dpkg -i packages-microsoft-prod.deb +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + dotnet-runtime-2.1 \ + && apt-get clean + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN locale-gen $LANG && update-locale + +# Install PowerShell package +ADD $PACKAGELOCATION/$PACKAGENAME . +RUN mkdir -p /opt/microsoft/powershell \ + && tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Download and run tests +RUN $TESTDOWNLOADCOMMAND +RUN dotnet /opt/microsoft/powershell/pwsh.dll -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/fxdependent-ubuntu18.04/Dockerfile b/docker/tests/Templates/fxdependent-ubuntu18.04/Dockerfile new file mode 100644 index 000000000000..adc9219a07d8 --- /dev/null +++ b/docker/tests/Templates/fxdependent-ubuntu18.04/Dockerfile @@ -0,0 +1,31 @@ +FROM microsoft/dotnet:2.1.7-runtime-bionic + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-utils \ + ca-certificates \ + apt-transport-https \ + locales \ + git \ + && apt-get clean + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN locale-gen $LANG && update-locale + +# Install PowerShell package +ADD $PACKAGELOCATION/$PACKAGENAME . +RUN mkdir -p /opt/microsoft/powershell \ + && tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Download and run tests +RUN $TESTDOWNLOADCOMMAND +RUN dotnet /opt/microsoft/powershell/pwsh.dll -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/kalilinux/Dockerfile b/docker/tests/Templates/kalilinux/Dockerfile deleted file mode 100644 index f97424c0c6ad..000000000000 --- a/docker/tests/Templates/kalilinux/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM kalilinux/kali-linux-docker:latest - -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB - -# Install dependencies -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - ca-certificates \ - curl \ - apt-transport-https \ - locales \ - git - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN locale-gen $LANG && update-locale - -RUN curl -L -o libssl1.0.0_1.0.1t-1+deb8u7_amd64.deb http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u7_amd64.deb -RUN curl -L -o powershell_$PSVERSIONSTUB-1.ubuntu.16.04_amd64.deb $PACKAGELOCATIONSTUB/powershell_$PSVERSIONSTUB-1.ubuntu.16.04_amd64.deb -RUN dpkg -i libssl1.0.0_1.0.1t-1+deb8u7_amd64.deb || : -RUN dpkg -i powershell_$PSVERSIONSTUB-1.ubuntu.16.04_amd64.deb || : -RUN apt-get install -y -f -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" diff --git a/docker/tests/Templates/opensuse42.2/Dockerfile b/docker/tests/Templates/opensuse42.2/Dockerfile deleted file mode 100644 index d44cbb32ff50..000000000000 --- a/docker/tests/Templates/opensuse42.2/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM opensuse:42.2 - -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB - -ARG POWERSHELL_LINKFILE=/usr/bin/pwsh - -# Install dependencies -RUN zypper --non-interactive update --skip-interactive \ - && zypper --non-interactive install \ - glibc-locale \ - glibc-i18ndata \ - tar \ - curl \ - libunwind \ - libicu \ - openssl \ - git - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG - -RUN curl -L -o powershell-$PSVERSIONSTUB-linux-x64.tar.gz $PACKAGELOCATIONSTUB/powershell-$PSVERSIONSTUB-linux-x64.tar.gz - -# Create the target folder where powershell will be placed -RUN mkdir -p /opt/microsoft/powershell/$PSVERSIONSTUB -# Expand powershell to the target folder -RUN tar zxf powershell-$PSVERSIONSTUB-linux-x64.tar.gz -C /opt/microsoft/powershell/$PSVERSIONSTUB - -# Create the symbolic link that points to powershell -RUN ln -s /opt/microsoft/powershell/$PSVERSIONSTUB/pwsh $POWERSHELL_LINKFILE - -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" diff --git a/docker/tests/Templates/opensuse42.3/Dockerfile b/docker/tests/Templates/opensuse42.3/Dockerfile new file mode 100644 index 000000000000..d401e611382b --- /dev/null +++ b/docker/tests/Templates/opensuse42.3/Dockerfile @@ -0,0 +1,39 @@ +FROM opensuse:42.3 + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +ARG POWERSHELL_LINKFILE=/usr/bin/pwsh + +# Install dependencies +RUN zypper --non-interactive update --skip-interactive \ + && zypper --non-interactive install \ + glibc-locale \ + glibc-i18ndata \ + tar \ + curl \ + libunwind \ + libicu \ + openssl \ + git + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN localedef --charmap=UTF-8 --inputfile=en_US $LANG + +RUN curl -L -o $PACKAGENAME $PACKAGELOCATION/$PACKAGENAME + +# Create the target folder where powershell will be placed +RUN mkdir -p /opt/microsoft/powershell +# Expand powershell to the target folder +RUN tar zxf $PACKAGENAME -C /opt/microsoft/powershell + +# Create the symbolic link that points to powershell +RUN ln -s /opt/microsoft/powershell/pwsh $POWERSHELL_LINKFILE + +RUN $TESTDOWNLOADCOMMAND +RUN pwsh -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/ubuntu14.04/Dockerfile b/docker/tests/Templates/ubuntu14.04/Dockerfile deleted file mode 100644 index 181610b6c282..000000000000 --- a/docker/tests/Templates/ubuntu14.04/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ubuntu:trusty - -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB - -# Install dependencies -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - ca-certificates \ - curl \ - apt-transport-https \ - locales \ - git - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN locale-gen $LANG && update-locale - -RUN curl -L -o powershell_$PSVERSIONSTUB-1.ubuntu.14.04_amd64.deb $PACKAGELOCATIONSTUB/powershell_$PSVERSIONSTUB-1.ubuntu.14.04_amd64.deb -RUN dpkg -i powershell_$PSVERSIONSTUB-1.ubuntu.14.04_amd64.deb || : -RUN apt-get install -y -f -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" diff --git a/docker/tests/Templates/ubuntu16.04/Dockerfile b/docker/tests/Templates/ubuntu16.04/Dockerfile index 211e6d974e58..7439eda5a7dc 100644 --- a/docker/tests/Templates/ubuntu16.04/Dockerfile +++ b/docker/tests/Templates/ubuntu16.04/Dockerfile @@ -1,9 +1,10 @@ FROM ubuntu:xenial -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" # Install dependencies RUN apt-get update \ @@ -13,15 +14,16 @@ RUN apt-get update \ curl \ apt-transport-https \ locales \ - git + git \ + && apt-get clean # Setup the locale ENV LANG en_US.UTF-8 ENV LC_ALL $LANG RUN locale-gen $LANG && update-locale -RUN curl -L -o powershell_$PSVERSIONSTUB-1.ubuntu.16.04_amd64.deb $PACKAGELOCATIONSTUB/powershell_$PSVERSIONSTUB-1.ubuntu.16.04_amd64.deb -RUN dpkg -i powershell_$PSVERSIONSTUB-1.ubuntu.16.04_amd64.deb || : -RUN apt-get install -y -f -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" +RUN curl -L -o $PACKAGENAME $PACKAGELOCATION/$PACKAGENAME +RUN dpkg -i $PACKAGENAME || : +RUN apt-get install -y -f --no-install-recommends +RUN $TESTDOWNLOADCOMMAND +RUN pwsh$PREVIEWSUFFIX -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/Templates/ubuntu17.04/Dockerfile b/docker/tests/Templates/ubuntu17.04/Dockerfile deleted file mode 100644 index dae4b3fe0c0a..000000000000 --- a/docker/tests/Templates/ubuntu17.04/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ubuntu:zesty - -ARG PSVERSIONSTUB -ARG PSVERSIONSTUBRPM -ARG PACKAGELOCATIONSTUB -ARG TESTLISTSTUB - -# Install dependencies -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - ca-certificates \ - curl \ - apt-transport-https \ - locales \ - git - -# Setup the locale -ENV LANG en_US.UTF-8 -ENV LC_ALL $LANG -RUN locale-gen $LANG && update-locale - -RUN curl -L -o powershell_$PSVERSIONSTUB-1.ubuntu.17.04_amd64.deb $PACKAGELOCATIONSTUB/powershell_$PSVERSIONSTUB-1.ubuntu.17.04_amd64.deb -RUN dpkg -i powershell_$PSVERSIONSTUB-1.ubuntu.17.04_amd64.deb || : -RUN apt-get install -y -f -RUN git clone --recursive https://github.com/PowerShell/PowerShell.git -RUN pwsh -c "Import-Module /PowerShell/build.psm1;Restore-PSPester -Destination /usr/local/share/powershell/Modules;exit (Invoke-Pester $TESTLISTSTUB -PassThru).FailedCount" diff --git a/docker/tests/Templates/ubuntu18.04/Dockerfile b/docker/tests/Templates/ubuntu18.04/Dockerfile new file mode 100644 index 000000000000..6c7a960130dd --- /dev/null +++ b/docker/tests/Templates/ubuntu18.04/Dockerfile @@ -0,0 +1,29 @@ +FROM ubuntu:bionic + +ARG PACKAGENAME +ARG PACKAGELOCATION +ARG PREVIEWSUFFIX= +ARG TESTLIST=/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module +ARG TESTDOWNLOADCOMMAND="git clone --recursive https://github.com/PowerShell/PowerShell.git" + +# Install dependencies +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-utils \ + ca-certificates \ + curl \ + apt-transport-https \ + locales \ + git \ + && apt-get clean + +# Setup the locale +ENV LANG en_US.UTF-8 +ENV LC_ALL $LANG +RUN locale-gen $LANG && update-locale + +RUN curl -L -o $PACKAGENAME $PACKAGELOCATION/$PACKAGENAME +RUN dpkg -i $PACKAGENAME || : +RUN apt-get install -y -f --no-install-recommends +RUN $TESTDOWNLOADCOMMAND +RUN pwsh$PREVIEWSUFFIX -c "Import-Module /PowerShell/build.psm1;\$dir='/usr/local/share/powershell/Modules';\$null=New-Item -Type Directory -Path \$dir -ErrorAction SilentlyContinue;Restore-PSPester -Destination \$dir;exit (Invoke-Pester $TESTLIST -PassThru).FailedCount" diff --git a/docker/tests/container.tests.ps1 b/docker/tests/container.tests.ps1 deleted file mode 100644 index 0ee22870b039..000000000000 --- a/docker/tests/container.tests.ps1 +++ /dev/null @@ -1,104 +0,0 @@ -Import-module -Name "$PSScriptRoot\containerTestCommon.psm1" -Force -$script:linuxContainerTests = Get-LinuxContainer -$script:windowsContainerTests = Get-WindowsContainer -$script:skipLinux = Test-SkipLinux -$script:skipWindows = Test-SkipWindows - -Describe "Build Linux Containers" -Tags 'Build', 'Linux' { - BeforeAll { - Set-RepoName 'pscontainertest' - } - - it "$(Get-RepoName): builds from ''" -TestCases $script:linuxContainerTests -Skip:$script:skipLinux { - param( - [Parameter(Mandatory=$true)] - [string] - $name, - - [Parameter(Mandatory=$true)] - [string] - $path - ) - { Invoke-Docker -Command build -Params '--pull', '--quiet', '-t', "$(Get-RepoName):${Name}", $path -SuppressHostOutput} | should not throw - } -} - -Describe "Build Windows Containers" -Tags 'Build', 'Windows' { - BeforeAll { - Set-RepoName 'pscontainertest' - } - - it "$(Get-RepoName): builds from ''" -TestCases $script:windowsContainerTests -skip:$script:skipWindows { - param( - [Parameter(Mandatory=$true)] - [string] - $name, - - [Parameter(Mandatory=$true)] - [string] - $path - ) - - { Invoke-Docker -Command build -Params @( - '--pull' - '--quiet' - '-t' - "$(Get-RepoName):${Name}" - $path - ) -SuppressHostOutput} | should not throw - } -} - -Describe "Linux Containers run PowerShell" -Tags 'Behavior', 'Linux' { - BeforeAll{ - $testContext = Get-TestContext -type Linux - } - AfterAll{ - # prune unused volumes - $null=Invoke-Docker -Command 'volume', 'prune' -Params '--force' -SuppressHostOutput - } - BeforeEach - { - Remove-Item $testContext.resolvedXmlPath -ErrorAction SilentlyContinue - Remove-Item $testContext.resolvedLogPath -ErrorAction SilentlyContinue - } - - it "Get PSVersion table from $(Get-RepoName):" -TestCases $script:linuxContainerTests -Skip:$script:skipLinux { - param( - [Parameter(Mandatory=$true)] - [string] - $name, - - [Parameter(Mandatory=$true)] - [string] - $path - ) - - Get-ContainerPowerShellVersion -TestContext $testContext -Name $Name -RepoName (Get-RepoName) | should be '6.0.0-rc.2' - } -} - -Describe "Windows Containers run PowerShell" -Tags 'Behavior', 'Windows' { - BeforeAll{ - $testContext = Get-TestContext -type Windows - } - BeforeEach - { - Remove-Item $testContext.resolvedXmlPath -ErrorAction SilentlyContinue - Remove-Item $testContext.resolvedLogPath -ErrorAction SilentlyContinue - } - - it "Get PSVersion table from $(Get-RepoName):" -TestCases $script:windowsContainerTests -skip:$script:skipWindows { - param( - [Parameter(Mandatory=$true)] - [string] - $name, - - [Parameter(Mandatory=$true)] - [string] - $path - ) - - Get-ContainerPowerShellVersion -TestContext $testContext -Name $Name -RepoName (Get-RepoName) | should be '6.0.0-rc.2' - } -} diff --git a/docker/tests/containerTestCommon.psm1 b/docker/tests/containerTestCommon.psm1 index 37b3489172f5..4816812b6440 100644 --- a/docker/tests/containerTestCommon.psm1 +++ b/docker/tests/containerTestCommon.psm1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + $script:forcePull = $true # Get docker Engine OS function Get-DockerEngineOs @@ -65,14 +68,13 @@ function Invoke-Docker # Return a list of Linux Container Test Cases function Get-LinuxContainer { - foreach($os in 'centos7','ubuntu14.04','ubuntu16.04') + foreach($os in 'centos7','ubuntu16.04') { Write-Output @{ Name = $os Path = "$psscriptroot/../release/$os" } } - } # Return a list of Windows Container Test Cases @@ -87,7 +89,6 @@ function Get-WindowsContainer } } - $script:repoName = 'microsoft/powershell' function Get-RepoName { @@ -110,7 +111,27 @@ function Test-SkipWindows function Test-SkipLinux { - return !((Get-DockerEngineOs) -like 'Alpine Linux*') + $os = Get-DockerEngineOs + + switch -wildcard ($os) + { + '*Linux*' { + return $false + } + '*Mac' { + return $false + } + # Docker for Windows means we are running the linux kernel + 'Docker for Windows' { + return $false + } + 'Windows*' { + return $true + } + default { + throw "Unknown docker os '$os'" + } + } } function Get-TestContext @@ -191,6 +212,64 @@ function Get-ContainerPowerShellVersion return (Get-Content -Encoding Ascii $testContext.resolvedLogPath)[0] } +# Function defines a config mapping for testing Preview packages. +# The list of supported OS for each release can be found here: +# https://github.com/PowerShell/PowerShell-Docs/blob/staging/reference/docs-conceptual/PowerShell-Core-Support.md#supported-platforms +function Get-DefaultPreviewConfigForPackageValidation +{ + # format: = + @{ 'centos7'='rhel.7'; + 'debian.9'='debian.9'; + 'fedora28'='rhel.7'; + 'opensuse42.3'='linux-x64.tar.gz'; + 'ubuntu16.04'='ubuntu.16.04'; + 'ubuntu18.04'='ubuntu.18.04'; + 'fxdependent-centos7'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-debian.9'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-fedora28'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-opensuse42.3'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-ubuntu16.04'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-ubuntu18.04'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-dotnetsdk-latest'='linux-x64-fxd-dotnetsdk.tar.gz' + } +} + +# Function defines a config mapping for testing Stable packages. +# The list of supported OS for each release can be found here: +# https://github.com/PowerShell/PowerShell-Docs/blob/staging/reference/docs-conceptual/PowerShell-Core-Support.md#supported-platforms +function Get-DefaultStableConfigForPackageValidation +{ + # format: = + @{ 'centos7'='rhel.7'; + 'debian.9'='debian.9'; + 'opensuse42.3'='linux-x64.tar.gz'; + 'ubuntu16.04'='ubuntu.16.04'; + 'fxdependent-centos7'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-debian.9'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-opensuse42.3'='linux-x64-fxdependent.tar.gz'; + 'fxdependent-ubuntu16.04'='linux-x64-fxdependent.tar.gz' + } +} + +# Returns a list of files in a specified Azure container. +function Get-PackageNamesOnAzureBlob +{ + param( + [string] + $ContainerUrl, + + # $SAS (shared access signature) param should include beginning '?' and trailing '&' + [string] + $SAS + ) + + + $response = Invoke-RestMethod -Method Get -Uri $($ContainerUrl + $SAS + 'restype=container&comp=list') + + $xmlResponce = [xml]$response.Substring($response.IndexOf('`. -A submodule is just a Git repository; it just happens to be nested inside another repository. - -Please read the Git Book chapter on [submodules][]. - -[submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules diff --git a/docs/KNOWNISSUES.md b/docs/KNOWNISSUES.md deleted file mode 100644 index a6fd57bd9a18..000000000000 --- a/docs/KNOWNISSUES.md +++ /dev/null @@ -1,166 +0,0 @@ -# Known Issues - -## Known Issues for PowerShell on Non-Windows Platforms - -Alpha releases of PowerShell on Linux and macOS are mostly functional but do have some significant limitations and usability issues. -Beta releases of PowerShell on Linux and macOS are more functional and stable than alpha releases, but still may be lacking some set of features, and can contain bugs. -In some cases, these issues are simply bugs that haven't been fixed yet. -In other cases (as with the default aliases for ls, cp, etc.), we are looking for feedback from the community regarding the choices we make. - -Note: Due to the similarities of many underlying subsystems, PowerShell on Linux and macOS tend to share the same level of maturity in both features and bugs. -Except as noted below, the issues in this section will apply to both operating systems. - -### Case-sensitivity in PowerShell - -Historically, PowerShell has been uniformly case-insensitive, with few exceptions. -On UNIX-like operating systems, the file system is predominantly case-sensitive and PowerShell adheres to the standard of the file system; this is exposed through a number of ways, obvious and non-obvious. - -#### Directly - -- When specifying a file in PowerShell, the correct case must be used. - -#### Indirectly - -- If a script tries to load a module and the module name is not cased correctly, then the module load will fail. - This may cause a problem with existing scripts if the name by which the module is referenced doesn't match the actual file name. -- Tab-completion will not auto-complete if the file name case is wrong. - The fragment to complete must be cased properly. - (Completion is case-insensitive for type name and type member completions.) - -### .PS1 File Extensions - -PowerShell scripts must end in `.ps1` for the interpreter to understand how to load and run them in the current process. -Running scripts in the current process is the expected usual behavior for PowerShell. -The `#!` magic number may be added to a script that doesn't have a `.ps1` extension, but this will cause the script to be run in a new PowerShell instance preventing the script from working properly when interchanging objects. -(Note: this may be the desirable behavior when executing a PowerShell script from `bash` or another shell.) - -### Missing command aliases - -On Linux/macOS, the "convenience aliases" for the basic commands `ls`, `cp`, `mv`, `rm`, `cat`, `man`, `mount`, `ps` have been removed. -On Windows, PowerShell provides a set of aliases that map to Linux command names for user convenience. -These aliases have been removed from the default PowerShell on Linux/macOS distributions, allowing the native executable to be run without specifying a path. - -There are pros and cons to doing this. -Removing the aliases exposes the native command experience to the PowerShell user, but reduces functionality in the shell because the native commands return strings instead of objects. - -> NOTE: This is an area where the PowerShell team is looking for feedback. -> What is the preferred solution? Should we leave it as is or add the convenience aliases back? See -> [Issue #929](https://github.com/PowerShell/PowerShell/issues/929). - -### Missing Wildcard (globbing) Support - -Currently, PowerShell only does wildcard expansion (globbing) for built-in cmdlets on Windows, and for external commands or binaries as well as cmdlets on Linux. -This means that a command like `ls *.txt` will fail because the asterisk will not be expanded to match file names. -You can work around this by doing `ls (gci *.txt | % name)` or, more simply, `gci *.txt` using the PowerShell built-in equivalent to `ls`. - -See [#954](https://github.com/PowerShell/PowerShell/issues/954) to give us feedback on how to improve the globbing experience on Linux/macOS. - -### .NET Framework vs .NET Core Framework - -PowerShell on Linux/macOS uses .NET Core which is a subset of the full .NET Framework on Microsoft Windows. -This is significant because PowerShell provides direct access to the underlying framework types, methods, etc. -As a result, scripts that run on Windows may not run on non-Windows platforms because of the differences in the frameworks. -For more information about .NET Core Framework, see - -With the advent of [.NET Standard 2.0](https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard/), .NET Core 2.0 will bring back many of the traditional types and methods present in the full .NET Framework. -This means that PowerShell Core will be able to load many traditional Windows PowerShell modules without modification. -You can follow our .NET Standard 2.0 related work [here](https://github.com/PowerShell/PowerShell/projects/4). - -### Redirection Issues - -Input redirection is not supported in PowerShell on any platform. -[Issue #1629](https://github.com/PowerShell/PowerShell/issues/1629) - -Use `Get-Content` to write the contents of a file into the pipeline. - -Redirected output will contain the Unicode byte order mark (BOM) when the default UTF-8 encoding is used. -The BOM will cause problems when working with utilities that do not expect it or when appending to a file. -Use `-Encoding Ascii` to write ASCII text (which, not being Unicode, will not have a BOM). -(Note: see [RFC0020](https://github.com/PowerShell/PowerShell-RFC/issues/71) to give us feedback on improving the encoding experience for PowerShell Core across all platforms. -We are working to support UTF-8 without a BOM and potentially changing the encoding defaults for various cmdlets across platforms.) - -### Job Control - -There is no job-control support in PowerShell on Linux/macOS. -The `fg` and `bg` commands are not available. - -For the time being, you can use [PowerShell jobs](https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_jobs) which do work across all platforms. - -### Remoting Support - -Currently, PowerShell Core supports PowerShell Remoting (PSRP) over WSMan with Basic authentication on macOS and Linux, and with NTLM-based authentication on Linux. -(Kerberos-based authentication is not supported.) - -The work for WSMan-based remoting is being done in the [psl-omi-provider](https://github.com/PowerShell/psl-omi-provider) repo. - -PowerShell Core also supports PowerShell Remoting (PSRP) over SSH on all platforms (Windows, macOS, and Linux). -While this is not currently supported in production, you can learn more about setting this up [here](https://github.com/PowerShell/PowerShell/tree/master/demos/SSHRemoting). - -### Just-Enough-Administration (JEA) Support - -The ability to create constrained administration (JEA) remoting endpoints is not currently available in PowerShell on Linux/macOS. -This feature is currently not in scope for 6.0 and something we will consider post 6.0 as it requires significant design work. - -### `sudo`, `exec`, and PowerShell - -Because PowerShell runs most commands in memory (like Python or Ruby), you can't use sudo directly with PowerShell built-ins. -(You can, of course, run `powershell` from sudo.) -If it is necessary to run a PowerShell cmdlet from within PowerShell with sudo, for example, `sudo Set-Date 8/18/2016`, then you would do `sudo powershell Set-Date 8/18/2016`. -Likewise, you can't exec a PowerShell built-in directly. -Instead you would have to do `exec powershell item_to_exec`. - -This issue is currently being tracked as part of #3232. - -### Missing Cmdlets - -A large number of the commands (cmdlets) normally available in PowerShell are not available on Linux/macOS. -In many cases, these commands make no sense on these platforms (e.g. Windows-specific features like the registry). -Other commands like the service control commands (Get/Start/Stop-Service) are present, but not functional. -Future releases will correct these problems, fixing the broken cmdlets and adding new ones over time. - -### Command Availability - -The following table lists commands that are known not to work in PowerShell on Linux/macOS. - - - - - - - - - - - - - - - - - - - -
CommandsOperational StateNotes
Get-Service, New-Service, Restart-Service, Resume-Service, Set-Service, Start-Service, Stop-Service, Suspend-Service -Not available. -These commands will not be recognized. This should be fixed in a future release. -
Get-Acl, Set-Acl -Not available. -These commands will not be recognized. This should be fixed in a future release. -
Get-AuthenticodeSignature, Set-AuthenticodeSignature -Not available. -These commands will not be recognized. This should be fixed in a future release. -
Wait-Process -Available, doesn't work properly. For example `Start-Process gvim -PassThru | Wait-Process` doesn't work; it fails to wait for the process. -
Register-PSSessionConfiguration, Unregister-PSSessionConfiguration, Get-PSSessionConfiguration -Available but doesn't work. -Writes an error message indicating that the commands are not working. These should be fixed in a future release. -
Get-Event, New-Event, Register-EngineEvent, Register-WmiEvent, Remove-Event, Unregister-Event -Available but no event sources are available. -The PowerShell eventing commands are present but most of the event sources used with the commands (such as System.Timers.Timer) are not available on Linux making the commands useless in the Alpha release. -
Set-ExecutionPolicy -Available but doesn't work. -Returns a message saying not supported on this platform. Execution policy is a user-focused "safety belt" that helps prevent the user from making expensive mistakes. It is not a security boundary. -
New-PSSessionOption, New-PSTransportOption -Available but New-PSSession doesn't work. -New-PSSessionOption and New-PSTransportOption are not currently verified to work now that New-PSSession works. -
diff --git a/docs/building/internals.md b/docs/building/internals.md index 9880df8dd990..e6d800167b57 100644 --- a/docs/building/internals.md +++ b/docs/building/internals.md @@ -16,7 +16,7 @@ We are calling `dotnet` tool build for `$Top` directory ### Dummy dependencies We use dummy dependencies between projects to leverage `dotnet` build functionality. -For example, `src\powershell-win-core\powershell-win-core.csproj` has dependency on `Microsoft.PowerShell.PSReadLine`, +For example, `src\powershell-win-core\powershell-win-core.csproj` has dependency on `Microsoft.PowerShell.Commands.Diagnostics.csproj`, but in reality, there is no build dependency. Dummy dependencies allows us to build just `$Top` folder, instead of building several folders. @@ -30,8 +30,9 @@ it should be listed as a dependency for `$Top` folder (`src\powershell-unix` or ### ResGen -Until the .NET CLI `dotnet-resgen` tool supports the generation of strongly typed classes, -we run our own tool C# [ResGen tool](../../src/ResGen). +Until the .NET CLI `dotnet-resgen` tool supports the generation of strongly typed resource access classes +(tracked by [Microsoft/msbuild #2272](https://github.com/Microsoft/msbuild/issues/2272)), +we run our own C# [ResGen tool](../../src/ResGen). While the `Start-PSBuild` command runs this automatically via the `Start-ResGen` function, it does *not* require PowerShell. The same command can be run manually: @@ -42,12 +43,12 @@ dotnet restore dotnet run ``` -Running the program does everything else: +Running the program does the following work: - For each project, given a `resources` folder, create a `gen` folder. - For each `*.resx` file from the `resources` folder, - fill in a strongly typed C# class, - and write it out to the corresponding `*.cs` file in the `gen` folder. + create a strongly typed C# resource access class, + and write it to the corresponding `*.cs` file in the `gen` folder. These files are *not* automatically updated on each build, as the project lacks the ability to detect changes. @@ -70,28 +71,29 @@ dotnet restore dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs powershell.inc ``` -The file `powershell.inc` is generated by running a custom MSBuild target, -which can be set-up by navigating to the `src` directory and running the following commands: +The file `powershell.inc` is generated by running a custom MSBuild target. +`Start-TypeGen` handles generating this file, +but you can also do it manually by navigating to the `src` directory and running the following commands: ```sh targetFile="Microsoft.PowerShell.SDK/obj/Microsoft.PowerShell.SDK.csproj.TypeCatalog.targets" cat > $targetFile <<-"EOF" - - - <_RefAssemblyPath Include="%(_ReferencesFromRAR.ResolvedPath)%3B" Condition=" '%(_ReferencesFromRAR.Type)' == 'assembly' And '%(_ReferencesFromRAR.PackageName)' != 'Microsoft.Management.Infrastructure' " /> - - - + + + <_RefAssemblyPath Include="%(_ReferencesFromRAR.HintPath)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> + + + EOF -dotnet msbuild Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$(pwd)/src/TypeCatalogGen/powershell.inc" /nologo +dotnet msbuild Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$(pwd)/TypeCatalogGen/powershell.inc" /nologo ``` `powershell.inc` contains the resolved paths to the DLLs of each dependency of PowerShell, and is taken as input to the [`TypeCatalogGen`](../../src/TypeCatalogGen) tool, -which generates a source file `CorePsTypeCatalog.cs` for the `Microsoft.PowerShell.CoreCLR.AssemblyLoadContext` project. +which generates the source file `CorePsTypeCatalog.cs` for the `System.Management.Automation` project. The error `The name 'InitializeTypeCatalog' does not exist in the current context` indicates that the `CorePsTypeCatalog.cs` source file does not exist, @@ -136,12 +138,12 @@ For example, the following builds the release flavor of the binary targeting arm Start-BuildNativeWindowsBinaries -Configuration Release -Arch x64_arm64 ``` -Be sure to build and test for all supported architectures: x86, x64, x64_arm, and x64_arm64. +Be sure to build and test for all supported architectures: `x86`, `x64`, `x64_arm`, and `x64_arm64`. The `x64_arm` and `x64_arm64` architectures mean that the host system needs to be x64 to cross-compile to ARM. When building for multiple architectures, be sure to use the `-clean` switch as cmake will cache the previous run and the wrong compiler will be used to generate the subsequent architectures. -After that, the binary `pwrshplugin.dll`, its PDB file, and `powershell.core.instrumentation.dll` will be placed under 'src\powershell-win-core'. +After that, the binary `pwrshplugin.dll`, its PDB file, and `powershell.core.instrumentation.dll` will be placed under `src\powershell-win-core`. To create a new NuGet package for `pwrshplugin.dll`, first you need to get the `psrp.windows.nuspec` from an existing `psrp.windows` package. You can find it at `~/.nuget/packages/psrp.windows` on your windows machine if you have recently built PowerShell on it. diff --git a/docs/building/linux.md b/docs/building/linux.md index 55870983860e..351f02cef4cd 100644 --- a/docs/building/linux.md +++ b/docs/building/linux.md @@ -5,7 +5,7 @@ We'll start by showing how to set up your environment from scratch. ## Environment -These instructions are written assuming the Ubuntu 14.04 LTS, since that's the distro the team uses. +These instructions are written assuming the Ubuntu 16.04 LTS, since that's the distro the team uses. The build module works on a best-effort basis for other distributions. ### Git Setup @@ -24,7 +24,7 @@ and [CMake][] to build the native components. Installing the toolchain is as easy as running `Start-PSBootstrap` in PowerShell. Of course, this requires a self-hosted copy of PowerShell on Linux. -Fortunately, this is as easy as [downloading and installing the package](../installation/linux.md). +Fortunately, this is as easy as [downloading and installing the package](https://docs.microsoft.com/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-6#binary-archives). The `./tools/install-powershell.sh` script will also install the PowerShell package. In Bash: @@ -71,7 +71,7 @@ Start-PSBuild Congratulations! If everything went right, PowerShell is now built. The `Start-PSBuild` script will output the location of the executable: -`./src/powershell-unix/bin/Linux/netcoreapp2.0/linux-x64/publish/pwsh`. +`./src/powershell-unix/bin/Debug/netcoreapp3.0/linux-x64/publish/pwsh`. You should now be running the PowerShell Core that you just built, if your run the above executable. You can run our cross-platform Pester tests with `Start-PSPester`, and our xUnit tests with `Start-PSxUnit`. diff --git a/docs/building/macos.md b/docs/building/macos.md index f4760018a0f7..d6f3cac5480b 100644 --- a/docs/building/macos.md +++ b/docs/building/macos.md @@ -3,20 +3,20 @@ This guide supplements the [Linux instructions](./linux.md), as building on macOS is almost identical. -.NET Core 2.0 (and by transitivity, us) only supports macOS 10.12. +.NET Core 2.x (and by transitivity, us) only supports macOS 10.12+. ## Environment -You will want [Homebrew](http://brew.sh/), the missing package manager for macOS. +You will want [Homebrew](https://brew.sh/), the missing package manager for macOS. Once installed, follow the same instructions to download and -install a self-hosted copy of PowerShell on your macOS machine, -and use `Start-PSBootstrap` to install the dependencies. +install a self-hosted copy of PowerShell on your macOS machine. +From `pwsh.exe`, run `Import-Module ./build.psm1` and use `Start-PSBootstrap` to install the dependencies. The `Start-PSBootstrap` function does the following: - Uses `brew` to install CMake, OpenSSL, and GNU WGet - Uninstalls any prior versions of .NET CLI -- Downloads and installs a preview version of .NET Core SDK 2.0 to `~/.dotnet` +- Downloads and installs .NET Core SDK to `~/.dotnet` If you want to use `dotnet` outside of `Start-PSBuild`, add `~/.dotnet` to your `PATH` environment variable. @@ -36,5 +36,4 @@ We cannot do this for you in the build module due to #[847][]. Start a PowerShell session by running `pwsh`, and then use `Start-PSBuild` from the module. -After building, PowerShell will be at `./src/powershell-unix/bin/Linux/netcoreapp2.0/osx.10.12-x64/publish/powershell`. -Note that configuration is still `Linux`. +After building, PowerShell will be at `./src/powershell-unix/bin/Debug/netcoreapp3.0/osx-x64/publish/pwsh`. diff --git a/docs/building/windows-core.md b/docs/building/windows-core.md index 54d0a099b17b..ed45a2ae958f 100644 --- a/docs/building/windows-core.md +++ b/docs/building/windows-core.md @@ -58,11 +58,11 @@ Import-Module ./build.psm1 Start-PSBuild ``` -Congratulations! If everything went right, PowerShell is now built and executable as `./src/powershell-win-core/bin/Debug/netcoreapp2.0/win7-x64/publish/pwsh`. +Congratulations! If everything went right, PowerShell is now built and executable as `./src/powershell-win-core/bin/Debug/netcoreapp3.0/win7-x64/publish/pwsh.exe`. This location is of the form `./[project]/bin/[configuration]/[framework]/[rid]/publish/[binary name]`, and our project is `powershell`, configuration is `Debug` by default, -framework is `netcoreapp2.0`, runtime identifier is `win7-x64` by default, +framework is `netcoreapp3.0`, runtime identifier is `win7-x64` by default, and binary name is `pwsh`. The function `Get-PSOutput` will return the path to the executable; thus you can execute the development copy via `& (Get-PSOutput)`. diff --git a/docs/cmdlet-example/Images/Std21.png b/docs/cmdlet-example/Images/Std21.png index 30761d793cbe..2c3d83858bd8 100644 Binary files a/docs/cmdlet-example/Images/Std21.png and b/docs/cmdlet-example/Images/Std21.png differ diff --git a/docs/cmdlet-example/Images/Std22.png b/docs/cmdlet-example/Images/Std22.png index c10e52b578ab..9406f4a9fff0 100644 Binary files a/docs/cmdlet-example/Images/Std22.png and b/docs/cmdlet-example/Images/Std22.png differ diff --git a/docs/cmdlet-example/Images/Std3.png b/docs/cmdlet-example/Images/Std3.png index 850680080d47..ec70d176d147 100644 Binary files a/docs/cmdlet-example/Images/Std3.png and b/docs/cmdlet-example/Images/Std3.png differ diff --git a/docs/cmdlet-example/Images/Std4.png b/docs/cmdlet-example/Images/Std4.png index 3b755c78a03e..fb883d97ecfc 100644 Binary files a/docs/cmdlet-example/Images/Std4.png and b/docs/cmdlet-example/Images/Std4.png differ diff --git a/docs/cmdlet-example/Images/Std5.png b/docs/cmdlet-example/Images/Std5.png index 74fe290b84ae..e70bdf8d2443 100644 Binary files a/docs/cmdlet-example/Images/Std5.png and b/docs/cmdlet-example/Images/Std5.png differ diff --git a/docs/cmdlet-example/Images/Std61.png b/docs/cmdlet-example/Images/Std61.png index e26bdf54de09..e9211e4910bb 100644 Binary files a/docs/cmdlet-example/Images/Std61.png and b/docs/cmdlet-example/Images/Std61.png differ diff --git a/docs/cmdlet-example/Images/Std62.png b/docs/cmdlet-example/Images/Std62.png index 1d992b98163b..69996460f283 100644 Binary files a/docs/cmdlet-example/Images/Std62.png and b/docs/cmdlet-example/Images/Std62.png differ diff --git a/docs/cmdlet-example/Images/Std63.png b/docs/cmdlet-example/Images/Std63.png index 6cb497db70e1..cce343e61914 100644 Binary files a/docs/cmdlet-example/Images/Std63.png and b/docs/cmdlet-example/Images/Std63.png differ diff --git a/docs/cmdlet-example/Images/Step1.png b/docs/cmdlet-example/Images/Step1.png index 6a11151ff71d..aa63140a3fd4 100644 Binary files a/docs/cmdlet-example/Images/Step1.png and b/docs/cmdlet-example/Images/Step1.png differ diff --git a/docs/cmdlet-example/Images/Step2.png b/docs/cmdlet-example/Images/Step2.png index fc8f2fb4f9f2..3b84716f7c5f 100644 Binary files a/docs/cmdlet-example/Images/Step2.png and b/docs/cmdlet-example/Images/Step2.png differ diff --git a/docs/cmdlet-example/Images/Step3.png b/docs/cmdlet-example/Images/Step3.png index 1b01b8741c8d..ed13cf8929dc 100644 Binary files a/docs/cmdlet-example/Images/Step3.png and b/docs/cmdlet-example/Images/Step3.png differ diff --git a/docs/cmdlet-example/Images/Step4.png b/docs/cmdlet-example/Images/Step4.png index 63926f317ea3..a9644edd6555 100644 Binary files a/docs/cmdlet-example/Images/Step4.png and b/docs/cmdlet-example/Images/Step4.png differ diff --git a/docs/cmdlet-example/Images/Step5.png b/docs/cmdlet-example/Images/Step5.png index f5e4f75aeb5b..0cf0384a3005 100644 Binary files a/docs/cmdlet-example/Images/Step5.png and b/docs/cmdlet-example/Images/Step5.png differ diff --git a/docs/cmdlet-example/Images/Step6.png b/docs/cmdlet-example/Images/Step6.png index ab2eaab0ebd6..b57deb6aad2b 100644 Binary files a/docs/cmdlet-example/Images/Step6.png and b/docs/cmdlet-example/Images/Step6.png differ diff --git a/docs/cmdlet-example/Images/Step7.png b/docs/cmdlet-example/Images/Step7.png index a18ac91f4745..644eebce5161 100644 Binary files a/docs/cmdlet-example/Images/Step7.png and b/docs/cmdlet-example/Images/Step7.png differ diff --git a/docs/cmdlet-example/Images/Step8.png b/docs/cmdlet-example/Images/Step8.png index bcaafca26e19..155e8c3d3592 100644 Binary files a/docs/cmdlet-example/Images/Step8.png and b/docs/cmdlet-example/Images/Step8.png differ diff --git a/docs/cmdlet-example/command-line-simple-example.md b/docs/cmdlet-example/command-line-simple-example.md index 0a2682413bd5..1af04f4f261f 100644 --- a/docs/cmdlet-example/command-line-simple-example.md +++ b/docs/cmdlet-example/command-line-simple-example.md @@ -23,9 +23,9 @@ different implementations of PowerShell. to install PowerShell Core for the distribution and version of Linux you're running. You can get that version info by running the command `lsb_release -a` from the WSL console. -* .NET Core 2.0 SDK +* .NET Core 2.x SDK - Download and install the [.NET Core 2.0 SDK][net-core-sdk] for your operating system. + Download and install the [.NET Core 2.x SDK][net-core-sdk] for your operating system. It is recommended that you use a package manager to install the SDK on Linux. See these [instructions][linux-install] on how to install the SDK on Linux. Be sure to pick your distribution of Linux e.g. RHEL, Debian, etc to get the @@ -40,7 +40,7 @@ different implementations of PowerShell. ``` This should output `2.0.0` or higher. If it returns a major version of 1, make sure you have - installed the .NET Core 2.0 SDK and have restarted your shell to get the newer version of + installed the .NET Core 2.x SDK and have restarted your shell to get the newer version of the SDK tools. 1. Use the `dotnet` CLI to create a starter `classlib` project based on .NET Standard 2.0 @@ -114,7 +114,7 @@ different implementations of PowerShell. ## Using a .NET Standard 2.0 based binary module in Windows PowerShell You may have heard that a .NET assembly compiled as a .NET Standard 2.0 class library -will load into both .NET Core 2.0 applications such as PowerShell Core and +will load into both .NET Core 2.x applications such as PowerShell Core and .NET Framework 4.6.1 (or higher) applications such as Windows PowerShell. This allows you to build a single, cross-platform binary module. @@ -171,30 +171,34 @@ can't find the `netstandard.dll` "implementation" assembly for the version of th ### The fix for missing netstandard.dll -If you install (or already have) the .NET Core 2.0 SDK for Windows, you can +If you install (or already have) the .NET Core SDK for Windows, you can find the `netstandard.dll` implementation assembly for .NET 4.6.1 in the following directory: -`C:\Program Files\dotnet\sdk\2.0.0\Microsoft\Microsoft.NET.Build.Extensions\net461\lib`. +`C:\Program Files\dotnet\sdk\\Microsoft\Microsoft.NET.Build.Extensions\net461\lib`. +Note that, the version number in the path may vary depending on the installed SDK. If you copy `netstandard.dll` from this directory to the directory containing `MyModule.dll`, the `Write-TimestampedMessage` command will work. Let's try that. -1. Install the [.NET Core SDK 2.0 for Windows][net-core-sdk], if it isn't already installed. +1. Install [.NET Core SDK for Windows][net-core-sdk], if it isn't already installed. 1. Start a new Windows PowerShell console. Remember that once a binary assembly is loaded into PowerShell it can't be unloaded. Restarting PowerShell is necessary to get it to reload `MyModule.dll`. 1. Copy the `netstandard.dll` implementation assembly for .NET 4.6.1 to the module's directory. + ```powershell cd 'path-to-where-you-copied-module.dll' - Copy-Item 'C:\Program Files\dotnet\sdk\2.0.0\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll' . + Copy-Item 'C:\Program Files\dotnet\sdk\\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll' . ``` 1. Import the module and execute the command: + ```powershell Import-Module .\MyModule.dll Write-TimestampedMessage "Test message." ``` + Now the command should succeed. Note: If it fails, restart Windows PowerShell to make sure @@ -211,14 +215,14 @@ class library that will run in PowerShell Core on multiple operating systems. It will also run in Windows PowerShell on Windows systems that have been updated to .NET Framework 4.7.1 as well as the Windows 10 Fall Creators Update which comes with that version pre-installed. Furthermore, this binary module can be built on Linux -and macOS as well as Windows using the .NET Core 2.0 SDK command-line tools. +and macOS as well as Windows using the .NET Core 2.x SDK command-line tools. For more information on .NET Standard, check out the [documentation][net-std-docs] and the [.NET Standard YouTube channel][net-std-chan]. -[dotnet-cli]: https://docs.microsoft.com/en-us/dotnet/core/tools/?tabs=netcore2x +[dotnet-cli]: https://docs.microsoft.com/dotnet/core/tools/?tabs=netcore2x [net-core-sdk]: https://www.microsoft.com/net/download/core -[net-std-docs]: https://docs.microsoft.com/en-us/dotnet/standard/net-standard +[net-std-docs]: https://docs.microsoft.com/dotnet/standard/net-standard [net-std-chan]: https://www.youtube.com/playlist?list=PLRAdsfhKI4OWx321A_pr-7HhRNk7wOLLY [pscore-os]: https://github.com/powershell/powershell#get-powershell [readme]: ../../README.md diff --git a/docs/cmdlet-example/visual-studio-simple-example.md b/docs/cmdlet-example/visual-studio-simple-example.md index 6f91d064a3e1..3d7144c82d3c 100644 --- a/docs/cmdlet-example/visual-studio-simple-example.md +++ b/docs/cmdlet-example/visual-studio-simple-example.md @@ -30,7 +30,8 @@ Add another package source with name `powershell-core` and source `https://power ![Step4](./Images/Step4.png) 1. Add the code of cmdlet: - ```CSharp + + ```csharp using System.Management.Automation; // PowerShell namespace. namespace SendGreeting @@ -55,6 +56,7 @@ Add another package source with name `powershell-core` and source `https://power } } ``` + At this point everything should look like this: ![Step5](./Images/Step5.png) @@ -90,7 +92,8 @@ It should find `PowerShellStandard.Library` package, select it and it will show ![StdImage3](./Images/Std3.png) 1. Add the code of cmdlet: - ```CSharp + + ```csharp using System.Management.Automation; // PowerShell namespace. namespace SendGreeting @@ -115,6 +118,7 @@ It should find `PowerShellStandard.Library` package, select it and it will show } } ``` + At this point everything should look like this: ![StdImage4](./Images/Std4.png) @@ -128,4 +132,4 @@ It should find `PowerShellStandard.Library` package, select it and it will show On PowerShell Core on Linux: ![StdImage62](./Images/Std62.png) On Windows PowerShell on Windows (this requires [.NET Framework 4.7.1](https://github.com/Microsoft/dotnet-framework-early-access/blob/master/instructions.md)): -![StdImage63](./Images/Std63.png) \ No newline at end of file +![StdImage63](./Images/Std63.png) diff --git a/docs/community/governance.md b/docs/community/governance.md index dbcda25a9c4c..4d7307b675ba 100644 --- a/docs/community/governance.md +++ b/docs/community/governance.md @@ -2,19 +2,21 @@ ## Terms -* [**PowerShell Committee**](#powershell-committee): A committee of project owners who are responsible for design decisions, approving [RFCs][RFC-repo], and approving new maintainers/committee members -* **Project Leads**: Project Leads support the PowerShell Committee, engineering teams, and community by working across Microsoft teams and leadership, and working through industry issues with other companies. -They also have optional votes on the PowerShell Committee when they choose to invoke them. The initial Project Leads for PowerShell are Angel Calvo ([AngelCalvo](https://github.com/AngelCalvo)) and Kenneth Hansen ([khansen00](https://github.com/khansen00)). +* [**PowerShell Committee**](#powershell-committee): A committee of project owners who are responsible for design decisions, + approving [RFCs][RFC-repo], and approving new maintainers/committee members * [**Repository maintainer**](#repository-maintainers): An individual responsible for merging pull requests (PRs) into `master` when all requirements are met (code review, tests, docs, and RFC approval as applicable). -Repository Maintainers are the only people with write permissions into `master`. + + Repository Maintainers are the only people with write permissions for the `master` branch. * [**Area experts**](#area-experts): People who are experts for specific components (e.g. PSReadline, the parser) or technologies (e.g. security, performance). -Area experts are responsible for code reviews, issue triage, and providing their expertise to others. -* **Corporation**: The Corporation owns the PowerShell repository and, under extreme circumstances, reserves the right to dissolve or reform the PowerShell Committee, the Project Leads, and the Corporate Maintainer. -The Corporation for PowerShell is Microsoft. -* **Corporate Maintainer**: The Corporate Maintainer is an entity, person or set of persons, with the ability to veto decisions made by the PowerShell Committee or any other collaborators on the PowerShell project. -This veto power will be used with restraint since it is intended that the community drive the project. -The Corporate Maintainer is determined by the Corporation both initially and in continuation. -The initial Corporate Maintainer for PowerShell is Jeffrey Snover ([jpsnover](https://github.com/jpsnover)). + Area experts are responsible for code reviews, issue triage, and providing their expertise to others. +* **Corporation**: The Corporation owns the PowerShell repository and, under extreme circumstances, + reserves the right to dissolve or reform the PowerShell Committee, the Project Leads, and the Corporate Maintainer. + The Corporation for PowerShell is Microsoft. +* **Corporate Maintainer**: The Corporate Maintainer is an entity, person or set of persons, + with the ability to veto decisions made by the PowerShell Committee or any other collaborators on the PowerShell project. + This veto power will be used with restraint since it is intended that the community drive the project. + The Corporate Maintainer is determined by the Corporation both initially and in continuation. + The initial Corporate Maintainer for PowerShell is Jeffrey Snover ([jpsnover](https://github.com/jpsnover)). * [**RFC process**][RFC-repo]: The "review-for-comment" (RFC) process whereby design decisions get made. ## PowerShell Committee @@ -24,11 +26,11 @@ The PowerShell Committee and its members (aka Committee Members) are the primary ### Current Committee Members * Bruce Payette ([BrucePay](https://github.com/BrucePay)) -* Steve Lee ([SteveL-MSFT](https://github.com/SteveL-MSFT)) -* Hemant Mahawar ([HemantMahawar](https://github.com/HemantMahawar)) -* Joey Aiello ([joeyaiello](https://github.com/joeyaiello)) * Dongbo Wang ([daxian-dbw](https://github.com/daxian-dbw)) * Jim Truher ([JamesWTruher](https://github.com/JamesWTruher)) +* Joey Aiello ([joeyaiello](https://github.com/joeyaiello)) +* Kenneth Hansen ([khansen00](https://github.com/khansen00)) +* Steve Lee ([SteveL-MSFT](https://github.com/SteveL-MSFT)) ### Committee Member Responsibilities @@ -39,7 +41,7 @@ Committee Members are responsible for reviewing and approving [PowerShell RFCs][ The following types of decisions require a written RFC and ample time for the community to respond with their feedback before a contributor begins work on the issue: * new features or capabilities in PowerShell (e.g. PowerShell classes, PSRP over SSH, etc.) -* anything that might require a breaking changes as defined in our [Breaking Changes Contract][breaking-changes] +* anything that might require a breaking change, as defined in our [Breaking Changes Contract][breaking-changes] * new modules, cmdlets, or parameters that ship in the core PowerShell modules (e.g. `Microsoft.PowerShell.*`, `PackageManagement`, `PSReadLine`) * the addition of new PowerShell Committee Members or Repository Maintainers * any changes to the process of maintaining the PowerShell repository (including the responsibilities of Committee Members, Repository Maintainers, and Area Experts) @@ -58,7 +60,7 @@ If any Committee Members feels like this behavior is large enough to warrant an As a PowerShell Committee Member: 1. **DO** reply to issues and pull requests with design opinions -(this could include offering support for good work or exciting new features) + (this could include offering support for good work or exciting new features) 1. **DO** encourage healthy discussion about the direction of PowerShell 1. **DO** raise "red flags" on PRs that haven't followed the proper RFC process when applicable 1. **DO** contribute to documentation and best practices @@ -69,7 +71,7 @@ As a PowerShell Committee Member: 1. **DON'T** constantly raise "red flags" for unimportant or minor problems to the point that the progress of the project is being slowed 1. **DON'T** offer up your opinions as the absolute opinion of the PowerShell Committee. -Members are encouraged to share their opinions, but they should be presented as such. + Members are encouraged to share their opinions, but they should be presented as such. ### PowerShell Committee Membership @@ -83,7 +85,7 @@ After the RFC has been discussed, a unanimous vote will be required for the new ## Repository Maintainers -Repository Maintainers are trusted stewards of the PowerShell repository responsible for maintaining consistency and quality of PowerShell code. +Repository Maintainers are trusted stewards of the PowerShell community/repository responsible for maintaining consistency and quality of PowerShell code. One of their primary responsibilities is merging pull requests after all requirements have been fulfilled. For more information on Repository Maintainers--their responsibilities, who they are, and how one becomes a Maintainer--see the [README for Repository Maintainers][maintainers]. @@ -98,6 +100,8 @@ They have [write access](https://help.github.com/articles/permission-levels-for- 1. Merge pull requests to all branches *except* `master` (though this should not be common given that [`master`is the only long-living branch](../git/README.md#understand-branches)). 1. Assign labels, milestones, and people to [issues](https://guides.github.com/features/issues/). +A list of Area Experts can be found [here][experts]. + ### Area Expert Responsibilities If you are an Area Expert, you are expected to be actively involved in any development, design, or contributions in your area of expertise. @@ -108,7 +112,7 @@ If you are an Area Expert: 1. **DO** assign yourself to issues labeled with your area of expertise 1. **DO** code reviews for issues where you're assigned or in your areas of expertise. 1. **DO** reply to new issues and pull requests that are related to your area of expertise -(while reviewing PRs, leave your comment even if everything looks good - a simple "Looks good to me" or "LGTM" will suffice, so that we know someone has already taken a look at it). + (while reviewing PRs, leave your comment even if everything looks good - a simple "Looks good to me" or "LGTM" will suffice, so that we know someone has already taken a look at it). 1. **DO** make sure contributors are following the [contributor guidelines](../../.github/CONTRIBUTING.md). 1. **DO** ask people to resend a pull request, if it [doesn't target `master`](../../.github/CONTRIBUTING.md#lifecycle-of-a-pull-request). 1. **DO** ensure that contributors [write Pester tests][pester] for all new/changed functionality @@ -132,6 +136,7 @@ See our [Pull Request Process][pull-request-process] [ci-system]: ../testing-guidelines/testing-guidelines.md#ci-system [breaking-changes]: ../dev-process/breaking-change-contract.md [issue-process]: ../maintainers/issue-management.md -[pull-request-process]: ../maintainers/pull-request-process.md +[pull-request-process]: ../../.github/CONTRIBUTING.md#lifecycle-of-a-pull-request [docs-contributing]: https://github.com/PowerShell/PowerShell-Docs/blob/staging/CONTRIBUTING.md [maintainers]: ../maintainers/README.md +[experts]: ../../.github/CODEOWNERS diff --git a/docs/debugging/README.md b/docs/debugging/README.md index fb074aa7881f..36107f1ba068 100644 --- a/docs/debugging/README.md +++ b/docs/debugging/README.md @@ -1,5 +1,4 @@ -Visual Studio Code -================== +# Visual Studio Code [Experimental .NET Core Debugging in VS Code][core-debug] enables cross-platform debugging with the [Visual Studio Code][vscode] editor. @@ -19,7 +18,7 @@ You can do this in Bash with `export PATH=$PATH:$HOME/.dotnet` or in PowerShell Once the extension is installed, you have to open a C# file to force VS Code to install the actual .NET Core debugger (the editor will tell you to do this if -you attempt to debug and haven't already open a C# file). +you attempt to debug and haven't already opened a C# file). The committed `.vscode` folder in the root of this repository contains the `launch.json` and `tasks.json` files which provide Core PowerShell @@ -39,17 +38,16 @@ launch an external console with PowerShell running interactively. If neither of these installed, the editor will tell you to do so. Alternatively, the ".NET Core Attach" configuration will start listening for a -process named `powershell`, and will attach to it. If you need more fine grained +process named `powershell`, and will attach to it. If you need more fine-grained control, replace `processName` with `processId` and provide a PID. (Please be careful not to commit such a change.) [core-debug]: https://blogs.msdn.microsoft.com/visualstudioalm/2016/03/10/experimental-net-core-debugging-in-vs-code/ [vscode]: https://code.visualstudio.com/ [OmniSharp]: https://github.com/OmniSharp/omnisharp-vscode -[vscclrdebugger]: http://aka.ms/vscclrdebugger +[vscclrdebugger]: https://aka.ms/vscclrdebugger -PowerShell -========== +## PowerShell The `Trace-Command` cmdlet can be used to enable tracing of certain PowerShell subsystems. Use `Get-TraceSource` for a list of tracers: @@ -91,8 +89,7 @@ The `-PSHost` specifies the sink, in this case the console host, so we can see the tracing messages. The `-Name` chooses the list of tracers to enable. -LLDB with SOS plug-in -===================== +## LLDB with SOS plug-in The `./tools/debug.sh` script can be used to launch PowerShell inside of LLDB with the SOS plug-in provided by .NET Core. This provides an additional way to @@ -104,14 +101,12 @@ The script is self-documented and contains a link to the [clr-debug]: https://github.com/dotnet/coreclr/blob/master/Documentation/building/debugging-instructions.md#debugging-coreclr-on-linux -corehost -======== +## `corehost` The native executable produced by .NET CLI will produce trace output if launched with `COREHOST_TRACE=1 ./powershell`. -CoreCLR PAL -=========== +## CoreCLR PAL The native code in the CLR has debug channels to selectively output information to the console. These are controlled by the @@ -123,8 +118,7 @@ you will need to narrow your scope. [header]: https://github.com/dotnet/coreclr/blob/release/1.0.0/src/pal/src/include/pal/dbgmsg.h -Debugging .NET Core -=================== +## Debugging .NET Core The .NET Core libraries downloaded from NuGet and shipped with PowerShell are release versions. This means that `PAL_DBG_CHANNELS` will not work with them, @@ -134,16 +128,14 @@ but should prove useful. They are currently written for Linux and are meant only as a shortcut means to debug. -Build and deploy CoreCLR ------------------------- +## Build and deploy CoreCLR * Clone CoreCLR: `git clone -b release/1.0.0 https://github.com/dotnet/coreclr.git` * Follow [building instructions](https://github.com/dotnet/coreclr/blob/release/1.0.0/Documentation/building/linux-instructions.md) * Wait for `./build.sh` to finish * Overwrite PowerShell libraries: `cp bin/Product/Linux.x64.Debug/*{so,dll} /path/to/powershell/` -Build and deploy CoreFX ------------------------ +## Build and deploy CoreFX * Clone CoreFX: `git clone -b release/1.0.0 https://github.com/dotnet/corefx.git` * Follow [building instructions](https://github.com/dotnet/corefx/blob/release/1.0.0/Documentation/building/unix-instructions.md) diff --git a/docs/dev-process/breaking-change-contract.md b/docs/dev-process/breaking-change-contract.md index 44950297c4c4..12121b31dfe0 100644 --- a/docs/dev-process/breaking-change-contract.md +++ b/docs/dev-process/breaking-change-contract.md @@ -4,34 +4,38 @@ We have a serious commitment to backwards compatibility with all earlier version Below is a summary of our approach to handing breaking changes including what kinds of things constitute breaking changes, how we categorize them, and how we decide what we're willing to take. -Note that these rules only apply to existing stable features that have shipped in a supported release. New features marked as “in preview” that are still under development may be modified from one preview release to the next. These are not considered breaking changes. +Note that these rules only apply to existing stable features that have shipped in a supported release. New features marked as “in preview” that are still under development may be modified from one preview release to the next. +These are **not** considered breaking changes. To help triage breaking changes, we classify them in to four buckets: 1. Public Contract -2. Reasonable Grey Area -3. Unlikely Grey Area -4. Clearly Non-Public +1. Reasonable Grey Area +1. Unlikely Grey Area +1. Clearly Non-Public ## Bucket 1: Public Contract Any change that is a clear violation of the public contract. -### Unacceptable changes: +### Unacceptable changes + A code change that results in a change to the existing behavior observed for a given input with an API, protocol or the PowerShell language. -+ Renaming or removing a public type, type member, or type parameter; renaming or removing a cmdlet or cmdlet parameter (note: it is possible to rename a cmdlet parameter if a parameter alias is added. This is an acceptable solution for PowerShell scripts but may break .NET code that depends on the name of the original member on the cmdlet object type.) ++ Renaming or removing a public type, type member, or type parameter; renaming or removing a cmdlet or cmdlet parameter (note: it is possible to rename a cmdlet parameter if a parameter alias is added. + +This is an acceptable solution for PowerShell scripts but may break .NET code that depends on the name of the original member on the cmdlet object type.) + + Decreasing the range of accepted values within a given parameter. + Changing the value of a public constant or enum member; changing the type of a cmdlet parameter to a more restrictive type. + Example: A cmdlet with a parameter -p1 that was previously type as [object] cannot be changed to be or a more restrictive type such as [int]. + Making an incompatible change to any protocol without increasing the protocol version number. -### Acceptable changes: +### Acceptable changes + Any existing behavior that results in an error message generally may be changed to provide new functionality. + A new instance field is added to a type (this impacts .NET serialization but not PowerShell serialization and so is considered acceptable.) + Adding new types, new type members and new cmdlets -+ Making changes to the protocols with a protocol version increment. Older versions of the protocol would still need to be maintained to allow communication with earlier systems. This would require that protocol negotiation take place between the two systems. In addition to any protocol code changes, the Microsoft Open Specification program requires that the formal protocol specification for a protocol be updated in a timely manner. An example of a MS protocol specification document (MS-PSRP) can be found at: https://msdn.microsoft.com/en-us/library/dd357801.aspx ++ Making changes to the protocols with a protocol version increment. Older versions of the protocol would still need to be maintained to allow communication with earlier systems. This would require that protocol negotiation take place between the two systems. In addition to any protocol code changes, the Microsoft Open Specification program requires that the formal protocol specification for a protocol be updated in a timely manner. An example of a MS protocol specification document (MS-PSRP) can be found at: https://msdn.microsoft.com/library/mt242417.aspx ## Bucket 2: Reasonable Grey Area @@ -44,7 +48,8 @@ Examples: + Change in parsing of input and throwing new errors (even if parsing behavior is not specified in the docs) + Example: a script may be using a JSON parser that is forgiving to minor syntactic errors in the JSON text. Changing that parser to be more rigorous in its processing would result in errors being thrown when no error was generated in the past thus breaking scripts. -Judiciously making changes in these type of features require judgement: how predictable, obvious, consistent was the behavior? In general, a significant external preview of the change would need to be done also possibly requiring an RFC to be created to allow for community input on the proposal. +Judiciously making changes in these type of features require judgement: how predictable, obvious, consistent was the behavior? +In general, a significant external preview of the change would need to be done also possibly requiring an RFC to be created to allow for community input on the proposal. ## Bucket 3: Unlikely Grey Area @@ -66,11 +71,14 @@ Changes to surface area or behavior that is clearly internal or non-breaking in Examples: -+ Changes to internal APIs that break private reflection ++ Changes to internal APIs that break private reflection. ++ Changes to APIs in the `System.Management.Automation.Internal` namespace (even if they are public, they are still considered internal and subject to change). ++ Renaming a parameter set (see related discussion [here](https://github.com/PowerShell/PowerShell/issues/10058)). -It is impossible to evolve a code base without making such changes, so we don't require up-front approval for these, but we will sometimes have to go back and revisit such change if there's too much pain inflicted on the ecosystem through a popular app or library. +It is impossible to evolve a code base without making such changes, so we don't require up-front approval for these, but we will sometimes have to go back and +revisit such change if there's too much pain inflicted on the ecosystem through a popular app or library. -# What This Means for Contributors +## What This Means for Contributors + All bucket 1, 2, and 3 breaking changes require contacting team at @powershell/powershell. + If you're not sure into which bucket a given change falls, contact us as well. @@ -78,4 +86,3 @@ It is impossible to evolve a code base without making such changes, so we don't + If a change is deemed too breaking, we can help identify alternatives such as introducing a new API or cmdlet and obsoleting the old one. Request for clarifications or suggested alterations to this document should be done by opening issues against this document. - diff --git a/docs/dev-process/coding-guidelines.md b/docs/dev-process/coding-guidelines.md index 2c0d3947b5fe..3472296251b0 100644 --- a/docs/dev-process/coding-guidelines.md +++ b/docs/dev-process/coding-guidelines.md @@ -86,7 +86,7 @@ We also run the [.NET code formatter tool](https://github.com/dotnet/codeformatt * Make sure the added/updated comments are meaningful, accurate and easy to understand. -* Public members must use [doc comments](https://msdn.microsoft.com/en-us/library/b2s063f7.aspx). +* Public members must use [doc comments](https://docs.microsoft.com/dotnet/csharp/programming-guide/xmldoc/xml-documentation-comments). Internal and private members may use doc comments but it is not required. ## Performance Considerations @@ -108,6 +108,9 @@ Some general guidelines: * Be aware of APIs such as `String.Split(params char[])` that do not provide overloads to avoid array allocation. When calling such APIs, reuse a static array when possible (e.g. `Utils.Separators.Colon`). +* Avoid using string interpolations and overloads with implicit parameters such as `Culture` and `StringComparison`. + Instead, use overloads with more explicit parameters such as `String.Format(IFormatProvider, String, Object[])` and `Equals(String, String, StringComparison)`. + * Avoid creating empty arrays. Instead, reuse the static ones via `Utils.EmptyArray`. @@ -152,7 +155,7 @@ such as `password`, `crypto`, `encryption`, `decryption`, `certificate`, `authen When facing a PR with such changes, the reviewers should request a designated security Subject Matter Expert (SME) to review the PR. -Currently, @PaulHigin and @TravisEz13 are our security SMEs. +Currently, [@PaulHigin](https://github.com/PaulHigin) and [@TravisEz13](https://github.com/TravisEz13) are our security SMEs. See [CODEOWNERS](../../.github/CODEOWNERS) for more information about the area experts. ## Best Practices @@ -162,7 +165,7 @@ See [CODEOWNERS](../../.github/CODEOWNERS) for more information about the area e * Avoid a method that is too long and complex. In such case, separate it to multiple methods or even a nested class as you see fit. -* Use `using` statement instead of `try/finally` if the only code in the `finally` block is to call the `Dispose` method. +* Use the `using` statement instead of `try/finally` if the only code in the `finally` block is to call the `Dispose` method. * Use of object initializers (e.g. `new Example { Name = "Name", ID = 1 }`) is encouraged for better readability, but not required. @@ -183,16 +186,16 @@ See [CODEOWNERS](../../.github/CODEOWNERS) for more information about the area e * Consider using the `Interlocked` class instead of the `lock` statement to atomically change simple states. The `Interlocked` class provides better performance for updates that must be atomic. * Here are some useful links for your reference: - * [Framework Design Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/index) - Naming, Design and Usage guidelines including: - * [Arrays](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/arrays) - * [Collections](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/guidelines-for-collections) - * [Exceptions](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/exceptions) - * [Best Practices for Developing World-Ready Applications](https://docs.microsoft.com/en-us/dotnet/standard/globalization-localization/best-practices-for-developing-world-ready-apps) - Unicode, Culture, Encoding and Localization. - * [Best Practices for Exceptions](https://docs.microsoft.com/en-us/dotnet/standard/exceptions/best-practices-for-exceptions) - * [Best Practices for Using Strings in .NET](https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings) - * [Best Practices for Regular Expressions in .NET](https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices) - * [Serialization Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/serialization/serialization-guidelines) - * [Managed Threading Best Practices](https://docs.microsoft.com/en-us/dotnet/standard/threading/managed-threading-best-practices) + * [Framework Design Guidelines](https://docs.microsoft.com/dotnet/standard/design-guidelines/index) - Naming, Design and Usage guidelines including: + * [Arrays](https://docs.microsoft.com/dotnet/standard/design-guidelines/arrays) + * [Collections](https://docs.microsoft.com/dotnet/standard/design-guidelines/guidelines-for-collections) + * [Exceptions](https://docs.microsoft.com/dotnet/standard/design-guidelines/exceptions) + * [Best Practices for Developing World-Ready Applications](https://docs.microsoft.com/dotnet/standard/globalization-localization/best-practices-for-developing-world-ready-apps) - Unicode, Culture, Encoding and Localization. + * [Best Practices for Exceptions](https://docs.microsoft.com/dotnet/standard/exceptions/best-practices-for-exceptions) + * [Best Practices for Using Strings in .NET](https://docs.microsoft.com/dotnet/standard/base-types/best-practices-strings) + * [Best Practices for Regular Expressions in .NET](https://docs.microsoft.com/dotnet/standard/base-types/best-practices) + * [Serialization Guidelines](https://docs.microsoft.com/dotnet/standard/serialization/serialization-guidelines) + * [Managed Threading Best Practices](https://docs.microsoft.com/dotnet/standard/threading/managed-threading-best-practices) ## Portable Code diff --git a/docs/dev-process/resx-files.md b/docs/dev-process/resx-files.md index 61bcfa4277df..ec9eace54fe4 100644 --- a/docs/dev-process/resx-files.md +++ b/docs/dev-process/resx-files.md @@ -9,33 +9,32 @@ We are using our own `Start-ResGen` to generate them. Usually it's called as part of the regular build with -``` -PS C:\> Start-PSBuild -ResGen +```powershell +Start-PSBuild -ResGen ``` If you see compilation errors related to resources, try to call `Start-ResGen` explicitly. -``` -PS C:\> Start-ResGen +```powershell +Start-ResGen ``` ## Editing `.resx` files -**Don't edit** `.resx` files from Visual Studio. +**Don't edit** `.resx` files from Visual Studio. It will try to create `.cs` files for you and you will get whole bunch of hard-to-understand errors. -To edit a resource file, use any **plain text editor**. +To edit a resource file, use any **plain text editor**. A resource file is a simple XML file, and it's easy to edit. - ## Convert `.txt` resource files into `.resx` files `dotnet cli` doesn't support embedding old-fashioned `.txt` resource. You can do a one-time conversion of `.txt` resources into `.resx` files with a helper function: -``` +```powershell # example, converting all .txt resources under src\Microsoft.WSMan.Management\resources -PS C:\> Convert-TxtResourceToXml -Path src\Microsoft.WSMan.Management\resources +Convert-TxtResourceToXml -Path src\Microsoft.WSMan.Management\resources ``` `.resx` files would be placed next to `.txt` files. diff --git a/docs/git/README.md b/docs/git/README.md index b896490aae3e..817e4930f6c8 100644 --- a/docs/git/README.md +++ b/docs/git/README.md @@ -1,28 +1,12 @@ -Working with PowerShell repository -================================== +# Working with PowerShell repository -#### Get the code for the first time +## Get the code for the first time ```sh -git clone --recursive https://github.com/PowerShell/PowerShell +git clone https://github.com/PowerShell/PowerShell.git --branch=master ``` -The PowerShell repository has **submodules**. -They are required to build and test PowerShell. -That's why you need `--recursive`, when you `git clone`. - -If you already cloned the repo without `--recursive`, update submodules manually - -```sh -git submodule init -git submodule update -``` - -See [FAQ](../FAQ.md#why-is-my-submodule-empty) for details. - - -Branches ---------- +## Branches * Don't commit your changes directly to master. It will make the collaborative workflow messy. @@ -33,18 +17,18 @@ Branches You must never EVER destroy other peoples history. You must not rebase commits other people did. Basically, if it doesn't have your sign-off on it, it's off limits: you can't rebase it, because it's not yours." -#### Understand branches +### Understand branches * **master** is the branch with the latest and greatest changes. It could be unstable. * Send your pull requests to **master**. -#### Sync your local repo +### Sync your local repo Use **git rebase** instead of **git merge** and **git pull**, when you're updating your feature-branch. ```sh -# fetch updates all remote branch references in the repo and all submodules +# fetch updates all remote branch references in the repo # --all : tells it to do it for all remotes (handy, when you use your fork) # -p : tells it to remove obsolete remote branch references (when they are removed from remote) git fetch --all -p @@ -53,7 +37,7 @@ git fetch --all -p git rebase origin/master ``` -#### More complex scenarios +### More complex scenarios Covering all possible git scenarios is behind the scope of the current document. Git has excellent documentation and lots of materials available online. @@ -62,16 +46,14 @@ We are leaving few links here: [Git pretty flowchart](http://justinhileman.info/article/git-pretty/): what to do, when your local repo became a mess. -[Linus]:http://thread.gmane.org/gmane.comp.video.dri.devel/34739/focus=34744 +[Linus]:https://wincent.com/wiki/git_rebase%3A_you're_doing_it_wrong - -Tags ------- +## Tags If you are looking for the source code for a particular release, you will find it via **tags**. -* `git tag` will show you list of all tags. +* `git tag` will show you list of all tags. * Find the tag that corresponds to the release. * Use `git checkout ` to get this version. @@ -87,31 +69,33 @@ checkout a new branch from this DETACHED HEAD state. git checkout -b vors/hotfix ``` - -Recommended Git configurations -============================== +## Recommended Git configurations We highly recommend these configurations to help deal with whitespace, rebasing, and general use of Git. > Auto-corrects your command when it's sure (`stats` to `status`) + ```sh git config --global help.autoCorrect -1 ``` > Refuses to merge when pulling, and only pushes to branch with same name. + ```sh git config --global pull.ff only git config --global push.default current ``` > Shows shorter commit hashes and always shows reference names in the log. + ```sh git config --global log.abbrevCommit true git config --global log.decorate short ``` > Ignores whitespace changes and uses more information when merging. + ```sh git config --global apply.ignoreWhitespace change git config --global rerere.enabled true diff --git a/docs/git/basics.md b/docs/git/basics.md index f1fcb6939c7e..a8a9bacf046e 100644 --- a/docs/git/basics.md +++ b/docs/git/basics.md @@ -1,14 +1,12 @@ -Getting started with Git -======================== +# Getting started with Git We are using Git version 2.9.0, but any recent version should be good. It's recommended to learn the `git` command-line tool for full cross-platform experience and a deeper understanding of Git itself. -Install ---------- +## Install -#### Windows +### Windows Install [Git for Windows][]. @@ -22,16 +20,12 @@ During the installation process, choose these recommended settings: [Git for Windows]: https://git-scm.com/download/win -#### Linux +### Linux -Install by using the package manager: +Install by using the package manager on your system. +A list of all the package managers and commands can be found [here][linux-git-dl]. -```sh -sudo apt-get install git -``` - -Interactive tutorials ----------------------- +### Interactive tutorials There are (too) many Git tutorials on the internet. Here we post references to our favorites. @@ -58,11 +52,10 @@ learn Git in couple hours. After finishing 50+ real-world scenarios you will have a pretty good idea about what and when you can do with Git. +## Authentication -Authentication --------------- +### Windows -#### Windows On Windows, the best way to use Git securely is [Git Credential Manager for Windows][manager]. It's included in the official Git installer for Windows. @@ -78,13 +71,12 @@ git config --global credential.helper store Alternatively, you can use [SSH key][]. In this case, you may want to use git-ssh even for HTTPS Git URLs. -It will help you to use submodules transparently. -``` +```none git config --global url.git@github.com:.insteadOf https://github.com/ ``` - [SSH key]: https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/#generating-a-new-ssh-key [token]: https://help.github.com/articles/creating-an-access-token-for-command-line-use/ [manager]: https://github.com/Microsoft/Git-Credential-Manager-for-Windows +[linux-git-dl]: https://git-scm.com/download/linux diff --git a/docs/git/submodules.md b/docs/git/submodules.md deleted file mode 100644 index 52acc6ad5f5f..000000000000 --- a/docs/git/submodules.md +++ /dev/null @@ -1,24 +0,0 @@ -# Submodules - -While most developers will not have to deal with submodules on a regular basis, those who do should read this information. -The submodules currently in this project are: - -- `src/libpsl-native/test/googletest`: The GoogleTest framework for - Linux native code - -[submodules]: https://www.git-scm.com/book/en/v2/Git-Tools-Submodules - -## Rebase and Fast-Forward Merge Pull Requests in Submodules - -Note: *This is not necessary in the superproject, only submodules!* - -**DO NOT** commit updates unless absolutely necessary. -When submodules must be updated, a separate Pull Request must be submitted, reviewed, and merged before updating the superproject. - -Because GitHub's "Merge Pull Request" button merges with `--no-ff`, an extra merge commit will always be created. -This is especially annoying when trying to commit updates to submodules. -Therefore our policy is to merge using the Git CLI after approval, with a rebase onto master to enable a fast-forward merge. - -When committing submodule updates, ensure no other changes are in the same commit. -Submodule bumps may be included in feature branches for ease of work, -but the update must be independently approved before merging into master. diff --git a/docs/host-powershell/README.md b/docs/host-powershell/README.md index 0b09af9dd063..3d96855b4131 100644 --- a/docs/host-powershell/README.md +++ b/docs/host-powershell/README.md @@ -1,153 +1,26 @@ # Host PowerShell Core in .NET Core Applications -## PowerShell Core v6.0.0-beta.3 and Later - -PowerShell Core is refactored in v6.0.0-beta.3 to remove the dependency on a customized `AssemblyLoadContext`. -With this change, hosting PowerShell Core in .NET Core will be the same as hosting Windows PowerShell in .NET. - -Please see the [.NET Core Sample Application](#net-core-sample-application) section for an example that uses PowerShell Core `beta.3` NuGet packages. - -## PowerShell Core v6.0.0-beta.2 and Prior - -### Overview - -Due to the lack of necessary APIs for manipulating assemblies in .NET Core 1.1 and prior, -PowerShell Core needs to control assembly loading via our customized `AssemblyLoadContext` ([CorePsAssemblyLoadContext.cs][]) in order to do tasks like type resolution. -So applications that want to host PowerShell Core (using PowerShell APIs) need to be bootstrapped from `PowerShellAssemblyLoadContextInitializer`. - -`PowerShellAssemblyLoadContextInitializer` exposes 2 APIs for this purpose: -`SetPowerShellAssemblyLoadContext` and `InitializeAndCallEntryMethod`. -They are for different scenarios: - -- `SetPowerShellAssemblyLoadContext` - It's designed to be used by a native host - whose Trusted Platform Assemblies (TPA) do not include PowerShell assemblies, - such as the in-box `powershell.exe` and other native CoreCLR host in Nano Server. - When using this API, instead of setting up a new load context, - `PowerShellAssemblyLoadContextInitializer` will register a handler to the [Resolving][] event of the default load context. - Then PowerShell Core will depend on the default load context to handle TPA and the `Resolving` event to handle other assemblies. - -- `InitializeAndCallEntryMethod` - It's designed to be used with `dotnet.exe` - where the TPA list includes PowerShell assemblies. - When using this API, `PowerShellAssemblyLoadContextInitializer` will set up a new load context to handle all assemblies. - PowerShell Core itself also uses this API for [bootstrapping][]. - -This documentation only covers the `InitializeAndCallEntryMethod` API, -as it's what you need when building a .NET Core application with .NET CLI. - -### Comparison - Hosting Windows PowerShell vs. Hosting PowerShell Core - -The following code demonstrates how to host Windows PowerShell in an application. -As shown below, you can insert your business logic code directly in the `Main` method. - -```CSharp -// MyApp.exe -using System; -using System.Management.Automation; - -public class Program -{ - static void Main(string[] args) - { - // My business logic code - using (PowerShell ps = PowerShell.Create()) - { - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - } - } -} -``` +## PowerShell Core v6.0.1 and Later -However, when it comes to hosting PowerShell Core, there will be a layer of redirection for the PowerShell load context to take effect. -In a .NET Core application, the entry point assembly that contains the `Main` method is loaded in the default load context, -and thus all assemblies referenced by the entry point assembly, implicitly or explicitly, will also be loaded into the default load context. - -In order to have the PowerShell load context to control assembly loading for the execution of an application, -the business logic code needs to be extracted out of the entry point assembly and put into a different assembly, say `Logic.dll`. -The entry point `Main` method shall do one thing only -- let the PowerShell load context load `Logic.dll` and start the execution of the business logic. -Once the execution starts this way, all further assembly loading requests will be handled by the PowerShell load context. - -So the above example needs to be altered as follows in a .NET Core application: - -```CSharp -// MyApp.exe -using System.Management.Automation; -using System.Reflection; - -namespace Application.Test -{ - public class Program - { - /// - /// Managed entry point shim, which starts the actual program - /// - public static int Main(string[] args) - { - // Application needs to use PowerShell AssemblyLoadContext if it needs to create PowerShell runspace - // PowerShell engine depends on PS ALC to provide the necessary assembly loading/searching support that is missing from .NET Core - string appBase = System.IO.Path.GetDirectoryName(typeof(Program).GetTypeInfo().Assembly.Location); - System.Console.WriteLine("\nappBase: {0}", appBase); - - // Initialize the PS ALC and let it load 'Logic.dll' and start the execution - return (int)PowerShellAssemblyLoadContextInitializer. - InitializeAndCallEntryMethod( - appBase, - new AssemblyName("Logic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), - "Application.Test.Logic", - "Start", - new object[] { args }); - } - } -} - -// Logic.dll -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; - -namespace Application.Test -{ - public sealed class Logic - { - /// - /// Start the actual logic - /// - public static int Start(string[] args) - { - // My business logic code - using (PowerShell ps = PowerShell.Create()) - { - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - } - return 0; - } - } -} -``` +The runtime assemblies for Windows, Linux and OSX are now published in NuGet package version 6.*. -[CorePsAssemblyLoadContext.cs]: https://github.com/PowerShell/PowerShell/blob/v6.0.0-beta.2/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs -[Resolving]: https://github.com/dotnet/corefx/blob/ec2a6190efa743ab600317f44d757433e44e859b/src/System.Runtime.Loader/ref/System.Runtime.Loader.cs#L35 -[bootstrapping]: https://github.com/PowerShell/PowerShell/blob/v6.0.0-beta.2/src/powershell/Program.cs#L27 +Please see the [.NET Core Sample Application](#net-core-sample-application) section for an example that uses PowerShell Core NuGet packages. ## .NET Core Sample Application -- [sample-dotnet1.1](./sample-dotnet1.1) - .NET Core `1.1` + PowerShell Core `alpha.17` NuGet packages. - [.NET Core SDK 1.0.1](https://github.com/dotnet/cli/releases/tag/v1.0.1) is required. -- [sample-dotnet2.0-powershell.beta.1](./sample-dotnet2.0-powershell.beta.1) - .NET Core `2.0.0` + PowerShell Core `beta.1` NuGet packages. - .NET Core SDK `2.0.0-preview1-005952` or higher is required. -- [sample-dotnet2.0-powershell.beta.3](./sample-dotnet2.0-powershell.beta.3) - .NET Core `2.0.0` + PowerShell Core `beta.3` NuGet packages. - .NET Core SDK `2.0.0-preview1-005952` or higher is required. +Note: The .NET Core `2.1` runtime and .NET Core SDK `2.1` or higher is required for the examples below: -You can find the sample application project `"MyApp"` in each of the above 3 sample folders. -To build the sample project, run the following commands (make sure the required .NET Core SDK is in use): +- [sample](./sample) + +You can find the sample application project `MyApp` in each of the above 2 sample folders. You can quickly test-run it using `dotnet run`. +To build the sample project properly for distribution, run the following command (make sure the required .NET Core SDK is in use): ```powershell -dotnet restore .\MyApp\MyApp.csproj -dotnet publish .\MyApp -c release -r win10-x64 +dotnet publish .\MyApp --configuration release ``` -Then you can run `MyApp.exe` from the publish folder and see the results: +This builds it for the runtimes specified by the `RuntimeIdentifiers` property in the `.csproj` file. +Then you can run the `MyApp` binary from the publish folder and see the results: ```none PS:> .\MyApp.exe @@ -162,8 +35,13 @@ System.Management.Automation.ActionPreference System.Management.Automation.AliasAttribute ``` -## Remaining Issue +## Special Hosting Scenario For Native Host + +There is a special hosting scenario for native hosts, +where Trusted Platform Assemblies (TPA) do not include PowerShell assemblies, +such as the in-box `powershell.exe` in Nano Server and the Azure DSC host. -PowerShell Core builds separately for Windows and Unix, so the assemblies are different between Windows and Unix platforms. -Unfortunately, all PowerShell NuGet packages that have been published so far only contain PowerShell assemblies built specifically for Windows. -The issue [#3417](https://github.com/PowerShell/PowerShell/issues/3417) was opened to track publishing PowerShell NuGet packages for Unix platforms. +For such hosting scenarios, the native host needs to bootstrap by calling [`PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext`](https://docs.microsoft.com/dotnet/api/system.management.automation.powershellassemblyloadcontextinitializer.setpowershellassemblyloadcontext). +When using this API, the native host can pass in the path to the directory that contains PowerShell assemblies. +A handler will then be registered to the [`Resolving`](https://github.com/dotnet/corefx/blob/d6678e9653defe3cdfff26b2ff62135b6b22c77f/src/System.Runtime.Loader/ref/System.Runtime.Loader.cs#L38) +event of the default load context to deal with the loading of assemblies from that directory. diff --git a/docs/host-powershell/sample-dotnet1.1/Logic/Logic.csproj b/docs/host-powershell/sample-dotnet1.1/Logic/Logic.csproj deleted file mode 100644 index dc8816bca50d..000000000000 --- a/docs/host-powershell/sample-dotnet1.1/Logic/Logic.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netstandard1.6 - Logic - win10-x64 - $(PackageTargetFallback);dnxcore50;portable-net45+win8 - - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet1.1/Logic/UseRunspace.cs b/docs/host-powershell/sample-dotnet1.1/Logic/UseRunspace.cs deleted file mode 100644 index f9aa64abfdd0..000000000000 --- a/docs/host-powershell/sample-dotnet1.1/Logic/UseRunspace.cs +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; - -namespace Application.Test -{ - public sealed class Logic - { - /// - /// Start the actual logic - /// - public static int Start(string[] args) - { - using (PowerShell ps = PowerShell.Create()) - { - Console.WriteLine("\nEvaluating 'Get-Command Write-Output' in PS Core Runspace\n"); - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - - ps.Commands.Clear(); - - Console.WriteLine("\nEvaluating '([S.M.A.ActionPreference], [S.M.A.AliasAttribute]).FullName' in PS Core Runspace\n"); - results = ps.AddScript("([System.Management.Automation.ActionPreference], [System.Management.Automation.AliasAttribute]).FullName").Invoke(); - foreach (dynamic result in results) - { - Console.WriteLine(result.ToString()); - } - } - return 0; - } - } -} diff --git a/docs/host-powershell/sample-dotnet1.1/MyApp/MyApp.csproj b/docs/host-powershell/sample-dotnet1.1/MyApp/MyApp.csproj deleted file mode 100644 index 012db33cc603..000000000000 --- a/docs/host-powershell/sample-dotnet1.1/MyApp/MyApp.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - netcoreapp1.1 - MyApp - Exe - win10-x64 - $(PackageTargetFallback);dnxcore50;portable-net45+win8 - 1.1.1 - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet1.1/MyApp/Program.cs b/docs/host-powershell/sample-dotnet1.1/MyApp/Program.cs deleted file mode 100644 index 9391a589827e..000000000000 --- a/docs/host-powershell/sample-dotnet1.1/MyApp/Program.cs +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System.Management.Automation; -using System.Reflection; - -namespace Application.Test -{ - public class Program - { - /// - /// Managed entry point shim, which starts the actual program - /// - public static int Main(string[] args) - { - // Application needs to use PowerShell AssemblyLoadContext if it needs to create powershell runspace - // PowerShell engine depends on PS ALC to provide the necessary assembly loading/searching support that is missing from .NET Core - string appBase = System.IO.Path.GetDirectoryName(typeof(Program).GetTypeInfo().Assembly.Location); - System.Console.WriteLine("\nappBase: {0}", appBase); - - // Initialize the PS ALC and let it load 'Logic.dll' and start the execution - return (int)PowerShellAssemblyLoadContextInitializer. - InitializeAndCallEntryMethod( - appBase, - new AssemblyName("Logic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), - "Application.Test.Logic", - "Start", - new object[] { args }); - } - } -} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/Logic.csproj b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/Logic.csproj deleted file mode 100644 index 0d32ce0bbfc4..000000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/Logic.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - Logic - win10-x64 - - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/UseRunspace.cs b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/UseRunspace.cs deleted file mode 100644 index f9aa64abfdd0..000000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/UseRunspace.cs +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; - -namespace Application.Test -{ - public sealed class Logic - { - /// - /// Start the actual logic - /// - public static int Start(string[] args) - { - using (PowerShell ps = PowerShell.Create()) - { - Console.WriteLine("\nEvaluating 'Get-Command Write-Output' in PS Core Runspace\n"); - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - - ps.Commands.Clear(); - - Console.WriteLine("\nEvaluating '([S.M.A.ActionPreference], [S.M.A.AliasAttribute]).FullName' in PS Core Runspace\n"); - results = ps.AddScript("([System.Management.Automation.ActionPreference], [System.Management.Automation.AliasAttribute]).FullName").Invoke(); - foreach (dynamic result in results) - { - Console.WriteLine(result.ToString()); - } - } - return 0; - } - } -} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/MyApp.csproj b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/MyApp.csproj deleted file mode 100644 index 6bdba82519be..000000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/MyApp.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - MyApp - Exe - win10-x64 - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/Program.cs b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/Program.cs deleted file mode 100644 index 9391a589827e..000000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/Program.cs +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System.Management.Automation; -using System.Reflection; - -namespace Application.Test -{ - public class Program - { - /// - /// Managed entry point shim, which starts the actual program - /// - public static int Main(string[] args) - { - // Application needs to use PowerShell AssemblyLoadContext if it needs to create powershell runspace - // PowerShell engine depends on PS ALC to provide the necessary assembly loading/searching support that is missing from .NET Core - string appBase = System.IO.Path.GetDirectoryName(typeof(Program).GetTypeInfo().Assembly.Location); - System.Console.WriteLine("\nappBase: {0}", appBase); - - // Initialize the PS ALC and let it load 'Logic.dll' and start the execution - return (int)PowerShellAssemblyLoadContextInitializer. - InitializeAndCallEntryMethod( - appBase, - new AssemblyName("Logic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), - "Application.Test.Logic", - "Start", - new object[] { args }); - } - } -} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/NuGet.config b/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/NuGet.config deleted file mode 100644 index 58f8d2c9b6d6..000000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/NuGet.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/MyApp.csproj b/docs/host-powershell/sample/MyApp/MyApp.csproj similarity index 67% rename from docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/MyApp.csproj rename to docs/host-powershell/sample/MyApp/MyApp.csproj index 6901e37dda8f..b03d053c16b3 100644 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/MyApp.csproj +++ b/docs/host-powershell/sample/MyApp/MyApp.csproj @@ -1,16 +1,16 @@  - netcoreapp2.0 + netcoreapp2.1 MyApp Exe - win10-x64 + win10-x64;linux-x64;osx-x64 - - - + + + diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/Program.cs b/docs/host-powershell/sample/MyApp/Program.cs similarity index 84% rename from docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/Program.cs rename to docs/host-powershell/sample/MyApp/Program.cs index 92f03751969a..1bd9f883ca34 100644 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/Program.cs +++ b/docs/host-powershell/sample/MyApp/Program.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -10,7 +9,7 @@ namespace Application.Test public class Program { /// - /// Managed entry point shim, which starts the actual program + /// Managed entry point shim, which starts the actual program. /// public static int Main(string[] args) { @@ -29,6 +28,7 @@ public static int Main(string[] args) Console.WriteLine(result.ToString()); } } + return 0; } } diff --git a/docs/host-powershell/sample-dotnet1.1/NuGet.config b/docs/host-powershell/sample/NuGet.config similarity index 100% rename from docs/host-powershell/sample-dotnet1.1/NuGet.config rename to docs/host-powershell/sample/NuGet.config diff --git a/docs/installation/linux.md b/docs/installation/linux.md deleted file mode 100644 index 6a0440ba60a7..000000000000 --- a/docs/installation/linux.md +++ /dev/null @@ -1,808 +0,0 @@ -# Package installation instructions - -Supports [Ubuntu 14.04][u14], [Ubuntu 16.04][u16], [Ubuntu 17.04][u17], [Debian 8][deb8], [Debian 9][deb9], -[CentOS 7][cos], [Red Hat Enterprise Linux (RHEL) 7][rhel7], [OpenSUSE 42.2][opensuse], [Fedora 25][fed25], -[Fedora 26][fed26], [Arch Linux][arch], and [macOS 10.12][mac]. - -For Linux distributions that are not officially supported, -you can try using the [PowerShell AppImage][lai]. -You can also try deploying PowerShell binaries directly using the Linux [`tar.gz` archive][tar], -but you would need to set up the necessary dependencies based on the OS in separate steps. - -All packages are available on our GitHub [releases][] page. -Once the package is installed, run `pwsh` from a terminal. - -[u14]: #ubuntu-1404 -[u16]: #ubuntu-1604 -[u17]: #ubuntu-1704 -[deb8]: #debian-8 -[deb9]: #debian-9 -[cos]: #centos-7 -[rhel7]: #red-hat-enterprise-linux-rhel-7 -[opensuse]: #opensuse-422 -[fed25]: #fedora-25 -[fed26]: #fedora-26 -[arch]: #arch-linux -[lai]: #linux-appimage -[mac]: #macos-1012 -[tar]: #binary-archives - -## Ubuntu 14.04 - -### Installation via Package Repository - Ubuntu 14.04 - -PowerShell Core, for Linux, is published to package repositories for easy installation (and updates). -This is the preferred method. - -```sh -# Import the public repository GPG keys -curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - -# Register the Microsoft Ubuntu repository -curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list - -# Update the list of products -sudo apt-get update - -# Install PowerShell -sudo apt-get install -y powershell - -# Start PowerShell -pwsh -``` - -After registering the Microsoft repository once as superuser, -from then on, you just need to use `sudo apt-get upgrade powershell` to update it. - -### Installation via Direct Download - Ubuntu 14.04 - -Download the Debian package -`powershell_6.0.0-rc.2-1.ubuntu.14.04_amd64.deb` -from the [releases][] page onto the Ubuntu machine. - -Then execute the following in the terminal: - -```sh -sudo dpkg -i powershell_6.0.0-rc.2-1.ubuntu.14.04_amd64.deb -sudo apt-get install -f -``` - -> Please note that `dpkg -i` will fail with unmet dependencies; -> the next command, `apt-get install -f` resolves these -> and then finishes configuring the PowerShell package. - -### Uninstallation - Ubuntu 14.04 - -```sh -sudo apt-get remove powershell -``` - -## Ubuntu 16.04 - -### Installation via Package Repository - Ubuntu 16.04 - -PowerShell Core, for Linux, is published to package repositories for easy installation (and updates). -This is the preferred method. - -```sh -# Import the public repository GPG keys -curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - -# Register the Microsoft Ubuntu repository -curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list - -# Update the list of products -sudo apt-get update - -# Install PowerShell -sudo apt-get install -y powershell - -# Start PowerShell -pwsh -``` - -After registering the Microsoft repository once as superuser, -from then on, you just need to use `sudo apt-get upgrade powershell` to update it. - -### Installation via Direct Download - Ubuntu 16.04 - -Download the Debian package -`powershell_6.0.0-rc.2-1.ubuntu.16.04_amd64.deb` -from the [releases][] page onto the Ubuntu machine. - -Then execute the following in the terminal: - -```sh -sudo dpkg -i powershell_6.0.0-rc.2-1.ubuntu.16.04_amd64.deb -sudo apt-get install -f -``` - -> Please note that `dpkg -i` will fail with unmet dependencies; -> the next command, `apt-get install -f` resolves these -> and then finishes configuring the PowerShell package. - -### Uninstallation - Ubuntu 16.04 - -```sh -sudo apt-get remove powershell -``` - -## Ubuntu 17.04 - -### Installation via Package Repository - Ubuntu 17.04 - -PowerShell Core, for Linux, is published to package repositories for easy installation (and updates). -This is the preferred method. - -```sh -# Import the public repository GPG keys -curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - -# Register the Microsoft Ubuntu repository -curl https://packages.microsoft.com/config/ubuntu/17.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list - -# Update the list of products -sudo apt-get update - -# Install PowerShell -sudo apt-get install -y powershell - -# Start PowerShell -pwsh -``` - -After registering the Microsoft repository once as superuser, -from then on, you just need to use `sudo apt-get upgrade powershell` to update it. - -### Installation via Direct Download - Ubuntu 17.04 - -Download the Debian package -`powershell_6.0.0-rc.2-1.ubuntu.17.04_amd64.deb` -from the [releases][] page onto the Ubuntu machine. - -Then execute the following in the terminal: - -```sh -sudo dpkg -i powershell_6.0.0-rc.2-1.ubuntu.17.04_amd64.deb -sudo apt-get install -f -``` - -> Please note that `dpkg -i` will fail with unmet dependencies; -> the next command, `apt-get install -f` resolves these -> and then finishes configuring the PowerShell package. - -### Uninstallation - Ubuntu 17.04 - -```sh -sudo apt-get remove powershell -``` - -## Debian 8 - -### Installation via Package Repository - Debian 8 - -PowerShell Core, for Linux, is published to package repositories for easy installation (and updates). -This is the preferred method. - -```sh -# Install system components -sudo apt-get update -sudo apt-get install curl apt-transport-https - -# Import the public repository GPG keys -curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - -# Register the Microsoft Product feed -sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-debian-jessie-prod jessie main" > /etc/apt/sources.list.d/microsoft.list' - -# Update the list of products -sudo apt-get update - -# Install PowerShell -sudo apt-get install -y powershell - -# Start PowerShell -pwsh -``` - -After registering the Microsoft repository once as superuser, -from then on, you just need to use `sudo apt-get upgrade powershell` to update it. - -### Installation via Direct Download - Debian 8 - -Download the Debian package -`powershell_6.0.0-rc.2-1.debian.8_amd64.deb` -from the [releases][] page onto the Debian machine. - -Then execute the following in the terminal: - -```sh -sudo dpkg -i powershell_6.0.0-rc.2-1.debian.8_amd64.deb -sudo apt-get install -f -``` - -> Please note that `dpkg -i` will fail with unmet dependencies; -> the next command, `apt-get install -f` resolves these -> and then finishes configuring the PowerShell package. - -### Uninstallation - Debian 8 - -```sh -sudo apt-get remove powershell -``` - -## Debian 9 - -### Installation via Package Repository - Debian 9 - -PowerShell Core, for Linux, is published to package repositories for easy installation (and updates). -This is the preferred method. - -```sh -# Install system components -sudo apt-get update -sudo apt-get install curl gnupg apt-transport-https - -# Import the public repository GPG keys -curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - -# Register the Microsoft Product feed -sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-debian-stretch-prod stretch main" > /etc/apt/sources.list.d/microsoft.list' - -# Update the list of products -sudo apt-get update - -# Install PowerShell -sudo apt-get install -y powershell - -# Start PowerShell -pwsh -``` - -After registering the Microsoft repository once as superuser, -from then on, you just need to use `sudo apt-get upgrade powershell` to update it. - -### Installation via Direct Download - Debian 9 - -Download the Debian package -`powershell_6.0.0-rc.2-1.debian.9_amd64.deb` -from the [releases][] page onto the Debian machine. - -Then execute the following in the terminal: - -```sh -sudo dpkg -i powershell_6.0.0-rc.2-1.debian.9_amd64.deb -sudo apt-get install -f -``` - -> Please note that `dpkg -i` will fail with unmet dependencies; -> the next command, `apt-get install -f` resolves these -> and then finishes configuring the PowerShell package. - -### Uninstallation - Debian 9 - -```sh -sudo apt-get remove powershell -``` - -## CentOS 7 - -> This package also works on Oracle Linux 7. - -### Installation via Package Repository (preferred) - CentOS 7 - -PowerShell Core for Linux is published to official Microsoft repositories for easy installation (and updates). - -```sh -# Register the Microsoft RedHat repository -curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo - -# Install PowerShell -sudo yum install -y powershell - -# Start PowerShell -pwsh -``` - -After registering the Microsoft repository once as superuser, -you just need to use `sudo yum update powershell` to update PowerShell. - -### Installation via Direct Download - CentOS 7 - -Using [CentOS 7][], download the RPM package -`powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm` -from the [releases][] page onto the CentOS machine. - -Then execute the following in the terminal: - -```sh -sudo yum install powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -You can also install the RPM without the intermediate step of downloading it: - -```sh -sudo yum install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -### Uninstallation - CentOS 7 - -```sh -sudo yum remove powershell -``` - -[CentOS 7]: https://www.centos.org/download/ - -## Red Hat Enterprise Linux (RHEL) 7 - -### Installation via Package Repository (preferred) - Red Hat Enterprise Linux (RHEL) 7 - -PowerShell Core for Linux is published to official Microsoft repositories for easy installation (and updates). - -```sh -# Register the Microsoft RedHat repository -curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo - -# Install PowerShell -sudo yum install -y powershell - -# Start PowerShell -pwsh -``` - -After registering the Microsoft repository once as superuser, -you just need to use `sudo yum update powershell` to update PowerShell. - -### Installation via Direct Download - Red Hat Enterprise Linux (RHEL) 7 - -Download the RPM package -`powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm` -from the [releases][] page onto the Red Hat Enterprise Linux machine. - -Then execute the following in the terminal: - -```sh -sudo yum install powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -You can also install the RPM without the intermediate step of downloading it: - -```sh -sudo yum install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -### Uninstallation - Red Hat Enterprise Linux (RHEL) 7 - -```sh -sudo yum remove powershell -``` - -## OpenSUSE 42.2 - -> **Note:** When installing PowerShell Core, OpenSUSE may report that nothing provides `libcurl`. -`libcurl` should already be installed on supported versions of OpenSUSE. -Run `zypper search libcurl` to confirm. -The error will present 2 'solutions'. Choose 'Solution 2' to continue installing PowerShell Core. - -### Installation via Package Repository (preferred) - OpenSUSE 42.2 - -PowerShell Core for Linux is published to official Microsoft repositories for easy installation (and updates). - -```sh -# Register the Microsoft signature key -sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc - -# Add the Microsoft Product feed -curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/zypp/repos.d/microsoft.repo - -# Update the list of products -sudo zypper update - -# Install PowerShell -sudo zypper install powershell - -# Start PowerShell -pwsh -``` - -### Installation via Direct Download - OpenSUSE 42.2 - -Download the RPM package `powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm` -from the [releases][] page onto the OpenSUSE machine. - -```sh -sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc -sudo zypper install powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -You can also install the RPM without the intermediate step of downloading it: - -```sh -sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc -sudo zypper install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -### Uninstallation - OpenSUSE 42.2 - -```sh -sudo zypper remove powershell -``` - -## Fedora 25 - -### Installation via Package Repository (preferred) - Fedora 25 - -PowerShell Core for Linux is published to official Microsoft repositories for easy installation (and updates). - -```sh -# Register the Microsoft signature key -sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc - -# Register the Microsoft RedHat repository -curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo - -# Update the list of products -sudo dnf update - -# Install PowerShell -sudo dnf install -y powershell - -# Start PowerShell -pwsh -``` - -### Installation via Direct Download - Fedora 25 - -Download the RPM package -`powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm` -from the [releases][] page onto the Fedora machine. - -Then execute the following in the terminal: - -```sh -sudo dnf install powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -You can also install the RPM without the intermediate step of downloading it: - -```sh -sudo dnf install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -### Uninstallation - Fedora 25 - -```sh -sudo dnf remove powershell -``` - -## Fedora 26 - -### Installation via Package Repository (preferred) - Fedora 26 - -PowerShell Core for Linux is published to official Microsoft repositories for easy installation (and updates). - -```sh -# Register the Microsoft signature key -sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc - -# Register the Microsoft RedHat repository -curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo - -# Update the list of products -sudo dnf update - -# Install a system component -sudo dnf install compat-openssl10 - -# Install PowerShell -sudo dnf install -y powershell - -# Start PowerShell -pwsh -``` - -### Installation via Direct Download - Fedora 26 - -Download the RPM package -`powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm` -from the [releases][] page onto the Fedora machine. - -Then execute the following in the terminal: - -```sh -sudo dnf update -sudo dnf install compat-openssl10 -sudo dnf install powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -You can also install the RPM without the intermediate step of downloading it: - -```sh -sudo dnf update -sudo dnf install compat-openssl10 -sudo dnf install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0_rc.2-1.rhel.7.x86_64.rpm -``` - -### Uninstallation - Fedora 26 - -```sh -sudo dnf remove powershell -``` - -## Arch Linux - -PowerShell is available from the [Arch Linux][] User Repository (AUR). - -* It can be compiled with the [latest tagged release][arch-release] -* It can be compiled from the [latest commit to master][arch-git] -* It can be installed using the [latest release binary][arch-bin] - -Packages in the AUR are community maintained - there is no official support. - -For more information on installing packages from the AUR, see the [Arch Linux wiki](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages) or the community [DockerFile](https://github.com/PowerShell/PowerShell/blob/master/docker/community/archlinux/Dockerfile). - -[Arch Linux]: https://www.archlinux.org/download/ -[arch-release]: https://aur.archlinux.org/packages/powershell/ -[arch-git]: https://aur.archlinux.org/packages/powershell-git/ -[arch-bin]: https://aur.archlinux.org/packages/powershell-bin/ - -## Linux AppImage - -Using a recent Linux distribution, -download the AppImage `powershell-6.0.0-rc.2-x86_64.AppImage` -from the [releases][] page onto the Linux machine. - -Then execute the following in the terminal: - -```bash -chmod a+x powershell-6.0.0-rc.2-x86_64.AppImage -./powershell-6.0.0-rc.2-x86_64.AppImage -``` - -The [AppImage][] lets you run PowerShell without installing it. -It is a portable application that bundles PowerShell and its dependencies -(including .NET Core's system dependencies) into one cohesive package. -This package works independently of the user's Linux distribution, -and is a single binary. - -[appimage]: http://appimage.org/ - -## macOS 10.12 - -### Installation via Homebrew (preferred) - macOS 10.12 - -[Homebrew][brew] is the missing package manager for macOS. -If the `brew` command is not found, -you need to install Homebrew following [their instructions][brew]. - -Once you've installed Homebrew, installing PowerShell is easy. -First, install [Homebrew-Cask][cask], so you can install more packages: - -```sh -brew tap caskroom/cask -``` - -Now, you can install PowerShell: - -```sh -brew cask install powershell -``` - -When new versions of PowerShell are released, -simply update Homebrew's formulae and upgrade PowerShell: - -```sh -brew update -brew cask reinstall powershell -``` - -> Note: because of [this issue in Cask](https://github.com/caskroom/homebrew-cask/issues/29301), you currently have to do a reinstall to upgrade. - -[brew]: http://brew.sh/ -[cask]: https://caskroom.github.io/ - -### Installation via Direct Download - macOS 10.12 - -Using macOS 10.12, download the PKG package -`powershell-6.0.0-rc.2-osx.10.12-x64.pkg` -from the [releases][] page onto the macOS machine. - -Either double-click the file and follow the prompts, -or install it from the terminal: - -```sh -sudo installer -pkg powershell-6.0.0-rc.2-osx.10.12-x64.pkg -target / -``` - -### Uninstallation - macOS 10.12 - -If you installed PowerShell with Homebrew, uninstallation is easy: - -```sh -brew cask uninstall powershell -``` - -If you installed PowerShell via direct download, -PowerShell must be removed manually: - -```sh -sudo rm -rf /usr/local/bin/pwsh /usr/local/microsoft/powershell -``` - -To uninstall the additional PowerShell paths (such as the user profile path) -please see the [paths][paths] section below in this document -and remove the desired the paths with `sudo rm`. -(Note: this is not necessary if you installed with Homebrew.) - -[paths]:#paths - -## Kali - -### Installation - -```sh -# Install prerequisites -apt-get install libunwind8 libicu55 -wget http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb -dpkg -i libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb - -# Install PowerShell -dpkg -i powershell_6.0.0-rc.2-1.ubuntu.16.04_amd64.deb - -# Start PowerShell -pwsh -``` - -### Run PowerShell in latest Kali (Kali GNU/Linux Rolling) without installing it - -```sh -# Grab the latest App Image -wget https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-x86_64.AppImage - -# Make executable -chmod a+x powershell-6.0.0-rc.2-x86_64.AppImage - -# Start PowerShell -./powershell-6.0.0-rc.2-x86_64.AppImage -``` - -### Uninstallation - Kali - -```sh -dpkg -r powershell_6.0.0-rc.2-1.ubuntu.16.04_amd64.deb -``` - -## Raspbian - -Currently, PowerShell is only supported on Raspbian Stretch. - -### Installation - -```sh -# Install prerequisites -sudo apt-get install libunwind8 - -# Grab the latest tar.gz -wget https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-linux-arm32.tar.gz - -# Make folder to put powershell -mkdir ~/powershell - -# Unpack the tar.gz file -tar -xvf ./powershell-6.0.0-rc.2-linux-arm32.tar.gz -C ~/powershell - -# Start PowerShell -~/powershell/pwsh -``` - -### Uninstallation - Raspbian - -```sh -rm -rf ~/powershell -``` - -## Binary Archives - -PowerShell binary `tar.gz` archives are provided for macOS and Linux platforms to enable advanced deployment scenarios. - -### Dependencies - -For Linux, PowerShell builds portable binaries for all Linux distributions. -But .NET Core runtime requires different dependencies on different distributions, -and hence PowerShell does the same. - -The following chart shows the .NET Core 2.0 dependencies on different Linux distributions that are officially supported. - -| OS | Dependencies | -| ------------------ | ------------ | -| Ubuntu 14.04 | libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6,
libcurl3, libunwind8, libuuid1, zlib1g, libssl1.0.0, libicu52 | -| Ubuntu 16.04 | libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6,
libcurl3, libunwind8, libuuid1, zlib1g, libssl1.0.0, libicu55 | -| Ubuntu 17.04 | libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6,
libcurl3, libunwind8, libuuid1, zlib1g, libssl1.0.0, libicu57 | -| Debian 8 (Jessie) | libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6,
libcurl3, libunwind8, libuuid1, zlib1g, libssl1.0.0, libicu52 | -| Debian 9 (Stretch) | libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6,
libcurl3, libunwind8, libuuid1, zlib1g, libssl1.0.2, libicu57 | -| CentOS 7
Oracle Linux 7
RHEL 7
OpenSUSE 42.2
Fedora 25 | libunwind, libcurl, openssl-libs, libicu | -| Fedora 26 | libunwind, libcurl, openssl-libs, libicu, compat-openssl10 | - -In order to deploy PowerShell binaries on Linux distributions that are not officially supported, -you would need to install the necessary dependencies for the target OS in separate steps. -For example, our [Amazon Linux dockerfile][amazon-dockerfile] installs dependencies first, -and then extracts the Linux `tar.gz` archive. - -[amazon-dockerfile]: https://github.com/PowerShell/PowerShell/blob/master/docker/community/amazonlinux/Dockerfile - -### Installation - Binary Archives - -#### Linux - -```sh -# Download the powershell '.tar.gz' archive -curl -L -o /tmp/powershell.tar.gz https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-linux-x64.tar.gz - -# Create the target folder where powershell will be placed -sudo mkdir -p /opt/microsoft/powershell/6.0.0-rc.2 - -# Expand powershell to the target folder -sudo tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/6.0.0-rc.2 - -# Set execute permissions -sudo chmod +x /usr/local/microsoft/powershell/6.0.0-rc.2/pwsh - -# Create the symbolic link that points to pwsh -sudo ln -s /opt/microsoft/powershell/6.0.0-rc.2/pwsh /usr/bin/pwsh -``` - -#### macOS - -```sh -# Download the powershell '.tar.gz' archive -curl -L -o /tmp/powershell.tar.gz https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-rc.2/powershell-6.0.0-rc.2-osx-x64.tar.gz - -# Create the target folder where powershell will be placed -sudo mkdir -p /usr/local/microsoft/powershell/6.0.0-rc.2 - -# Expand powershell to the target folder -sudo tar zxf /tmp/powershell.tar.gz -C /usr/local/microsoft/powershell/6.0.0-rc.2 - -# Set execute permissions -sudo chmod +x /usr/local/microsoft/powershell/6.0.0-rc.2/pwsh - -# Create the symbolic link that points to pwsh -sudo ln -s /usr/local/microsoft/powershell/6.0.0-rc.2/pwsh /usr/local/bin/pwsh -``` - -### Uninstallation - Binary Archives - -#### Linux - -```sh -sudo rm -rf /usr/bin/pwsh /opt/microsoft/powershell -``` - -#### macOS - -```sh -sudo rm -rf /usr/local/bin/pwsh /usr/local/microsoft/powershell -``` - -## Paths - -* `$PSHOME` is `/opt/microsoft/powershell/6.0.0-rc.2/` -* User profiles will be read from `~/.config/powershell/profile.ps1` -* Default profiles will be read from `$PSHOME/profile.ps1` -* User modules will be read from `~/.local/share/powershell/Modules` -* Shared modules will be read from `/usr/local/share/powershell/Modules` -* Default modules will be read from `$PSHOME/Modules` -* PSReadline history will be recorded to `~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt` - -The profiles respect PowerShell's per-host configuration, -so the default host-specific profiles exists at `Microsoft.PowerShell_profile.ps1` in the same locations. - -On Linux and macOS, the [XDG Base Directory Specification][xdg-bds] is respected. - -Note that because macOS is a derivation of BSD, -instead of `/opt`, the prefix used is `/usr/local`. -Thus, `$PSHOME` is `/usr/local/microsoft/powershell/6.0.0-rc.2/`, -and the symlink is placed at `/usr/local/bin/pwsh`. - -[releases]: https://github.com/PowerShell/PowerShell/releases/latest -[xdg-bds]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html diff --git a/docs/installation/windows.md b/docs/installation/windows.md deleted file mode 100644 index 3d1dc891f02c..000000000000 --- a/docs/installation/windows.md +++ /dev/null @@ -1,194 +0,0 @@ -# Package Installation Instructions - -## MSI - -To install PowerShell on Windows Full SKU (works on Windows 7 SP1 and later), download either the MSI from [AppVeyor][] for a nightly build, -or a released package from our GitHub [releases][] page. The MSI file looks like this - `PowerShell-6.0.0...msi` - -Once downloaded, double-click the installer and follow the prompts. - -There is a shortcut placed in the Start Menu upon installation. - -* By default the package is installed to `$env:ProgramFiles\PowerShell\` -* You can launch PowerShell via the Start Menu or `$env:ProgramFiles\PowerShell\pwsh.exe` - -### Prerequisites - -To enable PowerShell remoting over WinRM, the following prerequisites need to be met: - -* Install the [Universal C Runtime](https://www.microsoft.com/download/details.aspx?id=50410) on Windows versions prior to Windows 10. - It is available via direct download or Windows Update. - Fully patched (including optional packages), supported systems will already have this installed. -* Install the Windows Management Framework (WMF) [4.0](https://www.microsoft.com/download/details.aspx?id=40855) - or newer ([5.0](https://www.microsoft.com/download/details.aspx?id=50395), - [5.1](https://www.microsoft.com/download/details.aspx?id=54616)) on Windows 7. - -## ZIP - -PowerShell binary ZIP archives are provided to enable advanced deployment scenarios. -Be noted that when using the ZIP archive, you won't get the prerequisites check as in the MSI package. -So in order for remoting over WinRM to work properly on Windows versions prior to Windows 10, -you need to make sure the [prerequisites](#prerequisites) are met. - -## Deploying on Windows IoT - -Windows IoT already comes with Windows PowerShell which we will use to deploy PowerShell Core 6. - -* Create `PSSession` to target device - -```powershell -$s = New-PSSession -ComputerName -Credential Administrator -``` - -* Copy the zip package to the device - -```powershell -# change the destination to however you had partitioned it with sufficient space for the zip and the unzipped contents -# the path should be local to the device -Copy-Item .\PowerShell-6.0.0-rc.2-win-arm32.zip -Destination u:\users\administrator\Downloads -ToSession $s -``` - -* Connect to the device and expand the archive - -```powershell -Enter-PSSession $s -cd u:\users\administrator\downloads -Expand-Archive .\PowerShell-6.0.0-rc.2-win-arm32.zip -``` - -* Setup remoting to PowerShell Core 6 - -```powershell -cd .\PowerShell-6.0.0-rc.2-win-arm32 -# Be sure to use the -PowerShellHome parameter otherwise it'll try to create a new endpoint with Windows PowerShell 5.1 -.\Install-PowerShellRemoting.ps1 -PowerShellHome . -# You'll get an error message and will be disconnected from the device because it has to restart WinRM -``` - -* Connect to PowerShell Core 6 endpoint on device - -```powershell -# Be sure to use the -Configuration parameter. If you omit it, you will connect to Windows PowerShell 5.1 -Enter-PSSession -ComputerName -Credential Administrator -Configuration powershell.6.0.0-rc.2 -``` - -## Deploying on Nano Server - -These instructions assume that Windows PowerShell is running on the Nano Server image and that it has been generated by the [Nano Server Image Builder](https://technet.microsoft.com/windows-server-docs/get-started/deploy-nano-server). -Nano Server is a "headless" OS and deployment of PowerShell Core binaries can happen in two different ways: - -1. Offline - Mount the Nano Server VHD and unzip the contents of the zip file to your chosen location within the mounted image. -1. Online - Transfer the zip file over a PowerShell Session and unzip it in your chosen location. - -In both cases, you will need the Windows 10 x64 Zip release package and will need to run the commands within an "Administrator" PowerShell instance. - -### Offline Deployment of PowerShell Core - -1. Use your favorite zip utility to unzip the package to a directory within the mounted Nano Server image. -1. Unmount the image and boot it. -1. Connect to the inbox instance of Windows PowerShell. -1. Follow the instructions to create a remoting endpoint using the [another instance technique](#executed-by-another-instance-of-powershell-on-behalf-of-the-instance-that-it-will-register). - -### Online Deployment of PowerShell Core - -The following steps will guide you through the deployment of PowerShell Core to a running instance of Nano Server and the configuration of its remote endpoint. - -* Connect to the inbox instance of Windows PowerShell - -```powershell -$session = New-PSSession -ComputerName -Credential -``` - -* Copy the file to the Nano Server instance - -```powershell -Copy-Item \powershell--win-x64.zip c:\ -ToSession $session -``` - -* Enter the session - -```powershell -Enter-PSSession $session -``` - -* Extract the Zip file - -```powershell -# Insert the appropriate version. -Expand-Archive -Path C:\powershell--win-x64.zip -DestinationPath "C:\PowerShellCore_" -``` - -* Follow the instructions to create a remoting endpoint using the [another instance technique](#executed-by-another-instance-of-powershell-on-behalf-of-the-instance-that-it-will-register). - -## Instructions to Create a Remoting Endpoint - -Beginning with 6.0.0-alpha.9, the PowerShell package for Windows includes a WinRM plug-in (pwrshplugin.dll) and an installation script (Install-PowerShellRemoting.ps1). -These files enable PowerShell to accept incoming PowerShell remote connections when its endpoint is specified. - -### Motivation - -An installation of PowerShell can establish PowerShell sessions to remote computers using `New-PSSession` and `Enter-PSSession`. -To enable it to accept incoming PowerShell remote connections, the user must create a WinRM remoting endpoint. -This is an explicit opt-in scenario where the user runs Install-PowerShellRemoting.ps1 to create the WinRM endpoint. -The installation script is a short-term solution until we add additional functionality to `Enable-PSRemoting` to perform the same action. -For more details, please see issue [#1193](https://github.com/PowerShell/PowerShell/issues/1193). - -### Script Actions - -The script - -1. Creates a directory for the plug-in within %windir%\System32\PowerShell -1. Copies pwrshplugin.dll to that location -1. Generates a configuration file -1. Registers that plug-in with WinRM - -### Registration - -The script must be executed within an Administrator-level PowerShell session and runs in two modes. - -#### Executed by the instance of PowerShell that it will register - -``` powershell -Install-PowerShellRemoting.ps1 -``` - -#### Executed by another instance of PowerShell on behalf of the instance that it will register - -``` powershell -\Install-PowerShellRemoting.ps1 -PowerShellHome "" -PowerShellVersion "" -``` - -For Example: - -``` powershell -C:\Program Files\PowerShell\6.0.0.9\Install-PowerShellRemoting.ps1 -PowerShellHome "C:\Program Files\PowerShell\6.0.0.9\" -PowerShellVersion "6.0.0-alpha.9" -``` - -**NOTE:** The remoting registration script will restart WinRM, so all existing PSRP sessions will terminate immediately after the script is run. If run during a remote session, this will terminate the connection. - -## How to Connect to the New Endpoint - -Create a PowerShell session to the new PowerShell endpoint by specifying `-ConfigurationName "some endpoint name"`. To connect to the PowerShell instance from the example above, use either: - -``` powershell -New-PSSession ... -ConfigurationName "powershell.6.0.0-alpha.9" -Enter-PSSession ... -ConfigurationName "powershell.6.0.0-alpha.9" -``` - -Note that `New-PSSession` and `Enter-PSSession` invocations that do not specify `-ConfigurationName` will target the default PowerShell endpoint, `microsoft.powershell`. - -## Artifact Installation Instructions - -We publish an archive with CoreCLR bits on every CI build with [AppVeyor][]. - -[releases]: https://github.com/PowerShell/PowerShell/releases -[signing]: ../../tools/Sign-Package.ps1 -[AppVeyor]: https://ci.appveyor.com/project/PowerShell/powershell - -## CoreCLR Artifacts - -* Download zip package from **artifacts** tab of the particular build. -* Unblock zip file: right-click in File Explorer -> Properties -> - check 'Unblock' box -> apply -* Extract zip file to `bin` directory -* `./bin/pwsh.exe` diff --git a/docs/learning-powershell/README.md b/docs/learning-powershell/README.md index 526dffbd833f..ba70b54f99db 100644 --- a/docs/learning-powershell/README.md +++ b/docs/learning-powershell/README.md @@ -1,5 +1,4 @@ -Learning PowerShell -==== +# Learning PowerShell Whether you're a Developer, a DevOps or an IT Professional, this doc will help you getting started with PowerShell. In this document we'll cover the following: @@ -10,18 +9,16 @@ You won't be a PowerShell guru at the end of reading this material but you will If you have 30 minutes now, let’s try it. - -Installing PowerShell ----- +## Installing PowerShell First you need to set up your computer working environment if you have not done so. Choose the platform below and follow the instructions. At the end of this exercise, you should be able to launch the PowerShell session. - Get PowerShell by installing package - * [PowerShell on Linux][inst-linux] - * [PowerShell on macOS][inst-macos] - * [PowerShell on Windows][inst-win] + * [PowerShell on Linux][inst-linux] + * [PowerShell on macOS][inst-macos] + * [PowerShell on Windows][inst-win] For this tutorial, you do not need to install PowerShell if you are running on Windows. You can launch PowerShell console by pressing Windows key, typing PowerShell, and clicking on Windows PowerShell. @@ -29,12 +26,12 @@ At the end of this exercise, you should be able to launch the PowerShell session - Alternatively you can get the PowerShell by [building it](../../README.md#building-powershell) -[inst-linux]: ../installation/linux.md -[inst-win]: ../installation/windows.md -[inst-macos]: ../installation/linux.md#os-x-1011 +[inst-linux]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-linux?view=powershell-6 +[inst-win]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-windows?view=powershell-6 +[inst-macos]: https://docs.microsoft.com/powershell/scripting/setup/installing-powershell-core-on-macos?view=powershell-6 + +## Getting Started with PowerShell -Getting Started with PowerShell ----- PowerShell commands follow a Verb-Noun semantic with a set of parameters. It's easy to learn and use PowerShell. For example, `Get-Process` will display all the running processes on your system. @@ -43,94 +40,89 @@ Let's walk through with a few examples from the [PowerShell Beginner's Guide](po Now you have learned the basics of PowerShell. Please continue reading if you want to do some development work in PowerShell. -PowerShell Editor ----- +### PowerShell Editor In this section, you will create a PowerShell script using a text editor. You can use your favorite editor to write scripts. We use Visual Studio Code (VS Code) which works on Windows, Linux, and macOS. Click on the following link to create your first PowerShell script. -- [Using Visual Studio Code (VS Code)][use-vscode-editor] +- [Using Visual Studio Code (VS Code)](https://docs.microsoft.com/powershell/scripting/components/vscode/using-vscode?view=powershell-6) -PowerShell Debugger ----- +### PowerShell Debugger Debugging can help you find bugs and fix problems in your PowerShell scripts. Click on the link below to learn more about debugging: -- [Using Visual Studio Code (VS Code)][use-vscode-debugger] +- [Using Visual Studio Code (VS Code)](https://docs.microsoft.com/powershell/scripting/components/vscode/using-vscode?view=powershell-6#debugging-with-visual-studio-code) - [PowerShell Command-line Debugging][cli-debugging] [use-vscode-editor]:./using-vscode.md#editing-with-vs-code -[use-vscode-debugger]:./using-vscode.md#debugging-with-vs-code [cli-debugging]:./debugging-from-commandline.md [get-powershell]:../../README.md#get-powershell [build-powershell]:../../README.md#building-the-repository - -PowerShell Testing ----- +### PowerShell Testing We recommend using Pester testing tool which is initiated by the PowerShell Community for writing test cases. -To use the tool please read [ Pester Guides](https://github.com/pester/Pester) and [Writing Pester Tests Guidelines](https://github.com/PowerShell/PowerShell/blob/master/docs/testing-guidelines/WritingPesterTests.md). +To use the tool please read [Pester Guides](https://github.com/pester/Pester) and [Writing Pester Tests Guidelines](https://github.com/PowerShell/PowerShell/blob/master/docs/testing-guidelines/WritingPesterTests.md). - -Map Book for Experienced Bash users ----- +### Map Book for Experienced Bash users The table below lists the usage of some basic commands to help you get started on PowerShell faster. Note that all bash commands should continue working on PowerShell session. - -| Bash | PowerShell | Description -|:--------------------|:----------------------------|:--------------------- -| ls |dir, Get-ChildItem |List files and folders -| tree |dir -Recurse |List all files and folders -| cd |cd, Set-Location |Change directory -| pwd |pwd, $pwd, Get-Location |Show working directory -| clear, Ctrl+L, reset| cls, clear |Clear screen -| mkdir |New-Item -ItemType Directory |Create a new folder -| touch test.txt |New-Item -Path test.txt |Create a new empty file -| cat test1.txt test2.txt |Get-Content test1.txt, test2.txt |Display files contents -| cp ./source.txt ./dest/dest.txt |Copy-Item source.txt dest/dest.txt |Copy a file -| cp -r ./source ./dest |Copy-Item ./source ./dest -Recurse |Recursively copy from one folder to another -| mv ./source.txt ./dest/dest.txt |Move-Item ./source.txt ./dest/dest.txt |Move a file to other folder -| rm test.txt |Remove-Item test.txt |Delete a file -| rm -r <folderName> |Remove-Item <folderName> -Recurse |Delete a folder -| find -name build* |Get-ChildItem build* -Recurse |Find a file or folder starting with 'build' +| Bash | PowerShell | Description +|:--------------------------------|:----------------------------------------|:--------------------- +| ls | dir, Get-ChildItem | List files and folders +| tree | dir -Recurse, Get-ChildItem -Recurse | List all files and folders +| cd | cd, Set-Location | Change directory +| pwd | pwd, $pwd, Get-Location | Show working directory +| clear, Ctrl+L, reset | cls, clear | Clear screen +| mkdir | New-Item -ItemType Directory | Create a new folder +| touch test.txt | New-Item -Path test.txt | Create a new empty file +| cat test1.txt test2.txt | Get-Content test1.txt, test2.txt | Display files contents +| cp ./source.txt ./dest/dest.txt | Copy-Item source.txt dest/dest.txt | Copy a file +| cp -r ./source ./dest | Copy-Item ./source ./dest -Recurse | Recursively copy from one folder to another +| mv ./source.txt ./dest/dest.txt | Move-Item ./source.txt ./dest/dest.txt | Move a file to other folder +| rm test.txt | Remove-Item test.txt | Delete a file +| rm -r <folderName> | Remove-Item <folderName> -Recurse | Delete a folder +| find -name build* | Get-ChildItem build* -Recurse | Find a file or folder starting with 'build' | grep -Rin "sometext" --include="*.cs" |Get-ChildItem -Recurse -Filter *.cs
\| Select-String -Pattern "sometext" | Recursively case-insensitive search for text in files +| curl https://github.com | Invoke-RestMethod https://github.com | Transfer data to or from the web +### Recommended Training and Reading -Recommended Training and Reading ----- - Microsoft Virtual Academy: [Getting Started with PowerShell][getstarted-with-powershell] - [Why Learn PowerShell][why-learn-powershell] by Ed Wilson - PowerShell Web Docs: [Basic cookbooks][basic-cookbooks] -- [PowerShell eBook][ebook-from-powershell.com] from PowerShell.com +- [The Guide to Learning PowerShell][ebook-from-Idera] by Tobias Weltner - [PowerShell-related Videos][channel9-learn-powershell] on Channel 9 -- [Learn PowerShell Video Library][powershell.com-learn-powershell] from PowerShell.com - [PowerShell Quick Reference Guides][quick-reference] by PowerShellMagazine.com +- [Learn PowerShell Video Library][idera-learn-powershell] from Idera - [PowerShell 5 How-To Videos][script-guy-how-to] by Ed Wilson -- [PowerShell TechNet Resources](https://technet.microsoft.com/en-us/scriptcenter/dd742419.aspx) from ScriptCenter +- [PowerShell Documentation](https://docs.microsoft.com/powershell) +- [Interactive learning with PSKoans](https://aka.ms/pskoans) +### Commercial Resources -Commercial Resources ----- -- [Windows PowerShell in Action][in-action] by Bruce Payette +- [Windows PowerShell in Action][in-action] by [Bruce Payette](https://github.com/brucepay) - [Introduction to PowerShell][powershell-intro] from Pluralsight - [PowerShell Training and Tutorials][lynda-training] from Lynda.com +- [Learn Windows PowerShell in a Month of Lunches][learn-powershell] by Don Jones and Jeffrey Hicks [in-action]: https://www.amazon.com/Windows-PowerShell-Action-Second-Payette/dp/1935182137 [powershell-intro]: https://www.pluralsight.com/courses/powershell-intro [lynda-training]: https://www.lynda.com/PowerShell-training-tutorials/5779-0.html +[learn-powershell]: https://www.amazon.com/Learn-Windows-PowerShell-Month-Lunches/dp/1617294160 [getstarted-with-powershell]: https://channel9.msdn.com/Series/GetStartedPowerShell3 [why-learn-powershell]: https://blogs.technet.microsoft.com/heyscriptingguy/2014/10/18/weekend-scripter-why-learn-powershell/ -[basic-cookbooks]: https://msdn.microsoft.com/en-us/powershell/scripting/getting-started/basic-cookbooks -[ebook-from-powershell.com]: http://powershell.com/cs/blogs/ebookv2/default.aspx +[Using Windows PowerShell for Administration]: https://docs.microsoft.com/powershell/scripting/getting-started/fundamental/using-windows-powershell-for-administration?view=powershell-6 +[ebook-from-Idera]:https://www.idera.com/resourcecentral/whitepapers/powershell-ebook [channel9-learn-powershell]: https://channel9.msdn.com/Search?term=powershell#ch9Search -[powershell.com-learn-powershell]: http://powershell.com/cs/media/14/default.aspx -[quick-reference]: http://www.powershellmagazine.com/2014/04/24/windows-powershell-4-0-and-other-quick-reference-guides/ +[idera-learn-powershell]: https://community.idera.com/database-tools/powershell/video_library/ +[quick-reference]: https://www.powershellmagazine.com/2014/04/24/windows-powershell-4-0-and-other-quick-reference-guides/ [script-guy-how-to]:https://blogs.technet.microsoft.com/tommypatterson/2015/09/04/ed-wilsons-powershell5-videos-now-on-channel9-2/ +[basic-cookbooks]:https://docs.microsoft.com/powershell/scripting/samples/sample-scripts-for-administration?view=powershell-6 diff --git a/docs/learning-powershell/create-powershell-scripts.md b/docs/learning-powershell/create-powershell-scripts.md index f5657587d2f9..5f93eb97ab3e 100644 --- a/docs/learning-powershell/create-powershell-scripts.md +++ b/docs/learning-powershell/create-powershell-scripts.md @@ -1,14 +1,14 @@ -How to Create and Run PowerShell Scripts -==== +# How to Create and Run PowerShell Scripts You can combine a series of commands in a text file and save it with the file extension '.ps1', and the file will become a PowerShell script. This would begin by opening your favorite text editor and pasting in the following example. -``` PowerShell +```powershell # Script to return current IPv4 addresses on a Linux or MacOS host $ipInfo = ifconfig | Select-String 'inet' $ipInfo = [regex]::matches($ipInfo,"addr:\b(?:\d{1,3}\.){3}\d{1,3}\b") | ForEach-Object value -foreach ($ip in $ipInfo) { +foreach ($ip in $ipInfo) +{ $ip.Replace('addr:','') } ``` @@ -16,46 +16,50 @@ foreach ($ip in $ipInfo) { Then save the file to something memorable, such as .\NetIP.ps1. In the future when you need to get the IP addresses for the node, you can simplify this task by executing the script. -``` PowerShell -PS> .\NetIP.ps1 +```powershell +.\NetIP.ps1 10.0.0.1 127.0.0.1 ``` + You can accomplish this same task on Windows. -```PowerShell +```powershell # One line script to return current IPv4 addresses on a Windows host Get-NetIPAddress | Where-Object {$_.AddressFamily -eq 'IPv4'} | ForEach-Object IPAddress ``` + As before, save the file as .\NetIP.ps1 and execute within a PowerShell environment. 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. -```PowerShell -PS C:\> NetIP.ps1 +```powershell +NetIP.ps1 127.0.0.1 10.0.0.1 ``` -Creating a script that can accomplish the same task on multiple operating systems ----- +## Creating a script that can accomplish the same task on multiple operating systems If you would like to author one script that will return the IP address across Linux, MacOS, or Windows, you could accomplish this using an IF statement. -```PowerShell +```powershell # Script to return current IPv4 addresses for Linux, MacOS, or Windows -$IP = if ($IsLinux -or $IsMacOS) { +$IP = if ($IsLinux -or $IsMacOS) +{ $ipInfo = ifconfig | Select-String 'inet' $ipInfo = [regex]::matches($ipInfo,"addr:\b(?:\d{1,3}\.){3}\d{1,3}\b") | ForEach-Object value foreach ($ip in $ipInfo) { $ip.Replace('addr:','') } } -else { +else +{ Get-NetIPAddress | Where-Object {$_.AddressFamily -eq 'IPv4'} | ForEach-Object IPAddress } # Remove loopback address from output regardless of platform $IP | Where-Object {$_ -ne '127.0.0.1'} ``` -[run-ps]:http://windowsitpro.com/powershell/running-powershell-scripts-easy-1-2-3 \ No newline at end of file + +[run-ps]:https://www.itprotoday.com/powershell/running-powershell-scripts-easy-1-2-3 diff --git a/docs/learning-powershell/debugging-from-commandline.md b/docs/learning-powershell/debugging-from-commandline.md index 2880774a0c04..f6a247ab9671 100644 --- a/docs/learning-powershell/debugging-from-commandline.md +++ b/docs/learning-powershell/debugging-from-commandline.md @@ -1,11 +1,12 @@ -Debugging in PowerShell Command-line -===== +# Debugging in PowerShell Command-line -As we know, we can debug PowerShell code via GUI tools like [Visual Studio Code](./using-vscode.md#debugging-with-vs-code). 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. +As we know, we can debug PowerShell code via GUI tools like [Visual Studio Code](https://docs.microsoft.com/en-us/powershell/scripting/components/vscode/using-vscode?view=powershell-6#debugging-with-visual-studio-code). 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. -```PowerShell +```powershell # Convert Fahrenheit to Celsius function ConvertFahrenheitToCelsius([double] $fahrenheit) { @@ -17,32 +18,32 @@ $celsius $fahrenheit = Read-Host 'Input a temperature in Fahrenheit' $result =[int](ConvertFahrenheitToCelsius($fahrenheit)) Write-Host "$result Celsius" - ``` - - **1. Setting a Breakpoint on a Line** + 1. **Setting a Breakpoint on a Line** - Open a [PowerShell editor](README.md#powershell-editor) - Save the above code snippet to a file. For example, "test.ps1" - Go to your command-line PowerShell - Clear existing breakpoints if any -```PowerShell +```powershell PS /home/jen/debug>Get-PSBreakpoint | Remove-PSBreakpoint - ``` +``` + - 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 ID Script Line Command Variable Action -- ------ ---- ------- -------- ------ 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. -```PowerShell +```powershell PS /home/jen/debug> ./test.ps1 Input a temperature in Fahrenheit: 80 @@ -102,16 +103,16 @@ PS /home/jen/debug> ``` - -**2. Setting a Breakpoint on a Variable** +1. **Setting a Breakpoint on a Variable** - Clear existing breakpoints if there are any -```PowerShell +```powershell PS /home/jen/debug>Get-PSBreakpoint | Remove-PSBreakpoint ``` + - Use **Set-PSBreakpoint** cmdlet to set a debug breakpoint. In this case, we set it to line 5 -```PowerShell +```powershell PS /home/jen/debug>Set-PSBreakpoint -Variable "celsius" -Mode write -Script ./test.ps1 @@ -122,9 +123,8 @@ PS /home/jen/debug> 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. The following is an example of debugging output. -```PowerShell - -PS /home/jen/debug> ./test.ps1 +```powershell +./test.ps1 Input a temperature in Fahrenheit: 80 Hit Variable breakpoint on '/home/jen/debug/test.ps1:$celsius' (Write access) @@ -167,8 +167,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. +## More Reading -More Reading -===== -- [about_Debuggers](https://technet.microsoft.com/en-us/library/hh847790.aspx) +- [about_Debuggers](https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_debuggers?view=powershell-6) - [PowerShell Debugging](https://blogs.technet.microsoft.com/heyscriptingguy/tag/debugging/) diff --git a/docs/learning-powershell/powershell-beginners-guide.md b/docs/learning-powershell/powershell-beginners-guide.md index 3f0c1cfaafbf..1667bbcdd44c 100644 --- a/docs/learning-powershell/powershell-beginners-guide.md +++ b/docs/learning-powershell/powershell-beginners-guide.md @@ -1,18 +1,16 @@ -PowerShell Beginner’s Guide -==== +# PowerShell Beginner’s Guide If you are new to PowerShell, this document will walk you through a few examples to give you some basic ideas of PowerShell. We recommend that you open a PowerShell console/session and type along with the instructions in this document to get most out of this exercise. +## Launch PowerShell Console/Session -Launch PowerShell Console/Session ---- First you need to launch a PowerShell session by following the [Installing PowerShell Guide](./README.md#installing-powershell). +## 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 - discover what version of PowerShell you are currently using - exit a PowerShell session @@ -20,16 +18,17 @@ In this section, you will learn how to - find syntax of PowerShell cmdlets - and more -As mentioned above, PowerShell commands are designed to have Verb-Noun structure, for instance Get-Process, Set-Location, Clear-Host, etc. +As mentioned above, PowerShell commands are 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 />** as it appears on Linux in the following examples. -It is shown as **PS C:\\>** on Windows. +It is shown as `PS C:\>` on Windows. -**1. Get-Process**: Gets the processes that are running on the local computer or a remote computer. +1. `Get-Process`: Gets the processes that are running on the local computer or a remote computer. By default, you will get data back similar to the following: -``` PowerShell + +```powershell PS /> Get-Process Handles NPM(K) PM(K) WS(K) CPU(s) Id ProcessName @@ -41,9 +40,12 @@ Handles NPM(K) PM(K) WS(K) CPU(s) Id ProcessName … ``` -Only interested in the instance of firefox process that are running on your computer? + +Only interested in the instance of Firefox process that is running on your computer? + Try this: -```PowerShell + +```powershell PS /> Get-Process -Name firefox Handles NPM(K) PM(K) WS(K) CPU(s) Id ProcessName @@ -51,9 +53,11 @@ Handles NPM(K) PM(K) WS(K) CPU(s) Id ProcessName - - - 74 403.150 1209 firefox ``` + Want to get back more than one process? Then just specify process names and separate them with commas. -```PowerShell + +```powershell PS /> Get-Process -Name firefox, powershell Handles NPM(K) PM(K) WS(K) CPU(s) Id ProcessName ------- ------ ----- ----- ------ -- ----------- @@ -62,17 +66,21 @@ Handles NPM(K) PM(K) WS(K) CPU(s) Id ProcessName ``` -**2. Clear-Host**: Clears the display in the host program. -```PowerShell +1. `Clear-Host`: Clears the display in the host program. + +```powershell PS /> Get-Process PS /> Clear-Host ``` + Type too much just for clearing the screen? + Here is how the alias can help. -**3. Get-Alias**: Gets the aliases for the current session. -```PowerShell -PS /> Get-Alias +1. `Get-Alias`: Gets the aliases for the current session. + +```powershell +Get-Alias CommandType Name ----------- ---- @@ -80,6 +88,7 @@ CommandType Name Alias cd -> Set-Location Alias cls -> Clear-Host +Alias clear -> Clear-Host Alias copy -> Copy-Item Alias dir -> Get-ChildItem Alias gc -> Get-Content @@ -87,39 +96,43 @@ Alias gmo -> Get-Module Alias ri -> Remove-Item Alias type -> Get-Content … +``` + +As you can see `cls` or `clear` is an alias of `Clear-Host`. -As you can see "cls" is an alias of Clear-Host. Now try it: +```powershell PS /> Get-Process PS /> cls ``` -**4. cd - Set-Location**: Sets the current working location to a specified location. -```PowerShell + +1. `cd -> Set-Location`: Sets the current working location to a specified location. + +```powershell PS /> Set-Location /home PS /home> ``` -**5. dir - Get-ChildItem**: Gets the items and child items in one or more specified locations. -```PowerShell -Get all files under the current directory: +1. `dir -> Get-ChildItem`: Gets the items and child items in one or more specified locations. +```powershell +# Get all files under the current directory: PS /> Get-ChildItem -Get all files under the current directory as well as its subdirectories: +# Get all files under the current directory as well as its subdirectories: PS /> cd $home PS /home/jen> dir -Recurse -List all files with "txt" file extension. - +# List all files with "txt" file extension. PS /> cd $home PS /home/jen> dir –Path *.txt -Recurse ``` -**6. New-Item**: Creates a new item. +*6. `New-Item`: Creates a new item. -```PowerShell -An empty file is created if you type the following: +```powershell +# An empty file is created if you type the following: PS /home/jen> New-Item -Path ./test.txt @@ -130,11 +143,14 @@ Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 7/7/2016 7:17 PM 0 test.txt ``` -You can use the **-Value** parameter to add some data to your file. -For example, the following command adds the phrase "Hello world!" as a file content to the test.txt. -Because the test.txt file exists already, we use **-Force** parameter to replace the existing content. -```PowerShell +You can use the `-Value` parameter to add some data to your file. + +For example, the following command adds the phrase `Hello world!` as a file content to the `test.txt`. + +Because the test.txt file exists already, we use `-Force` parameter to replace the existing content. + +```powershell PS /home/jen> New-Item -Path ./test.txt -Value "Hello world!" -Force Directory: /home/jen @@ -145,44 +161,51 @@ Mode LastWriteTime Length Name -a---- 7/7/2016 7:19 PM 24 test.txt ``` + There are other ways to add some data to a file. -For example, you can use Set-Content to set the file contents: -```PowerShell +For example, you can use `Set-Content` to set the file contents: + +```powershell PS /home/jen>Set-Content -Path ./test.txt -Value "Hello world again!" ``` -Or simply use ">" as below: -``` + +Or simply use `>` as below: + +```powershell # create an empty file -"" > test.txt +"" > test.txt # set "Hello world!" as content of test.txt file "Hello world!!!" > test.txt ``` -The pound sign (#) above is used for comments in PowerShell. -**7. type - Get-Content**: Gets the content of the item at the specified location. +The pound sign `#` above is used for comments in PowerShell. + +1. `type -> Get-Content`: Gets the content of the item at the specified location. -```PowerShell +```powershell PS /home/jen> Get-Content -Path ./test.txt PS /home/jen> type -Path ./test.txt Hello world again! ``` -**8. del - Remove-Item**: Deletes the specified items. -This cmdlet will delete the file /home/jen/test.txt: -```PowerShell +1. `del -> Remove-Item`: Deletes the specified items. + +This cmdlet will delete the file `/home/jen/test.txt`: + +```powershell PS /home/jen> Remove-Item ./test.txt ``` -**9. $PSVersionTable**: Displays the version of PowerShell you are currently using. +1. `$PSVersionTable`: Displays the version of PowerShell you are currently using. -Type **$PSVersionTable** in your PowerShell session, you will see something like below. +Type `$PSVersionTable` in your PowerShell session, you will see something like below. "PSVersion" indicates the PowerShell version that you are using. -```PowerShell +```powershell Name Value ---- ----- PSVersion 6.0.0-alpha @@ -190,65 +213,77 @@ PSEdition Core PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 3.0.0.0 GitCommitId v6.0.0-alpha.12 -CLRVersion +CLRVersion WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 ``` -**10. Exit**: To exit the PowerShell session, type "exit". -```PowerShell -PS /home/jen> exit +1. `Exit`: To exit the PowerShell session, type `exit`. + +```powershell +exit ``` -Need Help? ----- -The most important command in PowerShell is possibly the Get-Help, which allows you to quickly learn PowerShell without having to search around the internet. -The Get-Help cmdlet also shows you how PowerShell commands work with examples. +## Need Help? -It shows the syntax and other technical information of the Get-Process cmdlet. -```PowerShell +The most important command in PowerShell is possibly the `Get-Help`, which allows you to quickly learn PowerShell without having to search around the internet. + +The `Get-Help` cmdlet also shows you how PowerShell commands work with examples. + +It shows the syntax and other technical information of the `Get-Process` cmdlet. + +```powershell PS /> Get-Help -Name Get-Process ``` -It displays the examples how to use the Get-Process cmdlet. -```PowerShell +It displays the examples how to use the `Get-Process` cmdlet. + +```powershell PS />Get-Help -Name Get-Process -Examples ``` If you use **-Full** parameter, for example, `Get-Help -Name Get-Process -Full`, it will display more technical information. +## Discover Commands Available on Your System -Discover Commands Available on Your System ----- +You want to discover what PowerShell cmdlets available on your system? Just run `Get-Command` as below: -You want to discover what PowerShell cmdlets available on your system? Just run "Get-Command" as below: -```PowerShell +```powershell PS /> Get-Command ``` + If you want to know whether a particular cmdlet exists on your system, you can do something like below: -```PowerShell + +```powershell PS /> Get-Command Get-Process ``` -If you want to know the syntax of Get-Process cmdlet, type: -```PowerShell + +If you want to know the syntax of `Get-Process` cmdlet, type: + +```powershell PS /> Get-Command Get-Process -Syntax ``` -If you want to know how to use the Get-Process, type: -```PowerShell + +If you want to know how to use the `Get-Process`, type: + +```powershell 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 and folders in a descending order. To achieve that, type: -```PowerShell + +```powershell PS /home/jen> dir | Sort-Object -Descending ``` + Say you want to get the largest file in a directory -```PowerShell + +```powershell PS /home/jen> dir | Sort-Object -Property Length -Descending | Select-Object -First 1 @@ -260,17 +295,16 @@ Mode LastWriteTime Length Name -a---- 5/16/2016 1:15 PM 32972 test.log ``` -How to Create and Run PowerShell scripts ----- + +## How to Create and Run PowerShell scripts + You can use Visual Studio Code or your favorite editor to create a PowerShell script and save it with a `.ps1` file extension. For more details, see [Create and Run PowerShell Script Guide][create-run-script] +## Recommended Training and Reading -Recommended Training and Reading ----- - Video: [Get Started with PowerShell][remoting] from Channel9 -- [eBooks from PowerShell.org](https://powershell.org/ebooks/) -- [eBooks from PowerShell.com][ebooks-powershell.com] +- [eBooks from PowerShell.org](https://leanpub.com/u/devopscollective) - [eBooks List][ebook-list] by Martin Schvartzman - [Tutorial from MVP][tutorial] - Script Guy blog: [The best way to Learn PowerShell][to-learn] @@ -284,26 +318,24 @@ Recommended Training and Reading - [Writing a PowerShell module in C#][writing-ps-module] - [Examples of Cmdlets Code][sample-code] +## Commercial Resources -Commercial Resources ----- - [Windows PowerShell in Action][in-action] by Bruce Payette - [Windows PowerShell Cookbook][cookbook] by Lee Holmes -[in-action]: https://www.amazon.com/Windows-PowerShell-Action-Second-Payette/dp/1935182137 +[in-action]: https://www.amazon.com/Windows-PowerShell-Action-Bruce-Payette/dp/1633430294 [cookbook]: http://shop.oreilly.com/product/9780596801519.do -[ebook-list]: https://blogs.technet.microsoft.com/pstips/2014/05/26/free-powershell-ebooks/ -[ebooks-powershell.com]: http://powershell.com/cs/blogs/ebookv2/default.aspx -[tutorial]: http://www.computerperformance.co.uk/powershell/index.htm +[ebook-list]: https://martin77s.wordpress.com/2014/05/26/free-powershell-ebooks/ +[tutorial]: https://www.computerperformance.co.uk/powershell/index.htm [to-learn]:https://blogs.technet.microsoft.com/heyscriptingguy/2015/01/04/weekend-scripter-the-best-ways-to-learn-powershell/ -[ps-module]:https://msdn.microsoft.com/en-us/library/dd878324%28v=vs.85%29.aspx -[create-ps-module]:http://www.tomsitpro.com/articles/powershell-modules,2-846.html +[ps-module]:https://msdn.microsoft.com/library/dd878324%28v=vs.85%29.aspx +[create-ps-module]:https://www.business.com/articles/powershell-modules/ [remoting]:https://channel9.msdn.com/Series/GetStartedPowerShell3/06 [in-depth]: https://channel9.msdn.com/events/MMS/2012/SV-B406 -[remote-mgmt]:http://windowsitpro.com/powershell/powershell-basics-remote-management -[remote-commands]:https://msdn.microsoft.com/en-us/powershell/scripting/core-powershell/running-remote-commands -[examples]:http://examples.oreilly.com/9780596528492/ -[examples-ps-module]:https://msdn.microsoft.com/en-us/library/dd878340%28v=vs.85%29.aspx -[writing-ps-module]:http://www.powershellmagazine.com/2014/03/18/writing-a-powershell-module-in-c-part-1-the-basics/ -[sample-code]:https://msdn.microsoft.com/en-us/library/ff602031%28v=vs.85%29.aspx +[remote-mgmt]:https://www.itprotoday.com/powershell/powershell-basics-remote-management +[remote-commands]:https://docs.microsoft.com/powershell/scripting/core-powershell/running-remote-commands?view=powershell-6 +[examples]:https://examples.oreilly.com/9780596528492/ +[examples-ps-module]:https://msdn.microsoft.com/library/dd878340%28v=vs.85%29.aspx +[writing-ps-module]:https://www.powershellmagazine.com/2014/03/18/writing-a-powershell-module-in-c-part-1-the-basics/ +[sample-code]:https://msdn.microsoft.com/library/ff602031%28v=vs.85%29.aspx [create-run-script]:./create-powershell-scripts.md diff --git a/docs/learning-powershell/using-vscode.md b/docs/learning-powershell/using-vscode.md deleted file mode 100644 index 3623039153de..000000000000 --- a/docs/learning-powershell/using-vscode.md +++ /dev/null @@ -1,181 +0,0 @@ -Using Visual Studio Code for PowerShell Development -==== - -If you are working on Linux and macOS, you cannot use the PowerShell 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 Visual Studio Code as a PowerShell editor. - -You can use Visual Studio Code on Windows with PowerShell version 5 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. -By following the [Installing PowerShell](./README.md#installing-powershell) instructions you can install PowerShell and launch a PowerShell session. - -Editing with Visual Studio Code ----- -[**1. Installing Visual Studio Code**](https://code.visualstudio.com/Docs/setup/setup-overview) - -* **Linux**: follow the installation instructions on the [Running VS Code on Linux](https://code.visualstudio.com/docs/setup/linux) page - -* **macOS**: follow the installation instructions on the [Running VS Code on macOS](https://code.visualstudio.com/docs/setup/mac) page - - **NOTE:** On OS X you must install OpenSSL for the PowerShell extension to work correctly. - The easiest way to accomplish this is to install [Homebrew](http://brew.sh/) and then run `brew install openssl`. - The PowerShell extension will now be able to load successfully. - -* **Windows**: follow the installation instructions on the [Running VS Code on Windows](https://code.visualstudio.com/docs/setup/windows) page - - -**2. Installing PowerShell Extension** - -- Launch the Visual Studio Code app by: - * **Windows**: typing **code** in your PowerShell session - * **Linux**: typing **code** in your terminal - * **macOS**: typing **code** in your terminal - -- Launch **Quick Open** by pressing **Ctrl+P** (**Cmd+P** on Mac). -- In Quick Open, type **ext install powershell** and hit **Enter**. -- The **Extensions** view will open on the Side Bar. Select the PowerShell extension from Microsoft. - You will see something like below: - - ![VSCode](vscode.png) - -- Click the **Install** button on the PowerShell extension from Microsoft. -- After the install, you will see the **Install** button turns to **Reload**. - Click on **Reload**. -- After Visual Studio Code has reload, 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" next to the file name. -To exit Visual Studio Code, **File->Exit**. - -#### Using a specific installed version of PowerShell - -If you wish to use a specific installation of PowerShell with Visual Studio Code, you will need to add a new variable to your user settings file. - -1. Click **File -> Preferences -> Settings** -2. Two editor panes will appear. - In the right-most pane (`settings.json`), insert the setting below appropriate for your OS somewhere between the two curly brackets (`{` and `}`) and replace ** with the installed PowerShell version: - - ```json - // On Windows: - "powershell.powerShellExePath": "c:/Program Files/PowerShell//pwsh.exe" - - // On Linux: - "powershell.powerShellExePath": "/opt/microsoft/powershell//pwsh" - - // On macOS: - "powershell.powerShellExePath": "/usr/local/microsoft/powershell//pwsh" - ``` - -3. Replace the setting with the path to the desired PowerShell executable -4. Save the settings file and restart Visual Studio Code - -#### Configuration settings for Visual Studio Code - -By using the steps in the previous paragraph you can add configuration settings in `settings.json`. - -We recommend the following configuration settings for Visual Studio Code: - -```json -{ - "csharp.suppressDotnetRestoreNotification": true, - "editor.renderWhitespace": "all", - "editor.renderControlCharacters": true, - "omnisharp.projectLoadTimeout": 120, - "files.trimTrailingWhitespace": true -} -``` - -Debugging with Visual Studio Code ----- -### No-workspace debugging -As of Visual Studio Code version 1.9 you can debug PowerShell scripts without having to open the folder containing the PowerShell script. -Simply open the PowerShell script file with **File->Open File...**, set a breakpoint on a line (press F9) and then press F5 to start debugging. -You will see the Debug actions pane appear which allows you to break into the debugger, step, resume and stop debugging. - -### Workspace debugging -Workspace debugging refers to debugging in the context of a folder that you have opened in Visual Studio Code using **Open Folder...** from the **File** menu. -The folder you open is typically your PowerShell project folder and/or the root of your Git repository. - -Even in this mode, you can start debugging the currently selected PowerShell script by simply pressing F5. -However, workspace debugging allows you to define multiple debug configurations other than just debugging the currently open file. -For instance, you can add a configurations to: - -* Launch Pester tests in the debugger -* Launch a specific file with arguments in the debugger -* Launch an interactive session in the debugger -* Attach the debugger to a PowerShell host process - -Follow these steps to create your debug configuration file: -1. Open the **Debug** view by pressing **Ctrl+Shift+D** (**Cmd+Shift+D** on Mac). -2. Press the **Configure** gear icon in the toolbar. -3. Visual Studio Code will prompt you to **Select Environment**. -Choose **PowerShell**. - - When you do this, Visual Studio Code creates a directory and a file ".vscode\launch.json" in the root of your workspace folder. - This is where your debug configuration is stored. If your files are in a Git repository, you will typically want to commit the launch.json file. - The contents of the launch.json file are: - -```json -{ - "version": "0.2.0", - "configurations": [ - { - "type": "PowerShell", - "request": "launch", - "name": "PowerShell Launch (current file)", - "script": "${file}", - "args": [], - "cwd": "${file}" - }, - { - "type": "PowerShell", - "request": "attach", - "name": "PowerShell Attach to Host Process", - "processId": "${command.PickPSHostProcess}", - "runspaceId": 1 - }, - { - "type": "PowerShell", - "request": "launch", - "name": "PowerShell Interactive Session", - "cwd": "${workspaceRoot}" - } - ] -} - -``` -This represents the common debug scenarios. -However, when you open this file in the editor, you will see an **Add Configuration...** button. -You can press this button to add more PowerShell debug configurations. One handy configuration to add is **PowerShell: Launch Script**. -With this configuration, you can specify a specific file with optional arguments that should be launched whenever you press F5 no matter which file is currently active in the editor. - -Once the debug configuration is established, you can select which configuration you want to use during a debug session by selecting one from the debug configuration drop-down in the **Debug** view's toolbar. - -There are a few blogs that may be helpful to get you started using PowerShell extension for Visual Studio Code - -- Visual Studio Code: [PowerShell Extension][ps-extension] -- [Write and debug PowerShell scripts in Visual Studio Code][debug] -- [Debugging Visual Studio Code Guidance][vscode-guide] -- [Debugging PowerShell in Visual Studio Code][ps-vscode] -- [Get started with PowerShell development in Visual Studio Code][getting-started] -- [Visual Studio Code editing features for PowerShell development – Part 1][editing-part1] -- [Visual Studio Code editing features for PowerShell development – Part 2][editing-part2] -- [Debugging PowerShell script in Visual Studio Code – Part 1][debugging-part1] -- [Debugging PowerShell script in Visual Studio Code – Part 2][debugging-part2] - -[ps-extension]:https://blogs.msdn.microsoft.com/cdndevs/2015/12/11/visual-studio-code-powershell-extension/ -[debug]:https://blogs.msdn.microsoft.com/powershell/2015/11/16/announcing-powershell-language-support-for-visual-studio-code-and-more/ -[vscode-guide]:https://johnpapa.net/debugging-with-visual-studio-code/ -[ps-vscode]:https://github.com/PowerShell/vscode-powershell/tree/master/examples -[getting-started]:https://blogs.technet.microsoft.com/heyscriptingguy/2016/12/05/get-started-with-powershell-development-in-visual-studio-code/ -[editing-part1]:https://blogs.technet.microsoft.com/heyscriptingguy/2017/01/11/visual-studio-code-editing-features-for-powershell-development-part-1/ -[editing-part2]:https://blogs.technet.microsoft.com/heyscriptingguy/2017/01/12/visual-studio-code-editing-features-for-powershell-development-part-2/ -[debugging-part1]:https://blogs.technet.microsoft.com/heyscriptingguy/2017/02/06/debugging-powershell-script-in-visual-studio-code-part-1/ -[debugging-part2]:https://blogs.technet.microsoft.com/heyscriptingguy/2017/02/13/debugging-powershell-script-in-visual-studio-code-part-2/ - -PowerShell Extension for Visual Studio Code ----- - -The PowerShell extension's source code can be found on [GitHub](https://github.com/PowerShell/vscode-powershell). diff --git a/docs/learning-powershell/vscode.png b/docs/learning-powershell/vscode.png deleted file mode 100644 index 4c9354bd0c90..000000000000 Binary files a/docs/learning-powershell/vscode.png and /dev/null differ diff --git a/docs/learning-powershell/working-with-powershell-objects.md b/docs/learning-powershell/working-with-powershell-objects.md index adbdc3eeef6b..ab127483cfee 100644 --- a/docs/learning-powershell/working-with-powershell-objects.md +++ b/docs/learning-powershell/working-with-powershell-objects.md @@ -1,5 +1,5 @@ -Working with PowerShell Objects -==== +# Working with PowerShell Objects + When cmdlets are executed in PowerShell, the output is an Object, as opposed to only returning text. This provides the ability to store information as properties. As a result, handling large amounts of data and getting only specific properties is a trivial task. @@ -7,8 +7,9 @@ As a result, handling large amounts of data and getting only specific properties As a simple example, the following function retrieves information about storage Devices on a Linux or MacOS operating system platform. This is accomplished by parsing the output of an existing command, *parted -l* in administrative context, and creating an object from the raw text by using the *New-Object* cmdlet. -```PowerShell -Function Get-DiskInfo { +```powershell +function Get-DiskInfo +{ $disks = sudo parted -l | Select-String "Disk /dev/sd*" -Context 1,0 $diskinfo = @() foreach ($disk in $disks) { @@ -27,7 +28,7 @@ The results are formatted as a table with the default view. *Note: in this example, the disks are virtual disks in a Microsoft Azure virtual machine.* -```PowerShell +```powershell PS /home/psuser> $d = Get-DiskInfo [sudo] password for psuser: PS /home/psuser> $d @@ -44,7 +45,7 @@ This is because the value of *$d* is not just text output. The value is actually an array of .Net objects with methods and properties. The properties include Device, Friendly Name, and Total Size. -```PowerShell +```powershell PS /home/psuser> $d | Get-Member @@ -63,7 +64,7 @@ Total Size NoteProperty string Total Size= 31.5GB To confirm, we can call the GetType() method interactively from the console. -```PowerShell +```powershell PS /home/psuser> $d.GetType() IsPublic IsSerial Name BaseType @@ -73,7 +74,7 @@ True True Object[] System.Array To index in to the array and return only specific objects, use the square brackets. -```PowerShell +```powershell PS /home/psuser> $d[0] Friendly Name Total Size Device @@ -89,7 +90,7 @@ True False PSCustomObject System.Object To return a specific property, the property name can be called interactively from the console. -```PowerShell +```powershell PS /home/psuser> $d.Device /dev/sda /dev/sdb @@ -97,7 +98,7 @@ PS /home/psuser> $d.Device To output a view of the information other than default, such as a view with only specific properties selected, pass the value to the *Select-Object* cmdlet. -```PowerShell +```powershell PS /home/psuser> $d | Select-Object Device, 'Total Size' Device Total Size @@ -107,10 +108,10 @@ Device Total Size ``` Finally, the example below demonstrates use of the *ForEach-Object* cmdlet to iterate through the array and manipulate the value of a specific property of each object. -In this case the Total Size property, which was given in Gigabytes, is changed to Megabytes. +In this case the Total Size property, which was given in Gigabytes, is changed to Megabytes. Alternatively, index in to a position in the array as shown below in the third example. -```PowerShell +```powershell PS /home/psuser> $d | ForEach-Object 'Total Size' 31.5GB 145GB @@ -121,4 +122,4 @@ PS /home/psuser> $d | ForEach-Object {$_.'Total Size' / 1MB} PS /home/psuser> $d[1].'Total Size' / 1MB 148480 -``` \ No newline at end of file +``` diff --git a/docs/maintainers/Images/merge-commit-confirm.png b/docs/maintainers/Images/merge-commit-confirm.png new file mode 100644 index 000000000000..a26e1aa0b4f3 Binary files /dev/null and b/docs/maintainers/Images/merge-commit-confirm.png differ diff --git a/docs/maintainers/Images/merge-commit.png b/docs/maintainers/Images/merge-commit.png new file mode 100644 index 000000000000..2ae3b6a8ba5f Binary files /dev/null and b/docs/maintainers/Images/merge-commit.png differ diff --git a/docs/maintainers/Images/squash-confirm.png b/docs/maintainers/Images/squash-confirm.png new file mode 100644 index 000000000000..3a5df89be14d Binary files /dev/null and b/docs/maintainers/Images/squash-confirm.png differ diff --git a/docs/maintainers/Images/squash-merge.png b/docs/maintainers/Images/squash-merge.png new file mode 100644 index 000000000000..98147cdd6a7b Binary files /dev/null and b/docs/maintainers/Images/squash-merge.png differ diff --git a/docs/maintainers/README.md b/docs/maintainers/README.md index 82dee5ec4545..b5d3bc2f2556 100644 --- a/docs/maintainers/README.md +++ b/docs/maintainers/README.md @@ -6,8 +6,8 @@ One of their primary responsibilities is merging pull requests after all require They have [write access](https://help.github.com/articles/repository-permission-levels-for-an-organization/) to the PowerShell repositories which gives them the power to: 1. `git push` to the official PowerShell repository -1. Merge pull requests -1. Assign labels, milestones, and people to [issues](https://guides.github.com/features/issues/) +1. Merge [pull requests](https://www.thinkful.com/learn/github-pull-request-tutorial/) +1. Assign labels, milestones, and people to [issues](https://guides.github.com/features/issues/) and [pull requests](https://www.thinkful.com/learn/github-pull-request-tutorial/) ## Table of Contents @@ -20,14 +20,22 @@ They have [write access](https://help.github.com/articles/repository-permission- ## Current Repository Maintainers -* Sergei Vorobev ([vors](https://github.com/vors)) -* Jason Shirk ([lzybkr](https://github.com/lzybkr)) -* Dongbo Wang ([daxian-dbw](https://github.com/daxian-dbw)) -* Travis Plunk ([TravisEz13](https://github.com/TravisEz13)) -* Mike Richmond ([mirichmo](https://github.com/mirichmo)) -* Andy Schwartzmeyer ([andschwa](https://github.com/andschwa)) -* Aditya Patwardhan ([adityapatwardhan](https://github.com/adityapatwardhan)) -* Ilya Sazonov ([iSazonov](https://github.com/iSazonov)) + + +- Aditya Patwardhan ([adityapatwardhan](https://github.com/adityapatwardhan)) +- Andrew Menagarishvili ([anmenaga](https://github.com/anmenaga)) +- Dongbo Wang ([daxian-dbw](https://github.com/daxian-dbw)) +- Ilya Sazonov ([iSazonov](https://github.com/iSazonov)) +- Travis Plunk ([TravisEz13](https://github.com/TravisEz13)) + +## Former Repository Maintainers + + + +- Andy Schwartzmeyer ([andschwa](https://github.com/andschwa)) +- Jason Shirk ([lzybkr](https://github.com/lzybkr)) +- Mike Richmond ([mirichmo](https://github.com/mirichmo)) +- Sergei Vorobev ([vors](https://github.com/vors)) ## Repository Maintainer Responsibilities @@ -35,7 +43,7 @@ Repository Maintainers enable rapid contributions while maintaining a high level If you are a Repository Maintainer, you: -1. **MUST** ensure that each contributor has signed a valid Contributor License Agreement (CLA) +1. **MUST** ensure that each contributor has signed a valid Microsoft Contributor License Agreement (CLA) 1. **MUST** verify compliance with any third party code license terms (e.g., requiring attribution, etc.) if the contribution contains third party code. 1. **MUST** make sure that [any change requiring approval from the PowerShell Committee](../community/governance.md#changes-that-require-an-rfc) has gone through the proper [RFC][RFC-repo] or approval process 1. **MUST** validate that code reviews have been conducted before merging a pull request when no code is written @@ -54,10 +62,10 @@ If you are a Repository Maintainer, you: However, they should be reminded to create an issue in the future to frontload any potential problems with the work and to minimize duplication of efforts. 1. **SHOULD** encourage contributors to create meaningful titles for all PRs. Edit the title if necessary to provide clarity on the problem -1. **SHOULD** encourage contributes to write meaningful, descriptive git commits +1. **SHOULD** encourage contributors to write meaningful, descriptive git commits 1. **SHOULD NOT** merge pull requests with a failed CI build (unless, for instance, the pull request is being submitted to fix broken CI) -1. **SHOULD NOT** merge pull requests without the label `cla-signed` or `cla-not-required` from the Microsoft CLA bot +1. **SHOULD NOT** merge pull requests without the status check passing from the Microsoft CLA bot (unless the CLA bot is broken, and CLA signing can be confirmed through other means) 1. **SHOULD NOT** merge pull requests too quickly after they're submitted. Even if the pull request meets all the requirements, people should have time to give their input @@ -73,6 +81,10 @@ Please see [Issue Management][issue-management] Please see [Contributing][CONTRIBUTING] +## Maintainer Best Practices + +Please see [Best Practices][best-practice] + ## Becoming a Repository Maintainer Repository Maintainers currently consist mostly of Microsoft employees. @@ -82,10 +94,11 @@ Eligibility is heavily dependent on the level of contribution and expertise: ind At any point in time, the existing Repository Maintainers can unanimously nominate a strong community member to become a Repository Maintainer. Nominations are brought to the PowerShell Committee to understand the reasons and justification. A simple majority of the PowerShell Committee is required to veto the nomination. -Once a nominee has been approved, a PR will be submitted by a current Maintainer to update this document to add the nominee's name to +When a nominee has been approved, a PR will be submitted by a current Maintainer to update this document to add the nominee's name to the [Current Repository Maintainers](#Current-Repository-Maintainers) with justification as the description of the PR to serve as the public announcement. [RFC-repo]: https://github.com/PowerShell/PowerShell-RFC [ci-system]: ../testing-guidelines/testing-guidelines.md#ci-system [issue-management]: issue-management.md [CONTRIBUTING]: ../../.github/CONTRIBUTING.md +[best-practice]: best-practice.md diff --git a/docs/maintainers/best-practice.md b/docs/maintainers/best-practice.md new file mode 100644 index 000000000000..47cc304cf610 --- /dev/null +++ b/docs/maintainers/best-practice.md @@ -0,0 +1,50 @@ +# Maintainer Best Practices + +## PR Types + +- Feature-work PR: A PR that implements an RFC, which usually involves relatively large set of changes. +- Regular PR: A bug fix or an enhancement change that are not backed by an RFC. + +## Review PRs + +- Ask the author to reword the PR title based on guidelines in [Contributing](../../.github/CONTRIBUTING.md). +- Ask the author to apply `[feature]` tag to trigger full test builds if it's necessary. +- Label the PR with `Breaking-Change`, `Documentation Needed` and `Area-XXX` as appropriate. +- When labelling a PR with `Review-Committee`, leave a detailed comment to summarize the issue you want the committee to look into. + It's recommended to include examples to explain/demonstrate behaviors. + +## Merge PRs + +- Use `Squash and merge` by default to keep clean commit history in Master branch. + + ![Squash Merge Example](./Images/squash-merge.png)    ![Squash Confirm Example](./Images/squash-confirm.png) + +- Use `Create a merge commit` for feature-work PRs **only if** the commit history of the PR is reasonably clean. + After using this option, GitHub will make it your default option for merging a PR. + Do remember to change the default back to `Squash and merge` as it will be useful next time. + + ![Merge Commit Example](./Images/merge-commit.png)    ![Merge Confirm Example](./Images/merge-commit-confirm.png) + +- Avoid `Rebase and merge` unless you have a strong argument for using it. + +- Before clicking `Confirm squash and merge` or `Confirm merge`, + make sure you run through the following steps: + + 1. The commit title should be a short summary of the PR. + + - When merging with the `Squash and merge` option, + the PR title will be used as the commit title by default. + **Reword the title as needed** to make sure it makes sense (can be used without change in `CHANGELOG.md`). + + - When merging with the `Create a merge commit` option, + the default commit title would be `Merge pull request XXX from YYY`. + **Replace it with a short summary of the PR**, and add the PR number to the end, like `(#1234)`. + + 1. The optional extended description is required for feature-work PRs, or regular PRs with breaking changes. + For other PRs, it's not required but good to have based on the judgement of the maintainer. + + - If a PR introduces breaking changes, + make sure you put the tag `[breaking change]` at the first line of the extended description, + and start the description text from the second line. + + 1. Use the present tense and imperative mood for both the commit title and description. diff --git a/docs/maintainers/issue-management.md b/docs/maintainers/issue-management.md index 13d6da4e5900..4021d44c82a8 100644 --- a/docs/maintainers/issue-management.md +++ b/docs/maintainers/issue-management.md @@ -1,12 +1,18 @@ # Issue Management +## Security Vulnerabilities + +If you believe that there is a security vulnerability in PowerShell, +first follow the [vulnerability issue reporting policy](../../.github/SECURITY.md) before submitting an issue. + ## Long-living issue labels -======= -## Issue and PR Labels + +### Issue and PR Labels Issues are opened for many different reasons. We use the following labels for issue classifications: +* `Issue-Announcement`: the issue is for discussing an [Announcement](https://github.com/PowerShell/Announcements) * `Issue-Bug`: the issue is reporting a bug * `Issue-Code Cleanup`: the issue is for cleaning up the code with no impact on functionality * `Issue-Discussion`: the issue may not have a clear classification yet. @@ -14,7 +20,7 @@ We use the following labels for issue classifications: * `Issue-Enhancement`: the issue is more of a feature request than a bug. * `Issue-Meta`: an issue used to track multiple issues. * `Issue-Question`: ideally support can be provided via other mechanisms, - but sometimes folks to open an issue to get a question answered and we will use this label for such issues. + but sometimes folks do open an issue to get a question answered and we will use this label for such issues. [ln-rfc]: https://github.com/PowerShell/PowerShell-RFC @@ -46,21 +52,22 @@ These labels describe what feature area of PowerShell that an issue affects: * `Area-HelpSystem`: anything related to the help infrastructure and formatting of help * `Area-Intellisense`: tab completion * `Area-Language`: parser, language semantics -* `Area-OMI`: omi +* `Area-OMI`: OMI * `Area-PackageManagement`: PackageManagement related issues * `Area-Performance`: a performance issue * `Area-Portability`: anything affecting script portability * `Area-PowerShellGet`: PowerShellGet related issues -* `Area-Providers`: PowerShell providers like FileSystem, Certificates, Registry, etc... +* `Area-Providers`: PowerShell providers such as FileSystem, Certificates, Registry, etc... * `Area-PSReadline`: PSReadline related issues * `Area-Remoting`: PSRP issues with any transport layer -* `Area-Security`: security related areas like [JEA](https://github.com/powershell/JEA) +* `Area-Security`: security related areas such as [JEA](https://github.com/powershell/JEA) * `Area-SideBySide`: side by side support * `Area-Test`: issues in a test or in test infrastructure ### Operating Systems These are for issues that are specific to certain Operating Systems: + * `OS-Linux` * `OS-macOS` * `OS-Windows` @@ -72,24 +79,27 @@ The following labels are used on PRs: * `Review - Needed` : The PR is being reviewed. Please see [Pull Request - Code Review](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---code-review) * `Review - Waiting on Author` : The PR was reviewed by the team and requires changes or comments from the author before being accepted. -* `Review - Abandoned` : The PR was not updated for significant number of days (the exact number could vary over time). +* `Review - Abandoned` : The PR was not updated for a significant number of days (the exact number could vary over time). Maintainers should look into such PRs and re-evaluate them. * `Review - Committee` : The PR/Issue needs a review from [powershell-committee](../community/governance.md#powershell-committee) ### Miscellaneous labels -* `Committee-Reviewed` : The PR/Issue has been reviewed by the [powershell-committee](../community/governance.md#powershell-committee) -* `Up-for-Grabs`: We've acknowledged the issue but have no immediate plans to address it. - If you're looking for a way to contribute, these issues can be a good place to start. -* `Blocked`: an issue cannot be addressed due to external factors, +* `Blocked` : An issue cannot be addressed due to external factors, but should not be closed because those external factors are temporary. -* `BVT/DRT`: an issue affecting or exposed by tests that have not been open sourced. -* `Porting`: an issue that affects a feature not yet ported to other platforms. -* `Usability`: this label is used to help us filter issues that might be higher priority - because they more directly affect the usability of a particular feature or area. -* `Changelog Needed`: The PR requires an addition to the changelog, +* `BVT/DRT` : An issue affecting or exposed by tests that have not been open sourced. +* `Changelog Needed` : The PR requires an addition to the changelog, and should be removed when it has been added. -* `Documentation Needed` : The PR has changes that require a documentation change or new documentation added to [PowerShell-Docs](http://github.com/powershell/powershell-docs) +* `Committee-Reviewed` : The PR/Issue has been reviewed by the [powershell-committee](../community/governance.md#powershell-committee) * `Compliance` : Issues with the compliance label are required to be fixed either in the long term or short term for Microsoft to continue to sign and release packages from the project as official Microsoft packages. The time frame in which it needs to be fixed should be identified in the issue. +* `Documentation Needed` : The PR has changes that require a documentation change or new documentation added to [PowerShell-Docs](https://github.com/powershell/powershell-docs) +* `First-Time-Issue` : An issue that is identified as being easy and a good candidate for first time contributors +* `Hackathon` or `Hacktoberfest` : An issue that would be a good candidate for hackathons such as `Hacktoberfest` or `Hackillinois` +* `Porting` : An issue that affects a feature not yet ported to other platforms. +* `Up-for-Grabs` : We've acknowledged the issue but have no immediate plans to address it. + If you're looking for a way to contribute, these issues can be a good place to start. +* `Usability` : This label is used to help us filter issues that might be higher priority + because they more directly affect the usability of a particular feature or area. +* `Waiting - DotNetCore` : An issue waiting on a fix/change in DotNetCore. diff --git a/docs/maintainers/releasing.md b/docs/maintainers/releasing.md index f423ed25aca2..e3ac1998f77e 100644 --- a/docs/maintainers/releasing.md +++ b/docs/maintainers/releasing.md @@ -14,7 +14,7 @@ This is to help track the release preparation work. > Note: Step 2, 3 and 4 can be done in parallel. -1. Create a branch named `release` in `PowerShell/PowerShell` repository. +1. Create a branch named `release-` in our private repository. All release related changes should happen in this branch. 1. Prepare packages - [Build release packages](#building-packages). @@ -28,7 +28,7 @@ This is to help track the release preparation work. 1. [Create NuGet packages](#nuget-packages) and publish them to [powershell-core feed][ps-core-feed]. 1. [Create the release tag](#release-tag) and push the tag to `PowerShell/PowerShell` repository. 1. Create the draft and publish the release in Github. -1. Merge the `release` branch to `master` and delete the `release` branch. +1. Merge the `release-` branch to `master` in `powershell/powershell` and delete the `release-` branch. 1. Publish Linux packages to Microsoft YUM/APT repositories. 1. Trigger the release docker builds for Linux and Windows container images. - Linux: push a branch named `docker` to `powershell/powershell` repository to trigger the build at [powershell docker hub](https://hub.docker.com/r/microsoft/powershell/builds/). @@ -173,16 +173,9 @@ Start-PSPackage -Type zip -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64' ## NuGet Packages -In the `release` branch, run `Publish-NuGetFeed` to generate PowerShell NuGet packages: - -```powershell -# Assume the to-be-used release tag is 'v6.0.0-beta.1' -Publish-NuGetFeed -ReleaseTag 'v6.0.0-beta.1' -``` - -PowerShell NuGet packages and the corresponding symbol packages will be generated at `PowerShell/nuget-artifacts` by default. -Currently the NuGet packages published to [powershell-core feed][ps-core-feed] only contain assemblies built for Windows. -Maintainers are working on including the assemblies built for non-Windows platforms. +The NuGet packages for hosting PowerShell for Windows and non-Windows are being built in our release build pipeline. +The assemblies from the individual Windows and Linux builds are consumed and packed into NuGet packages. +These are then released to [powershell-core feed][ps-core-feed]. [ps-core-feed]: https://powershell.myget.org/gallery/powershell-core @@ -207,15 +200,20 @@ GitHub will see the tag and present it as an option when creating a new [release Start the release, use the annotated tag's summary as the title, and save the release as a draft while you upload the binary packages. -[semver]: http://semver.org/ +[semver]: https://semver.org/ [tag]: https://git-scm.com/book/en/v2/Git-Basics-Tagging [release]: https://help.github.com/articles/creating-releases/ ## Homebrew -After the release, you can update homebrew formula. +After the release, update homebrew formula. +You need macOS to do it. -On macOS: +There are 2 homebrew formulas: main and preview. + +### Main + +Update it on stable releases. 1. Make sure that you have [homebrew cask](https://caskroom.github.io/). 1. `brew update` @@ -226,5 +224,21 @@ On macOS: 1. Update `checkpoint` value. To do that run `brew cask _appcast_checkpoint --calculate 'https://github.com/PowerShell/PowerShell/releases.atom'` 1. `brew cask style --fix ./powershell.rb`, make sure there are no errors 1. `brew cask audit --download ./powershell.rb`, make sure there are no errors -1. `brew cask reinstall powershell`, make sure that powershell was updates successfully +1. `brew cask upgrade powershell`, make sure that powershell was updates successfully 1. Commit your changes, send a PR to [homebrew-cask](https://github.com/caskroom/homebrew-cask) + +### Preview + +Update it on preview releases. + +1. Add [homebrew cask versions](https://github.com/Homebrew/homebrew-cask-versions): `brew tap homebrew/cask-versions` +1. `brew update` +1. `cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask-versions/Casks` +1. Edit `./powershell-preview.rb`: + 1. Update `version` + 1. Update `sha256` to the checksum of produced `.pkg` (note lower-case string for the consistent style) + 1. Update `checkpoint` value. To do that run `brew cask _appcast_checkpoint --calculate 'https://github.com/PowerShell/PowerShell/releases.atom'` +1. `brew cask style --fix ./powershell-preview.rb`, make sure there are no errors +1. `brew cask audit --download ./powershell-preview.rb`, make sure there are no errors +1. `brew cask upgrade powershell-preview`, make sure that powershell was updates successfully +1. Commit your changes, send a PR to [homebrew-cask-versions](https://github.com/Homebrew/homebrew-cask-versions) diff --git a/docs/testing-guidelines/CodeCoverageAnalysis.md b/docs/testing-guidelines/CodeCoverageAnalysis.md index 3766827c5750..bee669ea7472 100644 --- a/docs/testing-guidelines/CodeCoverageAnalysis.md +++ b/docs/testing-guidelines/CodeCoverageAnalysis.md @@ -1,48 +1,40 @@ -# Code coverage analysis for commit [2ae5d07](https://codecov.io/gh/PowerShell/PowerShell/tree/c7b959bd6e5356fbbd395f22ba0c6cba49f354f6/src) +# Code coverage analysis for commit [de5f69c](https://codecov.io/gh/PowerShell/PowerShell/tree/de5f69cf942a85839c907f11a29cf9c09f9de8b4/src) -Code coverage runs are enabled on daily Windows builds for PowerShell Core 6.0. -The results of the latest build are available at: [CodeCov.io](https://codecov.io/gh/PowerShell/PowerShell) +Code coverage runs are enabled on daily Windows builds for PowerShell Core 6. +The results of the latest build are available at [codecov.io](https://codecov.io/gh/PowerShell/PowerShell) The goal of this analysis is to find the hot spots of missing coverage. The metrics used for selection of these hot spots were: # missing lines and likelihood of code path usage. ## Coverage Status -The following table shows the status for the above commit, dated 06/18/2017 +The following table shows the status for the above commit, dated 2018-11-28 | Assembly | Hit % | | -------- |:-----:| -| Microsoft.PowerShell.Commands.Diagnostics | 58.01% | -| Microsoft.PowerShell.Commands.Management | 32.02% | -| Microsoft.PowerShell.Commands.Utility | 67.55% | -| Microsoft.PowerShell.ConsoleHost | 41.15% | -| Microsoft.PowerShell.CoreCLR.AssemblyLoadContext | 97.65% | -| Microsoft.PowerShell.CoreCLR.Eventing | 29.91% | -| Microsoft.PowerShell.LocalAccounts | 86.35% | -| Microsoft.PowerShell.PSReadLine | 10.18% | -| Microsoft.PowerShell.Security | 44.44% | -| Microsoft.WSMan.Management | 4.91% | -| System.Management.Automation | 50.42% | -| Microsoft.WSMan.Runtime/WSManSessionOption.cs | 100% | -| powershell/Program.cs | 100% | +| Microsoft.Management.Infrastructure.CimCmdlets | 48.18% | +| Microsoft.PowerShell.Commands.Diagnostics | 47.58% | +| Microsoft.PowerShell.Commands.Management | 61.06% | +| Microsoft.PowerShell.Commands.Utility | 70.76% | +| Microsoft.PowerShell.ConsoleHost | 46.39% | +| Microsoft.PowerShell.CoreCLR.Eventing | 37.84% | +| Microsoft.PowerShell.MarkdownRender | 70.68% | +| Microsoft.PowerShell.Security | 49.36% | +| Microsoft.WSMan.Management | 62.36% | +| System.Management.Automation | 63.35% | +| Microsoft.WSMan.Runtime/WSManSessionOption.cs | 100.00% | +| powershell/Program.cs | 100.00% | ## Hot Spots with missing coverage ### Microsoft.PowerShell.Commands.Management -- [ ] CDXML cmdlet coverage. It is 0% as CDXML is broken due to CoreCLR [issue](https://github.com/dotnet/corefx/issues/18877). -- [ ] Add tests for *-Computer cmdlets [#4146](https://github.com/PowerShell/PowerShell/issues/4146) -- [ ] Add tests for *-Service cmdlets [#4147](https://github.com/PowerShell/PowerShell/issues/4147) - [ ] Add tests for *-Item cmdlets. Especially for literal paths and error cases. [#4148](https://github.com/PowerShell/PowerShell/issues/4148) -- [ ] Add tests for Get-Content -Tail. [#4150](https://github.com/PowerShell/PowerShell/issues/4150) - [ ] Lots of resource strings not covered. Will probably get covered when coverage is added for error cases. [#4148](https://github.com/PowerShell/PowerShell/issues/4148) ### Microsoft.PowerShell.Commands.Utility -- [ ] Add tests for Trace-Command. Especially Trace-Command -Expression [#4151](https://github.com/PowerShell/PowerShell/issues/4151) -- [ ] Add tests for ConvertTo-XML serialization of PSObjects [#4152](https://github.com/PowerShell/PowerShell/issues/4152) - [ ] Add tests for Debug-Runspace [#4153](https://github.com/PowerShell/PowerShell/issues/4153) -- [ ] Add tests for New-Object for ArgumentList, ComObject [#4154](https://github.com/PowerShell/PowerShell/issues/4154) ### Microsoft.PowerShell.ConsoleHost @@ -52,15 +44,11 @@ The following table shows the status for the above commit, dated 06/18/2017 - [ ] Add tests for ETW events. [#4156](https://github.com/PowerShell/PowerShell/issues/4156) -### Microsoft.PowerShell.PSReadLine - -- [ ] We need tests from PSReadline repo or ignore coverage data for this module. (This will be filtered out.) - ### Microsoft.PowerShell.Security -- [ ] Add tests for *-Acl cmdlets. [4157] (https://github.com/PowerShell/PowerShell/issues/4157) -- [ ] Add tests for *-AuthenticodeSignature cmdlets. [4157] (https://github.com/PowerShell/PowerShell/issues/4157) -- [ ] Add coverage to various utility methods under src/Microsoft.PowerShell.Security/security/Utils.cs [4157] (https://github.com/PowerShell/PowerShell/issues/4157) +- [ ] Add tests for *-Acl cmdlets. [#4157](https://github.com/PowerShell/PowerShell/issues/4157) +- [ ] Add tests for *-AuthenticodeSignature cmdlets. [#4157](https://github.com/PowerShell/PowerShell/issues/4157) +- [ ] Add coverage to various utility methods under src/Microsoft.PowerShell.Security/security/Utils.cs [#4157](https://github.com/PowerShell/PowerShell/issues/4157) ### Microsoft.WSMan.Management @@ -72,24 +60,14 @@ The following table shows the status for the above commit, dated 06/18/2017 #### CoreCLR -- [ ] Lots of non-windows code can be ifdef'ed out. Issue #[3565](https://github.com/PowerShell/PowerShell/issues/3565) - -#### CIMSupport - -- [ ] Missing coverage possibly due to: CoreCLR [issue](https://github.com/dotnet/corefx/issues/18877). -[4159](https://github.com/PowerShell/PowerShell/issues/4159) +- [ ] Lots of non-windows code can be ifdef'ed out. [#3565](https://github.com/PowerShell/PowerShell/issues/3565) #### Engine -- [ ] Add tests for COM. [#4154](https://github.com/PowerShell/PowerShell/issues/4154) - [ ] Add tests for Tab Completion of various types of input. [#4160](https://github.com/PowerShell/PowerShell/issues/4160) -- [ ] Add tests for Import-Module / Get-Module over PSRP and CIMSession. [#4161](https://github.com/PowerShell/PowerShell/issues/4161) -- [ ] Add tests for debugging PS Jobs.[#4153](https://github.com/PowerShell/PowerShell/issues/4153) -- [ ] Add test for -is, -isnot, -contains, -notcontains and -like operators.[#4162](https://github.com/PowerShell/PowerShell/issues/4162) -- [ ] Remove Snapin code from CommandDiscovery. Issue #[4118](https://github.com/PowerShell/PowerShell/issues/4118) +- [ ] Add tests for debugging PS Jobs. [#4153](https://github.com/PowerShell/PowerShell/issues/4153) +- [ ] Remove Snapin code from CommandDiscovery. [#4118](https://github.com/PowerShell/PowerShell/issues/4118) - [ ] Add tests SessionStateItem, SessionStateContainer error cases, dynamic parameters. Coverage possibly added by *-Item, *-ChildItem error case tests. [#4148](https://github.com/PowerShell/PowerShell/issues/4148) -- [ ] Add tests for Get-Command -ShowCommandInfo [#4163](https://github.com/PowerShell/PowerShell/issues/4163) -- [ ] Add tests for Proxy Commands [#4164](https://github.com/PowerShell/PowerShell/issues/4164) - [ ] Add more tests using PSCredential [#4165](https://github.com/PowerShell/PowerShell/issues/4165) #### Remoting @@ -101,17 +79,9 @@ The following table shows the status for the above commit, dated 06/18/2017 - [ ] Add tests for Connect/Disconnect session [#4166](https://github.com/PowerShell/PowerShell/issues/4166) - [ ] Add more tests for Start-Job's various options [#4166](https://github.com/PowerShell/PowerShell/issues/4166) -#### HelpSystem - -- [ ] Add tests for Alias help [#4167](https://github.com/PowerShell/PowerShell/issues/4167) -- [ ] Add tests for Class help [#4167](https://github.com/PowerShell/PowerShell/issues/4167) -- [ ] Add tests for SaveHelp [#4167](https://github.com/PowerShell/PowerShell/issues/4167) -- [ ] Add tests for HelpProviderWithCache [#4167](https://github.com/PowerShell/PowerShell/issues/4167) -- [ ] HelpProviderWithFullCache, potential dead code. [#4167](https://github.com/PowerShell/PowerShell/issues/4167) - #### Security -- [ ] Add more tests under various ExecutionPolicy modes. [4168](https://github.com/PowerShell/PowerShell/issues/4168) +- [ ] Add more tests under various ExecutionPolicy modes. [#4168](https://github.com/PowerShell/PowerShell/issues/4168) #### Utils diff --git a/docs/testing-guidelines/Images/AppVeyor-Badge-Green.png b/docs/testing-guidelines/Images/AppVeyor-Badge-Green.png deleted file mode 100644 index 777ca2c4b443..000000000000 Binary files a/docs/testing-guidelines/Images/AppVeyor-Badge-Green.png and /dev/null differ diff --git a/docs/testing-guidelines/Images/AppVeyor-Github.png b/docs/testing-guidelines/Images/AppVeyor-Github.png index e467d28accf4..4afb37d9a4ff 100644 Binary files a/docs/testing-guidelines/Images/AppVeyor-Github.png and b/docs/testing-guidelines/Images/AppVeyor-Github.png differ diff --git a/docs/testing-guidelines/Images/AzDevOps-Success.png b/docs/testing-guidelines/Images/AzDevOps-Success.png new file mode 100644 index 000000000000..be0439f7c839 Binary files /dev/null and b/docs/testing-guidelines/Images/AzDevOps-Success.png differ diff --git a/docs/testing-guidelines/Images/CoverageReportFilter.PNG b/docs/testing-guidelines/Images/CoverageReportFilter.PNG new file mode 100644 index 000000000000..69e2e28ace5e Binary files /dev/null and b/docs/testing-guidelines/Images/CoverageReportFilter.PNG differ diff --git a/docs/testing-guidelines/Images/CoverageReportTop.PNG b/docs/testing-guidelines/Images/CoverageReportTop.PNG new file mode 100644 index 000000000000..f1737e9da5d7 Binary files /dev/null and b/docs/testing-guidelines/Images/CoverageReportTop.PNG differ diff --git a/docs/testing-guidelines/Images/Travis-CI-Badge-Green.png b/docs/testing-guidelines/Images/Travis-CI-Badge-Green.png deleted file mode 100644 index 9207e71cc132..000000000000 Binary files a/docs/testing-guidelines/Images/Travis-CI-Badge-Green.png and /dev/null differ diff --git a/docs/testing-guidelines/TestRoadmap.md b/docs/testing-guidelines/TestRoadmap.md index 0b0b92c6657e..aea71be5aec2 100644 --- a/docs/testing-guidelines/TestRoadmap.md +++ b/docs/testing-guidelines/TestRoadmap.md @@ -44,7 +44,6 @@ Running code coverage more often on full PowerShell is something that we should We currently run only those tests which are tagged `CI` excluding the tag `SLOW` as part of our continuous integration systems. This means roughly 1/3rd of our github tests are not being run on any regular schedule. In order to provide us with higher confidence in our code, we should be running *ALL* of our tests on a regular basis. -We have recently added to `AppVeyor` running all of our tests on a daily basis, but are not yet running these tests on Linux/Mac via `Travis`, which should be done. However, running the tests is only the first step, we need an easy way to be notified of test failures, and to track progress of those runs over time. Tracking this over time affords us the ability to see how our test count increases, implying an improvement in coverage. It also provides us mechanism whereby we can see trends in instability. @@ -80,7 +79,7 @@ We need to be sure that we can easily enable remoting for the non-Windows platfo * Our current multi-machine tests do not test the connection code, they simply execute test code remotely and retrieve results and assume a good connection. The infrastructure used for these tests is STEX which is not an open environment. We will need to create automation to create and configure the test systems in the test matrix and then invoke tests on them. -It is not clear that our current CI systems can accommodate our needs here as neither AppVeyor or Travis can supply us with all of the OS images needed. +It is not clear that our current CI systems can accommodate our needs here as Azure DevOps can supply us with all of the OS images needed. We may need to create our own heterogeneous environment in Azure, or look to other teams (MS Build Lab/Jenkins) for assistance. We need to investigate whether there are solutions available, and if not, design/implement an environment to meet our needs. @@ -89,9 +88,6 @@ We need to investigate whether there are solutions available, and if not, design Currently, we report against the simplest of KPI: * is the CI build error free (which is part of the PR/Merge process - and reported on our landing page) -We are also collecting data for a daily build, but not yet report on the following KPI -* is the daily build error free (we are running this on AppVeyor, we still need to do this for Travis-CI) - There are a number of KPIs which we could report on: * Code KPIs * What is the coverage (% blocks covered) of our `CI` tests @@ -194,4 +190,4 @@ Below is my suggestion for prioritization to reduce risk and improve confidence 6. Replace in-lab tests with PowerShell Core tests 7. Investigate feasibility of running current in-lab tests on PowerShell Core -These are [tracked](https://github.com/PowerShell/PowerShell/issues?utf8=%E2%9C%93&q=is%3Aissue%20%23testability%20) as issues \ No newline at end of file +These are [tracked](https://github.com/PowerShell/PowerShell/issues?utf8=%E2%9C%93&q=is%3Aissue%20%23testability%20) as issues diff --git a/docs/testing-guidelines/WritingPesterTests.md b/docs/testing-guidelines/WritingPesterTests.md index df0ea928f060..5225dd94a223 100755 --- a/docs/testing-guidelines/WritingPesterTests.md +++ b/docs/testing-guidelines/WritingPesterTests.md @@ -1,129 +1,143 @@ -### Writing Pester Tests -Note that this document does not replace the documents found in the [Pester](https://github.com/pester/pester "Pester") project. This is just -some quick tips and suggestions for creating Pester tests for this project. The Pester community is vibrant and active, if you have questions -about Pester or creating tests, the [Pester Wiki](https://github.com/pester/pester/wiki) has a lot of great information. +# Writing Pester Tests + +Note that this document does not replace the documents found in the [Pester](https://github.com/pester/pester) project. +This is just some quick tips and suggestions for creating Pester tests for this project. +The Pester community is vibrant and active, if you have questions about Pester or creating tests, the [Pester Wiki](https://github.com/pester/pester/wiki) has a lot of great information. +As of January 2018, PowerShell Core is using Pester version 4 which has some changes from earlier versions. +See [Migrating from Pester 3 to Pester 4](https://github.com/pester/Pester/wiki/Migrating-from-Pester-3-to-Pester-4) for more information. When creating tests, keep the following in mind: -* Tests should not be overly complicated and test too many things - * boil down your tests to their essence, test only what you need -* Tests should be as simple as they can -* Tests should generally not rely on any other test -Examples: -Here's the simplest of tests +- Tests should not be overly complicated and test too many things. + - Boil down your tests to their essence, test only what you need. +- Tests should be as simple as they can. +- Tests should generally not rely on any other test. + +## Examples + +Here's the simplest of tests: ```powershell Describe "A variable can be assigned and retrieved" { - It "Create a variable and make sure its value is correct" { + It "Creates a variable and makes sure its value is correct" { $a = 1 - $a | Should be 1 + $a | Should -Be 1 } } ``` -If you need to do type checking, that can be done as well +If you need to do type checking, that can be done as well: ```powershell Describe "One is really one" { It "Compare 1 to 1" { $a = 1 - $a | Should be 1 + $a | Should -Be 1 } It "1 is really an int" { $i = 1 - $i.GetType() | Should Be "int" + $i | Should -BeOfType System.Int32 } } ``` -alternatively, you could do the following: +If you are checking for proper errors, use the `Should -Throw -ErrorId` Pester syntax. +It checks against `FullyQualifiedErrorId` property, which is recommended because it does not change based on culture as an error message might. ```powershell -Describe "One is really one" { - It "Compare 1 to 1" { - $a = 1 - $a | Should be 1 - } - It "1 is really an int" { - $i = 1 - $i.GetType() | Should Be ([System.Int32]) - } +... +It "Get-Item on a nonexisting file should have error PathNotFound" { + { Get-Item "ThisFileCannotPossiblyExist" -ErrorAction Stop } | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand" } ``` -If you are checking for proper errors, use the `ShouldBeErrorId` helper defined in HelpersCommon.psm1 module which is in your path if you import `build.psm1`. -Checking against `FullyQualifiedErrorId` is recommended because it does not change based on culture as an error message might. +Note that if `Get-Item` were to succeed, the test will fail. + +However, if you need to check the `InnerException` or other members of the ErrorRecord, you should use `-PassThru` parameter: ```powershell -... -It "Get-Item on a nonexisting file should have error PathNotFound" { - { Get-Item "ThisFileCannotPossiblyExist" -ErrorAction Stop } | ShouldBeErrorId "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand" +It "InnerException sample" { + $e = { Invoke-WebRequest https://expired.badssl.com/ } | Should -Throw -ErrorId "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" -PassThru + $e.Exception.InnerException.NativeErrorCode | Should -Be 12175 } ``` -Note that if get-item were to succeed, a different FullyQualifiedErrorId would be thrown and the test will fail. -This is the suggested path because Pester wants to check the error message, which will likely not work here because of localized builds, but the FullyQualifiedErrorId is constant regardless of the locale. +## Describe/Context/It -However, if you need to check the `InnerException` or other members of the ErrorRecord, the recommended pattern to use is: +For creation of PowerShell tests, the `Describe` block is the level of granularity suggested and one of three tags should be used: `CI`, `Feature`, or `Scenario`. -```powershell - It "InnerException sample" { +If the tag is not provided, the build process will fail. - $e = { Invoke-WebRequest https://expired.badssl.com/ } | ShouldBeErrorId "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" - $e.Exception.InnerException.NativeErrorCode | Should Be 12175 - ... - } -``` +### Describe + +Creates a logical group of tests. +All `Mocks` and `TestDrive` contents defined within a `Describe` block are scoped to that `Describe`; +they will no longer be present when the `Describe` block exits. +A `Describe` block may contain any number of `Context` and `It` blocks. + +### Context + +Provides logical grouping of `It` blocks within a single `Describe` block. Any `Mocks` defined inside a `Context` are removed at the end of the `Context` scope, as are any files or folders added to the `TestDrive` during the `Context` block's execution. + +Any `BeforeEach` or `AfterEach` blocks defined inside a `Context` also only apply to tests within that `Context`. + +### It + +The `It` block is intended to be used inside of a `Describe` or `Context` block. If you are familiar with the AAA pattern (Arrange-Act-Assert), the body of the `It` block is the appropriate location for an assert. -### Describe/Context/It -For creation of PowerShell tests, the Describe block is the level of granularity suggested and one of three tags should be used: "CI", "Feature", or "Scenario". If the tag is not provided, tests in that describe block will be run any time tests are executed. +The convention is to assert a single expectation for each `It` block. The code inside of the `It` block should throw a terminating error if the expectation of the test is not met and thus cause the test to fail. -#### Describe -Creates a logical group of tests. All Mocks and TestDrive contents defined within a Describe block are scoped to that Describe; they will no longer be present when the Describe block exits. A `Describe block may contain any number of Context and It blocks. +The name of the `It` block should expressively state the expectation of the test. -#### Context -Provides logical grouping of It blocks within a single Describe block. Any Mocks defined inside a Context are removed at the end of the Context scope, as are any files or folders added to the TestDrive during the Context block's execution. Any BeforeEach or AfterEach blocks defined inside a Context also only apply to tests within that Context . +## Admin privileges in tests -#### It -The It block is intended to be used inside of a Describe or Context Block. If you are familiar with the AAA pattern (Arrange-Act-Assert), the body of the It block is the appropriate location for an assert. The convention is to assert a single expectation for each It block. The code inside of the It block should throw a terminating error if the expectation of the test is not met and thus cause the test to fail. The name of the It block should expressively state the expectation of the test. +Tests that require admin privileges **on Windows** must be additionally marked with `RequireAdminOnWindows` Pester tag. -### Admin privileges in tests -Tests that require admin privileges **on windows** should be additionally marked with 'RequireAdminOnWindows' Pester tag. -In the AppVeyor CI, we run two different passes: +In the Azure DevOps Windows CI, we run two different passes: -- The pass with exclusion of tests with 'RequireAdminOnWindows' tag -- The pass where we run only 'RequireAdminOnWindows' tests +- The pass with exclusion of `RequireAdminOnWindows` tagged tests. +- The pass where only `RequireAdminOnWindows` tagged tests are being executed. In each case, tests are executed with appropriate privileges. -### Selected Features +Tests that need to be run with sudo **on Unix systems** must be additionally marked with `RequireSudoOnUnix` Pester tag. -#### Test Drive -A PSDrive is available for file activity during a tests and this drive is limited to the scope of a single Describe block. The contents of the drive are cleared when a context block is exited. -A test may need to work with file operations and validate certain types of file activities. It is usually desirable not to perform file activity tests that will produce side effects outside of an individual test. Pester creates a PSDrive inside the user's temporary drive that is accessible via a names PSDrive TestDrive:. Pester will remove this drive after the test completes. You may use this drive to isolate the file operations of your test to a temporary store. +`RequireSudoOnUnix` tag takes precedence over all other tags like `CI`, `Feature`, etc. (which are ignored when `RequireSudoOnUnix` is present). +Tests tagged with `RequireSudoOnUnix` will run as a separate pass for any Unix test. + +## Selected Features + +### Test Drive + +A `PSDrive` is available for file activity during a test and this drive is limited to the scope of a single `Describe` block. The contents of the drive are cleared when a `Context` block is exited. + +A test may need to work with file operations and validate certain types of file activities. It is usually desirable not to perform file activity tests that will produce side effects outside of an individual test. + +Pester creates a `PSDrive` inside the user's temporary drive that is accessible via `TestDrive:` or `$TestDrive`. **Pester will remove** this drive after the test completes. +You may use this drive to isolate the file operations of your test to a temporary store. The following example illustrates the feature: ```powershell function Add-Footer($path, $footer) { - Add-Content $path -Value $footer + Add-Content $path -Value $footer } Describe "Add-Footer" { - $testPath="TestDrive:\test.txt" - Set-Content $testPath -value "my test text." - Add-Footer $testPath "-Footer" - $result = Get-Content $testPath + $testPath="TestDrive:\test.txt" + Set-Content $testPath -value "my test text." + Add-Footer $testPath "-Footer" + $result = Get-Content $testPath - It "adds a footer" { - (-join $result) | Should Be("my test text.-Footer") - } + It "adds a footer" { + (-join $result) | Should -BeExactly "my test text.-Footer" + } } ``` -When this test completes, the contents of the TestDrive PSDrive will be removed. +When this test completes, the contents of the `TestDrive:` will be removed. -#### Parameter Generation +### Parameter Generation ```powershell $testCases = @( @@ -134,30 +148,34 @@ $testCases = @( ) Describe "A test" { - It " -xor should be " -testcase $testcases { + It " -xor should be " -TestCases $testCases { param ($a, $b, $ExpectedResult) - $a -xor $b | Should be $ExpectedResult + $a -xor $b | Should -Be $ExpectedResult } } ``` -You can also construct loops and pass values as parameters, including the expected value, but Pester does this for you. +### Mocking + +Mocks the behavior of an existing command with an alternate implementation. This creates new behavior for any existing command within the scope of a `Describe` or `Context` block. +The function allows you to specify a script block that will become the command's new behavior. -#### Mocking -Mocks the behavior of an existing command with an alternate implementation. This creates new behavior for any existing command within the scope of a Describe or Context block. The function allows you to specify a script block that will become the command's new behavior. The following example illustrates simple use: ```powershell Context "Get-Random is not random" { - Mock Get-Random { return 3 } - It "Get-Random returns 3" { - Get-Random | Should be 3 - } + Mock Get-Random { return 3 } + + It "Get-Random returns 3" { + Get-Random | Should -Be 3 } +} ``` -More information may be found on the [wiki](https://github.com/pester/Pester/wiki/Mock) +More information may be found [here](https://github.com/pester/Pester/wiki/Mock). + ### Free Code in a Describe block + Code execution in Pester can be very subtle and can cause issues when executing test code. The execution of code which lays outside of the usual code blocks may not happen as you expect. Consider the following: ```powershell @@ -177,7 +195,7 @@ Describe it { Write-Host -for DarkRed "Before It" It "should not be a surprise" { - 1 | should be 1 + 1 | should -Be 1 } Write-Host -for DarkRed "After It" } @@ -188,7 +206,7 @@ Describe it { } ``` -Now, when run, you can see the execution schedule +Now, when run, you can see the execution schedule: ``` PS# invoke-pester c:\temp\pester.demo.tests.ps1 @@ -214,11 +232,19 @@ Tests completed in 79ms Passed: 1 Failed: 0 Skipped: 0 Pending: 0 ``` -The DESCRIBE BeforeAll block is executed before any other code even though it was at the bottom of the Describe block, so if state is set elsewhere in the describe BLOCK, that state will not be visible (as the code will not yet been run). Notice, too, that the BEFOREALL block in Context is executed before any other code in that block. -Generally, you should have code reside in one of the code block elements of `[Before|After][All|Each]`, especially if those block rely on state set by free code elsewhere in the block. +The `Describe` - `BeforeAll` block is executed before any other code even though it was at the bottom of the `Describe` block. +So if some state is set elsewhere in the `Describe` block, that state will not yet be visible (as the code will not yet been run). + +Notice, too, that the `BeforeAll` block in `Context` is executed before any other code in that block. +Generally, you should have code reside in one of the code block elements of `BeforeAll`, `BeforeEach`, `AfterEach` and/or `AfterAll`, especially if those blocks rely on some state set by free code elsewhere in the block. + +### Skipping Tests in Bulk + +Sometimes it is beneficial to skip all the tests in a particular `Describe` block. +For example, tests which are not applicable to a platform could be skipped, and they would be reported as skipped. + +The following is an example of how this may be done: -#### Skipping tests in bulk -Sometimes it is beneficial to skip all the tests in a particular `Describe` block. For example, tests which are not applicable to a platform could be skipped, and they would be reported as skipped. The following is an example of how this may be done: ```powershell Describe "Should not run these tests on non-Windows platforms" { BeforeAll { @@ -232,23 +258,25 @@ Describe "Should not run these tests on non-Windows platforms" { } Context "Block 1" { It "This block 1 test 1" { - 1 | should be 1 + 1 | should -Be 1 } It "This is block 1 test 2" { - 1 | should be 1 + 1 | should -Be 1 } } Context "Block 2" { It "This block 2 test 1" { - 2 | should be 1 + 2 | should -Be 1 } It "This is block 2 test 2" { - 2 | should be 1 + 2 | should -Be 1 } } } ``` + Here is the output when run on a Linux distribution: + ``` Describing Should not run these tests on non-Windows platforms Context Block 1 @@ -258,7 +286,9 @@ Describing Should not run these tests on non-Windows platforms [!] This block 2 test 1 73ms [!] This is block 2 test 2 6ms ``` + and here is the output when run on a Windows distribution: + ``` Describing Should not run these tests on non-Windows platforms Context Block 1 @@ -268,41 +298,40 @@ Describing Should not run these tests on non-Windows platforms [-] This block 2 test 1 52ms Expected: {1} But was: {2} - 22: 2 | should be 1 + 22: 2 | should -Be 1 at , : line 22 [-] This is block 2 test 2 77ms Expected: {1} But was: {2} - 25: 2 | should be 1 + 25: 2 | should -Be 1 at , : line 25 ``` -this technique uses the `$PSDefaultParameterValues` feature of PowerShell to temporarily set the It block parameter `-skip` to true (or in the case of Windows, it is not set at all) - +This technique uses the `$PSDefaultParameterValues` feature of PowerShell to temporarily set the `It` block parameter `-skip` to true (or in the case of Windows, it is not set at all) -#### Multi-line strings +### Multi-line strings -You may want to have a test like +You may want to have a test like: ```powershell It 'tests multi-line string' { - Get-MultiLineString | Should Be @' + Get-MultiLineString | Should -Be @' first line second line '@ } ``` -There are problems with using here-strings with verifying the output results. +There are problems with using multi-line strings with verifying the output results. The reason for it are line-ends. They cause problems for two reasons: -* They are different on different platforms (`\r\n` on windows and `\n` on unix). -* Even on the same system, they depends on the way how the repo was cloned. +- They are different on different platforms (`\r\n` on Windows and `\n` on Unix). +- Even on the same system, they depend on the way how the repo was cloned (local git configuration). -Particularly, in the default AppVeyour CI windows image, you will get `\n` line ends in all your files. -That causes problems, because at runtime `Get-MultiLineString` would likely produce `\r\n` line ends on windows. +Particularly, in the default Azure DevOps CI Windows image, you will get `\n` line ends in all your files. +That causes problems, because at runtime `Get-MultiLineString` would likely produce `\r\n` line ends on Windows. Some workaround could be added, but they are sub-optimal and make reading test code harder. @@ -313,7 +342,7 @@ function normalizeEnds([string]$text) } It 'tests multi-line string' { - normalizeEnds (Get-MultiLineString) | Should Be (normalizeEnds @' + normalizeEnds (Get-MultiLineString) | Should -Be (normalizeEnds @' first line second line '@) @@ -323,43 +352,45 @@ second line When appropriate, you can avoid creating multi-line strings at the first place. These commands create an array of strings: -* `Get-Content` -* `Out-String -Stream` - -Pester Do and Don't -=================== - -## Do -1. Name your files .tests.ps1 -2. Keep tests simple - 1. Test only what you need - 2. Reduce dependencies -3. Be sure to tag your `Describe` blocks based on their purpose - 1. Tag `CI` indicates that it will be run as part of the continuous integration process. These should be unit test like, and generally take less than a second. - 2. Tag `Feature` indicates a higher level feature test (we will run these on a regular basis), for example, tests which go to remote resources, or test broader functionality - 3. Tag `Scenario` indicates tests of integration with other features (these will be run on a less regular basis and test even broader functionality than feature tests. -4. Make sure that `Describe`/`Context`/`It` descriptions are useful - 1. The error message should not be the place where you describe the test -5. Use `Context` to group tests - 1. Multiple `Context` blocks can help you group your test suite into logical sections -6. Use `BeforeAll`/`AfterAll`/`BeforeEach`/`AfterEach` instead of custom initiators -7. Prefer Try-Catch for expected errors and check $_.fullyQualifiedErrorId (don't use `should throw`) -8. Use `-testcases` when iterating over multiple `It` blocks -9. Use code coverage functionality where appropriate -10. Use `Mock` functionality when you don't have your entire environment -11. Avoid free code in a `Describe` block - 1. Use `[Before|After][Each|All]` see [Free Code in a Describe block](WritingPesterTests.md#free-code-in-a-describe-block) -12. Avoid creating or using test files outside of TESTDRIVE: - 1. TESTDRIVE: has automatic clean-up -13. Keep in mind that we are creating cross platform tests - 1. Avoid using the registry - 2. Avoid using COM -14. Avoid being too specific about the _count_ of a resource as these can change platform to platform - 1. ex: checking for the count of loaded format files, check rather for format data for a specific type - -## Don't -1. Don't have too many evaluations in a single It block - 1. The first `Should` failure will stop that block -2. Don't use `Should` outside of an `It` Block -3. Don't use the word "Error" or "Fail" to test a positive case - 1. ex: "Get-ChildItem TESTDRIVE: shouldn't fail", rather "Get-ChildItem should be able to retrieve file listing from TESTDRIVE" +- `Get-Content` +- `Out-String -Stream` + +## Pester Do and Don't + +### Do + +1. Name your file `.tests.ps1`. +2. Keep tests simple: + - Test only what you need. + - Reduce dependencies. +3. Be sure to tag your `Describe` blocks based on their purpose: + - Tag `CI` indicates that it will be run as part of the continuous integration process. These should be unit test like, and generally take less than a second. + - Tag `Feature` indicates a higher level feature test (we will run these on a regular basis), for example, tests which go to remote resources, or test broader functionality. + - Tag `Scenario` indicates tests of integration with other features (these will be run on a less regular basis and test even broader functionality than feature tests. +4. Make sure that `Describe`/`Context`/`It` descriptions are useful. + - The error message should not be the place where you describe the test. +5. Use `Context` to group tests. + - Multiple `Context` blocks can help you group your test suite into logical sections. +6. Use `BeforeAll`/`BeforeEach`/`AfterEach`/`AfterAll` instead of custom initiators. +7. Use `Should -Throw -ErrorId` to check for expected errors. +8. Use `-TestCases` when iterating over multiple `It` blocks. +9. Use code coverage functionality where appropriate. +10. Use `Mock` functionality when you don't have your entire environment. +11. Avoid free code in a `Describe` block. + - Use `BeforeAll`/`BeforeEach`/`AfterEach`/`AfterAll`. + - See [Free Code in a Describe block](WritingPesterTests.md#free-code-in-a-describe-block) +12. Avoid creating or using test files outside of `TESTDRIVE:`. + - `TESTDRIVE:` has automatic clean-up. +13. Keep in mind that we are creating cross platform tests. + - Avoid using the registry. + - Avoid using COM. +14. Avoid being too specific about the _count_ of a resource as these can change platform to platform. + - Example: Avoid checking for the count of loaded format files, but rather check for format data for a specific type. + +### Don't + +1. Don't have too many evaluations in a single `It` block. + - The first `Should` failure will stop that block. +2. Don't use `Should` outside of an `It` Block. +3. Don't use the word "Error" or "Fail" to test a positive case. + - Example: Rephrase the negative sentence `"Get-ChildItem TESTDRIVE: shouldn't fail"` to the following positive case `"Get-ChildItem should be able to retrieve file listing from TESTDRIVE"`. diff --git a/docs/testing-guidelines/getting-code-coverage.md b/docs/testing-guidelines/getting-code-coverage.md new file mode 100644 index 000000000000..0f2bc8eb9836 --- /dev/null +++ b/docs/testing-guidelines/getting-code-coverage.md @@ -0,0 +1,172 @@ +# Getting Code Coverage Analysis for PowerShell + +**Note: Code coverage is currently only supported on Windows, since we use OpenCover.** + +The PowerShell code base is configured to build with code coverage support using [OpenCover]. + +You can see the testing coverage of the current [`master`] branch build at any time at [codecov.io]. + +To run test coverage analysis of PowerShell on your own branch/machine, +you will need to take the following steps +(and be aware that running the code coverage analysis can take as long as 8 hours). + +## Running tests with code coverage analysis + +**First**: Open PowerShell in an **elevated** session. +OpenCover needs elevated privileges to work. + +Now, in PowerShell: + +```powershell +# Go to your PowerShell build directory root +PS> Set-Location "C:\Path\to\powershell\build\dir" + +# Import the PowerShell build module +PS> Import-Module .\build.psm1 + +# Build PowerShell. You may need to add other flags here like +# -ResGen or -Restore +PS> Start-PSBuild -Configuration CodeCoverage -Clean -PsModuleRestore + +# Now ensure Pester is installed +PS> Restore-PSPester + +# We also need to build the test executor +PS> Publish-PSTestTools + +# Import the OpenCover module +PS> Import-Module $PWD\test\tools\OpenCover + +# Install OpenCover to a temporary directory +PS> Install-OpenCover -TargetDirectory $env:TEMP -Force + +# Finally, run the tests with code coverage analysis. +# If you want to run only the continuous integration tests, +# add -CIOnly, which will take less time +PS> Invoke-OpenCover -OutputLog coverage.xml -OpenCoverPath $env:TEMP\OpenCover +``` + +## Examining the code coverage data + +Once the code coverage test run is done, you'll want to examine the data: + +```powershell +# Collect the coverage data using Get-CodeCoverage from the OpenCover +# module that was imported above. This operation is generally expensive +# to compute, so worth storing in a variable +PS> $coverageData = Get-CodeCoverage .\coverage.xml + +# Take a look at a summary of the results +PS> $coverageData.CoverageSummary + +NumSequencePoints : 298237 +VisitedSequencePoints : 125949 +NumBranchPoints : 101477 +VisitedBranchPoints : 39389 +SequenceCoverage : 42.23 +BranchCoverage : 38.82 +MaxCyclomaticComplexity : 393 +MinCyclomaticComplexity : 1 +VisitedClasses : 1990 +NumClasses : 3187 +VisitedMethods : 15115 +NumMethods : 32517 + +# You can also view results by assembly +PS> $coverageData.Assembly | Format-Table AssemblyName,Branch,Sequence + +AssemblyName Branch Sequence +------------ ------ -------- +pwsh 100 100 +Microsoft.PowerShell.ConsoleHost 21.58 23.32 +System.Management.Automation 41.22 45.01 +Microsoft.PowerShell.CoreCLR.Eventing 1.88 2.03 +Microsoft.PowerShell.Security 17.32 20.09 +Microsoft.PowerShell.Commands.Utility 20.14 21.39 +Microsoft.PowerShell.Commands.Management 43.05 43.39 +Microsoft.WSMan.Management 52.58 56.98 +Microsoft.WSMan.Runtime 80.95 80.33 +Microsoft.PowerShell.Commands.Diagnostics 0 0 +``` + +If you have made changes to tests or code +and run a second code coverage run, +you can also compare code coverage results: + +```powershell +PS> $cov1 = Get-CodeCoverage ./coverage1.xml +PS> $cov2 = Get-CodeCoverage ./coverage2.xml +PS> Compare-CodeCoverage -Run1 $cov1 -Run2 $cov2 + +AssemblyName Sequence SequenceDelta Branch BranchDelta +------------ -------- ------------- ------ ----------- +Microsoft.PowerShell.Security 20.09 -30.12 17.32 -31.63 +Microsoft.PowerShell.Commands.Management 43.39 9.10 43.05 11.59 +System.Management.Automation 45.04 -10.63 41.23 -11.07 +Microsoft.PowerShell.Commands.Utility 21.39 -47.22 20.14 -46.47 +Microsoft.PowerShell.Commands.Diagnostics 0 -51.91 0 -48.62 +Microsoft.PowerShell.ConsoleHost 23.32 -22.28 21.58 -22.47 +pwsh 100 0.00 100 0.00 +Microsoft.WSMan.Management 57.73 48.23 53.02 43.22 +Microsoft.WSMan.Runtime 80.33 -19.67 80.95 -19.05 +Microsoft.PowerShell.CoreCLR.Eventing 2.03 -32.74 1.88 -26.01 +``` + +To get file-specific coverage data, +you can use `Compare-FileCoverage`: + +```powershell +PS> Compare-FileCoverage -ReferenceCoverage $cov2 -DifferenceCoverage $cov1 -FileName LanguagePrimitives.cs + +FileName ReferenceCoverage DifferenceCoverage CoverageDelta +-------- ----------------- ------------------ ------------- +LanguagePrimitives.cs 53.68 69.03 15.34 +``` + +You can see more ways to use `Compare-CodeCoverage` and `Compare-FileCoverage` +by running: + +```powershell +PS> Get-Help Compare-CodeCoverage -Full +# Or +PS> Get-Help Compare-FileCoverage -Full +``` + +## Visualizing code coverage + +For a more detailed, graphical representation of the code coverage results, +you can use the ReportGenerator package. +This generates an HTML report of the coverage from the XML file +and will provide much more detail about the coverage analysis. +The package is available on [NuGet], +and you can install and run it as follows: + +```powershell +# Install ReportGenerator +PS> Find-Package ReportGenerator ` +>> -ProviderName Nuget ` +>> -Source "https://nuget.org/api/v2" ` +>> | Install-Package -Scope CurrentUser + +# Get the ReportGenerator executable path +# Make sure use the appropriate version number in the path +$ReportGenExe = "$HOME\AppData\Local\PackageManagement\NuGet\Packages\ReportGenerator.\tools\ReportGenerator.exe" + +# Run ReportGenerator +& $ReportGenExe -report:coverage.xml -targetdir:C:\temp\Coverage + +# Finally, open the report in your browser +Invoke-Item C:\temp\Coverage\index.htm +``` + +This should open a screen in the browser like this: +![Coverage report browser page](Images/CoverageReportTop.PNG) + +The main report, which is below the summary and risk hot spots, has +a filter functionality as well (when "Enable Filtering" is clicked on): +![Coverage report with filter on](Images/CoverageReportFilter.PNG) + +[OpenCover]: https://github.com/OpenCover/opencover +[codecov.io]: https://codecov.io +[`master`]: https://github.com/PowerShell/PowerShell +[NuGet]: https://nuget.org/packages/ReportGenerator diff --git a/docs/testing-guidelines/testing-guidelines.md b/docs/testing-guidelines/testing-guidelines.md index 92072071e94d..b7b952f1a1aa 100755 --- a/docs/testing-guidelines/testing-guidelines.md +++ b/docs/testing-guidelines/testing-guidelines.md @@ -13,35 +13,21 @@ When adding new tests, place them in the directories as [outlined below](#test-l ## CI System -We use [AppVeyor](http://www.appveyor.com/) as a continuous integration (CI) system for Windows -and [Travis CI](http://www.travis-ci.com) for non-Windows platforms. +We use [Azure DevOps](https://azure.microsoft.com/en-us/solutions/devops) as a continuous integration (CI) system for Windows +and non-Windows platforms. -### AppVeyor - -In the `README.md` at the top of the repo, you can see AppVeyor badge. +In the `README.md` at the top of the repository, you can see Azure CI badge. It indicates the last build status of `master` branch. Hopefully, it's green: -![AppVeyor-Badge-Green.png](Images/AppVeyor-Badge-Green.png) - -This badge is **clickable**; you can open corresponding build page with logs, artifacts, and tests results. -From there you can easily navigate to the build history. - -### Travis CI - -Travis CI works similarly to AppVeyor. -For Travis CI there will be multiple badges. -The badges indicate the last build status of `master` branch for different platforms. -Hopefully, it's green: - -![Travis-CI-Badge-Green.png](Images/Travis-CI-Badge-Green.png) +![AzDevOps-Success.png](Images/AzDevOps-Success.png) This badge is **clickable**; you can open corresponding build page with logs, artifacts, and tests results. From there you can easily navigate to the build history. ### Getting CI Results -CI System builds (AppVeyor and Travis CI) and runs tests on every pull request and provides quick feedback about it. +CI System builds and runs tests on every pull request and provides quick feedback about it. ![AppVeyor-Github](Images/AppVeyor-Github.png) @@ -69,9 +55,11 @@ The Pester framework allows `Describe` blocks to be tagged, and our CI system re One of the following tags must be used: * `CI` - this tag indicates that the tests in the `Describe` block will be executed as part of the CI/PR process -* `Feature` - tests with this tag will not be executed as part of the CI/PR process, but they will be executed on a daily basis as part of a `cron` driven build. - They indicate that the test will be validating more behavior, or will be using remote network resources (ex: package management tests) * `Scenario` - this tag indicates a larger scale test interacting with multiple areas of functionality and/or remote resources, these tests are also run daily. +* `Feature` - tests with this tag will not be executed as part of the CI/PR process, + but they will be executed on a daily basis as part of a `cron` driven build. + They indicate that the test will be validating more behavior, + or will be using remote network resources (ex: package management tests) Additionally, the tag: @@ -108,14 +96,11 @@ Currently, we have a minuscule number of tests which are run by using xUnit. When working on new features or fixes, it is natural to want to run those tests locally before making a PR. Three helper functions are part of the build.psm1 module to help with that: -* `Restore-PSPester` will restore Pester, which is needed to run `Start-PSPester` * `Start-PSPester` will execute all Pester tests which are run by the CI system * `Start-PSxUnit` will execute the available xUnit tests run by the CI system Our CI system runs these as well; there should be no difference between running these on your dev system, versus in CI. -Make sure that you run `Restore-PSPester` before running `Start-PSPester`, or it will fail to run. - When running tests in this way, be sure that you have started PowerShell with `-noprofile` as some tests will fail if the environment is not the default or has any customization. diff --git a/global.json b/global.json index d427e5ce3507..4201a8ffdf78 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.0.2" + "version": "3.0.100-preview8-013656" } } diff --git a/license_thirdparty_proprietary.txt b/license_thirdparty_proprietary.txt deleted file mode 100644 index 911a40b8dcd2..000000000000 --- a/license_thirdparty_proprietary.txt +++ /dev/null @@ -1,771 +0,0 @@ -PowerShell 6.0 -Copyright (c) Microsoft Corporation. All rights reserved. -All rights reserved. -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this -software and associated documentation files (the "Software"), to deal in the Software -without restriction, including without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the following -conditions: -The above copyright notice and this permission notice shall be included in all copies -or substantial portions of the Software. -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -IMPORTANT NOTICE: THE SOFTWARE ALSO CONTAINS THIRD PARTY AND OTHER -PROPRIETARY SOFTWARE THAT ARE GOVERNED BY SEPARATE LICENSE TERMS. BY ACCEPTING -THE LICENSE TERMS ABOVE, YOU ALSO ACCEPT THE LICENSE TERMS GOVERNING THE -THIRD PARTY AND OTHER SOFTWARE, WHICH ARE SET FORTH BELOW: -The following components listed are governed by the license terms that follow the -component(s) name: ------------------------------------------------------- -Libmi.so ------------------------------------------------------- -Copyright (c) Microsoft Corporation. All rights reserved. -All rights reserved. -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this -software and associated documentation files (the "Software"), to deal in the Software -without restriction, including without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the following -conditions: -The above copyright notice and this permission notice shall be included in all copies -or substantial portions of the Software. -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -The following components are governed by the MIT license, a copy of which appears -below the list of components: ------------------------------------------------------- -Newtonsoft.Json ------------------------------------------------------- -Copyright (c) 2007 James Newton-King -All rights reserved. -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this -software and associated documentation files (the "Software"), to deal in the Software -without restriction, including without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the following -conditions: -The above copyright notice and this permission notice shall be included in all copies -or substantial portions of the Software. -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------- -Libuv v.1.9.0 ---------------------------------------------------------- - -https://raw.githubusercontent.com/aspnet/libuv-package/dev/content/License.txt - -This software is licensed to you by Microsoft Corporation under the original terms of -the copyright holder provided below: - -========================================= - -libuv is part of the Node project: http://nodejs.org/ -libuv may be distributed alone under Node's license: - -==== - -Copyright Joyent, Inc. and other Node contributors. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - -==== - -This license applies to all parts of libuv that are not externally -maintained libraries. - -The externally maintained libraries used by libuv are: - - - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. - - - inet_pton and inet_ntop implementations, contained in src/inet.c, are -copyright the Internet Systems Consortium, Inc., and licensed under the ISC -license. - - - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three - clause BSD license. - - - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile - Communications AB. Three clause BSD license. - - - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design Inc, -Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement - n° 289016). Three clause BSD license. - -========================================= - - ----------------------------------------------------- -• dotnet-test-xunit 2.2.0-preview2-build1029 -• xunit -• xunit.abstractions -• xunit.assert -• xunit.core -• xunit.extensibility.core -• xunit.extensibility.execution -• xunit.runner.reporters -• xunit.runner.utility ----------------------------------------------------- - -https://www.nuget.org/packages - -Copyright 2015 Outercurve Foundation - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - - --------------------------------------------------- -• Microsoft.CodeAnalysis.Analyzers -• Microsoft.CodeAnalysis.Common -• Microsoft.CodeAnalysis.CSharp -• Microsoft.CodeAnalysis.VisualBasic -• Microsoft.CSharp -• Microsoft.DiaSymReader -• Microsoft.DiaSymReader.Native -• Microsoft.DotNet.Cli.Utils -• Microsoft.DotNet.InternalAbstractions -• Microsoft.DotNet.ProjectModel -• Microsoft.Extensions.DependencyModel -• Microsoft.Extensions.Testing.Abstractions -• Microsoft.NETCore -• Microsoft.NETCore.App -• Microsoft.NETCore.DotNetHost -• Microsoft.NETCore.DotNetHostPolicy -• Microsoft.NETCore.DotNetHostResolver -• Microsoft.NETCore.Jit -• Microsoft.NETCore.Platforms -• Microsoft.NETCore.Portable.Compatibility -• Microsoft.NETCore.Runtime -• Microsoft.NETCore.Runtime.CoreCLR -• Microsoft.NETCore.Runtime.Native -• Microsoft.NETCore.Targets -• Microsoft.NETCore.Windows.ApiSets -• Microsoft.VisualBasic -• Microsoft.Win32.Primitives -• Microsoft.Win32.Registry -• Microsoft.Win32.Registry.AccessControl -• NETStandard.Library -• runtime.any.System.Collections -• runtime.any.System.Diagnostics.Tools -• runtime.any.System.Diagnostics.Tracing -• runtime.any.System.Globalization -• runtime.any.System.Globalization.Calendars -• runtime.any.System.IO -• runtime.any.System.Reflection -• runtime.any.System.Reflection.Extensions -• runtime.any.System.Reflection.Primitives -• runtime.any.System.Resources.ResourceManager -• runtime.any.System.Runtime -• runtime.any.System.Runtime.Handles -• runtime.any.System.Runtime.InteropServices -• runtime.any.System.Text.Encoding -• runtime.any.System.Text.Encoding.Extensions -• runtime.any.System.Threading.Tasks -• runtime.any.System.Threading.Timer -• runtime.debian.8-x64.Microsoft.NETCore.DotNetHost -• runtime.debian.8-x64.Microsoft.NETCore.DotNetHostPolicy -• runtime.debian.8-x64.Microsoft.NETCore.DotNetHostResolver -• runtime.debian.8-x64.Microsoft.NETCore.Jit -• runtime.debian.8-x64.Microsoft.NETCore.Runtime.CoreCLR -• runtime.debian.8-x64.runtime.native.System -• runtime.debian.8-x64.runtime.native.System.IO.Compression -• runtime.debian.8-x64.runtime.native.System.Net.Http -• runtime.debian.8-x64.runtime.native.System.Net.Security -• runtime.debian.8-x64.runtime.native.System.Security.Cryptography -• runtime.native.System -• runtime.native.System.Data.SqlClient.sni -• runtime.native.System.IO.Compression -• runtime.native.System.Net.Http -• runtime.native.System.Net.Security -• runtime.native.System.Security.Cryptography -• runtime.osx.10.10-x64.Microsoft.NETCore.DotNetHost -• runtime.osx.10.10-x64.Microsoft.NETCore.DotNetHostPolicy -• runtime.osx.10.10-x64.Microsoft.NETCore.DotNetHostResolver -• runtime.osx.10.10-x64.Microsoft.NETCore.Jit -• runtime.osx.10.10-x64.Microsoft.NETCore.Runtime.CoreCLR -• runtime.osx.10.10-x64.runtime.native.System -• runtime.osx.10.10-x64.runtime.native.System.IO.Compression -• runtime.osx.10.10-x64.runtime.native.System.Net.Http -• runtime.osx.10.10-x64.runtime.native.System.Net.Security -• runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography -• runtime.rhel.7-x64.Microsoft.NETCore.DotNetHost -• runtime.rhel.7-x64.Microsoft.NETCore.DotNetHostPolicy -• runtime.rhel.7-x64.Microsoft.NETCore.DotNetHostResolver -• runtime.rhel.7-x64.Microsoft.NETCore.Jit -• runtime.rhel.7-x64.Microsoft.NETCore.Runtime.CoreCLR -• runtime.rhel.7-x64.runtime.native.System -• runtime.rhel.7-x64.runtime.native.System.IO.Compression -• runtime.rhel.7-x64.runtime.native.System.Net.Http -• runtime.rhel.7-x64.runtime.native.System.Net.Security -• runtime.rhel.7-x64.runtime.native.System.Security.Cryptography -• runtime.ubuntu.14.04-x64.Microsoft.NETCore.DotNetHost -• runtime.ubuntu.14.04-x64.Microsoft.NETCore.DotNetHostPolicy -• runtime.ubuntu.14.04-x64.Microsoft.NETCore.DotNetHostResolver -• runtime.ubuntu.14.04-x64.Microsoft.NETCore.Jit -• runtime.ubuntu.14.04-x64.Microsoft.NETCore.Runtime.CoreCLR -• runtime.ubuntu.14.04-x64.runtime.native.System -• runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression -• runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http -• runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security -• runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography -• runtime.ubuntu.16.04-x64.Microsoft.NETCore.DotNetHost -• runtime.ubuntu.16.04-x64.Microsoft.NETCore.DotNetHostPolicy -• runtime.ubuntu.16.04-x64.Microsoft.NETCore.DotNetHostResolver -• runtime.ubuntu.16.04-x64.Microsoft.NETCore.Jit -• runtime.ubuntu.16.04-x64.Microsoft.NETCore.Runtime.CoreCLR -• runtime.ubuntu.16.04-x64.runtime.native.System -• runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression -• runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http -• runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security -• runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography -• runtime.unix.Microsoft.Win32.Primitives -• runtime.unix.System.Console -• runtime.unix.System.Diagnostics.Debug -• runtime.unix.System.IO.FileSystem -• runtime.unix.System.Net.Primitives -• runtime.unix.System.Net.Sockets -• runtime.unix.System.Private.Uri -• runtime.unix.System.Runtime.Extensions -• runtime.win.Microsoft.Win32.Primitives -• runtime.win.System.Console -• runtime.win.System.Diagnostics.Debug -• runtime.win.System.IO.FileSystem -• runtime.win.System.Net.Primitives -• runtime.win.System.Net.Sockets -• runtime.win.System.Runtime.Extensions -• runtime.win7-x64.Microsoft.NETCore.DotNetHost -• runtime.win7-x64.Microsoft.NETCore.DotNetHostPolicy -• runtime.win7-x64.Microsoft.NETCore.DotNetHostResolver -• runtime.win7-x64.Microsoft.NETCore.Jit -• runtime.win7-x64.Microsoft.NETCore.Runtime.CoreCLR -• runtime.win7-x64.Microsoft.NETCore.Windows.ApiSets -• runtime.win7-x64.runtime.native.System.Data.SqlClient.sni -• runtime.win7-x64.runtime.native.System.IO.Compression -• runtime.win7-x86.runtime.native.System.Data.SqlClient.sni -• runtime.win7.System.Private.Uri -• runtime.win81-x64.Microsoft.NETCore.Windows.ApiSets -• System.AppContext -• System.Buffers -• System.Collections -• System.Collections.Concurrent -• System.Collections.Immutable -• System.Collections.NonGeneric -• System.Collections.Specialized -• System.ComponentModel -• System.ComponentModel.Annotations -• System.ComponentModel.EventBasedAsync -• System.ComponentModel.Primitives -• System.ComponentModel.TypeConverter -• System.Console -• System.Data.Common -• System.Data.SqlClient -• System.Diagnostics.Contracts -• System.Diagnostics.Debug -• System.Diagnostics.DiagnosticSource -• System.Diagnostics.FileVersionInfo -• System.Diagnostics.Process -• System.Diagnostics.StackTrace -• System.Diagnostics.TextWriterTraceListener -• System.Diagnostics.Tools -• System.Diagnostics.TraceSource -• System.Diagnostics.Tracing -• System.Dynamic.Runtime -• System.Globalization -• System.Globalization.Calendars -• System.Globalization.Extensions -• System.IO -• System.IO.Compression -• System.IO.Compression.ZipFile -• System.IO.FileSystem -• System.IO.FileSystem.AccessControl -• System.IO.FileSystem.DriveInfo -• System.IO.FileSystem.Primitives -• System.IO.FileSystem.Watcher -• System.IO.MemoryMappedFiles -• System.IO.Packaging -• System.IO.Pipes -• System.IO.UnmanagedMemoryStream -• System.Linq -• System.Linq.Expressions -• System.Linq.Parallel -• System.Linq.Queryable -• System.Net.Http -• System.Net.Http.WinHttpHandler -• System.Net.NameResolution -• System.Net.NetworkInformation -• System.Net.Ping -• System.Net.Primitives -• System.Net.Requests -• System.Net.Security -• System.Net.Sockets -• System.Net.WebHeaderCollection -• System.Net.WebSockets -• System.Net.WebSockets.Client -• System.Numerics.Vectors -• System.ObjectModel -• System.Private.DataContractSerialization -• System.Private.ServiceModel -• System.Private.Uri -• System.Reflection -• System.Reflection.DispatchProxy -• System.Reflection.Emit -• System.Reflection.Emit.ILGeneration -• System.Reflection.Emit.Lightweight -• System.Reflection.Extensions -• System.Reflection.Metadata -• System.Reflection.Primitives -• System.Reflection.TypeExtensions -• System.Resources.Reader -• System.Resources.ResourceManager -• System.Runtime -• System.Runtime.CompilerServices.VisualC -• System.Runtime.Extensions -• System.Runtime.Handles -• System.Runtime.InteropServices -• System.Runtime.InteropServices.PInvoke -• System.Runtime.InteropServices.RuntimeInformation -• System.Runtime.Loader -• System.Runtime.Numerics -• System.Runtime.Serialization.Json -• System.Runtime.Serialization.Primitives -• System.Runtime.Serialization.Xml -• System.Security.AccessControl -• System.Security.Claims -• System.Security.Cryptography.Algorithms -• System.Security.Cryptography.Cng -• System.Security.Cryptography.Csp -• System.Security.Cryptography.Encoding -• System.Security.Cryptography.OpenSsl -• System.Security.Cryptography.Pkcs -• System.Security.Cryptography.Primitives -• System.Security.Cryptography.X509Certificates -• System.Security.Principal -• System.Security.Principal.Windows -• System.Security.SecureString -• System.ServiceModel.Duplex -• System.ServiceModel.Http -• System.ServiceModel.NetTcp -• System.ServiceModel.Primitives -• System.ServiceModel.Security -• System.ServiceProcess.ServiceController -• System.Text.Encoding -• System.Text.Encoding.CodePages -• System.Text.Encoding.Extensions -• System.Text.Encodings.Web -• System.Text.RegularExpressions -• System.Threading -• System.Threading.AccessControl -• System.Threading.Overlapped -• System.Threading.Tasks -• System.Threading.Tasks.Dataflow -• System.Threading.Tasks.Extensions -• System.Threading.Tasks.Parallel -• System.Threading.Thread -• System.Threading.ThreadPool -• System.Threading.Timer -• System.Xml.ReaderWriter -• System.Xml.XDocument -• System.Xml.XmlDocument -• System.Xml.XmlSerializer -• System.Xml.XPath -• System.Xml.XPath.XDocument -• System.Xml.XPath.XmlDocument -------------------------------------------------------- - -MICROSOFT SOFTWARE LICENSE TERMS -MICROSOFT .NET LIBRARY -These license terms are an agreement between Microsoft Corporation (or based on where you -live, one of its affiliates) and you. Please read them. They apply to the software named above, -which includes the media on which you received it, if any. The terms also apply to any Microsoft -• updates, -• supplements, -• Internet-based services, and -• support services -for this software, unless other terms accompany those items. If so, those terms apply. -BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT -USE THE SOFTWARE. -IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE PERPETUAL RIGHTS BELOW. -1. INSTALLATION AND USE RIGHTS. -a. Installation and Use. You may install and use any number of copies of the software to design, -develop and test your programs. -b. Third Party Programs. The software may include third party programs that Microsoft, not the -third party, licenses to you under this agreement. Notices, if any, for the third party program are -included for your information only. -2. DATA. The software may collect information about you and your use of the software, and send that -to Microsoft. Microsoft may use this information to improve our products and services. You can learn -more about data collection and use in the help documentation and the privacy statement -at https://go.microsoft.com/fwlink/?LinkId=528096 . Your use of the software operates as your -consent to these practices. -3. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. -a. DISTRIBUTABLE CODE. The software is comprised of Distributable Code. “Distributable -Code” is code that you are permitted to distribute in programs you develop if you comply with -the terms below. -i . Right to Use and Distribute. -• You may copy and distribute the object code form of the software. -• Third Party Distribution. You may permit distributors of your programs to copy and -distribute the Distributable Code as part of those programs. -ii. Distribution Requirements. For any Distributable Code you distribute, you must -• add significant primary functionality to it in your programs; -• require distributors and external end users to agree to terms that protect it at least as -much as this agreement; -• display your valid copyright notice on your programs; and -• indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ -fees, related to the distribution or use of your programs. -iii. Distribution Restrictions. You may not -• alter any copyright, trademark or patent notice in the Distributable Code; -• use Microsoft’s trademarks in your programs’ names or in a way that suggests your -programs come from or are endorsed by Microsoft; -• include Distributable Code in malicious, deceptive or unlawful programs; or -• modify or distribute the source code of any Distributable Code so that any part of it -becomes subject to an Excluded License. An Excluded License is one that requires, as a -condition of use, modification or distribution, that -• the code be disclosed or distributed in source code form; or -• others have the right to modify it. -4. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to -use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite -this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you -must comply with any technical limitations in the software that only allow you to use it in certain ways. -You may not -• work around any technical limitations in the software; -• reverse engineer, decompile or disassemble the software, except and only to the extent that -applicable law expressly permits, despite this limitation; -• publish the software for others to copy; -• rent, lease or lend the software; -• transfer the software or this agreement to any third party; or -• use the software for commercial software hosting services. -5. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the -software. -6. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy -and use the documentation for your internal, reference purposes. -7. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You -must comply with all domestic and international export laws and regulations that apply to the software. -These laws include restrictions on destinations, end users and end use. For additional information, -see www.microsoft.com/exporting. -8. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. -9. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based -services and support services that you use, are the entire agreement for the software and support -services. -10. APPLICABLE LAW. -a. United States. If you acquired the software in the United States, Washington state law governs the -interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws -principles. The laws of the state where you live govern all other claims, including claims under state -consumer protection laws, unfair competition laws, and in tort. -b. Outside the United States. If you acquired the software in any other country, the laws of -that country apply. -11. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the -laws of your country. You may also have rights with respect to the party from whom you acquired the -software. This agreement does not change your rights under the laws of your country if the laws of your -country do not permit it to do so. -12. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF -USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. -YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR -LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED -UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. -FOR AUSTRALIA – YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER -LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS. -13. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM -MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT -RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, -INDIRECT OR INCIDENTAL DAMAGES. -This limitation applies to -• anything related to the software, services, content (including code) on third party Internet sites, or -third party programs; and -• claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, -or other tort to the extent permitted by applicable law. -It also applies even if Microsoft knew or should have known about the possibility of the damages. The above -limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of -incidental, consequential or other damages. -Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are -provided below in French. -Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies -ci-dessous en français. -EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce -logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez -bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne -peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, -d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues. -LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES -DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de -dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation -pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. -Cette limitationconcerne: -• tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des -sites Internet tiers ou dans des programmes tiers ; et -• les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité -stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur. -Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. -Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, -accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne -s’appliquera pas à votre égard. -EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits -prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de -votre pays si celles-ci ne le permettent pas. - - --------------------------------------------------------- -• NuGet.Common -• NuGet.Configuration -• NuGet.DependencyResolver.Core -• NuGet.Frameworks -• NuGet.LibraryModel -• NuGet.Packaging -• NuGet.Packaging.Core -• NuGet.Packaging.Core.Types -• NuGet.ProjectModel -• NuGet.Protocol.Core.Types -• NuGet.Protocol.Core.v3 -• NuGet.Repositories -• NuGet.RuntimeModel -• NuGet.Versioning ----------------------------------------------------------- - -Copyright (c) .NET Foundation. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -these files except in compliance with the License. You may obtain a copy of the -License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed -under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. - - ---------------------------------------------------------- -• Microsoft.Management.Infrastructure.dll -• Microsoft.Management.Infrastructure.Native.dll -• Microsoft.Management.Infrastructure.Unmanaged.dll ----------------------------------------------------------- -MICROSOFT SOFTWARE LICENSE TERMS -MANAGEMENT.INFRASTRUCTURE.DLL -MANAGEMENT.INFRASTRUCTURE.NATIVE.DLL -MANAGEMENT.INFRASTRUCTURE.UNMANAGED.DLL - -These license terms are an agreement between you and Microsoft Corporation (or one of its affiliates). They -apply to the software named above and any Microsoft services or software updates (except to the extent such -services or updates are accompanied by new or additional terms, in which case those different terms apply -prospectively and do not alter your or Microsoft’s rights relating to pre-updated software or services). IF YOU -COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU -ACCEPT THESE TERMS. -1. INSTALLATION AND USE RIGHTS -a) General. You may install and use any number of copies of the software on your devices. -b) Included Microsoft Applications. The software may include other Microsoft applications. These -license terms apply to those included applications, if any, unless other license terms are provided with -the other Microsoft applications. -c) Third Party Software. The software may include third party applications that are licensed to you -under this agreement or under their own terms. License terms, notices, and acknowledgements, if any, -for the third party applications may be accessible online at http://aka.ms/thirdpartynotices or in an -accompanying notices file. Even if such applications are governed by other agreements, the disclaimer, -limitations on, and exclusions of damages below also apply to the extent allowed by applicable law. -2. TIME-SENSITIVE SOFTWARE -a) Period. The software is time-sensitive and may stop running on a date that is defined in the software. -b) Notice. You may receive periodic reminder notices of this date through the software. -c) Access to data. You may not be able to access data used in the software when it stops running. -3. PRE-RELEASE SOFTWARE. The software is a pre-release version. It may not operate correctly. It may be -different from the commercially released version. -4. FEEDBACK. If you give feedback about the software to Microsoft, you give to Microsoft, without charge, -the right to use, share and commercialize your feedback in any way and for any purpose. You will not give -feedback that is subject to a license that requires Microsoft to license its software or documentation to -third parties because Microsoft includes your feedback in them. These rights survive this agreement. -5. DATA COLLECTION. The software may collect information about you and your use of the software and -send that to Microsoft. Microsoft may use this information to provide services and improve Microsoft’s -products and services. Your opt-out rights, if any, are described in the product documentation. Some -features in the software may enable collection of data from users of your applications that access or use the -software. If you use these features to enable data collection in your applications, you must comply with -applicable law, including getting any required user consent, and maintain a prominent privacy policy that -accurately informs users about how you use, collect, and share their data. You can learn more about -Microsoft’s data collection and use in the product documentation and the Microsoft Privacy Statement at -https://go.microsoft.com/fwlink/?LinkId=521839. You agree to comply with all applicable provisions of the -Microsoft Privacy Statement. -6. FONTS. While the software is running, you may use its fonts to display and print content. You may only (i) -embed fonts in content as permitted by the embedding restrictions in the fonts; and (ii) temporarily -download them to a printer or other output device to help print content. -7. SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all other rights. Unless applicable -law gives you more rights despite this limitation, you will not (and have no right to): -a) work around any technical limitations in the software that only allow you to use it in certain ways; -b) reverse engineer, decompile or disassemble the software; -c) remove, minimize, block, or modify any notices of Microsoft or its suppliers in the software; -d) use the software in any way that is against the law or to create or propagate malware; or -e) share, publish, distribute, or lend the software, provide the software as a stand-alone hosted solution -for others to use, or transfer the software or this agreement to any third party. -8. EXPORT RESTRICTIONS. You must comply with all domestic and international export laws and regulations -that apply to the software, which include restrictions on destinations, end users, and end use. For further -information on export restrictions, visit http://aka.ms/exporting. -9. SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any support services for -the software. Any support provided is “as is”, “with all faults”, and without warranty of any kind. -10. UPDATES. The software may periodically check for updates, and download and install them for you. You -may obtain updates only from Microsoft or authorized sources. Microsoft may need to update your system -to provide you with updates. You agree to receive these automatic updates without any additional notice. -Updates may not include or support all existing software features, services, or peripheral devices. -11. ENTIRE AGREEMENT. This agreement, and any other terms Microsoft may provide for supplements, -updates, or third-party applications, is the entire agreement for the software. -12. APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in the United States -or Canada, the laws of the state or province where you live (or, if a business, where your principal place of -business is located) govern the interpretation of this agreement, claims for its breach, and all other claims -(including consumer protection, unfair competition, and tort claims), regardless of conflict of laws -principles. If you acquired the software in any other country, its laws apply. If U.S. federal jurisdiction exists, -you and Microsoft consent to exclusive jurisdiction and venue in the federal court in King County, -Washington for all disputes heard in court. If not, you and Microsoft consent to exclusive jurisdiction and -venue in the Superior Court of King County, Washington for all disputes heard in court. -13. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You may -have other rights, including consumer rights, under the laws of your state, province, or country. Separate -and apart from your relationship with Microsoft, you may also have rights with respect to the party from -which you acquired the software. This agreement does not change those other rights if the laws of your -state, province, or country do not permit it to do so. For example, if you acquired the software in one of the -below regions, or mandatory country law applies, then the following provisions apply to you: -a) Australia. You have statutory guarantees under the Australian Consumer Law and nothing in this -agreement is intended to affect those rights. -b) Canada. If you acquired this software in Canada, you may stop receiving updates by turning off the -automatic update feature, disconnecting your device from the Internet (if and when you re-connect to -the Internet, however, the software will resume checking for and installing updates), or uninstalling the -software. The product documentation, if any, may also specify how to turn off updates for your specific -device or software. -c) Germany and Austria. -i. Warranty. The properly licensed software will perform substantially as described in -any Microsoft materials that accompany the software. However, Microsoft gives no -contractual guarantee in relation to the licensed software. -ii. Limitation of Liability. In case of intentional conduct, gross negligence, claims based -on the Product Liability Act, as well as, in case of death or personal or physical injury, -Microsoft is liable according to the statutory law. -Subject to the foregoing clause ii., Microsoft will only be liable for slight negligence if Microsoft is in -breach of such material contractual obligations, the fulfillment of which facilitate the due performance -of this agreement, the breach of which would endanger the purpose of this agreement and the -compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases -of slight negligence, Microsoft will not be liable for slight negligence. -14. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF USING -IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO THE EXTENT -PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED WARRANTIES, -INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. -15. LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING -DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM -MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER -ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR -INCIDENTAL DAMAGES. -This limitation applies to (a) anything related to the software, services, content (including code) on -third party Internet sites, or third party applications; and (b) claims for breach of contract, warranty, -guarantee, or condition; strict liability, negligence, or other tort; or any other claim; in each case to -the extent permitted by applicable law. -It also applies even if Microsoft knew or should have known about the possibility of the damages. -The above limitation or exclusion may not apply to you because your state, province, or country -may not allow the exclusion or limitation of incidental, consequential, or other damages. - -Please note: As this software is distributed in Canada, some of the clauses in this agreement are -provided below in French. -Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce contrat sont fournies ci- -dessous en français. -EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de -ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous -pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, -que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de -qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues. -LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. -Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs -uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres -dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. -Cette limitation concerne: -• tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites -Internet tiers ou dans des programmes tiers; et -• les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, -de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur. -Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel -dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages -indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci- -dessus ne s’appliquera pas à votre égard. -EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits -prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois -de votre pays si celles-ci ne le permettent pas. - -The following components are governed by the MIT license, a copy of which appears -below the list of components: ------------------------------------------------------- -tools/appimage.sh ------------------------------------------------------- -Copyright (c) 2016 Simon Peter -All rights reserved. -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this -software and associated documentation files (the "Software"), to deal in the Software -without restriction, including without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the following -conditions: -The above copyright notice and this permission notice shall be included in all copies -or substantial portions of the Software. -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------- -DotNet/CoreFX -https://github.com/dotnet/corefx ---------------------------------------------------------- -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/nuget.config b/nuget.config index ca674f6c218e..5ec994d9118b 100644 --- a/nuget.config +++ b/nuget.config @@ -4,6 +4,8 @@ + + diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/AssemblyInfo.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/AssemblyInfo.cs index 7a2005fee6c7..25ea29305592 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/AssemblyInfo.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/AssemblyInfo.cs @@ -1,13 +1,6 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. -using System.Diagnostics; -using System.Reflection; using System.Runtime.CompilerServices; [assembly:InternalsVisibleTo("Microsoft.Windows.DSC.CoreConfProviders,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] -[assembly:InternalsVisibleTo("Microsoft.Management.Infrastructure.CimCmdlets.Test,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] -//This is equal to Debuggable(true,true) which enables IsJITTracking and Disable Optimization. CoreCLR does not have constructor Debuggable(true,true) -[assembly: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations)] diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs index bbf97b2fb50d..b7e418e05b64 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs @@ -1,16 +1,14 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; using System.Management.Automation; using System.Threading; -using System.Globalization; #endregion @@ -29,7 +27,7 @@ internal abstract class CimAsyncOperation : IDisposable #region Constructor /// - /// Constructor + /// Constructor. /// public CimAsyncOperation() { @@ -52,7 +50,7 @@ public CimAsyncOperation() /// /// object raised the event /// - /// event argument + /// Event argument. protected void NewCmdletActionHandler(object cimSession, CmdletActionEventArgs actionArgs) { DebugHelper.WriteLogEx("Disposed {0}, action type = {1}", 0, this._disposed, actionArgs.Action); @@ -64,6 +62,7 @@ protected void NewCmdletActionHandler(object cimSession, CmdletActionEventArgs a // unblock the thread waiting for response (actionArgs.Action as CimSyncAction).OnComplete(); } + return; } @@ -82,14 +81,14 @@ protected void NewCmdletActionHandler(object cimSession, CmdletActionEventArgs a /// /// /// - /// object raised the event + /// object raised the event. /// - /// event argument + /// Event argument. protected void OperationCreatedHandler(object cimSession, OperationEventArgs actionArgs) { DebugHelper.WriteLogEx(); - lock (this.myLock) + lock (this.a_lock) { this.operationCount++; } @@ -102,14 +101,14 @@ protected void OperationCreatedHandler(object cimSession, OperationEventArgs act /// /// /// - /// object raised the event + /// object raised the event. /// - /// event argument + /// Event argument. protected void OperationDeletedHandler(object cimSession, OperationEventArgs actionArgs) { DebugHelper.WriteLogEx(); - lock (this.myLock) + lock (this.a_lock) { this.operationCount--; if (this.operationCount == 0) @@ -127,7 +126,7 @@ protected void OperationDeletedHandler(object cimSession, OperationEventArgs act /// /// /// - /// wrapper of cmdlet, for details + /// wrapper of cmdlet, for details. /// public void ProcessActions(CmdletOperationBase cmdletOperation) { @@ -148,11 +147,11 @@ public void ProcessActions(CmdletOperationBase cmdletOperation) /// /// /// process remaining actions until all operations are completed or - /// current cmdlet is terminated by user + /// current cmdlet is terminated by user. /// /// /// - /// wrapper of cmdlet, for details + /// wrapper of cmdlet, for details. /// public void ProcessRemainActions(CmdletOperationBase cmdletOperation) { @@ -166,6 +165,7 @@ public void ProcessRemainActions(CmdletOperationBase cmdletOperation) DebugHelper.WriteLogEx("Either disposed or all operations completed.", 2); break; } + try { this.moreActionEvent.Wait(); @@ -179,6 +179,7 @@ public void ProcessRemainActions(CmdletOperationBase cmdletOperation) break; } } + ProcessActions(cmdletOperation); } @@ -186,11 +187,11 @@ public void ProcessRemainActions(CmdletOperationBase cmdletOperation) /// /// - /// Get action object from action queue + /// Get action object from action queue. /// /// - /// next action to execute - /// true indicates there is an valid action, otherwise false + /// Next action to execute. + /// True indicates there is an valid action, otherwise false. protected bool GetActionAndRemove(out CimBaseAction action) { return this.actionQueue.TryDequeue(out action); @@ -201,8 +202,8 @@ protected bool GetActionAndRemove(out CimBaseAction action) /// Add temporary object to cache. /// /// - /// Computer name of the cimsession - /// cimsession wrapper object + /// Computer name of the cimsession. + /// Cimsession wrapper object. protected void AddCimSessionProxy(CimSessionProxy sessionproxy) { lock (cimSessionProxyCacheLock) @@ -211,6 +212,7 @@ protected void AddCimSessionProxy(CimSessionProxy sessionproxy) { this.cimSessionProxyCache = new List(); } + if (!this.cimSessionProxyCache.Contains(sessionproxy)) { this.cimSessionProxyCache.Add(sessionproxy); @@ -223,7 +225,7 @@ protected void AddCimSessionProxy(CimSessionProxy sessionproxy) /// Are there active operations? /// /// - /// true for having active operations, otherwise false. + /// True for having active operations, otherwise false. protected bool IsActive() { DebugHelper.WriteLogEx("Disposed {0}, Operation Count {1}", 2, this.Disposed, this.operationCount); @@ -294,8 +296,7 @@ protected CimSessionProxy CreateCimSessionProxy(string computerName) /// /// /// - protected CimSessionProxy CreateCimSessionProxy(string computerName, - CimInstance cimInstance) + protected CimSessionProxy CreateCimSessionProxy(string computerName, CimInstance cimInstance) { CimSessionProxy proxy = new CimSessionProxy(computerName, cimInstance); this.SubscribeEventAndAddProxytoCache(proxy); @@ -317,7 +318,7 @@ protected CimSessionProxy CreateCimSessionProxy(string computerName, CimInstance } /// - /// Subscribe event from proxy and add proxy to cache + /// Subscribe event from proxy and add proxy to cache. /// /// protected void SubscribeEventAndAddProxytoCache(CimSessionProxy proxy) @@ -342,7 +343,7 @@ protected virtual void SubscribeToCimSessionProxyEvent(CimSessionProxy proxy) } /// - /// Retrieve the base object out if wrapped in psobject + /// Retrieve the base object out if wrapped in psobject. /// /// /// @@ -368,6 +369,7 @@ protected object GetBaseObject(object value) { arraybaseObject[i] = GetBaseObject(arrayObject[i]); } + return arraybaseObject; } } @@ -379,7 +381,7 @@ protected object GetBaseObject(object value) /// if not thrown exception. /// /// - /// output the cimtype of the value, either Reference or ReferenceArray + /// Output the cimtype of the value, either Reference or ReferenceArray. /// protected object GetReferenceOrReferenceArrayObject(object value, ref CimType referenceType) { @@ -392,6 +394,7 @@ protected object GetReferenceOrReferenceArrayObject(object value, ref CimType re { return null; } + referenceType = CimType.Reference; return cimInstance; } @@ -406,6 +409,7 @@ protected object GetReferenceOrReferenceArrayObject(object value, ref CimType re { return null; } + CimInstance[] cimInstanceArray = new CimInstance[cimReferenceArray.Length]; for (int i = 0; i < cimReferenceArray.Length; i++) { @@ -414,6 +418,7 @@ protected object GetReferenceOrReferenceArrayObject(object value, ref CimType re { return null; } + object baseObject = GetBaseObject(tempCimReference.Value); cimInstanceArray[i] = baseObject as CimInstance; if (cimInstanceArray[i] == null) @@ -421,6 +426,7 @@ protected object GetReferenceOrReferenceArrayObject(object value, ref CimType re return null; } } + referenceType = CimType.ReferenceArray; return cimInstanceArray; } @@ -438,9 +444,10 @@ protected bool Disposed { get { - return (Interlocked.Read(ref this._disposed) == 1); + return Interlocked.Read(ref this._disposed) == 1; } } + private long _disposed; /// @@ -453,6 +460,7 @@ protected bool Disposed public void Dispose() { Dispose(true); + // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SuppressFinalize to // take this object off the finalization queue @@ -472,7 +480,7 @@ public void Dispose() /// other objects. Only unmanaged resources can be disposed. /// /// - /// Whether it is directly called + /// Whether it is directly called. protected virtual void Dispose(bool disposing) { if (Interlocked.CompareExchange(ref this._disposed, 1, 0) == 0) @@ -508,6 +516,7 @@ private void Cleanup() (action as CimSyncAction).OnComplete(); } } + if (this.cimSessionProxyCache != null) { List temporaryProxy; @@ -516,6 +525,7 @@ private void Cleanup() temporaryProxy = new List(this.cimSessionProxyCache); this.cimSessionProxyCache.Clear(); } + // clean up all proxy objects foreach (CimSessionProxy proxy in temporaryProxy) { @@ -529,6 +539,7 @@ private void Cleanup() { this.ackedEvent.Dispose(); } + DebugHelper.WriteLog("Cleanup complete.", 2); } @@ -537,17 +548,17 @@ private void Cleanup() #region private members /// - /// lock object + /// Lock object. /// - private readonly object myLock = new object(); + private readonly object a_lock = new object(); /// - /// number of active operations + /// Number of active operations. /// - private UInt32 operationCount = 0; + private uint operationCount; /// - /// Event to notify ps thread that more action is available + /// Event to notify ps thread that more action is available. /// private ManualResetEventSlim moreActionEvent; @@ -559,12 +570,12 @@ private void Cleanup() private ConcurrentQueue actionQueue; /// - /// lock object + /// Lock object. /// private readonly object cimSessionProxyCacheLock = new object(); /// - /// cache all objects related to + /// Cache all objects related to /// the current operation. /// private List cimSessionProxyCache; @@ -584,6 +595,5 @@ private void Cleanup() internal const string ComputerNameArgument = @"ComputerName"; internal const string CimSessionArgument = @"CimSession"; #endregion - - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimBaseAction.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimBaseAction.cs index 773f81ad6d28..c76fb819697a 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimBaseAction.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimBaseAction.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -52,13 +50,15 @@ protected XOperationContextBase Context { return this.context; } + set { this.context = value; } } + private XOperationContextBase context; - }//End Class + } /// /// @@ -69,7 +69,7 @@ protected XOperationContextBase Context internal class CimSyncAction : CimBaseAction, IDisposable { /// - /// Constructor + /// Constructor. /// public CimSyncAction() { @@ -82,7 +82,7 @@ public CimSyncAction() /// Block current thread until action completed /// /// - /// Response from user + /// Response from user. public virtual CimResponseType GetResponse() { this.Block(); @@ -124,12 +124,12 @@ protected virtual void Block() #region members /// - /// action completed event + /// Action completed event. /// private ManualResetEventSlim completeEvent; /// - /// response result + /// Response result. /// protected CimResponseType responseType; @@ -137,7 +137,7 @@ protected virtual void Block() #region IDisposable interface /// - /// IDisposable interface + /// IDisposable interface. /// private bool _disposed; @@ -170,7 +170,7 @@ public void Dispose() /// other objects. Only unmanaged resources can be disposed. /// /// - /// Whether it is directly called + /// Whether it is directly called. protected virtual void Dispose(bool disposing) { // Check to see if Dispose has already been called. @@ -197,5 +197,5 @@ protected virtual void Dispose(bool disposing) } } #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCmdletModuleInitialize.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCmdletModuleInitialize.cs index b9f9962710d8..7f9a1da4057c 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCmdletModuleInitialize.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCmdletModuleInitialize.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -48,6 +46,7 @@ public void OnImport() invoker.AddScript(string.Format(CultureInfo.CurrentUICulture, "Set-Alias -Name {0} -Value {1} -Option {2} -ErrorAction SilentlyContinue", alias.Name, alias.Value, alias.Options)); DebugHelper.WriteLog(@"Add commands {0} of {1} with option {2} to current runspace.", 1, alias.Name, alias.Value, alias.Options); } + System.Collections.ObjectModel.Collection psObjects = invoker.Invoke(); DebugHelper.WriteLog(@"Invoke results {0}.", 1, psObjects.Count); } @@ -76,21 +75,24 @@ internal CimCmdletAliasEntry(string name, string value) } /// - /// The string defining the name of this alias + /// The string defining the name of this alias. /// internal string Name { get { return this._name; } } + private string _name; /// - /// The string defining real cmdlet name + /// The string defining real cmdlet name. /// internal string Value { get { return this._value; } } - private string _value = String.Empty; + + private string _value = string.Empty; /// - /// The string defining real cmdlet name + /// The string defining real cmdlet name. /// internal ScopedItemOptions Options { get { return this._options; } } + private ScopedItemOptions _options = ScopedItemOptions.AllScope | ScopedItemOptions.ReadOnly; } @@ -112,5 +114,5 @@ internal CimCmdletAliasEntry(string name, string value) new CimCmdletAliasEntry("gcls", "Get-CimClass"), }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCommandBase.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCommandBase.cs index 2f5dd0ac2ab9..9b8b69fe6e83 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCommandBase.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimCommandBase.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -27,7 +25,7 @@ namespace Microsoft.Management.Infrastructure.CimCmdlets internal class ParameterDefinitionEntry { /// - /// constructor + /// Constructor. /// /// /// @@ -38,7 +36,7 @@ internal ParameterDefinitionEntry(string parameterSetName, bool mandatory) } /// - /// property ParameterSetName + /// Property ParameterSetName. /// internal string ParameterSetName { @@ -47,10 +45,11 @@ internal string ParameterSetName return this.parameterSetName; } } + private readonly string parameterSetName = null; /// - /// Whether the parameter is mandatory to the set + /// Whether the parameter is mandatory to the set. /// internal bool IsMandatory { @@ -59,6 +58,7 @@ internal bool IsMandatory return this.mandatory; } } + private readonly bool mandatory = false; } @@ -70,7 +70,7 @@ internal bool IsMandatory internal class ParameterSetEntry { /// - /// constructor + /// Constructor. /// /// internal ParameterSetEntry(UInt32 mandatoryParameterCount) @@ -81,7 +81,7 @@ internal ParameterSetEntry(UInt32 mandatoryParameterCount) } /// - /// constructor + /// Constructor. /// /// internal ParameterSetEntry(ParameterSetEntry toClone) @@ -92,7 +92,7 @@ internal ParameterSetEntry(ParameterSetEntry toClone) } /// - /// constructor + /// Constructor. /// /// /// @@ -104,7 +104,7 @@ internal ParameterSetEntry(UInt32 mandatoryParameterCount, bool isDefault) } /// - /// reset the internal status + /// Reset the internal status. /// internal void reset() { @@ -113,7 +113,7 @@ internal void reset() } /// - /// property DefaultParameterSet + /// Property DefaultParameterSet /// internal bool IsDefaultParameterSet { @@ -122,10 +122,11 @@ internal bool IsDefaultParameterSet return this.isDefaultParameterSet; } } + private readonly bool isDefaultParameterSet = false; /// - /// property MandatoryParameterCount + /// Property MandatoryParameterCount /// internal UInt32 MandatoryParameterCount { @@ -134,10 +135,11 @@ internal UInt32 MandatoryParameterCount return this.mandatoryParameterCount; } } + private readonly UInt32 mandatoryParameterCount = 0; /// - /// property IsValueSet + /// Property IsValueSet /// internal bool IsValueSet { @@ -145,15 +147,17 @@ internal bool IsValueSet { return this.isValueSet; } + set { this.isValueSet = value; } } + private bool isValueSet = false; /// - /// property IsValueSetAtBeginProcess + /// Property IsValueSetAtBeginProcess /// internal bool IsValueSetAtBeginProcess { @@ -161,15 +165,17 @@ internal bool IsValueSetAtBeginProcess { return this.isValueSetAtBeginProcess; } + set { this.isValueSetAtBeginProcess = value; } } + private bool isValueSetAtBeginProcess = false; /// - /// property SetMandatoryParameterCount + /// Property SetMandatoryParameterCount /// internal UInt32 SetMandatoryParameterCount { @@ -177,15 +183,17 @@ internal UInt32 SetMandatoryParameterCount { return this.setMandatoryParameterCount; } + set { this.setMandatoryParameterCount = value; } } + private UInt32 setMandatoryParameterCount = 0; /// - /// property SetMandatoryParameterCountAtBeginProcess + /// Property SetMandatoryParameterCountAtBeginProcess /// internal UInt32 SetMandatoryParameterCountAtBeginProcess { @@ -193,11 +201,13 @@ internal UInt32 SetMandatoryParameterCountAtBeginProcess { return this.setMandatoryParameterCountAtBeginProcess; } + set { this.setMandatoryParameterCountAtBeginProcess = value; } } + private UInt32 setMandatoryParameterCountAtBeginProcess = 0; } @@ -207,7 +217,7 @@ internal UInt32 SetMandatoryParameterCountAtBeginProcess internal class ParameterBinder { /// - /// constructor + /// Constructor. /// /// /// @@ -249,7 +259,7 @@ internal class ParameterBinder private List parametersetNamesList = new List(); /// - /// Parameter names list + /// Parameter names list. /// private List parameterNamesList = new List(); @@ -263,7 +273,7 @@ internal class ParameterBinder private List parametersetNamesListAtBeginProcess = new List(); /// - /// Parameter names list before begin process + /// Parameter names list before begin process. /// private List parameterNamesListAtBeginProcess = new List(); @@ -300,7 +310,7 @@ internal void reset() /// /// /// - /// throw if conflict parameter was set + /// Throw if conflict parameter was set. internal void SetParameter(string parameterName, bool isBeginProcess) { DebugHelper.WriteLogEx("ParameterName = {0}, isBeginProcess = {1}", 0, parameterName, isBeginProcess); @@ -336,8 +346,10 @@ internal void SetParameter(string parameterName, bool isBeginProcess) { psEntry.SetMandatoryParameterCountAtBeginProcess++; } + DebugHelper.WriteLogEx("parameterset name = '{0}'; SetMandatoryParameterCount = '{1}'", 1, parameterDefinitionEntry.ParameterSetName, psEntry.SetMandatoryParameterCount); } + if (!psEntry.IsValueSet) { psEntry.IsValueSet = true; @@ -346,8 +358,10 @@ internal void SetParameter(string parameterName, bool isBeginProcess) psEntry.IsValueSetAtBeginProcess = true; } } + nameset.Add(parameterDefinitionEntry.ParameterSetName); } + this.parametersetNamesList = nameset; if (isBeginProcess) { @@ -370,6 +384,7 @@ internal void SetParameter(string parameterName, bool isBeginProcess) { psEntry.SetMandatoryParameterCountAtBeginProcess++; } + DebugHelper.WriteLogEx("parameterset name = '{0}'; SetMandatoryParameterCount = '{1}'", 1, entry.ParameterSetName, @@ -377,6 +392,7 @@ internal void SetParameter(string parameterName, bool isBeginProcess) } } } + if (nameset.Count == 0) { throw new PSArgumentException(Strings.UnableToResolveParameterSetName); @@ -393,7 +409,7 @@ internal void SetParameter(string parameterName, bool isBeginProcess) } /// - /// Get the parameter set name based on current binding results + /// Get the parameter set name based on current binding results. /// /// internal string GetParameterSet() @@ -422,12 +438,15 @@ internal string GetParameterSet() { defaultParameterSetName = parameterSetName; } + if (entry.IsValueSet) { noMandatoryParameterSet.Add(parameterSetName); } + continue; } + if ((entry.SetMandatoryParameterCount == entry.MandatoryParameterCount) && this.parametersetNamesList.Contains(parameterSetName)) { @@ -435,6 +454,7 @@ internal string GetParameterSet() { throw new PSArgumentException(Strings.UnableToResolveParameterSetName); } + boundParameterSetName = parameterSetName; } } @@ -464,11 +484,12 @@ internal string GetParameterSet() { throw new PSArgumentException(Strings.UnableToResolveParameterSetName); } + return boundParameterSetName; } /// - /// Deep clone the parameter entries to member variable + /// Deep clone the parameter entries to member variable. /// private void CloneParameterEntries( Dictionary> parameters, @@ -486,7 +507,7 @@ internal string GetParameterSet() #endregion /// - /// Base command for all cim cmdlets + /// Base command for all cim cmdlets. /// public class CimBaseCommand : Cmdlet, IDisposable { @@ -518,11 +539,12 @@ internal void CheckParameterSet() this.parameterBinder.reset(); } } + DebugHelper.WriteLog("current parameterset is: " + this.parameterSetName, 4); } /// - /// Redirect to parameterBinder to set one parameter + /// Redirect to parameterBinder to set one parameter. /// /// internal void SetParameter(object value, string parameterName) @@ -535,6 +557,7 @@ internal void SetParameter(object value, string parameterName) { return; } + if (this.parameterBinder != null) { this.parameterBinder.SetParameter(parameterName, this.AtBeginProcess); @@ -545,7 +568,7 @@ internal void SetParameter(object value, string parameterName) #region constructors /// - /// constructor + /// Constructor. /// internal CimBaseCommand() { @@ -554,7 +577,7 @@ internal CimBaseCommand() } /// - /// constructor + /// Constructor. /// internal CimBaseCommand(Dictionary> parameters, Dictionary sets) @@ -573,13 +596,13 @@ internal CimBaseCommand() protected override void StopProcessing() { Dispose(); - }//End StopProcessing() + } #endregion #region IDisposable interface /// - /// IDisposable interface + /// IDisposable interface. /// private bool disposed; @@ -612,7 +635,7 @@ public void Dispose() /// other objects. Only unmanaged resources can be disposed. /// /// - /// Whether it is directly called + /// Whether it is directly called. protected void Dispose(bool disposing) { // Check to see if Dispose has already been called. @@ -636,7 +659,7 @@ protected void Dispose(bool disposing) } /// - /// Clean up resources + /// Clean up resources. /// protected virtual void DisposeInternal() { @@ -651,7 +674,7 @@ protected virtual void DisposeInternal() #region private members /// - /// Parameter binder used to resolve parameter set name + /// Parameter binder used to resolve parameter set name. /// private ParameterBinder parameterBinder; @@ -663,7 +686,7 @@ protected virtual void DisposeInternal() private CimAsyncOperation operation; /// - /// lock object + /// Lock object. /// private readonly object myLock = new object(); @@ -677,7 +700,7 @@ protected virtual void DisposeInternal() /// /// This flag is introduced to resolve the parameter set name /// during process record - /// Whether at begin process time, false means in processrecord + /// Whether at begin process time, false means in processrecord. /// private bool atBeginProcess = true; internal bool AtBeginProcess @@ -686,6 +709,7 @@ internal bool AtBeginProcess { return this.atBeginProcess; } + set { this.atBeginProcess = value; @@ -711,6 +735,7 @@ internal CimAsyncOperation AsyncOperation this.operation = value; } } + get { return this.operation; @@ -731,7 +756,7 @@ internal string ParameterSetName } /// - /// Gets/Sets cmdlet operation wrapper object + /// Gets/Sets cmdlet operation wrapper object. /// internal virtual CmdletOperationBase CmdletOperation { @@ -755,78 +780,77 @@ internal void ThrowTerminatingError(Exception exception, string operation) #region internal const strings /// - /// alias CN - computer name + /// Alias CN - computer name. /// internal const string AliasCN = "CN"; /// - /// alias ServerName - computer name + /// Alias ServerName - computer name. /// internal const string AliasServerName = "ServerName"; /// - /// alias OT - operation timeout + /// Alias OT - operation timeout. /// internal const string AliasOT = "OT"; /// - /// session set name + /// Session set name. /// internal const string SessionSetName = "SessionSet"; /// - /// computer set name + /// Computer set name. /// internal const string ComputerSetName = "ComputerSet"; /// - /// class name computer set name + /// Class name computer set name. /// internal const string ClassNameComputerSet = "ClassNameComputerSet"; /// - /// resource Uri computer set name + /// Resource Uri computer set name. /// internal const string ResourceUriComputerSet = "ResourceUriComputerSet"; /// - /// computer set name + /// computer set name. /// internal const string CimInstanceComputerSet = "CimInstanceComputerSet"; /// - /// query computer set name + /// Query computer set name. /// internal const string QueryComputerSet = "QueryComputerSet"; /// - /// class name session set name + /// Class name session set name. /// internal const string ClassNameSessionSet = "ClassNameSessionSet"; - /// - /// resource Uri session set name + /// Resource Uri session set name. /// internal const string ResourceUriSessionSet = "ResourceUriSessionSet"; /// - /// session set name + /// session set name. /// internal const string CimInstanceSessionSet = "CimInstanceSessionSet"; /// - /// query session set name + /// Query session set name. /// internal const string QuerySessionSet = "QuerySessionSet"; /// - /// computer set name + /// computer set name. /// internal const string CimClassComputerSet = "CimClassComputerSet"; /// - /// session set name + /// session set name. /// internal const string CimClassSessionSet = "CimClassSessionSet"; @@ -848,17 +872,17 @@ internal void ThrowTerminatingError(Exception exception, string operation) #endregion /// - /// credential parameter set + /// Credential parameter set. /// internal const string CredentialParameterSet = "CredentialParameterSet"; /// - /// certificate parameter set + /// Certificate parameter set. /// internal const string CertificateParameterSet = "CertificateParameterSet"; /// - /// CimInstance parameter alias + /// CimInstance parameter alias. /// internal const string AliasCimInstance = "CimInstance"; @@ -879,7 +903,7 @@ internal void ThrowTerminatingError(Exception exception, string operation) string parameterName, PasswordAuthenticationMechanism authentication) { - string message = String.Format(CultureInfo.CurrentUICulture, Strings.InvalidAuthenticationTypeWithNullCredential, + string message = string.Format(CultureInfo.CurrentUICulture, Strings.InvalidAuthenticationTypeWithNullCredential, authentication, ImpersonatedAuthenticationMechanism.None, ImpersonatedAuthenticationMechanism.Negotiate, @@ -891,7 +915,7 @@ internal void ThrowTerminatingError(Exception exception, string operation) } /// - /// Throw conflict parameter error + /// Throw conflict parameter error. /// /// /// @@ -901,7 +925,7 @@ internal void ThrowTerminatingError(Exception exception, string operation) string parameterName, string conflictParameterName) { - string message = String.Format(CultureInfo.CurrentUICulture, + string message = string.Format(CultureInfo.CurrentUICulture, Strings.ConflictParameterWasSet, parameterName, conflictParameterName); PSArgumentException exception = new PSArgumentException(message, parameterName); @@ -927,9 +951,11 @@ internal void ThrowTerminatingError(Exception exception, string operation) { propList.Append(","); } + propList.Append(property); } - string message = String.Format(CultureInfo.CurrentUICulture, Strings.CouldNotFindPropertyFromGivenClass, + + string message = string.Format(CultureInfo.CurrentUICulture, Strings.CouldNotFindPropertyFromGivenClass, className, propList); PSArgumentOutOfRangeException exception = new PSArgumentOutOfRangeException( parameterName, actualValue, message); @@ -937,7 +963,7 @@ internal void ThrowTerminatingError(Exception exception, string operation) } /// - /// Create credentials based on given authentication type and PSCredential + /// Create credentials based on given authentication type and PSCredential. /// /// /// @@ -978,11 +1004,13 @@ internal void ThrowTerminatingError(Exception exception, string operation) ThrowInvalidAuthenticationTypeError(operationName, parameterName, passwordAuthentication); return null; } + credentials = new CimCredential(impersonatedAuthentication); } + DebugHelper.WriteLogEx("return credential {0}", 1, credentials); return credentials; } #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetAssociatedInstance.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetAssociatedInstance.cs index 47a0df297961..ec8b3eaab4e1 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetAssociatedInstance.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetAssociatedInstance.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -35,7 +33,7 @@ public CimGetAssociatedInstance() /// Base on parametersetName to retrieve associated ciminstances /// /// - /// object + /// object. public void GetCimAssociatedInstance(GetCimAssociatedInstanceCommand cmdlet) { IEnumerable computerNames = ConstValue.GetComputerNames(cmdlet.ComputerName); @@ -46,6 +44,7 @@ public void GetCimAssociatedInstance(GetCimAssociatedInstanceCommand cmdlet) // try to use namespace of ciminstance, then fall back to default namespace nameSpace = ConstValue.GetNamespace(cmdlet.CimInstance.CimSystemProperties.Namespace); } + List proxys = new List(); switch (cmdlet.ParameterSetName) { @@ -55,6 +54,7 @@ public void GetCimAssociatedInstance(GetCimAssociatedInstanceCommand cmdlet) CimSessionProxy proxy = CreateSessionProxy(computerName, cmdlet.CimInstance, cmdlet); proxys.Add(proxy); } + break; case CimBaseCommand.SessionSetName: foreach (CimSession session in cmdlet.CimSession) @@ -62,10 +62,12 @@ public void GetCimAssociatedInstance(GetCimAssociatedInstanceCommand cmdlet) CimSessionProxy proxy = CreateSessionProxy(session, cmdlet); proxys.Add(proxy); } + break; default: return; } + foreach (CimSessionProxy proxy in proxys) { proxy.EnumerateAssociatedInstancesAsync( @@ -119,7 +121,7 @@ public void GetCimAssociatedInstance(GetCimAssociatedInstanceCommand cmdlet) } /// - /// Create and set properties + /// Create and set properties. /// /// /// @@ -135,5 +137,5 @@ public void GetCimAssociatedInstance(GetCimAssociatedInstanceCommand cmdlet) #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetCimClass.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetCimClass.cs index e660b8ad4a96..ef334a93c959 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetCimClass.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetCimClass.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -49,12 +47,14 @@ internal class CimGetCimClassContext : XOperationContextBase /// Wildcard expansion should be allowed. /// /// - public String ClassName + public string ClassName { get { return className; } + set { className = value; } } - private String className; + + private string className; /// /// @@ -63,11 +63,12 @@ public String ClassName /// Then Filter the by given methodname /// /// - internal String MethodName + internal string MethodName { get { return methodName; } } - private String methodName; + + private string methodName; /// /// @@ -76,11 +77,12 @@ internal String MethodName /// Filter the by given property name. /// /// - internal String PropertyName + internal string PropertyName { get { return propertyName; } } - private String propertyName; + + private string propertyName; /// /// @@ -89,11 +91,12 @@ internal String PropertyName /// Filter the by given methodname /// /// - internal String QualifierName + internal string QualifierName { get { return qualifierName; } } - private String qualifierName; + + private string qualifierName; } /// @@ -118,7 +121,7 @@ public CimGetCimClass() /// Base on parametersetName to retrieve /// /// - /// object + /// object. public void GetCimClass(GetCimClassCommand cmdlet) { List proxys = new List(); @@ -142,6 +145,7 @@ public void GetCimClass(GetCimClassCommand cmdlet) proxys.Add(proxy); } } + break; case CimBaseCommand.SessionSetName: { @@ -152,6 +156,7 @@ public void GetCimClass(GetCimClassCommand cmdlet) proxys.Add(proxy); } } + break; default: return; @@ -210,7 +215,7 @@ public void GetCimClass(GetCimClassCommand cmdlet) } /// - /// Create and set properties + /// Create and set properties. /// /// /// @@ -227,5 +232,5 @@ public void GetCimClass(GetCimClassCommand cmdlet) #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetInstance.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetInstance.cs index ad23b933c3ea..9178fd873ef9 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetInstance.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimGetInstance.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -17,7 +15,7 @@ namespace Microsoft.Management.Infrastructure.CimCmdlets { /// - /// a class used to add pstypename to partial ciminstance + /// A class used to add pstypename to partial ciminstance /// for , if -KeyOnly /// or -SelectProperties is been specified, then add a pstypename: /// "Microsoft.Management.Infrastructure.CimInstance#__PartialCIMInstance" @@ -25,12 +23,12 @@ namespace Microsoft.Management.Infrastructure.CimCmdlets internal class FormatPartialCimInstance : IObjectPreProcess { /// - /// Partial ciminstance pstypename + /// Partial ciminstance pstypename. /// internal const string PartialPSTypeName = @"Microsoft.Management.Infrastructure.CimInstance#__PartialCIMInstance"; /// - /// Add pstypename to the resultobject if necessary + /// Add pstypename to the resultobject if necessary. /// /// /// @@ -42,6 +40,7 @@ public object Process(object resultObject) obj.TypeNames.Insert(0, PartialPSTypeName); return obj; } + return resultObject; } } @@ -67,7 +66,7 @@ public CimGetInstance() : base() /// Base on parametersetName to retrieve ciminstances /// /// - /// object + /// object. public void GetCimInstance(GetCimInstanceCommand cmdlet) { GetCimInstanceInternal(cmdlet); @@ -98,8 +97,10 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) { this.SetPreProcess(proxy, cmdlet as GetCimInstanceCommand); } + proxys.Add(proxy); } + break; case CimBaseCommand.ClassNameComputerSet: case CimBaseCommand.QueryComputerSet: @@ -111,8 +112,10 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) { this.SetPreProcess(proxy, cmdlet as GetCimInstanceCommand); } + proxys.Add(proxy); } + break; case CimBaseCommand.ClassNameSessionSet: case CimBaseCommand.CimInstanceSessionSet: @@ -125,12 +128,15 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) { this.SetPreProcess(proxy, cmdlet as GetCimInstanceCommand); } + proxys.Add(proxy); } + break; default: break; } + switch (cmdlet.ParameterSetName) { case CimBaseCommand.ClassNameComputerSet: @@ -154,6 +160,7 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) proxy.EnumerateInstancesAsync(nameSpace, GetClassName(cmdlet)); } } + break; case CimBaseCommand.CimInstanceComputerSet: case CimBaseCommand.CimInstanceSessionSet: @@ -165,6 +172,7 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) proxy.GetInstanceAsync(nameSpace, instance); } } + break; case CimBaseCommand.QueryComputerSet: case CimBaseCommand.QuerySessionSet: @@ -175,6 +183,7 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) ConstValue.GetQueryDialectWithDefault(GetQueryDialect(cmdlet)), GetQuery(cmdlet)); } + break; case CimBaseCommand.ResourceUriSessionSet: case CimBaseCommand.ResourceUriComputerSet: @@ -182,6 +191,7 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) { proxy.EnumerateInstancesAsync(GetNamespace(cmdlet), GetClassName(cmdlet)); } + break; default: break; @@ -190,7 +200,7 @@ protected void GetCimInstanceInternal(CimBaseCommand cmdlet) #region bridge methods to read properties from cmdlet - protected static String[] GetComputerName(CimBaseCommand cmdlet) + protected static string[] GetComputerName(CimBaseCommand cmdlet) { if (cmdlet is GetCimInstanceCommand) { @@ -204,10 +214,11 @@ protected static String[] GetComputerName(CimBaseCommand cmdlet) { return (cmdlet as SetCimInstanceCommand).ComputerName; } + return null; } - protected static String GetNamespace(CimBaseCommand cmdlet) + protected static string GetNamespace(CimBaseCommand cmdlet) { if (cmdlet is GetCimInstanceCommand) { @@ -221,6 +232,7 @@ protected static String GetNamespace(CimBaseCommand cmdlet) { return (cmdlet as SetCimInstanceCommand).Namespace; } + return null; } @@ -238,19 +250,21 @@ protected static CimSession[] GetCimSession(CimBaseCommand cmdlet) { return (cmdlet as SetCimInstanceCommand).CimSession; } + return null; } - protected static String GetClassName(CimBaseCommand cmdlet) + protected static string GetClassName(CimBaseCommand cmdlet) { if (cmdlet is GetCimInstanceCommand) { return (cmdlet as GetCimInstanceCommand).ClassName; } + return null; } - protected static String GetQuery(CimBaseCommand cmdlet) + protected static string GetQuery(CimBaseCommand cmdlet) { if (cmdlet is GetCimInstanceCommand) { @@ -264,6 +278,7 @@ protected static String GetQuery(CimBaseCommand cmdlet) { return (cmdlet as SetCimInstanceCommand).Query; } + return null; } @@ -278,10 +293,11 @@ internal static bool IsClassNameQuerySet(CimBaseCommand cmdlet) return true; } } + return false; } - protected static String CreateQuery(CimBaseCommand cmdlet) + protected static string CreateQuery(CimBaseCommand cmdlet) { DebugHelper.WriteLogEx(); GetCimInstanceCommand cmd = cmdlet as GetCimInstanceCommand; @@ -300,17 +316,20 @@ protected static String CreateQuery(CimBaseCommand cmdlet) { propertyList.Append(","); } + propertyList.Append(property); } } + return (cmd.Filter == null) ? - String.Format(CultureInfo.CurrentUICulture, queryWithoutWhere, propertyList, cmd.ClassName) : - String.Format(CultureInfo.CurrentUICulture, queryWithWhere, propertyList, cmd.ClassName, cmd.Filter); + string.Format(CultureInfo.CurrentUICulture, queryWithoutWhere, propertyList, cmd.ClassName) : + string.Format(CultureInfo.CurrentUICulture, queryWithWhere, propertyList, cmd.ClassName, cmd.Filter); } + return null; } - protected static String GetQueryDialect(CimBaseCommand cmdlet) + protected static string GetQueryDialect(CimBaseCommand cmdlet) { if (cmdlet is GetCimInstanceCommand) { @@ -324,6 +343,7 @@ protected static String GetQueryDialect(CimBaseCommand cmdlet) { return (cmdlet as SetCimInstanceCommand).QueryDialect; } + return null; } @@ -341,6 +361,7 @@ protected static CimInstance GetCimInstanceParameter(CimBaseCommand cmdlet) { return (cmdlet as SetCimInstanceCommand).CimInstance; } + return null; } #endregion @@ -377,6 +398,7 @@ protected static CimInstance GetCimInstanceParameter(CimBaseCommand cmdlet) { proxy.ResourceUri = removeCimInstance.ResourceUri; } + CimRemoveCimInstanceContext context = new CimRemoveCimInstanceContext( ConstValue.GetNamespace(removeCimInstance.Namespace), proxy); @@ -390,6 +412,7 @@ protected static CimInstance GetCimInstanceParameter(CimBaseCommand cmdlet) { proxy.ResourceUri = setCimInstance.ResourceUri; } + CimSetCimInstanceContext context = new CimSetCimInstanceContext( ConstValue.GetNamespace(setCimInstance.Namespace), setCimInstance.Property, @@ -438,7 +461,7 @@ protected static CimInstance GetCimInstanceParameter(CimBaseCommand cmdlet) } /// - /// Create and set properties + /// Create and set properties. /// /// /// @@ -472,7 +495,7 @@ protected static CimInstance GetCimInstanceParameter(CimBaseCommand cmdlet) } /// - /// Create and set properties + /// Create and set properties. /// /// /// @@ -489,7 +512,7 @@ protected static CimInstance GetCimInstanceParameter(CimBaseCommand cmdlet) /// /// Set object to proxy to pre-process - /// the result object if necessary + /// the result object if necessary. /// /// /// @@ -504,14 +527,14 @@ private void SetPreProcess(CimSessionProxy proxy, GetCimInstanceCommand cmdlet) #region const strings /// - /// wql query format with where clause + /// Wql query format with where clause. /// private const string queryWithWhere = @"SELECT {0} FROM {1} WHERE {2}"; /// - /// wql query format without where clause + /// Wql query format without where clause. /// private const string queryWithoutWhere = @"SELECT {0} FROM {1}"; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimIndicationWatcher.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimIndicationWatcher.cs index 34a6319f08a0..16cefeac4bb5 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimIndicationWatcher.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimIndicationWatcher.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -26,18 +24,19 @@ public abstract class CimIndicationEventArgs : EventArgs /// Returns an Object value for an operation context /// /// - public Object Context + public object Context { get { return context; } } - internal Object context; + + internal object context; } /// - /// Cimindication exception event args, which containing occurred exception + /// Cimindication exception event args, which containing occurred exception. /// public class CimIndicationEventExceptionEventArgs : CimIndicationEventArgs { @@ -53,6 +52,7 @@ public Exception Exception return exception; } } + private Exception exception; /// @@ -75,7 +75,7 @@ public CimIndicationEventExceptionEventArgs(Exception theException) public class CimIndicationEventInstanceEventArgs : CimIndicationEventArgs { /// - /// Get ciminstance of the indication object + /// Get ciminstance of the indication object. /// public CimInstance NewEvent { @@ -86,7 +86,7 @@ public CimInstance NewEvent } /// - /// Get MachineId of the indication object + /// Get MachineId of the indication object. /// public string MachineId { @@ -97,7 +97,7 @@ public string MachineId } /// - /// Get BookMark of the indication object + /// Get BookMark of the indication object. /// public string Bookmark { @@ -137,7 +137,7 @@ public CimIndicationEventInstanceEventArgs(CimSubscriptionResult result) public class CimIndicationWatcher { /// - /// status of object. + /// Status of object. /// internal enum Status { @@ -265,6 +265,7 @@ public bool EnableRaisingEvents { return enableRaisingEvents; } + set { DebugHelper.WriteLogEx(); @@ -275,6 +276,7 @@ public bool EnableRaisingEvents } } } + private bool enableRaisingEvents; /// @@ -308,6 +310,7 @@ public void Start() this.queryExpression, this.operationTimeout); } + status = Status.Started; } } @@ -331,6 +334,7 @@ public void Stop() DebugHelper.WriteLog("Dispose CimRegisterCimIndication object", 4); this.cimRegisterCimIndication.Dispose(); } + status = Status.Stopped; } } @@ -339,7 +343,7 @@ public void Stop() #region internal method /// /// Set the cmdlet object to throw ThrowTerminatingError - /// in case there is a subscription failure + /// in case there is a subscription failure. /// /// internal void SetCmdlet(Cmdlet cmdlet) @@ -360,22 +364,22 @@ internal void SetCmdlet(Cmdlet cmdlet) private CimRegisterCimIndication cimRegisterCimIndication; /// - /// the status of object + /// The status of object. /// private Status status; /// - /// lock started field + /// Lock started field. /// private object myLock; /// - /// CimSession parameter name + /// CimSession parameter name. /// private const string cimSessionParameterName = "cimSession"; /// - /// QueryExpression parameter name + /// QueryExpression parameter name. /// private const string queryExpressionParameterName = "queryExpression"; @@ -394,4 +398,4 @@ internal void SetCmdlet(Cmdlet cmdlet) #endregion #endregion } -}//End namespace +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimInvokeCimMethod.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimInvokeCimMethod.cs index 79f91a1d868a..19dcbf378dd6 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimInvokeCimMethod.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimInvokeCimMethod.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -58,6 +56,7 @@ internal string MethodName return this.methodName; } } + private string methodName; /// @@ -70,6 +69,7 @@ internal CimMethodParametersCollection ParametersCollection return this.collection; } } + private CimMethodParametersCollection collection; } @@ -88,7 +88,7 @@ public CimInvokeCimMethod() /// Base on parametersetName to retrieve ciminstances /// /// - /// object + /// object. public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) { IEnumerable computerNames = ConstValue.GetComputerNames(cmdlet.ComputerName); @@ -103,6 +103,7 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) { proxys.Add(CreateSessionProxy(computerName, cmdlet.CimInstance, cmdlet)); } + break; case CimBaseCommand.ClassNameComputerSet: case CimBaseCommand.CimClassComputerSet: @@ -112,6 +113,7 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) { proxys.Add(CreateSessionProxy(computerName, cmdlet)); } + break; case CimBaseCommand.ClassNameSessionSet: case CimBaseCommand.CimClassSessionSet: @@ -123,10 +125,12 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) CimSessionProxy proxy = CreateSessionProxy(session, cmdlet); proxys.Add(proxy); } + break; default: break; } + CimMethodParametersCollection paramsCollection = CreateParametersCollection(cmdlet.Arguments, cmdlet.CimClass, cmdlet.CimInstance, cmdlet.MethodName); @@ -147,12 +151,14 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) { nameSpace = ConstValue.GetNamespace(cmdlet.Namespace); } + foreach (CimSessionProxy proxy in proxys) { if (!cmdlet.ShouldProcess(target, action)) { return; } + proxy.InvokeMethodAsync( nameSpace, cmdlet.ClassName, @@ -160,6 +166,7 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) paramsCollection); } } + break; case CimBaseCommand.CimClassComputerSet: case CimBaseCommand.CimClassSessionSet: @@ -172,6 +179,7 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) { return; } + proxy.InvokeMethodAsync( nameSpace, cmdlet.CimClass.CimSystemProperties.ClassName, @@ -179,6 +187,7 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) paramsCollection); } } + break; case CimBaseCommand.QueryComputerSet: case CimBaseCommand.QuerySessionSet: @@ -195,6 +204,7 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) // firstly query instance and then invoke method upon returned instances proxy.QueryInstancesAsync(nameSpace, ConstValue.GetQueryDialectWithDefault(cmdlet.QueryDialect), cmdlet.Query); } + break; case CimBaseCommand.CimInstanceComputerSet: case CimBaseCommand.CimInstanceSessionSet: @@ -208,12 +218,14 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) { nameSpace = ConstValue.GetNamespace(cmdlet.CimInstance.CimSystemProperties.Namespace); } + foreach (CimSessionProxy proxy in proxys) { if (!cmdlet.ShouldProcess(target, action)) { return; } + proxy.InvokeMethodAsync( nameSpace, cmdlet.CimInstance, @@ -221,6 +233,7 @@ public void InvokeCimMethod(InvokeCimMethodCommand cmdlet) paramsCollection); } } + break; default: break; @@ -310,7 +323,7 @@ public void InvokeCimMethodOnCimInstance(CimInstance cimInstance, XOperationCont } /// - /// Create and set properties + /// Create and set properties. /// /// /// @@ -335,8 +348,8 @@ public void InvokeCimMethodOnCimInstance(CimInstance cimInstance, XOperationCont /// /// /// - /// See CimProperty.Create - /// CimProperty.Create + /// See CimProperty.Create. + /// CimProperty.Create. private CimMethodParametersCollection CreateParametersCollection( IDictionary parameters, CimClass cimClass, @@ -378,7 +391,7 @@ public void InvokeCimMethodOnCimInstance(CimInstance cimInstance, XOperationCont declaration = cimClass.CimClassMethods[methodName]; if (declaration == null) { - throw new ArgumentException(String.Format( + throw new ArgumentException(string.Format( CultureInfo.CurrentUICulture, Strings.InvalidMethod, methodName, className)); } } @@ -393,9 +406,10 @@ public void InvokeCimMethodOnCimInstance(CimInstance cimInstance, XOperationCont CimMethodParameterDeclaration paramDeclaration = declaration.Parameters[parameterName]; if (paramDeclaration == null) { - throw new ArgumentException(String.Format( + throw new ArgumentException(string.Format( CultureInfo.CurrentUICulture, Strings.InvalidMethodParameter, parameterName, methodName, className)); } + parameter = CimMethodParameter.Create( parameterName, parameterValue, @@ -436,23 +450,25 @@ public void InvokeCimMethodOnCimInstance(CimInstance cimInstance, XOperationCont } } } + if (parameter != null) collection.Add(parameter); } + return collection; } #endregion #region const strings /// - /// operation target + /// Operation target. /// private const string targetClass = @"{0}"; /// - /// action + /// Action. /// private const string actionTemplate = @"Invoke-CimMethod: {0}"; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimNewCimInstance.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimNewCimInstance.cs index 84b0883feb18..906fb4b3ff53 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimNewCimInstance.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimNewCimInstance.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -61,7 +59,7 @@ public CimNewCimInstance() /// either remotely or locally /// /// - /// object + /// object. public void NewCimInstance(NewCimInstanceCommand cmdlet) { DebugHelper.WriteLogEx(); @@ -83,11 +81,12 @@ public void NewCimInstance(NewCimInstanceCommand cmdlet) cmdlet); } + break; case CimBaseCommand.ResourceUriSessionSet: case CimBaseCommand.ResourceUriComputerSet: { - nameSpace = cmdlet.Namespace; //passing null is ok for resourceUri set + nameSpace = cmdlet.Namespace; // passing null is ok for resourceUri set cimInstance = CreateCimInstance("DummyClass", nameSpace, cmdlet.Key, @@ -95,6 +94,7 @@ public void NewCimInstance(NewCimInstanceCommand cmdlet) cmdlet); } + break; case CimBaseCommand.CimClassComputerSet: case CimBaseCommand.CimClassSessionSet: @@ -105,6 +105,7 @@ public void NewCimInstance(NewCimInstanceCommand cmdlet) cmdlet); } + break; default: return; @@ -150,6 +151,7 @@ public void NewCimInstance(NewCimInstanceCommand cmdlet) proxys.Add(CreateSessionProxy(computerName, cmdlet)); } } + break; case CimBaseCommand.CimClassSessionSet: case CimBaseCommand.ClassNameSessionSet: @@ -158,6 +160,7 @@ public void NewCimInstance(NewCimInstanceCommand cmdlet) { proxys.Add(CreateSessionProxy(session, cmdlet)); } + break; } @@ -233,7 +236,7 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont } /// - /// Create and set properties + /// Create and set properties. /// /// /// @@ -258,8 +261,8 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont /// /// /// - /// See CimProperty.Create - /// CimProperty.Create + /// See CimProperty.Create. + /// CimProperty.Create. private CimInstance CreateCimInstance( string className, string cimNamespace, @@ -291,6 +294,7 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont { flag = CimFlags.Key; } + object propertyValue = GetBaseObject(enumerator.Value); DebugHelper.WriteLog("Create and add new property to ciminstance: name = {0}; value = {1}; flags = {2}", 5, propertyName, propertyValue, flag); @@ -311,6 +315,7 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont } } + return cimInstance; } @@ -323,8 +328,8 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont /// /// /// - /// See CimProperty.Create - /// CimProperty.Create + /// See CimProperty.Create. + /// CimProperty.Create. private CimInstance CreateCimInstance( CimClass cimClass, IDictionary properties, @@ -335,6 +340,7 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont { return cimInstance; } + List notfoundProperties = new List(); foreach (string property in properties.Keys) { @@ -344,9 +350,11 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont cmdlet.ThrowInvalidProperty(notfoundProperties, cmdlet.CimClass.CimSystemProperties.ClassName, @"Property", action, properties); return null; } + object propertyValue = GetBaseObject(properties[property]); cimInstance.CimInstanceProperties[property].Value = propertyValue; } + return cimInstance; } @@ -354,9 +362,9 @@ internal void GetCimInstance(CimInstance cimInstance, XOperationContextBase cont #region const strings /// - /// action + /// Action. /// private const string action = @"New-CimInstance"; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimPromptUser.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimPromptUser.cs index 785e0f200029..2ebebfec1c6d 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimPromptUser.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimPromptUser.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using Microsoft.Management.Infrastructure.Options; @@ -24,7 +22,7 @@ namespace Microsoft.Management.Infrastructure.CimCmdlets internal sealed class CimPromptUser : CimSyncAction { /// - /// Constructor + /// Constructor. /// public CimPromptUser(string message, CimPromptType prompt) @@ -84,6 +82,7 @@ public override void Execute(CmdletOperationBase cmdlet) // unblocking the waiting thread this.OnComplete(); } + break; case CimPromptType.Normal: try @@ -108,17 +107,19 @@ public override void Execute(CmdletOperationBase cmdlet) // unblocking the waiting thread this.OnComplete(); } + break; default: break; } + this.OnComplete(); } #region members /// - /// prompt message + /// Prompt message. /// public string Message { @@ -127,13 +128,14 @@ public string Message return message; } } + private string message; /// - /// prompt type -Normal or Critical + /// Prompt type -Normal or Critical. /// private CimPromptType prompt; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRegisterCimIndication.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRegisterCimIndication.cs index 91005d8ecf00..20da97bbcc0b 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRegisterCimIndication.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRegisterCimIndication.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -27,14 +25,15 @@ internal abstract class CimSubscriptionEventArgs : EventArgs /// Returns an Object value for an operation context /// /// - public Object Context + public object Context { get { return context; } } - protected Object context; + + protected object context; } /// @@ -56,6 +55,7 @@ public CimSubscriptionResult Result return result; } } + private CimSubscriptionResult result; /// @@ -89,6 +89,7 @@ public Exception Exception return exception; } } + private Exception exception; /// @@ -131,7 +132,7 @@ public CimRegisterCimIndication() /// /// Start an indication subscription target to the given computer. /// - /// null stands for localhost + /// Null stands for localhost. /// /// /// @@ -153,12 +154,12 @@ public CimRegisterCimIndication() /// /// Start an indication subscription through a given . /// - /// Cannot be null + /// Cannot be null. /// /// /// /// - /// throw if cimSession is null + /// Throw if cimSession is null. public void RegisterCimIndication( CimSession cimSession, string nameSpace, @@ -169,8 +170,9 @@ public CimRegisterCimIndication() DebugHelper.WriteLogEx("queryDialect = '{0}'; queryExpression = '{1}'", 0, queryDialect, queryExpression); if (cimSession == null) { - throw new ArgumentNullException(String.Format(CultureInfo.CurrentUICulture, Strings.NullArgument, @"cimSession")); + throw new ArgumentNullException(string.Format(CultureInfo.CurrentUICulture, Strings.NullArgument, @"cimSession")); } + this.TargetComputerName = cimSession.ComputerName; CimSessionProxy proxy = CreateSessionProxy(cimSession, operationTimeout); proxy.SubscribeAsync(nameSpace, queryDialect, queryExpression); @@ -204,7 +206,7 @@ protected override void SubscribeToCimSessionProxyEvent(CimSessionProxy proxy) /// /// object raised the event /// - /// event argument + /// Event argument. private void CimIndicationHandler(object cimSession, CmdletActionEventArgs actionArgs) { DebugHelper.WriteLogEx("action is {0}. Disposed {1}", 0, actionArgs.Action, this.Disposed); @@ -226,6 +228,7 @@ private void CimIndicationHandler(object cimSession, CmdletActionEventArgs actio this.ackedEvent.Set(); return; } + EventHandler temp = this.OnNewSubscriptionResult; if (temp != null) { @@ -233,6 +236,7 @@ private void CimIndicationHandler(object cimSession, CmdletActionEventArgs actio temp(this, new CimSubscriptionExceptionEventArgs(this.exception)); } + DebugHelper.WriteLog("Got an exception: {0}", 2, exception); } @@ -267,7 +271,7 @@ private void CimIndicationHandler(object cimSession, CmdletActionEventArgs actio } /// - /// block the ps thread until ACK message or Error happened. + /// Block the ps thread until ACK message or Error happened. /// private void WaitForAckMessage() { @@ -292,6 +296,7 @@ private void WaitForAckMessage() throw this.exception; } } + DebugHelper.WriteLogEx("ACK happened", 0); } #endregion @@ -300,7 +305,7 @@ private void WaitForAckMessage() /// /// The cmdlet object who issue this subscription, /// to throw ThrowTerminatingError - /// in case there is a subscription failure + /// in case there is a subscription failure. /// /// internal Cmdlet Cmdlet @@ -310,9 +315,9 @@ internal Cmdlet Cmdlet } /// - /// target computername + /// Target computername. /// - internal String TargetComputerName + internal string TargetComputerName { set; get; @@ -339,7 +344,7 @@ internal String TargetComputerName } /// - /// Create and set properties + /// Create and set properties. /// /// /// @@ -357,7 +362,7 @@ internal String TargetComputerName #region private members /// - /// Exception occurred while start the subscription + /// Exception occurred while start the subscription. /// internal Exception Exception { @@ -366,9 +371,10 @@ internal Exception Exception return exception; } } + private Exception exception; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRemoveCimInstance.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRemoveCimInstance.cs index e5fed39d4029..1cff9b68eb76 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRemoveCimInstance.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimRemoveCimInstance.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -57,7 +55,7 @@ public CimRemoveCimInstance() /// Base on parametersetName to retrieve ciminstances /// /// - /// object + /// object. public void RemoveCimInstance(RemoveCimInstanceCommand cmdlet) { DebugHelper.WriteLogEx(); @@ -72,16 +70,19 @@ public void RemoveCimInstance(RemoveCimInstanceCommand cmdlet) { proxys.Add(CreateSessionProxy(computerName, cmdlet.CimInstance, cmdlet)); } + break; case CimBaseCommand.CimInstanceSessionSet: foreach (CimSession session in GetCimSession(cmdlet)) { proxys.Add(CreateSessionProxy(session, cmdlet)); } + break; default: break; } + switch (cmdlet.ParameterSetName) { case CimBaseCommand.CimInstanceComputerSet: @@ -95,6 +96,7 @@ public void RemoveCimInstance(RemoveCimInstanceCommand cmdlet) { nameSpace = ConstValue.GetNamespace(GetCimInstanceParameter(cmdlet).CimSystemProperties.Namespace); } + string target = cmdlet.CimInstance.ToString(); foreach (CimSessionProxy proxy in proxys) { @@ -102,8 +104,10 @@ public void RemoveCimInstance(RemoveCimInstanceCommand cmdlet) { return; } + proxy.DeleteInstanceAsync(nameSpace, cmdlet.CimInstance); } + break; case CimBaseCommand.QueryComputerSet: case CimBaseCommand.QuerySessionSet: @@ -139,9 +143,9 @@ internal void RemoveCimInstance(CimInstance cimInstance, XOperationContextBase c #region const strings /// - /// action + /// Action. /// private const string action = @"Remove-CimInstance"; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimResultObserver.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimResultObserver.cs index f8758d98a69f..74ea55fa3b0b 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimResultObserver.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimResultObserver.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -29,12 +27,12 @@ public enum AsyncResultType #region CimResultContext /// - /// Cim Result Context + /// Cim Result Context. /// internal class CimResultContext { /// - /// constructor + /// Constructor. /// /// internal CimResultContext(object ErrorSource) @@ -43,7 +41,7 @@ internal CimResultContext(object ErrorSource) } /// - /// ErrorSource property + /// ErrorSource property. /// internal object ErrorSource { @@ -52,6 +50,7 @@ internal object ErrorSource return this.errorSource; } } + private object errorSource; } #endregion @@ -65,7 +64,7 @@ internal object ErrorSource internal abstract class AsyncResultEventArgsBase : EventArgs { /// - /// Constructor + /// Constructor. /// /// /// @@ -81,7 +80,7 @@ internal abstract class AsyncResultEventArgsBase : EventArgs } /// - /// Constructor + /// Constructor. /// /// /// @@ -122,7 +121,7 @@ internal class AsyncResultCompleteEventArgs : AsyncResultEventArgsBase /// Constructor /// /// - /// object + /// object. /// public AsyncResultCompleteEventArgs( CimSession session, @@ -140,7 +139,7 @@ internal class AsyncResultCompleteEventArgs : AsyncResultEventArgsBase internal class AsyncResultObjectEventArgs : AsyncResultEventArgsBase { /// - /// Constructor + /// Constructor. /// /// /// @@ -165,7 +164,7 @@ internal class AsyncResultObjectEventArgs : AsyncResultEventArgsBase internal class AsyncResultErrorEventArgs : AsyncResultEventArgsBase { /// - /// Constructor + /// Constructor. /// /// /// @@ -180,7 +179,7 @@ internal class AsyncResultErrorEventArgs : AsyncResultEventArgsBase } /// - /// Constructor + /// Constructor. /// /// /// @@ -207,7 +206,7 @@ internal class AsyncResultErrorEventArgs : AsyncResultEventArgsBase /// EnumerateInstancesAsync operation of object. /// /// - /// (See http://channel9.msdn.com/posts/J.Van.Gogh/Reactive-Extensions-API-in-depth-Contract/) + /// (See https://channel9.msdn.com/posts/J.Van.Gogh/Reactive-Extensions-API-in-depth-Contract/) /// for the IObserver/IObservable contact /// - the only possible sequence is OnNext* (OnCompleted|OnError)? /// - callbacks are serialized @@ -221,22 +220,22 @@ internal class CimResultObserver : IObserver /// Define delegate that handles new cmdlet action come from /// the operations related to the current CimSession object. /// - /// cimSession object, which raised the event - /// Event args + /// CimSession object, which raised the event. + /// Event args. public delegate void ResultEventHandler( object observer, AsyncResultEventArgsBase resultArgs); /// - /// Define an Event based on the NewActionHandler + /// Define an Event based on the NewActionHandler. /// public event ResultEventHandler OnNewResult; /// - /// Constructor + /// Constructor. /// - /// object that issued the operation - /// Operation that can be observed + /// object that issued the operation. + /// Operation that can be observed. public CimResultObserver(CimSession session, IObservable observable) { this.session = session; @@ -244,10 +243,10 @@ public CimResultObserver(CimSession session, IObservable observable) } /// - /// Constructor + /// Constructor. /// - /// object that issued the operation - /// Operation that can be observed + /// object that issued the operation. + /// Operation that can be observed. public CimResultObserver(CimSession session, IObservable observable, CimResultContext cimResultContext) @@ -286,7 +285,7 @@ public virtual void OnCompleted() /// Operation completed with an error /// /// - /// error object + /// Error object. public virtual void OnError(Exception error) { try @@ -303,7 +302,7 @@ public virtual void OnError(Exception error) } /// - /// Deliver the result value + /// Deliver the result value. /// /// protected void OnNextCore(object value) @@ -327,7 +326,7 @@ protected void OnNextCore(object value) /// Operation got a new result object /// /// - /// result object + /// Result object. public virtual void OnNext(T value) { DebugHelper.WriteLogEx("value = {0}.", 1, value); @@ -336,13 +335,14 @@ public virtual void OnNext(T value) { return; } + this.OnNextCore(value); } #region members /// - /// Session object of the operation + /// Session object of the operation. /// protected CimSession CurrentSession { @@ -351,10 +351,11 @@ protected CimSession CurrentSession return session; } } + private CimSession session; /// - /// async operation that can be observed + /// Async operation that can be observed. /// private IObservable observable; @@ -366,12 +367,12 @@ protected CimSession CurrentSession } /// - /// CimSubscriptionResultObserver class definition + /// CimSubscriptionResultObserver class definition. /// internal class CimSubscriptionResultObserver : CimResultObserver { /// - /// constructor + /// Constructor. /// /// /// @@ -381,7 +382,7 @@ public CimSubscriptionResultObserver(CimSession session, IObservable obs } /// - /// constructor + /// Constructor. /// /// /// @@ -394,7 +395,7 @@ public CimSubscriptionResultObserver(CimSession session, IObservable obs } /// - /// Override the OnNext method + /// Override the OnNext method. /// /// public override void OnNext(CimSubscriptionResult value) @@ -405,12 +406,12 @@ public override void OnNext(CimSubscriptionResult value) } /// - /// CimMethodResultObserver class definition + /// CimMethodResultObserver class definition. /// internal class CimMethodResultObserver : CimResultObserver { /// - /// constructor + /// Constructor. /// /// /// @@ -420,7 +421,7 @@ public CimMethodResultObserver(CimSession session, IObservable observabl } /// - /// constructor + /// Constructor. /// /// /// @@ -434,7 +435,7 @@ public CimMethodResultObserver(CimSession session, IObservable observabl } /// - /// Override the OnNext method + /// Override the OnNext method. /// /// public override void OnNext(CimMethodResultBase value) @@ -468,28 +469,29 @@ public override void OnNext(CimMethodResultBase value) resultObject.Properties.Add(new PSNoteProperty(@"ItemValue", methodStreamedResult.ItemValue)); } } + if (resultObject != null) { resultObject.Properties.Add(new PSNoteProperty(@"PSComputerName", this.CurrentSession.ComputerName)); resultObject.TypeNames.Insert(0, resultObjectPSType); - resultObject.TypeNames.Insert(0, String.Format(CultureInfo.InvariantCulture, PSTypeCimMethodResultTemplate, resultObjectPSType, ClassName, MethodName)); + resultObject.TypeNames.Insert(0, string.Format(CultureInfo.InvariantCulture, PSTypeCimMethodResultTemplate, resultObjectPSType, ClassName, MethodName)); base.OnNextCore(resultObject); } } /// - /// methodname + /// Methodname. /// - internal String MethodName + internal string MethodName { get; set; } /// - /// classname + /// Classname. /// - internal String ClassName + internal string ClassName { get; set; @@ -497,12 +499,12 @@ internal String ClassName } /// - /// IgnoreResultObserver class definition + /// IgnoreResultObserver class definition. /// internal class IgnoreResultObserver : CimResultObserver { /// - /// constructor + /// Constructor. /// /// /// @@ -512,7 +514,7 @@ public IgnoreResultObserver(CimSession session, IObservable observable) } /// - /// Override the OnNext method + /// Override the OnNext method. /// /// public override void OnNext(CimInstance value) diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionOperations.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionOperations.cs index d1cf303cb50c..f41b658820cb 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionOperations.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionOperations.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -24,7 +22,7 @@ internal class CimSessionWrapper #region members /// - /// id of the cimsession + /// Id of the cimsession. /// public uint SessionId { @@ -33,10 +31,11 @@ public uint SessionId return this.sessionId; } } + private uint sessionId; /// - /// instanceId of the cimsession + /// InstanceId of the cimsession. /// public Guid InstanceId { @@ -45,10 +44,11 @@ public Guid InstanceId return this.instanceId; } } + private Guid instanceId; /// - /// name of the cimsession + /// Name of the cimsession. /// public string Name { @@ -57,10 +57,11 @@ public string Name return this.name; } } + private string name; /// - /// computer name of the cimsession + /// Computer name of the cimsession. /// public string ComputerName { @@ -69,10 +70,11 @@ public string ComputerName return this.computerName; } } + private string computerName; /// - /// wrapped cimsession object + /// Wrapped cimsession object. /// public CimSession CimSession { @@ -81,10 +83,11 @@ public CimSession CimSession return this.cimSession; } } + private CimSession cimSession; /// - /// computer name of the cimsession + /// Computer name of the cimsession. /// public string Protocol { @@ -101,14 +104,16 @@ public string Protocol } } } + internal ProtocolType GetProtocolType() { return protocol; } + private ProtocolType protocol; /// - /// PSObject that wrapped the cimSession + /// PSObject that wrapped the cimSession. /// private PSObject psObject; @@ -150,6 +155,7 @@ internal PSObject GetPSObject() psObject.Properties[CimSessionState.computernamePropName].Value = this.ComputerName; psObject.Properties[CimSessionState.protocolPropName].Value = this.Protocol; } + return psObject; } } @@ -177,7 +183,7 @@ internal class CimSessionState : IDisposable internal static string CimSessionClassName = "CimSession"; /// - /// CimSession object name + /// CimSession object name. /// internal static string CimSessionObject = "{CimSession Object}"; @@ -189,27 +195,27 @@ internal class CimSessionState : IDisposable internal static string SessionObjectPath = @"CimSession id = {0}, name = {2}, ComputerName = {3}, instance id = {1}"; /// - /// Id property name of cimsession wrapper object + /// Id property name of cimsession wrapper object. /// internal static string idPropName = "Id"; /// - /// Instanceid property name of cimsession wrapper object + /// Instanceid property name of cimsession wrapper object. /// internal static string instanceidPropName = "InstanceId"; /// - /// Name property name of cimsession wrapper object + /// Name property name of cimsession wrapper object. /// internal static string namePropName = "Name"; /// - /// Computer name property name of cimsession object + /// Computer name property name of cimsession object. /// internal static string computernamePropName = "ComputerName"; /// - /// Protocol name property name of cimsession object + /// Protocol name property name of cimsession object. /// internal static string protocolPropName = "Protocol"; @@ -290,7 +296,7 @@ internal int GetSessionsCount() /// Generates an unique session id. /// /// - /// Unique session id under current runspace + /// Unique session id under current runspace. internal UInt32 GenerateSessionId() { return this.sessionNameCounter++; @@ -333,7 +339,7 @@ public void Dispose() /// other objects. Only unmanaged resources can be disposed. /// /// - /// Whether it is directly called + /// Whether it is directly called. protected virtual void Dispose(bool disposing) { if (!this._disposed) @@ -360,6 +366,7 @@ public void Cleanup() { session.Dispose(); } + curCimSessionWrapper.Clear(); curCimSessionsByName.Clear(); curCimSessionsByComputerName.Clear(); @@ -386,8 +393,8 @@ public void Cleanup() CimSession session, UInt32 sessionId, Guid instanceId, - String name, - String computerName, + string name, + string computerName, ProtocolType protocol) { CimSessionWrapper wrapper = new CimSessionWrapper( @@ -399,6 +406,7 @@ public void Cleanup() objects = new HashSet(); this.curCimSessionsByComputerName.Add(computerName, objects); } + objects.Add(wrapper); if (!this.curCimSessionsByName.TryGetValue(name, out objects)) @@ -406,6 +414,7 @@ public void Cleanup() objects = new HashSet(); this.curCimSessionsByName.Add(name, objects); } + objects.Add(wrapper); this.curCimSessionsByInstanceId.Add(instanceId, wrapper); @@ -422,31 +431,36 @@ public void Cleanup() /// internal string GetRemoveSessionObjectTarget(PSObject psObject) { - String message = String.Empty; + string message = string.Empty; if (psObject.BaseObject is CimSession) { UInt32 id = 0x0; Guid instanceId = Guid.Empty; - String name = String.Empty; - String computerName = string.Empty; + string name = string.Empty; + string computerName = string.Empty; if (psObject.Properties[idPropName].Value is UInt32) { id = Convert.ToUInt32(psObject.Properties[idPropName].Value, null); } + if (psObject.Properties[instanceidPropName].Value is Guid) { instanceId = (Guid)psObject.Properties[instanceidPropName].Value; } + if (psObject.Properties[namePropName].Value is String) { - name = (String)psObject.Properties[namePropName].Value; + name = (string)psObject.Properties[namePropName].Value; } + if (psObject.Properties[computernamePropName].Value is String) { - computerName = (String)psObject.Properties[computernamePropName].Value; + computerName = (string)psObject.Properties[computernamePropName].Value; } - message = String.Format(CultureInfo.CurrentUICulture, SessionObjectPath, id, instanceId, name, computerName); + + message = string.Format(CultureInfo.CurrentUICulture, SessionObjectPath, id, instanceId, name, computerName); } + return message; } @@ -480,9 +494,10 @@ internal void RemoveOneSessionObjectFromCache(CimSession session) { return; } + CimSessionWrapper wrapper = this.curCimSessionWrapper[session]; - String name = wrapper.Name; - String computerName = wrapper.ComputerName; + string name = wrapper.Name; + string computerName = wrapper.ComputerName; DebugHelper.WriteLog("name {0}, computername {1}, id {2}, instanceId {3}", 1, name, computerName, wrapper.SessionId, wrapper.InstanceId); @@ -491,10 +506,12 @@ internal void RemoveOneSessionObjectFromCache(CimSession session) { objects.Remove(wrapper); } + if (this.curCimSessionsByName.TryGetValue(name, out objects)) { objects.Remove(wrapper); } + RemoveSessionInternal(session, wrapper); } @@ -534,17 +551,17 @@ private void RemoveSessionInternal(CimSession session, CimSessionWrapper wrapper { errRecords.Add( new ErrorRecord( - new CimException(String.Format(CultureInfo.CurrentUICulture, Strings.CouldNotFindCimsessionObject, propertyName, propertyValue)), + new CimException(string.Format(CultureInfo.CurrentUICulture, Strings.CouldNotFindCimsessionObject, propertyName, propertyValue)), string.Empty, ErrorCategory.ObjectNotFound, null)); } /// - /// Query session list by given id array + /// Query session list by given id array. /// /// - /// List of session wrapper objects + /// List of session wrapper objects. internal IEnumerable QuerySession(IEnumerable ids, out IEnumerable errorRecords) { @@ -568,14 +585,15 @@ private void RemoveSessionInternal(CimSession session, CimSessionWrapper wrapper AddErrorRecord(ref errRecords, idPropName, id); } } + return sessions; } /// - /// Query session list by given instance id array + /// Query session list by given instance id array. /// /// - /// List of session wrapper objects + /// List of session wrapper objects. internal IEnumerable QuerySession(IEnumerable instanceIds, out IEnumerable errorRecords) { @@ -599,14 +617,15 @@ private void RemoveSessionInternal(CimSession session, CimSessionWrapper wrapper AddErrorRecord(ref errRecords, instanceidPropName, instanceid); } } + return sessions; } /// - /// Query session list by given name array + /// Query session list by given name array. /// /// - /// List of session wrapper objects + /// List of session wrapper objects. internal IEnumerable QuerySession(IEnumerable nameArray, out IEnumerable errorRecords) { @@ -634,19 +653,21 @@ private void RemoveSessionInternal(CimSession session, CimSessionWrapper wrapper } } } + if (!foundSession && !WildcardPattern.ContainsWildcardCharacters(name)) { AddErrorRecord(ref errRecords, namePropName, name); } } + return sessions; } /// - /// Query session list by given computer name array + /// Query session list by given computer name array. /// /// - /// List of session wrapper objects + /// List of session wrapper objects. internal IEnumerable QuerySessionByComputerName( IEnumerable computernameArray, out IEnumerable errorRecords) @@ -671,19 +692,21 @@ private void RemoveSessionInternal(CimSession session, CimSessionWrapper wrapper } } } + if (!foundSession) { AddErrorRecord(ref errRecords, computernamePropName, computername); } } + return sessions; } /// - /// Query session list by given session objects array + /// Query session list by given session objects array. /// /// - /// List of session wrapper objects + /// List of session wrapper objects. internal IEnumerable QuerySession(IEnumerable cimsessions, out IEnumerable errorRecords) { @@ -707,14 +730,15 @@ private void RemoveSessionInternal(CimSession session, CimSessionWrapper wrapper AddErrorRecord(ref errRecords, CimSessionClassName, CimSessionObject); } } + return sessions; } /// - /// Query session wrapper object + /// Query session wrapper object. /// /// - /// session wrapper + /// Session wrapper. internal CimSessionWrapper QuerySession(CimSession cimsession) { CimSessionWrapper wrapper; @@ -723,10 +747,10 @@ internal CimSessionWrapper QuerySession(CimSession cimsession) } /// - /// Query session object with given CimSessionInstanceID + /// Query session object with given CimSessionInstanceID. /// /// - /// CimSession object + /// CimSession object. internal CimSession QuerySession(Guid cimSessionInstanceId) { if (this.curCimSessionsByInstanceId.ContainsKey(cimSessionInstanceId)) @@ -734,6 +758,7 @@ internal CimSession QuerySession(Guid cimSessionInstanceId) CimSessionWrapper wrapper = this.curCimSessionsByInstanceId[cimSessionInstanceId]; return wrapper.CimSession; } + return null; } #endregion @@ -756,7 +781,7 @@ internal class CimSessionBase #region constructor /// - /// Constructor + /// Constructor. /// public CimSessionBase() { @@ -768,6 +793,7 @@ public CimSessionBase() { Runspace.DefaultRunspace.StateChanged += DefaultRunspace_StateChanged; } + return new CimSessionState(); }); } @@ -783,7 +809,7 @@ public CimSessionBase() /// can running parallelly under more than one runspace(s). /// /// - static internal ConcurrentDictionary cimSessions + internal static ConcurrentDictionary cimSessions = new ConcurrentDictionary(); /// @@ -791,7 +817,7 @@ public CimSessionBase() /// Default runspace id /// /// - static internal Guid defaultRunspaceId = Guid.Empty; + internal static Guid defaultRunspaceId = Guid.Empty; /// /// @@ -802,7 +828,7 @@ public CimSessionBase() internal CimSessionState sessionState; /// - /// Get current runspace id + /// Get current runspace id. /// private static Guid CurrentRunspaceId { @@ -832,8 +858,8 @@ public static CimSessionState GetCimSessionState() /// clean up the dictionaries if the runspace is closed or broken. /// /// - /// Runspace - /// Event args + /// Runspace. + /// Event args. private static void DefaultRunspace_StateChanged(object sender, RunspaceStateEventArgs e) { Runspace runspace = (Runspace)sender; @@ -844,9 +870,10 @@ private static void DefaultRunspace_StateChanged(object sender, RunspaceStateEve CimSessionState state; if (cimSessions.TryRemove(runspace.InstanceId, out state)) { - DebugHelper.WriteLog(String.Format(CultureInfo.CurrentUICulture, DebugHelper.runspaceStateChanged, runspace.InstanceId, e.RunspaceStateInfo.State)); + DebugHelper.WriteLog(string.Format(CultureInfo.CurrentUICulture, DebugHelper.runspaceStateChanged, runspace.InstanceId, e.RunspaceStateInfo.State)); state.Dispose(); } + runspace.StateChanged -= DefaultRunspace_StateChanged; break; default: @@ -872,7 +899,7 @@ private static void DefaultRunspace_StateChanged(object sender, RunspaceStateEve internal class CimNewSession : CimSessionBase, IDisposable { /// - /// CimTestCimSessionContext + /// CimTestCimSessionContext. /// internal class CimTestCimSessionContext : XOperationContextBase { @@ -902,6 +929,7 @@ internal CimSessionWrapper CimSessionWrapper return this.cimSessionWrapper; } } + private CimSessionWrapper cimSessionWrapper; } @@ -918,7 +946,7 @@ internal CimNewSession() : base() /// /// Create a new base on given cmdlet - /// and its parameter + /// and its parameter. /// /// /// @@ -939,6 +967,7 @@ internal CimNewSession() : base() sessionOptions = CimSessionProxy.CreateCimSessionOption(computerName, cmdlet.OperationTimeoutSec, credential); } + proxy = new CimSessionProxyTestConnection(computerName, sessionOptions); string computerNameValue = (computerName == ConstValue.NullComputerName) ? ConstValue.LocalhostComputerName : computerName; CimSessionWrapper wrapper = new CimSessionWrapper(0, Guid.Empty, cmdlet.Name, computerNameValue, proxy.CimSession, proxy.Protocol); @@ -951,7 +980,7 @@ internal CimNewSession() : base() } else { - //CimSession will be returned as part of TestConnection + // CimSession will be returned as part of TestConnection this.cimTestSession.TestCimSession(computerName, proxy); } } @@ -972,7 +1001,7 @@ internal void AddSessionToCache(CimSession cimSession, XOperationContextBase con CimTestCimSessionContext testCimSessionContext = context as CimTestCimSessionContext; UInt32 sessionId = this.sessionState.GenerateSessionId(); string originalSessionName = testCimSessionContext.CimSessionWrapper.Name; - string sessionName = (originalSessionName != null) ? originalSessionName : String.Format(CultureInfo.CurrentUICulture, @"{0}{1}", CimSessionState.CimSessionClassName, sessionId); + string sessionName = (originalSessionName != null) ? originalSessionName : string.Format(CultureInfo.CurrentUICulture, @"{0}{1}", CimSessionState.CimSessionClassName, sessionId); // detach CimSession from the proxy object CimSession createdCimSession = testCimSessionContext.Proxy.Detach(); @@ -1020,7 +1049,7 @@ public void ProcessRemainActions(CmdletOperationBase cmdletOperation) /// /// private CimTestSession cimTestSession; - #endregion //private members + #endregion // private members #region IDisposable @@ -1036,6 +1065,7 @@ protected bool Disposed return _disposed; } } + private bool _disposed; /// @@ -1067,7 +1097,7 @@ public void Dispose() /// other objects. Only unmanaged resources can be disposed. /// /// - /// Whether it is directly called + /// Whether it is directly called. protected virtual void Dispose(bool disposing) { if (!this._disposed) @@ -1082,7 +1112,7 @@ protected virtual void Dispose(bool disposing) } } #endregion - }//End Class + } #endregion @@ -1096,7 +1126,7 @@ protected virtual void Dispose(bool disposing) internal class CimGetSession : CimSessionBase { /// - /// constructor + /// Constructor. /// public CimGetSession() : base() { @@ -1104,7 +1134,7 @@ public CimGetSession() : base() /// /// Get objects based on the given cmdlet - /// and its parameter + /// and its parameter. /// /// public void GetCimSession(GetCimSessionCommand cmdlet) @@ -1124,6 +1154,7 @@ public void GetCimSession(GetCimSessionCommand cmdlet) { sessionToGet = this.sessionState.QuerySessionByComputerName(cmdlet.ComputerName, out errorRecords); } + break; case CimBaseCommand.SessionIdSet: sessionToGet = this.sessionState.QuerySession(cmdlet.Id, out errorRecords); @@ -1137,6 +1168,7 @@ public void GetCimSession(GetCimSessionCommand cmdlet) default: break; } + if (sessionToGet != null) { foreach(PSObject psobject in sessionToGet) @@ -1144,6 +1176,7 @@ public void GetCimSession(GetCimSessionCommand cmdlet) cmdlet.WriteObject(psobject); } } + if (errorRecords != null) { foreach (ErrorRecord errRecord in errorRecords) @@ -1156,7 +1189,7 @@ public void GetCimSession(GetCimSessionCommand cmdlet) #region helper methods #endregion - }//End Class + } #endregion @@ -1170,12 +1203,12 @@ public void GetCimSession(GetCimSessionCommand cmdlet) internal class CimRemoveSession : CimSessionBase { /// - /// Remove session action string + /// Remove session action string. /// internal static string RemoveCimSessionActionName = "Remove CimSession"; /// - /// constructor + /// Constructor. /// public CimRemoveSession() : base() { @@ -1183,7 +1216,7 @@ public CimRemoveSession() : base() /// /// Remove the objects based on given cmdlet - /// and its parameter + /// and its parameter. /// /// public void RemoveCimSession(RemoveCimSessionCommand cmdlet) @@ -1212,6 +1245,7 @@ public void RemoveCimSession(RemoveCimSessionCommand cmdlet) default: break; } + if (sessionToRemove != null) { foreach (PSObject psobject in sessionToRemove) @@ -1222,6 +1256,7 @@ public void RemoveCimSession(RemoveCimSessionCommand cmdlet) } } } + if (errorRecords != null) { foreach (ErrorRecord errRecord in errorRecords) @@ -1230,7 +1265,7 @@ public void RemoveCimSession(RemoveCimSessionCommand cmdlet) } } } - }//End Class + } #endregion @@ -1243,7 +1278,7 @@ public void RemoveCimSession(RemoveCimSessionCommand cmdlet) internal class CimTestSession : CimAsyncOperation { /// - /// Constructor + /// Constructor. /// internal CimTestSession() : base() @@ -1268,4 +1303,4 @@ internal CimTestSession() #endregion -}//End namespace +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs index 2dd000d96d2a..1ba5c96220e7 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -24,7 +22,7 @@ namespace Microsoft.Management.Infrastructure.CimCmdlets #region Context base class /// - /// context base class for cross operations + /// Context base class for cross operations /// for example, some cmdlets need to query instance first and then /// remove instance, those scenarios need context object transferred /// from one operation to another. @@ -41,6 +39,7 @@ internal string Namespace return this.nameSpace; } } + protected string nameSpace; /// @@ -55,17 +54,18 @@ internal CimSessionProxy Proxy return this.proxy; } } + protected CimSessionProxy proxy; } /// - /// class provides all information regarding the - /// current invocation to .net api + /// Class provides all information regarding the + /// current invocation to .net api. /// internal class InvocationContext { /// - /// Constructor + /// Constructor. /// /// internal InvocationContext(CimSessionProxy proxy) @@ -78,7 +78,7 @@ internal InvocationContext(CimSessionProxy proxy) } /// - /// Constructor + /// Constructor. /// /// internal InvocationContext(string computerName, CimInstance targetCimInstance) @@ -119,8 +119,8 @@ internal virtual CimInstance TargetCimInstance #region Preprocessing of result object interface /// - /// Defines a method to preprocessing an result object before sending to - /// output pipeline. + /// Defines a method to preprocessing an result object before sending to + /// output pipeline. /// [ComVisible(false)] internal interface IObjectPreProcess @@ -129,7 +129,7 @@ internal interface IObjectPreProcess /// Performs pre processing of given result object. /// /// - /// Pre-processed object + /// Pre-processed object. object Process(object resultObject); } #endregion @@ -143,13 +143,14 @@ internal interface IObjectPreProcess internal sealed class CmdletActionEventArgs : EventArgs { /// - /// Constructor + /// Constructor. /// - /// CimBaseAction object bound to the event + /// CimBaseAction object bound to the event. public CmdletActionEventArgs(CimBaseAction action) { this.Action = action; } + public readonly CimBaseAction Action; } @@ -159,10 +160,10 @@ public CmdletActionEventArgs(CimBaseAction action) internal sealed class OperationEventArgs : EventArgs { /// - /// constructor + /// Constructor. /// - /// Object used to cancel the operation - /// Async observable operation + /// Object used to cancel the operation. + /// Async observable operation. public OperationEventArgs(IDisposable operationCancellation, IObservable operation, bool theSuccess) @@ -171,6 +172,7 @@ internal sealed class OperationEventArgs : EventArgs this.operation = operation; this.success = theSuccess; } + public readonly IDisposable operationCancellation; public readonly IObservable operation; public readonly bool success; @@ -196,7 +198,7 @@ internal class CimSessionProxy : IDisposable private static long gOperationCounter = 0; /// - /// temporary CimSession cache lock + /// Temporary CimSession cache lock. /// private static readonly object temporarySessionCacheLock = new object(); @@ -225,10 +227,10 @@ internal class CimSessionProxy : IDisposable /// otherwise insert it into the cache. /// /// - /// CimSession to be added + /// CimSession to be added. internal static void AddCimSessionToTemporaryCache(CimSession session) { - if (null != session) + if (session != null) { lock (temporarySessionCacheLock) { @@ -250,11 +252,11 @@ internal static void AddCimSessionToTemporaryCache(CimSession session) /// Wrapper function to remove CimSession from cache /// /// - /// Whether need to dispose the object + /// Whether need to dispose the object. private static void RemoveCimSessionFromTemporaryCache(CimSession session, bool dispose) { - if (null != session) + if (session != null) { bool removed = false; lock (temporarySessionCacheLock) @@ -293,7 +295,7 @@ internal static void AddCimSessionToTemporaryCache(CimSession session) /// If refcount became 0, call dispose on the object. /// /// - /// CimSession to be added + /// CimSession to be added. internal static void RemoveCimSessionFromTemporaryCache(CimSession session) { RemoveCimSessionFromTemporaryCache(session, true); @@ -306,14 +308,14 @@ internal static void RemoveCimSessionFromTemporaryCache(CimSession session) /// Define delegate that handles new cmdlet action come from /// the operations related to the current CimSession object. /// - /// cimSession object, which raised the event - /// Event args + /// CimSession object, which raised the event. + /// Event args. public delegate void NewCmdletActionHandler( object cimSession, CmdletActionEventArgs actionArgs); /// - /// Define an Event based on the NewActionHandler + /// Define an Event based on the NewActionHandler. /// public event NewCmdletActionHandler OnNewCmdletAction; @@ -321,14 +323,14 @@ internal static void RemoveCimSessionFromTemporaryCache(CimSession session) /// Define delegate that handles operation creation and complete /// issued by the current CimSession object. /// - /// cimSession object, which raised the event - /// Event args + /// CimSession object, which raised the event. + /// Event args. public delegate void OperationEventHandler( object cimSession, OperationEventArgs actionArgs); /// - /// Event triggered when a new operation is started + /// Event triggered when a new operation is started. /// public event OperationEventHandler OnOperationCreated; @@ -414,7 +416,8 @@ public CimSessionProxy(string computerName, CimInstance cimInstance) return; } } - String cimsessionComputerName = cimInstance.GetCimSessionComputerName(); + + string cimsessionComputerName = cimInstance.GetCimSessionComputerName(); CreateSetSession(cimsessionComputerName, null, null, null, false); this.isDefaultSession = (cimsessionComputerName == ConstValue.NullComputerName); @@ -423,11 +426,11 @@ public CimSessionProxy(string computerName, CimInstance cimInstance) /// /// Create by given computer name, - /// session options + /// session options. /// /// /// - /// Used when create async operation + /// Used when create async operation. public CimSessionProxy(string computerName, CimSessionOptions sessionOptions, CimOperationOptions operOptions) { CreateSetSession(computerName, null, sessionOptions, operOptions, false); @@ -439,7 +442,7 @@ public CimSessionProxy(string computerName, CimSessionOptions sessionOptions, Ci /// Then create wrapper object. /// /// - /// Used when create async operation + /// Used when create async operation. public CimSessionProxy(string computerName, CimOperationOptions operOptions) { CreateSetSession(computerName, null, null, operOptions, false); @@ -447,7 +450,7 @@ public CimSessionProxy(string computerName, CimOperationOptions operOptions) } /// - /// Create wrapper object by given session object + /// Create wrapper object by given session object. /// /// public CimSessionProxy(CimSession session) @@ -456,17 +459,17 @@ public CimSessionProxy(CimSession session) } /// - /// Create wrapper object by given session object + /// Create wrapper object by given session object. /// /// - /// Used when create async operation + /// Used when create async operation. public CimSessionProxy(CimSession session, CimOperationOptions operOptions) { CreateSetSession(null, session, null, operOptions, false); } /// - /// Initialize CimSessionProxy object + /// Initialize CimSessionProxy object. /// /// /// @@ -486,6 +489,7 @@ public CimSessionProxy(CimSession session, CimOperationOptions operOptions) this.CancelOperation = null; this.operation = null; } + InitOption(operOptions); this.protocol = ProtocolType.Wsman; this.isTemporaryCimSession = temporaryCimSession; @@ -522,6 +526,7 @@ public CimSessionProxy(CimSession session, CimOperationOptions operOptions) { this.session = CreateCimSessionByComputerName(computerName); } + this.isTemporaryCimSession = true; } @@ -529,6 +534,7 @@ public CimSessionProxy(CimSession session, CimOperationOptions operOptions) { AddCimSessionToTemporaryCache(this.session); } + this.invocationContextObject = new InvocationContext(this); DebugHelper.WriteLog("Protocol {0}, Is temporary session ? {1}", 1, this.protocol, this.isTemporaryCimSession); } @@ -538,7 +544,7 @@ public CimSessionProxy(CimSession session, CimOperationOptions operOptions) #region set operation options /// - /// Set timeout value (seconds) of the operation + /// Set timeout value (seconds) of the operation. /// public UInt32 OperationTimeout { @@ -548,6 +554,7 @@ public UInt32 OperationTimeout this.options.Timeout = TimeSpan.FromSeconds((double)value); } + get { return (UInt32)this.options.Timeout.TotalSeconds; @@ -555,7 +562,7 @@ public UInt32 OperationTimeout } /// - /// Set resource URI of the operation + /// Set resource URI of the operation. /// public Uri ResourceUri { @@ -565,6 +572,7 @@ public Uri ResourceUri this.options.ResourceUri= value; } + get { return this.options.ResourceUri; @@ -581,6 +589,7 @@ public bool EnableMethodResultStreaming { return this.options.EnableMethodResultStreaming; } + set { DebugHelper.WriteLogEx("EnableMethodResultStreaming {0}", 0, value); @@ -605,7 +614,7 @@ public bool EnablePromptUser } /// - /// Enable the pssemantics + /// Enable the pssemantics. /// private void EnablePSSemantics() { @@ -651,7 +660,7 @@ public SwitchParameter Shallow } /// - /// Initialize the operation option + /// Initialize the operation option. /// private void InitOption(CimOperationOptions operOptions) { @@ -665,6 +674,7 @@ private void InitOption(CimOperationOptions operOptions) { this.options = new CimOperationOptions(); } + this.EnableMethodResultStreaming = true; this.EnablePSSemantics(); } @@ -707,7 +717,7 @@ private void AddOperation(IObservable operation) } /// - /// Remove object from cache + /// Remove object from cache. /// /// private void RemoveOperation(IObservable operation) @@ -724,6 +734,7 @@ private void RemoveOperation(IObservable operation) { this.operation = null; } + if (this.session != null && this.ContextObject == null) { DebugHelper.WriteLog("Dispose this proxy object @ RemoveOperation"); @@ -757,6 +768,7 @@ protected void FireNewActionEvent(CimBaseAction action) { DebugHelper.WriteLog("Ignore action since OnNewCmdletAction is null.", 5); } + this.PostNewActionEvent(actionArgs); } @@ -780,6 +792,7 @@ protected void FireNewActionEvent(CimBaseAction action) { temp(this.session, args); } + this.PostOperationCreateEvent(args); } @@ -803,6 +816,7 @@ protected void FireNewActionEvent(CimBaseAction action) { temp(this.session, args); } + this.PostOperationDeleteEvent(args); this.RemoveOperation(operation); this.operationName = null; @@ -852,9 +866,11 @@ internal void WriteOperationStartMessage(string operation, Hashtable parameterLi { parameters.Append(","); } + parameters.Append(string.Format(CultureInfo.CurrentUICulture, @"'{0}' = {1}", key, parameterList[key])); } } + string operationStartMessage = string.Format(CultureInfo.CurrentUICulture, Strings.CimOperationStart, operation, @@ -937,7 +953,7 @@ public CimResponseType WriteError(CimInstance instance) } /// - /// PromptUser callback + /// PromptUser callback. /// /// /// @@ -966,8 +982,8 @@ public CimResponseType PromptUser(string message, CimPromptType prompt) /// Handle async event triggered by /// /// - /// object triggered the event - /// async result event argument + /// Object triggered the event. + /// Async result event argument. internal void ResultEventHandler( object observer, AsyncResultEventArgsBase resultArgs) @@ -982,6 +998,7 @@ public CimResponseType PromptUser(string message, CimPromptType prompt) AsyncResultCompleteEventArgs args = resultArgs as AsyncResultCompleteEventArgs; this.FireOperationDeletedEvent(args.observable, true); } + break; case AsyncResultType.Exception: { @@ -992,8 +1009,10 @@ public CimResponseType PromptUser(string message, CimPromptType prompt) { this.FireNewActionEvent(action); } + this.FireOperationDeletedEvent(args.observable, false); } + break; case AsyncResultType.Result: { @@ -1004,6 +1023,7 @@ public CimResponseType PromptUser(string message, CimPromptType prompt) { AddShowComputerNameMarker(resultObject); } + if (this.ObjectPreProcess != null) { resultObject = this.ObjectPreProcess.Process(resultObject); @@ -1014,6 +1034,7 @@ public CimResponseType PromptUser(string message, CimPromptType prompt) CimWriteResultObject action = new CimWriteResultObject(resultObject, this.ContextObject); this.FireNewActionEvent(action); } + break; default: break; @@ -1049,6 +1070,7 @@ private static bool GetIsCliXmlTestabilityHookActive() { return !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CDXML_CLIXML_TEST")); } + private object PostProcessCimInstance(object resultObject) { DebugHelper.WriteLogEx(); @@ -1057,9 +1079,10 @@ private object PostProcessCimInstance(object resultObject) string serializedForm = PSSerializer.Serialize(resultObject as CimInstance, depth: 1); object deserializedObject = PSSerializer.Deserialize(serializedForm); object returnObject = (deserializedObject is PSObject) ? (deserializedObject as PSObject).BaseObject : deserializedObject; - DebugHelper.WriteLogEx("Deserialized Object is {0}, type {1}", 1, returnObject, returnObject.GetType()); + DebugHelper.WriteLogEx("Deserialized object is {0}, type {1}", 1, returnObject, returnObject.GetType()); return returnObject; } + return resultObject; } #endif @@ -1090,7 +1113,7 @@ public void CreateInstanceAsync(string namespaceName, CimInstance instance) } /// - /// delete a cim instance asynchronously + /// Delete a cim instance asynchronously. /// /// /// @@ -1110,7 +1133,7 @@ public void DeleteInstanceAsync(string namespaceName, CimInstance instance) } /// - /// Get cim instance asynchronously + /// Get cim instance asynchronously. /// /// /// @@ -1130,7 +1153,7 @@ public void GetInstanceAsync(string namespaceName, CimInstance instance) } /// - /// Modify cim instance asynchronously + /// Modify cim instance asynchronously. /// /// /// @@ -1151,7 +1174,7 @@ public void ModifyInstanceAsync(string namespaceName, CimInstance instance) /// /// Enumerate cim instance associated with the - /// given instance asynchronously + /// given instance asynchronously. /// /// /// @@ -1185,7 +1208,7 @@ public void ModifyInstanceAsync(string namespaceName, CimInstance instance) } /// - /// Enumerate cim instance asynchronously + /// Enumerate cim instance asynchronously. /// /// /// @@ -1200,7 +1223,7 @@ public void EnumerateInstancesAsync(string namespaceName, string className) this.operationParameters.Add(@"className", className); this.WriteOperationStartMessage(this.operationName, this.operationParameters); CimAsyncMultipleResults asyncResult = this.session.EnumerateInstancesAsync(namespaceName, className, this.options); - string errorSource = String.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); + string errorSource = string.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); ConsumeCimInstanceAsync(asyncResult, new CimResultContext(errorSource)); } @@ -1250,7 +1273,7 @@ public void EnumerateInstancesAsync(string namespaceName, string className) } /// - /// Enumerate cim class asynchronously + /// Enumerate cim class asynchronously. /// /// /// @@ -1268,7 +1291,7 @@ public void EnumerateClassesAsync(string namespaceName) } /// - /// Enumerate cim class asynchronously + /// Enumerate cim class asynchronously. /// /// /// @@ -1282,12 +1305,12 @@ public void EnumerateClassesAsync(string namespaceName, string className) this.operationParameters.Add(@"className", className); this.WriteOperationStartMessage(this.operationName, this.operationParameters); CimAsyncMultipleResults asyncResult = this.session.EnumerateClassesAsync(namespaceName, className, this.options); - string errorSource = String.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); + string errorSource = string.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); ConsumeCimClassAsync(asyncResult, new CimResultContext(errorSource)); } /// - /// Get cim class asynchronously + /// Get cim class asynchronously. /// /// /// @@ -1302,12 +1325,12 @@ public void GetClassAsync(string namespaceName, string className) this.operationParameters.Add(@"className", className); this.WriteOperationStartMessage(this.operationName, this.operationParameters); CimAsyncResult asyncResult = this.session.GetClassAsync(namespaceName, className, this.options); - string errorSource = String.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); + string errorSource = string.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); ConsumeCimClassAsync(asyncResult, new CimResultContext(errorSource)); } /// - /// Invoke method of a given cim instance asynchronously + /// Invoke method of a given cim instance asynchronously. /// /// /// @@ -1334,7 +1357,7 @@ public void GetClassAsync(string namespaceName, string className) } /// - /// Invoke static method of a given class asynchronously + /// Invoke static method of a given class asynchronously. /// /// /// @@ -1356,7 +1379,7 @@ public void GetClassAsync(string namespaceName, string className) this.operationParameters.Add(@"methodName", methodName); this.WriteOperationStartMessage(this.operationName, this.operationParameters); CimAsyncMultipleResults asyncResult = this.session.InvokeMethodAsync(namespaceName, className, methodName, methodParameters, this.options); - string errorSource = String.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); + string errorSource = string.Format(CultureInfo.CurrentUICulture, "{0}:{1}", namespaceName, className); ConsumeCimInvokeMethodResultAsync(asyncResult, className, methodName, new CimResultContext(errorSource)); } @@ -1407,7 +1430,7 @@ public void TestConnectionAsync() #region pre action APIs /// - /// Called before new action event + /// Called before new action event. /// /// protected virtual bool PreNewActionEvent(CmdletActionEventArgs args) @@ -1415,7 +1438,7 @@ protected virtual bool PreNewActionEvent(CmdletActionEventArgs args) return true; } /// - /// Called before operation delete event + /// Called before operation delete event. /// /// protected virtual void PreOperationDeleteEvent(OperationEventArgs args) @@ -1426,21 +1449,21 @@ protected virtual void PreOperationDeleteEvent(OperationEventArgs args) #region post action APIs /// - /// Called after new action event + /// Called after new action event. /// /// protected virtual void PostNewActionEvent(CmdletActionEventArgs args) { } /// - /// Called after operation create event + /// Called after operation create event. /// /// protected virtual void PostOperationCreateEvent(OperationEventArgs args) { } /// - /// Called after operation delete event + /// Called after operation delete event. /// /// protected virtual void PostOperationDeleteEvent(OperationEventArgs args) @@ -1470,11 +1493,12 @@ internal CimSession CimSession return this.session; } } + private CimSession session; /// /// The current CimInstance object, against which issued - /// current operation, it could be null + /// current operation, it could be null. /// internal CimInstance TargetCimInstance { @@ -1483,6 +1507,7 @@ internal CimInstance TargetCimInstance return this.targetCimInstance; } } + private CimInstance targetCimInstance = null; /// @@ -1512,6 +1537,7 @@ internal CimOperationOptions OperationOptions return this.options; } } + private CimOperationOptions options; /// @@ -1523,38 +1549,38 @@ private bool Completed } /// - /// lock object used to lock - /// operation & cancelOperation members + /// Lock object used to lock + /// operation & cancelOperation members. /// private readonly object stateLock = new object(); /// - /// the operation issued by cimSession + /// The operation issued by cimSession. /// private IObservable operation; /// - /// the current operation name + /// The current operation name. /// private string operationName; /// - /// the current operation parameters + /// The current operation parameters. /// private Hashtable operationParameters = new Hashtable(); /// - /// handler used to cancel operation + /// Handler used to cancel operation. /// private IDisposable _cancelOperation; /// - /// cancelOperation disposed flag + /// CancelOperation disposed flag. /// private int _cancelOperationDisposed = 0; /// - /// Dispose the cancel operation + /// Dispose the cancel operation. /// private void DisposeCancelOperation() { @@ -1571,7 +1597,7 @@ private void DisposeCancelOperation() } /// - /// Set the cancel operation + /// Set the cancel operation. /// private IDisposable CancelOperation { @@ -1581,6 +1607,7 @@ private IDisposable CancelOperation this._cancelOperation = value; Interlocked.Exchange(ref this._cancelOperationDisposed, 0); } + get { return this._cancelOperation; @@ -1588,8 +1615,8 @@ private IDisposable CancelOperation } /// - /// current protocol name - /// DCOM or WSMAN + /// Current protocol name + /// DCOM or WSMAN. /// internal ProtocolType Protocol { @@ -1598,10 +1625,11 @@ internal ProtocolType Protocol return protocol; } } + private ProtocolType protocol; /// - /// cross operation context object + /// Cross operation context object. /// internal XOperationContextBase ContextObject { @@ -1609,20 +1637,22 @@ internal XOperationContextBase ContextObject { this.contextObject = value; } + get { return this.contextObject; } } + private XOperationContextBase contextObject; /// - /// invocation context object + /// Invocation context object. /// private InvocationContext invocationContextObject; /// - /// a preprocess object to pre-processing the result object, + /// A preprocess object to pre-processing the result object, /// for example, adding PSTypeName, etc. /// internal IObjectPreProcess ObjectPreProcess @@ -1631,11 +1661,13 @@ internal IObjectPreProcess ObjectPreProcess { this.objectPreprocess = value; } + get { return this.objectPreprocess; } } + private IObjectPreProcess objectPreprocess; /// @@ -1650,7 +1682,7 @@ internal IObjectPreProcess ObjectPreProcess #region IDisposable /// - /// IDisposable interface + /// IDisposable interface. /// private int _disposed; @@ -1691,6 +1723,7 @@ protected virtual void Dispose(bool disposing) this.options.Dispose(); this.options = null; } + DisposeTemporaryCimSession(); } } @@ -1838,8 +1871,8 @@ private void DisposeTemporaryCimSession() /// protected void ConsumeCimInvokeMethodResultAsync( IObservable asyncResult, - String className, - String methodName, + string className, + string methodName, CimResultContext cimResultContext) { CimMethodResultObserver observer = new CimMethodResultObserver(this.session, asyncResult, cimResultContext) @@ -1872,6 +1905,7 @@ private void CheckAvailability() throw new InvalidOperationException(Strings.OperationInProgress); } } + DebugHelper.WriteLog("KeyOnly {0},", 1, this.options.KeysOnly); } @@ -1939,21 +1973,24 @@ private CimSession CreateCimSessionByComputerName(string computerName) DebugHelper.WriteLog("<<<<<<<<<< Use protocol WSMAN {0}", 1, computerName); option = new WSManSessionOptions(); } + if (timeout != 0) { option.Timeout = TimeSpan.FromSeconds((double)timeout); } + if (credential != null) { option.AddDestinationCredentials(credential); } + DebugHelper.WriteLogEx("returned option :{0}.", 1, option); return option; } #endregion - }//End Class + } #region class CimSessionProxyTestConnection /// @@ -1982,7 +2019,7 @@ public CimSessionProxyTestConnection(string computerName, CimSessionOptions sess #region pre action APIs /// - /// Called after operation delete event + /// Called after operation delete event. /// /// protected override void PreOperationDeleteEvent(OperationEventArgs args) @@ -2040,7 +2077,7 @@ public CimSessionProxyGetCimClass(CimSession session) #region pre action APIs /// - /// Called before new action event + /// Called before new action event. /// /// protected override bool PreNewActionEvent(CmdletActionEventArgs args) @@ -2074,12 +2111,13 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) return false; } } + if (context.PropertyName != null) { - pattern = new WildcardPattern(context.PropertyName, WildcardOptions.IgnoreCase); bool match = false; if (cimClass.CimClassProperties != null) { + pattern = new WildcardPattern(context.PropertyName, WildcardOptions.IgnoreCase); foreach (CimPropertyDeclaration decl in cimClass.CimClassProperties) { DebugHelper.WriteLog("--- property name : {0}", 1, decl.Name); @@ -2097,12 +2135,13 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) return match; } } + if (context.MethodName != null) { - pattern = new WildcardPattern(context.MethodName, WildcardOptions.IgnoreCase); bool match = false; if (cimClass.CimClassMethods != null) { + pattern = new WildcardPattern(context.MethodName, WildcardOptions.IgnoreCase); foreach (CimMethodDeclaration decl in cimClass.CimClassMethods) { DebugHelper.WriteLog("--- method name : {0}", 1, decl.Name); @@ -2120,12 +2159,13 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) return match; } } + if (context.QualifierName != null) { - pattern = new WildcardPattern(context.QualifierName, WildcardOptions.IgnoreCase); bool match = false; if (cimClass.CimClassQualifiers != null) { + pattern = new WildcardPattern(context.QualifierName, WildcardOptions.IgnoreCase); foreach (CimQualifier qualifier in cimClass.CimClassQualifiers) { DebugHelper.WriteLog("--- qualifier name : {0}", 1, qualifier.Name); @@ -2143,6 +2183,7 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) return match; } } + DebugHelper.WriteLog("CimClass '{0}' is qualified.", 1, cimClass.CimSystemProperties.ClassName); return true; } @@ -2190,7 +2231,7 @@ public CimSessionProxyNewCimInstance(CimSession session, CimNewCimInstance opera #region pre action APIs /// - /// Called before new action event + /// Called before new action event. /// /// protected override bool PreNewActionEvent(CmdletActionEventArgs args) @@ -2247,7 +2288,7 @@ internal class CimSessionProxySetCimInstance : CimSessionProxy /// Then create wrapper object. /// /// object to clone. - /// PassThru, true means output the modified instance; otherwise does not output + /// PassThru, true means output the modified instance; otherwise does not output. public CimSessionProxySetCimInstance(CimSessionProxy originalProxy, bool passThru) : base(originalProxy) { @@ -2285,7 +2326,7 @@ public CimSessionProxySetCimInstance(CimSession session, bool passThru) #region pre action APIs /// - /// Called before new action event + /// Called before new action event. /// /// protected override bool PreNewActionEvent(CmdletActionEventArgs args) @@ -2305,7 +2346,7 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) #region private members /// - /// Ture indicates need to output the modified result + /// Ture indicates need to output the modified result. /// private bool passThru = false; @@ -2313,4 +2354,4 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) } #endregion -}//End namespace +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSetCimInstance.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSetCimInstance.cs index eadc0bc8e68b..eb651744fef0 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSetCimInstance.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSetCimInstance.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -11,7 +9,6 @@ using System.Globalization; using System.Management.Automation; - #endregion namespace Microsoft.Management.Infrastructure.CimCmdlets @@ -53,6 +50,7 @@ internal IDictionary Property return this.property; } } + private IDictionary property; /// @@ -65,6 +63,7 @@ internal string ParameterSetName return this.parameterSetName; } } + private string parameterSetName; /// @@ -77,6 +76,7 @@ internal bool PassThru return this.passThru; } } + private bool passThru; } @@ -102,7 +102,7 @@ public CimSetCimInstance() /// Base on parametersetName to set ciminstances /// /// - /// object + /// object. public void SetCimInstance(SetCimInstanceCommand cmdlet) { IEnumerable computerNames = ConstValue.GetComputerNames( @@ -116,6 +116,7 @@ public void SetCimInstance(SetCimInstanceCommand cmdlet) // create CimSessionProxySetCimInstance object internally proxys.Add(CreateSessionProxy(computerName, cmdlet.CimInstance, cmdlet, cmdlet.PassThru)); } + break; case CimBaseCommand.CimInstanceSessionSet: foreach (CimSession session in GetCimSession(cmdlet)) @@ -123,10 +124,12 @@ public void SetCimInstance(SetCimInstanceCommand cmdlet) // create CimSessionProxySetCimInstance object internally proxys.Add(CreateSessionProxy(session, cmdlet, cmdlet.PassThru)); } + break; default: break; } + switch (cmdlet.ParameterSetName) { case CimBaseCommand.CimInstanceComputerSet: @@ -151,8 +154,10 @@ public void SetCimInstance(SetCimInstanceCommand cmdlet) return; } } + proxy.ModifyInstanceAsync(nameSpace, instance); } + break; case CimBaseCommand.QueryComputerSet: case CimBaseCommand.QuerySessionSet: @@ -184,6 +189,7 @@ public void SetCimInstance(CimInstance cimInstance, CimSetCimInstanceContext con cmdlet.ThrowTerminatingError(exception, action); return; } + CimSessionProxy proxy = CreateCimSessionProxy(context.Proxy, context.PassThru); proxy.ModifyInstanceAsync(cimInstance.CimSystemProperties.Namespace, cimInstance); } @@ -208,6 +214,7 @@ private bool SetProperty(IDictionary properties, ref CimInstance cimInstance, re // simply ignore if empty properties was provided return true; } + IDictionaryEnumerator enumerator = properties.GetEnumerator(); while (enumerator.MoveNext()) { @@ -224,7 +231,7 @@ private bool SetProperty(IDictionary properties, ref CimInstance cimInstance, re if ((property.Flags & CimFlags.ReadOnly) == CimFlags.ReadOnly) { // can not modify ReadOnly property - exception = new CimException(String.Format(CultureInfo.CurrentUICulture, + exception = new CimException(string.Format(CultureInfo.CurrentUICulture, Strings.CouldNotModifyReadonlyProperty, key, cimInstance)); return false; } @@ -264,6 +271,7 @@ private bool SetProperty(IDictionary properties, ref CimInstance cimInstance, re CimFlags.Property); } } + try { cimInstance.CimInstanceProperties.Add(newProperty); @@ -272,7 +280,7 @@ private bool SetProperty(IDictionary properties, ref CimInstance cimInstance, re { if (e.NativeErrorCode == NativeErrorCode.Failed) { - string errorMessage = String.Format(CultureInfo.CurrentUICulture, + string errorMessage = string.Format(CultureInfo.CurrentUICulture, Strings.UnableToAddPropertyToInstance, newProperty.Name, cimInstance); @@ -282,8 +290,10 @@ private bool SetProperty(IDictionary properties, ref CimInstance cimInstance, re { exception = e; } + return false; } + DebugHelper.WriteLog("Add non-key property name '{0}' with value '{1}'.", 3, key, value); } } @@ -294,6 +304,7 @@ private bool SetProperty(IDictionary properties, ref CimInstance cimInstance, re return false; } } + return true; } @@ -301,9 +312,9 @@ private bool SetProperty(IDictionary properties, ref CimInstance cimInstance, re #region const strings /// - /// action + /// Action. /// private const string action = @"Set-CimInstance"; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteError.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteError.cs index 9b2396c7d290..8d8dadbf0869 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteError.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteError.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -31,8 +29,8 @@ internal sealed class ErrorToErrorRecord /// /// /// - /// the context starting the operation, which generated the error - /// the CimResultContext used to provide ErrorSource, etc. info. + /// The context starting the operation, which generated the error. + /// The CimResultContext used to provide ErrorSource, etc. info. /// internal static ErrorRecord ErrorRecordFromAnyException( InvocationContext context, @@ -72,7 +70,7 @@ internal sealed class ErrorToErrorRecord /// /// /// - /// the CimResultContext used to provide ErrorSource, etc. info. + /// The CimResultContext used to provide ErrorSource, etc. info. /// internal static ErrorRecord CreateFromCimException( InvocationContext context, @@ -91,7 +89,7 @@ internal sealed class ErrorToErrorRecord /// /// /// - /// the CimResultContext used to provide ErrorSource, etc. info. + /// The CimResultContext used to provide ErrorSource, etc. info. /// internal static ErrorRecord InitializeErrorRecord( InvocationContext context, @@ -113,7 +111,7 @@ internal sealed class ErrorToErrorRecord /// /// /// - /// the CimResultContext used to provide ErrorSource, etc. info. + /// The CimResultContext used to provide ErrorSource, etc. info. /// internal static ErrorRecord InitializeErrorRecord( InvocationContext context, @@ -131,6 +129,7 @@ internal sealed class ErrorToErrorRecord { errorRecord.CategoryInfo.TargetName = cimException.ErrorSource; } + return errorRecord; } @@ -141,7 +140,7 @@ internal sealed class ErrorToErrorRecord /// /// /// - /// the CimResultContext used to provide ErrorSource, etc. info. + /// The CimResultContext used to provide ErrorSource, etc. info. /// internal static ErrorRecord InitializeErrorRecordCore( InvocationContext context, @@ -155,6 +154,7 @@ internal sealed class ErrorToErrorRecord { theTargetObject = cimResultContext.ErrorSource; } + if (theTargetObject == null) { if (context != null) @@ -165,6 +165,7 @@ internal sealed class ErrorToErrorRecord } } } + ErrorRecord coreErrorRecord = new ErrorRecord( exception: exception, errorId: errorId, @@ -185,8 +186,6 @@ internal sealed class ErrorToErrorRecord originInfo); DebugHelper.WriteLogEx("Created RemotingErrorRecord.", 0); - // errorRecord.SetInvocationInfo(jobContext.CmdletInvocationInfo); - // errorRecord.PreserveInvocationInfoOnce = true; return errorRecord; } @@ -318,7 +317,7 @@ internal static ErrorCategory ConvertCimErrorToErrorCategory(CimInstance cimErro internal sealed class CimWriteError : CimSyncAction { /// - /// Constructor with an error + /// Constructor with an error. /// /// public CimWriteError(CimInstance error, InvocationContext context) @@ -328,7 +327,7 @@ public CimWriteError(CimInstance error, InvocationContext context) } /// - /// Construct with an exception object + /// Construct with an exception object. /// /// public CimWriteError(Exception exception, InvocationContext context, CimResultContext cimResultContext) @@ -398,6 +397,7 @@ internal Exception Exception return exception; } } + private Exception exception; /// @@ -416,7 +416,6 @@ internal InvocationContext CimInvocationContext } } - /// /// /// @@ -431,5 +430,5 @@ internal CimResultContext ResultContext } #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteMessage.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteMessage.cs index f0259d744b2e..ec8b1c6f867c 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteMessage.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteMessage.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -22,12 +20,12 @@ internal sealed class CimWriteMessage : CimBaseAction #region members /// - /// channel id + /// Channel id. /// private UInt32 channel; /// - /// message to write to the channel + /// Message to write to the channel. /// private string message; #endregion @@ -81,5 +79,5 @@ public override void Execute(CmdletOperationBase cmdlet) break; } } - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteProgress.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteProgress.cs index 23b34f60a0d3..5bf1f535741b 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteProgress.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteProgress.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -20,7 +18,7 @@ namespace Microsoft.Management.Infrastructure.CimCmdlets internal sealed class CimWriteProgress : CimBaseAction { /// - /// Constructor + /// Constructor. /// /// /// Activity identifier of the given activity @@ -48,7 +46,7 @@ internal sealed class CimWriteProgress : CimBaseAction this.activity = theActivity; this.activityID = theActivityID; this.currentOperation = theCurrentOperation; - if (String.IsNullOrEmpty(theStatusDescription)) + if (string.IsNullOrEmpty(theStatusDescription)) { this.statusDescription = Strings.DefaultStatusDescription; } @@ -56,6 +54,7 @@ internal sealed class CimWriteProgress : CimBaseAction { this.statusDescription = theStatusDescription; } + this.percentageCompleted = thePercentageCompleted; this.secondsRemaining = theSecondsRemaining; } @@ -91,32 +90,32 @@ public override void Execute(CmdletOperationBase cmdlet) #region members /// - /// Activity of the given activity + /// Activity of the given activity. /// private string activity; /// - /// Activity identifier of the given activity + /// Activity identifier of the given activity. /// private int activityID; /// - /// current operation text of the given activity + /// Current operation text of the given activity. /// private string currentOperation; /// - /// status description of the given activity + /// Status description of the given activity. /// private string statusDescription; /// - /// percentage completed of the given activity + /// Percentage completed of the given activity. /// private UInt32 percentageCompleted; /// - /// how many seconds remained for the given activity + /// How many seconds remained for the given activity. /// private UInt32 secondsRemaining; @@ -151,5 +150,5 @@ internal UInt32 SecondsRemaining } #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteResultObject.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteResultObject.cs index 1a87b451af33..57ce642c3739 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteResultObject.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimWriteResultObject.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -17,7 +15,7 @@ namespace Microsoft.Management.Infrastructure.CimCmdlets internal sealed class CimWriteResultObject : CimBaseAction { /// - /// Constructor + /// Constructor. /// public CimWriteResultObject(object result, XOperationContextBase theContext) { @@ -39,7 +37,7 @@ public override void Execute(CmdletOperationBase cmdlet) #region members /// - /// result object + /// Result object. /// internal object Result { @@ -48,8 +46,9 @@ internal object Result return result; } } + private object result; #endregion - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CmdletOperation.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CmdletOperation.cs index f5d84647cdd5..bb58c6a0b84b 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CmdletOperation.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CmdletOperation.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System.Management.Automation; @@ -42,58 +40,72 @@ public virtual bool ShouldContinue(string query, string caption) { return cmdlet.ShouldContinue(query, caption); } + public virtual bool ShouldContinue(string query, string caption, ref bool yesToAll, ref bool noToAll) { return cmdlet.ShouldContinue(query, caption, ref yesToAll, ref noToAll); } + public virtual bool ShouldProcess(string target) { return cmdlet.ShouldProcess(target); } + public virtual bool ShouldProcess(string target, string action) { return cmdlet.ShouldProcess(target, action); } + public virtual bool ShouldProcess(string verboseDescription, string verboseWarning, string caption) { return cmdlet.ShouldProcess(verboseDescription, verboseWarning, caption); } + public virtual bool ShouldProcess(string verboseDescription, string verboseWarning, string caption, out ShouldProcessReason shouldProcessReason) { return cmdlet.ShouldProcess(verboseDescription, verboseWarning, caption, out shouldProcessReason); } + public virtual void ThrowTerminatingError(ErrorRecord errorRecord) { cmdlet.ThrowTerminatingError(errorRecord); } + public virtual void WriteCommandDetail(string text) { cmdlet.WriteCommandDetail(text); } + public virtual void WriteDebug(string text) { cmdlet.WriteDebug(text); } + public virtual void WriteError(ErrorRecord errorRecord) { cmdlet.WriteError(errorRecord); } + public virtual void WriteObject(object sendToPipeline, XOperationContextBase context) { cmdlet.WriteObject(sendToPipeline); } + public virtual void WriteObject(object sendToPipeline, bool enumerateCollection, XOperationContextBase context) { cmdlet.WriteObject(sendToPipeline, enumerateCollection); } + public virtual void WriteProgress(ProgressRecord progressRecord) { cmdlet.WriteProgress(progressRecord); } + public virtual void WriteVerbose(string text) { cmdlet.WriteVerbose(text); } + public virtual void WriteWarning(string text) { cmdlet.WriteWarning(text); @@ -119,7 +131,7 @@ public CmdletOperationBase(Cmdlet cmdlet) ValidationHelper.ValidateNoNullArgument(cmdlet, "cmdlet"); this.cmdlet = cmdlet; } - }//End Class + } #region Class CmdletOperationRemoveCimInstance @@ -132,7 +144,7 @@ public CmdletOperationBase(Cmdlet cmdlet) internal class CmdletOperationRemoveCimInstance : CmdletOperationBase { /// - /// Constructor method + /// Constructor method. /// /// public CmdletOperationRemoveCimInstance(Cmdlet cmdlet, @@ -181,7 +193,7 @@ public override void WriteObject(object sendToPipeline, bool enumerateCollection private const string cimRemoveCimInstanceParameterName = @"cimRemoveCimInstance"; #endregion - }//End Class + } #endregion @@ -196,7 +208,7 @@ public override void WriteObject(object sendToPipeline, bool enumerateCollection internal class CmdletOperationSetCimInstance : CmdletOperationBase { /// - /// Constructor method + /// Constructor method. /// /// public CmdletOperationSetCimInstance(Cmdlet cmdlet, @@ -222,8 +234,8 @@ public override void WriteObject(object sendToPipeline, XOperationContextBase co CimSetCimInstanceContext setContext = context as CimSetCimInstanceContext; if (setContext != null) { - if ((String.Compare(setContext.ParameterSetName, CimBaseCommand.QueryComputerSet, StringComparison.OrdinalIgnoreCase) == 0) || - (String.Compare(setContext.ParameterSetName, CimBaseCommand.QuerySessionSet, StringComparison.OrdinalIgnoreCase) == 0)) + if ((string.Compare(setContext.ParameterSetName, CimBaseCommand.QueryComputerSet, StringComparison.OrdinalIgnoreCase) == 0) || + (string.Compare(setContext.ParameterSetName, CimBaseCommand.QuerySessionSet, StringComparison.OrdinalIgnoreCase) == 0)) { this.setCimInstance.SetCimInstance(sendToPipeline as CimInstance, setContext, this); return; @@ -238,6 +250,7 @@ public override void WriteObject(object sendToPipeline, XOperationContextBase co DebugHelper.WriteLog("Assert. CimSetCimInstance::SetCimInstance has NULL CimSetCimInstanceContext", 4); } } + base.WriteObject(sendToPipeline, context); } @@ -260,7 +273,7 @@ public override void WriteObject(object sendToPipeline, bool enumerateCollection private const string theCimSetCimInstanceParameterName = @"theCimSetCimInstance"; #endregion - }//End Class + } #endregion #region Class CmdletOperationInvokeCimMethod @@ -273,7 +286,7 @@ public override void WriteObject(object sendToPipeline, bool enumerateCollection internal class CmdletOperationInvokeCimMethod : CmdletOperationBase { /// - /// Constructor method + /// Constructor method. /// /// public CmdletOperationInvokeCimMethod(Cmdlet cmdlet, @@ -323,7 +336,7 @@ public override void WriteObject(object sendToPipeline, bool enumerateCollection private const string theCimInvokeCimMethodParameterName = @"theCimInvokeCimMethod"; #endregion - }//End Class + } #endregion @@ -338,7 +351,7 @@ public override void WriteObject(object sendToPipeline, bool enumerateCollection internal class CmdletOperationTestCimSession : CmdletOperationBase { /// - /// Constructor method + /// Constructor method. /// /// public CmdletOperationTestCimSession(Cmdlet cmdlet, @@ -384,7 +397,7 @@ public override void WriteObject(object sendToPipeline, XOperationContextBase co private const string theCimNewSessionParameterName = @"theCimNewSession"; #endregion - }//End Class + } #endregion -}//End namespace +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimAssociatedInstanceCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimAssociatedInstanceCommand.cs index 87f5466f121d..753487de7604 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimAssociatedInstanceCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimAssociatedInstanceCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -12,7 +10,6 @@ #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -35,7 +32,7 @@ public class GetCimAssociatedInstanceCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public GetCimAssociatedInstanceCommand() : base(parameters, parameterSets) @@ -55,12 +52,14 @@ public GetCimAssociatedInstanceCommand() [Parameter( Position = 1, ValueFromPipelineByPropertyName = true)] - public String Association + public string Association { get { return association; } + set { association = value; } } - private String association; + + private string association; /// /// The following is the definition of the input parameter "ResultClassName". @@ -68,37 +67,14 @@ public String Association /// the given instance. /// [Parameter] - public String ResultClassName + public string ResultClassName { get { return resultClassName; } + set { resultClassName = value; } } - private String resultClassName; - - /// - /// The following is the definition of the input parameter "AssociatorRole". - /// Specifies the name of the association role of the instances to be retrieved. - /// - //[Parameter(ValueFromPipelineByPropertyName = true)] - //public String AssociatorRole - //{ - // get { return associatorRole; } - // set { associatorRole = value; } - //} - //private String associatorRole; - /// - /// The following is the definition of the input parameter "SourceRole". - /// Specifies the name of the association role of the source instance where the - /// association traversal should begin. - /// - //[Parameter(ValueFromPipelineByPropertyName = true)] - //public String SourceRole - //{ - // get { return sourcerole; } - // set { sourcerole = value; } - //} - //private String sourcerole; + private string resultClassName; /// /// @@ -114,6 +90,7 @@ public String ResultClassName public CimInstance InputObject { get { return cimInstance; } + set { cimInstance = value; @@ -122,12 +99,13 @@ public CimInstance InputObject } /// - /// Property for internal usage purpose + /// Property for internal usage purpose. /// internal CimInstance CimInstance { get { return cimInstance; } } + private CimInstance cimInstance; /// @@ -136,12 +114,14 @@ internal CimInstance CimInstance /// is registered. /// [Parameter(ValueFromPipelineByPropertyName = true)] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; } } - private String nameSpace; + + private string nameSpace; /// /// The following is the definition of the input parameter "OperationTimeoutSec". @@ -155,8 +135,10 @@ public String Namespace public UInt32 OperationTimeoutSec { get { return operationTimeout; } + set { operationTimeout = value; } } + private UInt32 operationTimeout; /// @@ -169,12 +151,14 @@ public UInt32 OperationTimeoutSec public Uri ResourceUri { get { return resourceUri; } + set { this.resourceUri = value; base.SetParameter(value, nameResourceUri); } } + private Uri resourceUri; /// @@ -192,16 +176,18 @@ public Uri ResourceUri [Parameter( ParameterSetName = ComputerSetName)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computerName; } + set { computerName = value; base.SetParameter(value, nameComputerName); } } - private String[] computerName; + + private string[] computerName; /// /// The following is the definition of the input parameter "CimSession". @@ -215,12 +201,14 @@ public String[] ComputerName public Microsoft.Management.Infrastructure.CimSession[] CimSession { get { return cimSession; } + set { cimSession = value; base.SetParameter(value, nameCimSession); } } + private Microsoft.Management.Infrastructure.CimSession[] cimSession; /// @@ -234,8 +222,10 @@ public Microsoft.Management.Infrastructure.CimSession[] CimSession public SwitchParameter KeyOnly { get { return keyOnly; } + set { keyOnly = value; } } + private SwitchParameter keyOnly; #endregion @@ -249,7 +239,7 @@ protected override void BeginProcessing() { this.CmdletOperation = new CmdletOperationBase(this); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -262,9 +252,10 @@ protected override void ProcessRecord() { operation = this.CreateOperationAgent(); } + operation.GetCimAssociatedInstance(this); operation.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -274,7 +265,7 @@ protected override void EndProcessing() CimGetAssociatedInstance operation = this.GetOperationAgent(); if (operation != null) operation.ProcessRemainActions(this.CmdletOperation); - }//End EndProcessing() + } #endregion @@ -309,7 +300,7 @@ CimGetAssociatedInstance CreateOperationAgent() #region internal const strings /// - /// Noun of current cmdlet + /// Noun of current cmdlet. /// internal const string Noun = @"CimAssociatedInstance"; @@ -318,18 +309,14 @@ CimGetAssociatedInstance CreateOperationAgent() #region private members #region const string of parameter names - // internal const string nameAssociation = "Association"; internal const string nameCimInstance = "InputObject"; - // internal const string nameNamespace = "Namespace"; - // internal const string nameOperationTimeoutSec = "OperationTimeoutSec"; internal const string nameComputerName = "ComputerName"; internal const string nameCimSession = "CimSession"; internal const string nameResourceUri = "ResourceUri"; - // internal const string nameKeyOnly = "KeyOnly"; #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -358,7 +345,7 @@ CimGetAssociatedInstance CreateOperationAgent() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -366,5 +353,5 @@ CimGetAssociatedInstance CreateOperationAgent() { CimBaseCommand.ComputerSetName, new ParameterSetEntry(1, true) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimClassCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimClassCommand.cs index 58a8538e0776..a12da58c3560 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimClassCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimClassCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -32,7 +30,7 @@ public class GetCimClassCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public GetCimClassCommand() : base(parameters, parameterSets) @@ -55,12 +53,14 @@ public GetCimClassCommand() [Parameter( Position = 0, ValueFromPipelineByPropertyName = true)] - public String ClassName + public string ClassName { get { return className; } + set { className = value; } } - private String className; + + private string className; /// /// @@ -76,12 +76,14 @@ public String ClassName [Parameter( Position = 1, ValueFromPipelineByPropertyName = true)] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; } } - private String nameSpace; + + private string nameSpace; /// /// The following is the definition of the input parameter "OperationTimeoutSec". @@ -93,8 +95,10 @@ public String Namespace public UInt32 OperationTimeoutSec { get { return operationTimeout;} + set { operationTimeout = value; } } + private UInt32 operationTimeout; /// @@ -109,12 +113,14 @@ public UInt32 OperationTimeoutSec public CimSession[] CimSession { get { return cimSession;} + set { cimSession = value; base.SetParameter(value, nameCimSession); } } + private CimSession[] cimSession; /// @@ -130,16 +136,18 @@ public CimSession[] CimSession ValueFromPipelineByPropertyName = true, ParameterSetName = ComputerSetName)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computerName; } + set { computerName = value; base.SetParameter(value, nameComputerName); } } - private String[] computerName; + + private string[] computerName; /// /// @@ -149,12 +157,14 @@ public String[] ComputerName /// /// [Parameter(ValueFromPipelineByPropertyName = true)] - public String MethodName + public string MethodName { get { return methodName; } + set { methodName = value; } } - private String methodName; + + private string methodName; /// /// @@ -164,12 +174,14 @@ public String MethodName /// /// [Parameter(ValueFromPipelineByPropertyName = true)] - public String PropertyName + public string PropertyName { get { return propertyName; } + set { propertyName = value; } } - private String propertyName; + + private string propertyName; /// /// @@ -179,12 +191,14 @@ public String PropertyName /// /// [Parameter(ValueFromPipelineByPropertyName = true)] - public String QualifierName + public string QualifierName { get { return qualifierName; } + set { qualifierName = value; } } - private String qualifierName; + + private string qualifierName; #endregion @@ -197,7 +211,7 @@ protected override void BeginProcessing() { this.CmdletOperation = new CmdletOperationBase(this); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -210,9 +224,10 @@ protected override void ProcessRecord() { cimGetCimClass = CreateOperationAgent(); } + cimGetCimClass.GetCimClass(this); cimGetCimClass.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -224,7 +239,7 @@ protected override void EndProcessing() { cimGetCimClass.ProcessRemainActions(this.CmdletOperation); } - }//End EndProcessing() + } #endregion @@ -260,7 +275,7 @@ CimGetCimClass CreateOperationAgent() #region internal const strings /// - /// Noun of current cmdlet + /// Noun of current cmdlet. /// internal const string Noun = @"CimClass"; @@ -274,7 +289,7 @@ CimGetCimClass CreateOperationAgent() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -292,7 +307,7 @@ CimGetCimClass CreateOperationAgent() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -300,5 +315,5 @@ CimGetCimClass CreateOperationAgent() { CimBaseCommand.ComputerSetName, new ParameterSetEntry(0, true) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimInstanceCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimInstanceCommand.cs index a59208be6a8c..e9c296194882 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimInstanceCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimInstanceCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -13,7 +11,6 @@ #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -28,7 +25,7 @@ public class GetCimInstanceCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public GetCimInstanceCommand() : base(parameters, parameterSets) @@ -66,12 +63,14 @@ public GetCimInstanceCommand() public CimSession[] CimSession { get { return cimSession; } + set { cimSession = value; base.SetParameter(value, nameCimSession); } } + private CimSession[] cimSession; /// @@ -88,16 +87,18 @@ public CimSession[] CimSession Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ClassNameComputerSet)] - public String ClassName + public string ClassName { get { return className; } + set { this.className = value; base.SetParameter(value, nameClassName); } } - private String className; + + private string className; /// /// @@ -124,12 +125,14 @@ public String ClassName public Uri ResourceUri { get { return resourceUri; } + set { this.resourceUri = value; base.SetParameter(value, nameResourceUri); } } + private Uri resourceUri; /// @@ -155,16 +158,18 @@ public Uri ResourceUri [Parameter( ParameterSetName = CimBaseCommand.CimInstanceComputerSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computerName; } + set { computerName = value; base.SetParameter(value, nameComputerName); } } - private String[] computerName; + + private string[] computerName; /// /// @@ -180,12 +185,14 @@ public String[] ComputerName public SwitchParameter KeyOnly { get { return keyOnly; } + set { keyOnly = value; base.SetParameter(value, nameKeyOnly); } } + private SwitchParameter keyOnly; /// @@ -210,16 +217,18 @@ public SwitchParameter KeyOnly ParameterSetName = CimBaseCommand.QueryComputerSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QuerySessionSet)] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; base.SetParameter(value, nameNamespace); } } - private String nameSpace; + + private string nameSpace; /// /// @@ -235,8 +244,10 @@ public String Namespace public UInt32 OperationTimeoutSec { get { return operationTimeout; } + set { operationTimeout = value; } } + private UInt32 operationTimeout; /// @@ -266,6 +277,7 @@ public UInt32 OperationTimeoutSec public CimInstance InputObject { get { return cimInstance; } + set { cimInstance = value; @@ -274,12 +286,13 @@ public CimInstance InputObject } /// - /// Property for internal usage purpose + /// Property for internal usage purpose. /// internal CimInstance CimInstance { get { return cimInstance; } } + private CimInstance cimInstance; /// @@ -293,16 +306,18 @@ internal CimInstance CimInstance [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QuerySessionSet)] - public String Query + public string Query { get { return query; } + set { query = value; base.SetParameter(value, nameQuery); } } - private String query; + + private string query; /// /// @@ -320,16 +335,18 @@ public String Query [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ClassNameComputerSet)] - public String QueryDialect + public string QueryDialect { get { return queryDialect; } + set { queryDialect = value; base.SetParameter(value, nameQueryDialect); } } - private String queryDialect; + + private string queryDialect; /// /// @@ -349,12 +366,14 @@ public String QueryDialect public SwitchParameter Shallow { get { return shallow; } + set { shallow = value; base.SetParameter(value, nameShallow); } } + private SwitchParameter shallow; /// @@ -371,16 +390,18 @@ public SwitchParameter Shallow ParameterSetName = CimBaseCommand.ResourceUriSessionSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ResourceUriComputerSet)] - public String Filter + public string Filter { get { return filter; } + set { filter = value; base.SetParameter(value, nameFilter); } } - private String filter; + + private string filter; /// /// @@ -398,9 +419,10 @@ public String Filter ParameterSetName = CimBaseCommand.ResourceUriComputerSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Alias("SelectProperties")] - public String[] Property + public string[] Property { get { return property; } + set { property = value; @@ -408,13 +430,14 @@ public String[] Property } } /// - /// Property for internal usage + /// Property for internal usage. /// - internal String[] SelectProperties + internal string[] SelectProperties { get { return property; } } - private String[] property; + + private string[] property; #endregion @@ -427,7 +450,7 @@ protected override void BeginProcessing() { this.CmdletOperation = new CmdletOperationBase(this); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -441,9 +464,10 @@ protected override void ProcessRecord() { cimGetInstance = CreateOperationAgent(); } + cimGetInstance.GetCimInstance(this); cimGetInstance.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -455,7 +479,7 @@ protected override void EndProcessing() { cimGetInstance.ProcessRemainActions(this.CmdletOperation); } - }//End EndProcessing() + } #endregion @@ -489,7 +513,7 @@ CimGetInstance CreateOperationAgent() } /// - /// check argument value + /// Check argument value. /// private void CheckArgument() { @@ -526,7 +550,7 @@ private void CheckArgument() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -630,7 +654,7 @@ private void CheckArgument() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -644,5 +668,5 @@ private void CheckArgument() { CimBaseCommand.QuerySessionSet, new ParameterSetEntry(2) } }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimSessionCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimSessionCommand.cs index 57e610ddcc65..f621f249e666 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimSessionCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/GetCimSessionCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -10,7 +8,6 @@ using System.Management.Automation; #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -25,7 +22,7 @@ public sealed class GetCimSessionCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public GetCimSessionCommand() : base(parameters, parameterSets) @@ -59,16 +56,18 @@ public GetCimSessionCommand() ValueFromPipelineByPropertyName = true, ParameterSetName = ComputerNameSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computername;} + set { computername = value; base.SetParameter(value, nameComputerName); } } - private String[] computername; + + private string[] computername; /// /// The following is the definition of the input parameter "Id". @@ -82,17 +81,19 @@ public String[] ComputerName public UInt32[] Id { get { return id;} + set { id = value; base.SetParameter(value, nameId); } } + private UInt32[] id; /// /// The following is the definition of the input parameter "InstanceID". - /// Specifies one or Session Instance IDs + /// Specifies one or Session Instance IDs. /// [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, @@ -101,12 +102,14 @@ public UInt32[] Id public Guid[] InstanceId { get { return instanceid;} + set { instanceid = value; base.SetParameter(value, nameInstanceId); } } + private Guid[] instanceid; /// @@ -118,16 +121,18 @@ public Guid[] InstanceId ValueFromPipelineByPropertyName = true, ParameterSetName = NameSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Name + public string[] Name { get { return name;} + set { name = value; base.SetParameter(value, nameName); } } - private String[] name; + + private string[] name; #endregion @@ -139,7 +144,7 @@ protected override void BeginProcessing() { cimGetSession = new CimGetSession(); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -148,13 +153,13 @@ protected override void ProcessRecord() { base.CheckParameterSet(); cimGetSession.GetCimSession(this); - }//End ProcessRecord() + } #endregion #region private members /// - /// object used to search CimSession from cache + /// object used to search CimSession from cache. /// private CimGetSession cimGetSession; @@ -166,7 +171,7 @@ protected override void ProcessRecord() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -193,7 +198,7 @@ protected override void ProcessRecord() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -203,5 +208,5 @@ protected override void ProcessRecord() { CimBaseCommand.NameSet, new ParameterSetEntry(1) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/InvokeCimMethodCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/InvokeCimMethodCommand.cs index f67ee6cb5ba6..3585c464e8cd 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/InvokeCimMethodCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/InvokeCimMethodCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -11,7 +9,6 @@ using System.Management.Automation; #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -30,7 +27,7 @@ public class InvokeCimMethodCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public InvokeCimMethodCommand() : base(parameters, parameterSets) @@ -55,16 +52,18 @@ public InvokeCimMethodCommand() ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ClassNameSessionSet)] [Alias("Class")] - public String ClassName + public string ClassName { get { return className; } + set { className = value; base.SetParameter(value, nameClassName); } } - private String className; + + private string className; /// /// @@ -85,12 +84,14 @@ public String ClassName public Uri ResourceUri { get { return resourceUri; } + set { this.resourceUri = value; base.SetParameter(value, nameResourceUri); } } + private Uri resourceUri; /// @@ -108,12 +109,14 @@ public Uri ResourceUri public CimClass CimClass { get { return cimClass; } + set { cimClass = value; base.SetParameter(value, nameCimClass); } } + private CimClass cimClass; /// @@ -129,12 +132,14 @@ public CimClass CimClass public string Query { get { return query; } + set { query = value; base.SetParameter(value, nameQuery); } } + private string query; /// @@ -148,21 +153,23 @@ public string Query ParameterSetName = CimBaseCommand.QueryComputerSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QuerySessionSet)] - public String QueryDialect + public string QueryDialect { get { return queryDialect; } + set { queryDialect = value; base.SetParameter(value, nameQueryDialect); } } - private String queryDialect; + + private string queryDialect; /// /// The following is the definition of the input parameter "InputObject". /// Takes a CimInstance object retrieved by a Get-CimInstance call. - /// Invoke the method against the given instance + /// Invoke the method against the given instance. /// [Parameter(Mandatory = true, Position = 0, @@ -176,6 +183,7 @@ public String QueryDialect public CimInstance InputObject { get { return cimInstance; } + set { cimInstance = value; @@ -184,12 +192,13 @@ public CimInstance InputObject } /// - /// Property for internal usage purpose + /// Property for internal usage purpose. /// internal CimInstance CimInstance { get { return cimInstance; } } + private CimInstance cimInstance; /// @@ -218,9 +227,10 @@ internal CimInstance CimInstance ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ResourceUriComputerSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computerName; } + set { DebugHelper.WriteLogEx(); @@ -228,7 +238,8 @@ public String[] ComputerName base.SetParameter(value, nameComputerName); } } - private String[] computerName; + + private string[] computerName; /// /// @@ -259,12 +270,14 @@ public String[] ComputerName public CimSession[] CimSession { get { return cimSession; } + set { cimSession = value; base.SetParameter(value, nameCimSession); } } + private CimSession[] cimSession; /// @@ -277,8 +290,10 @@ public CimSession[] CimSession public IDictionary Arguments { get { return arguments; } + set { arguments = value; } } + private IDictionary arguments; /// @@ -289,16 +304,18 @@ public IDictionary Arguments Position = 2, ValueFromPipelineByPropertyName = true)] [Alias("Name")] - public String MethodName + public string MethodName { get { return methodName; } + set { methodName = value; base.SetParameter(value, nameMethodName); } } - private String methodName; + + private string methodName; /// /// The following is the definition of the input parameter "Namespace". @@ -318,16 +335,18 @@ public String MethodName [Parameter( ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ResourceUriSessionSet)] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; base.SetParameter(value, nameNamespace); } } - private String nameSpace; + + private string nameSpace; /// /// The following is the definition of the input parameter "OperationTimeoutSec". @@ -339,8 +358,10 @@ public String Namespace public UInt32 OperationTimeoutSec { get { return operationTimeout; } + set { operationTimeout = value; } } + private UInt32 operationTimeout; #endregion @@ -357,9 +378,10 @@ protected override void BeginProcessing() { cimInvokeMethod = CreateOperationAgent(); } + this.CmdletOperation = new CmdletOperationInvokeCimMethod(this, cimInvokeMethod); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -371,7 +393,7 @@ protected override void ProcessRecord() CimInvokeCimMethod cimInvokeMethod = this.GetOperationAgent(); cimInvokeMethod.InvokeCimMethod(this); cimInvokeMethod.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -383,7 +405,7 @@ protected override void EndProcessing() { cimInvokeMethod.ProcessRemainActions(this.CmdletOperation); } - }//End EndProcessing() + } #endregion @@ -415,7 +437,7 @@ CimInvokeCimMethod CreateOperationAgent() } /// - /// check argument value + /// Check argument value. /// private void CheckArgument() { @@ -449,7 +471,7 @@ private void CheckArgument() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -536,7 +558,7 @@ private void CheckArgument() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -552,5 +574,5 @@ private void CheckArgument() { CimBaseCommand.CimClassSessionSet, new ParameterSetEntry(3) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/Microsoft.Management.Infrastructure.CimCmdlets.csproj b/src/Microsoft.Management.Infrastructure.CimCmdlets/Microsoft.Management.Infrastructure.CimCmdlets.csproj index d7db6f540259..95516295d7b9 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/Microsoft.Management.Infrastructure.CimCmdlets.csproj +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/Microsoft.Management.Infrastructure.CimCmdlets.csproj @@ -1,7 +1,7 @@  - PowerShell Core's Microsoft.Management.Infrastructure.CimCmdlets project + PowerShell's Microsoft.Management.Infrastructure.CimCmdlets project $(NoWarn);CS1570;CS1572;CS1573;CS1574;CS1584;CS1587;CS1591 Microsoft.Management.Infrastructure.CimCmdlets @@ -10,9 +10,4 @@ - - $(DefineConstants);CORECLR - portable - - diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimInstanceCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimInstanceCommand.cs index c843acdb0456..058ddcd3cbcd 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimInstanceCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimInstanceCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -11,7 +9,6 @@ using System.Management.Automation; #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -31,7 +28,7 @@ public class NewCimInstanceCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public NewCimInstanceCommand() : base(parameters, parameterSets) @@ -57,16 +54,18 @@ public NewCimInstanceCommand() Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ClassNameComputerSet)] - public String ClassName + public string ClassName { get { return className; } + set { className = value; base.SetParameter(value, nameClassName); } } - private String className; + + private string className; /// /// @@ -83,12 +82,14 @@ public String ClassName public Uri ResourceUri { get { return resourceUri; } + set { this.resourceUri = value; base.SetParameter(value, nameResourceUri); } } + private Uri resourceUri; /// @@ -113,16 +114,18 @@ public Uri ResourceUri ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ResourceUriComputerSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Key + public string[] Key { get { return key; } + set { key = value; base.SetParameter(value, nameKey); } } - private String[] key; + + private string[] key; /// /// The following is the definition of the input parameter "CimClass". @@ -141,12 +144,14 @@ public String[] Key public CimClass CimClass { get { return cimClass; } + set { cimClass = value; base.SetParameter(value, nameCimClass); } } + private CimClass cimClass; /// @@ -166,8 +171,10 @@ public CimClass CimClass public IDictionary Property { get { return property; } + set { property = value; } } + private IDictionary property; /// @@ -187,16 +194,18 @@ public IDictionary Property [Parameter( ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.ResourceUriComputerSet)] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; base.SetParameter(value, nameNamespace); } } - private String nameSpace; + + private string nameSpace; /// /// The following is the definition of the input parameter "OperationTimeoutSec". @@ -208,8 +217,10 @@ public String Namespace public UInt32 OperationTimeoutSec { get { return operationTimeout; } + set { operationTimeout = value; } } + private UInt32 operationTimeout; /// @@ -234,12 +245,14 @@ public UInt32 OperationTimeoutSec public CimSession[] CimSession { get { return cimSession; } + set { cimSession = value; base.SetParameter(value, nameCimSession); } } + private CimSession[] cimSession; /// @@ -261,16 +274,18 @@ public CimSession[] CimSession ValueFromPipelineByPropertyName = true, ParameterSetName = CimClassComputerSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computerName; } + set { computerName = value; base.SetParameter(value, nameComputerName); } } - private String[] computerName; + + private string[] computerName; /// /// @@ -290,11 +305,13 @@ public String[] ComputerName public SwitchParameter ClientOnly { get { return clientOnly; } + set { clientOnly = value; base.SetParameter(value, nameClientOnly); } } + private SwitchParameter clientOnly; #endregion @@ -308,7 +325,7 @@ protected override void BeginProcessing() { this.CmdletOperation = new CmdletOperationBase(this); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -320,15 +337,16 @@ protected override void ProcessRecord() if (this.ClientOnly) { string conflictParameterName = null; - if (null != this.ComputerName) + if (this.ComputerName != null) { conflictParameterName = @"ComputerName"; } - else if (null != this.CimSession) + else if (this.CimSession != null) { conflictParameterName = @"CimSession"; } - if (null != conflictParameterName) + + if (conflictParameterName != null) { ThrowConflictParameterWasSet(@"New-CimInstance", conflictParameterName, @"ClientOnly"); return; @@ -340,9 +358,10 @@ protected override void ProcessRecord() { cimNewCimInstance = CreateOperationAgent(); } + cimNewCimInstance.NewCimInstance(this); cimNewCimInstance.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -354,7 +373,7 @@ protected override void EndProcessing() { cimNewCimInstance.ProcessRemainActions(this.CmdletOperation); } - }//End EndProcessing() + } #endregion @@ -386,7 +405,7 @@ CimNewCimInstance CreateOperationAgent() } /// - /// check argument value + /// Check argument value. /// private void CheckArgument() { @@ -418,7 +437,7 @@ private void CheckArgument() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -481,7 +500,7 @@ private void CheckArgument() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -493,5 +512,5 @@ private void CheckArgument() { CimBaseCommand.ResourceUriComputerSet, new ParameterSetEntry(1) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionCommand.cs index 8e601f60e921..39db6e2a018c 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -11,7 +9,6 @@ #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -36,12 +33,14 @@ public sealed class NewCimSessionCommand : CimBaseCommand public PasswordAuthenticationMechanism Authentication { get { return authentication;} + set { authentication = value; authenticationSet = true; } } + private PasswordAuthenticationMechanism authentication; private bool authenticationSet = false; @@ -55,8 +54,10 @@ public PasswordAuthenticationMechanism Authentication public PSCredential Credential { get { return credential; } + set { credential = value; } } + private PSCredential credential; /// @@ -65,12 +66,14 @@ public PSCredential Credential /// [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CertificateParameterSet)] - public String CertificateThumbprint + public string CertificateThumbprint { get { return certificatethumbprint; } + set { certificatethumbprint = value; } } - private String certificatethumbprint; + + private string certificatethumbprint; /// /// The following is the definition of the input parameter "ComputerName". @@ -83,12 +86,14 @@ public String CertificateThumbprint ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computername;} + set { computername = value; } } - private String[] computername; + + private string[] computername; /// /// @@ -102,12 +107,14 @@ public String[] ComputerName /// /// [Parameter(ValueFromPipelineByPropertyName = true)] - public String Name + public string Name { get { return name;} + set { name = value; } } - private String name; + + private string name; /// /// @@ -124,12 +131,14 @@ public String Name public UInt32 OperationTimeoutSec { get { return operationTimeout; } + set { operationTimeout = value; operationTimeoutSet = true; } } + private UInt32 operationTimeout; internal bool operationTimeoutSet = false; @@ -143,11 +152,13 @@ public UInt32 OperationTimeoutSec public SwitchParameter SkipTestConnection { get { return skipTestConnection; } + set { skipTestConnection = value; } } + private SwitchParameter skipTestConnection; /// @@ -159,12 +170,14 @@ public SwitchParameter SkipTestConnection public UInt32 Port { get { return port; } + set { port = value; portSet = true; } } + private UInt32 port; private bool portSet = false; @@ -185,8 +198,10 @@ public UInt32 Port public Microsoft.Management.Infrastructure.Options.CimSessionOptions SessionOption { get { return sessionOption; } + set { sessionOption = value; } } + private Microsoft.Management.Infrastructure.Options.CimSessionOptions sessionOption; #endregion @@ -201,7 +216,7 @@ protected override void BeginProcessing() cimNewSession = new CimNewSession(); this.CmdletOperation = new CmdletOperationTestCimSession(this, this.cimNewSession); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -213,7 +228,7 @@ protected override void ProcessRecord() BuildSessionOptions(out outputOptions, out outputCredential); cimNewSession.NewCimSession(this, outputOptions, outputCredential); cimNewSession.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -221,15 +236,15 @@ protected override void ProcessRecord() protected override void EndProcessing() { cimNewSession.ProcessRemainActions(this.CmdletOperation); - }//End EndProcessing() + } #endregion #region helper methods /// - /// Build a CimSessionOptions, used to create CimSession + /// Build a CimSessionOptions, used to create CimSession. /// - /// Null means no prefer CimSessionOptions + /// Null means no prefer CimSessionOptions. internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCredential outputCredential) { DebugHelper.WriteLogEx(); @@ -247,6 +262,7 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr options = new DComSessionOptions(this.sessionOption as DComSessionOptions); } } + outputOptions = null; outputCredential = null; if (options != null) @@ -261,11 +277,13 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr conflict = true; parameterName = @"CertificateThumbprint"; } + if (portSet) { conflict = true; parameterName = @"Port"; } + if (conflict) { ThrowConflictParameterWasSet(@"New-CimSession", parameterName, @"DComSessionOptions"); @@ -273,6 +291,7 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr } } } + if (portSet || (this.CertificateThumbprint != null)) { WSManSessionOptions wsmanOptions = (options == null) ? new WSManSessionOptions() : options as WSManSessionOptions; @@ -281,13 +300,16 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr wsmanOptions.DestinationPort = this.Port; portSet = false; } + if (this.CertificateThumbprint != null) { CimCredential credentials = new CimCredential(CertificateAuthenticationMechanism.Default, this.CertificateThumbprint); wsmanOptions.AddDestinationCredentials(credentials); } + options = wsmanOptions; } + if (this.operationTimeoutSet) { if (options != null) @@ -295,6 +317,7 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr options.Timeout = TimeSpan.FromSeconds((double)this.OperationTimeoutSec); } } + if (this.authenticationSet || (this.credential != null)) { PasswordAuthenticationMechanism authentication = this.authenticationSet ? this.Authentication : PasswordAuthenticationMechanism.Default; @@ -302,6 +325,7 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr { this.authenticationSet = false; } + CimCredential credentials = CreateCimCredentials(this.Credential, authentication, @"New-CimSession", @"Authentication"); if (credentials == null) { @@ -316,6 +340,7 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr options.AddDestinationCredentials(credentials); } } + DebugHelper.WriteLogEx("Set outputOptions: {0}", 1, outputOptions); outputOptions = options; } @@ -335,7 +360,7 @@ internal void BuildSessionOptions(out CimSessionOptions outputOptions, out CimCr #region IDisposable /// - /// Clean up resources + /// Clean up resources. /// protected override void DisposeInternal() { @@ -348,5 +373,5 @@ protected override void DisposeInternal() } } #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs index c03352af0121..f22cd2a8b539 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -12,7 +10,6 @@ using Microsoft.Management.Infrastructure.Options; #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -45,7 +42,7 @@ public sealed class NewCimSessionOptionCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public NewCimSessionOptionCommand() : base(parameters, parameterSets) @@ -65,6 +62,7 @@ public NewCimSessionOptionCommand() public SwitchParameter NoEncryption { get { return noEncryption; } + set { noEncryption = value; @@ -72,18 +70,20 @@ public SwitchParameter NoEncryption base.SetParameter(value, nameNoEncryption); } } + private SwitchParameter noEncryption; private bool noEncryptionSet = false; /// /// The following is the definition of the input parameter "CertificateCACheck". - /// Switch indicating if Certificate Authority should be validated + /// Switch indicating if Certificate Authority should be validated. /// [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = WSManParameterSet)] public SwitchParameter SkipCACheck { get { return skipCACheck; } + set { skipCACheck = value; @@ -91,18 +91,20 @@ public SwitchParameter SkipCACheck base.SetParameter(value, nameSkipCACheck); } } + private SwitchParameter skipCACheck; private bool skipCACheckSet = false; /// /// The following is the definition of the input parameter "CertificateCNCheck". - /// Switch indicating if Certificate Name should be validated + /// Switch indicating if Certificate Name should be validated. /// [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = WSManParameterSet)] public SwitchParameter SkipCNCheck { get { return skipCNCheck; } + set { skipCNCheck = value; @@ -110,6 +112,7 @@ public SwitchParameter SkipCNCheck base.SetParameter(value, nameSkipCNCheck); } } + private SwitchParameter skipCNCheck; private bool skipCNCheckSet = false; @@ -122,6 +125,7 @@ public SwitchParameter SkipCNCheck public SwitchParameter SkipRevocationCheck { get { return skipRevocationCheck; } + set { skipRevocationCheck = value; @@ -129,18 +133,20 @@ public SwitchParameter SkipRevocationCheck base.SetParameter(value, nameSkipRevocationCheck); } } + private SwitchParameter skipRevocationCheck; private bool skipRevocationCheckSet = false; /// /// The following is the definition of the input parameter "EncodePortInServicePrincipalName". - /// Switch indicating if to encode Port In Service Principal Name + /// Switch indicating if to encode Port In Service Principal Name. /// [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = WSManParameterSet)] public SwitchParameter EncodePortInServicePrincipalName { get { return encodeportinserviceprincipalname; } + set { encodeportinserviceprincipalname = value; @@ -148,6 +154,7 @@ public SwitchParameter EncodePortInServicePrincipalName base.SetParameter(value, nameEncodePortInServicePrincipalName); } } + private SwitchParameter encodeportinserviceprincipalname; private bool encodeportinserviceprincipalnameSet = false; @@ -162,6 +169,7 @@ public SwitchParameter EncodePortInServicePrincipalName public PacketEncoding Encoding { get { return encoding; } + set { encoding = value; @@ -169,6 +177,7 @@ public PacketEncoding Encoding base.SetParameter(value, nameEncoding); } } + private PacketEncoding encoding; private bool encodingSet = false; @@ -182,12 +191,14 @@ public PacketEncoding Encoding public Uri HttpPrefix { get { return httpprefix; } + set { httpprefix = value; base.SetParameter(value, nameHttpPrefix); } } + private Uri httpprefix; /// @@ -199,6 +210,7 @@ public Uri HttpPrefix public UInt32 MaxEnvelopeSizeKB { get { return maxenvelopesizekb; } + set { maxenvelopesizekb = value; @@ -206,6 +218,7 @@ public UInt32 MaxEnvelopeSizeKB base.SetParameter(value, nameMaxEnvelopeSizeKB); } } + private UInt32 maxenvelopesizekb; private bool maxenvelopesizekbSet = false; @@ -218,6 +231,7 @@ public UInt32 MaxEnvelopeSizeKB public PasswordAuthenticationMechanism ProxyAuthentication { get { return proxyAuthentication; } + set { proxyAuthentication = value; @@ -225,6 +239,7 @@ public PasswordAuthenticationMechanism ProxyAuthentication base.SetParameter(value, nameProxyAuthentication); } } + private PasswordAuthenticationMechanism proxyAuthentication; private bool proxyauthenticationSet = false; @@ -233,16 +248,18 @@ public PasswordAuthenticationMechanism ProxyAuthentication /// [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = WSManParameterSet)] - public String ProxyCertificateThumbprint + public string ProxyCertificateThumbprint { get { return proxycertificatethumbprint; } + set { proxycertificatethumbprint = value; base.SetParameter(value, nameProxyCertificateThumbprint); } } - private String proxycertificatethumbprint; + + private string proxycertificatethumbprint; /// /// The following is the definition of the input parameter "ProxyCredential". @@ -253,12 +270,14 @@ public String ProxyCertificateThumbprint public PSCredential ProxyCredential { get { return proxycredential; } + set { proxycredential = value; base.SetParameter(value, nameProxyCredential); } } + private PSCredential proxycredential; /// @@ -271,6 +290,7 @@ public PSCredential ProxyCredential public ProxyType ProxyType { get { return proxytype; } + set { proxytype = value; @@ -278,6 +298,7 @@ public ProxyType ProxyType base.SetParameter(value, nameProxyType); } } + private ProxyType proxytype; private bool proxytypeSet = false; @@ -290,6 +311,7 @@ public ProxyType ProxyType public SwitchParameter UseSsl { get { return usessl; } + set { usessl = value; @@ -297,6 +319,7 @@ public SwitchParameter UseSsl base.SetParameter(value, nameUseSsl); } } + private SwitchParameter usessl; private bool usesslSet = false; @@ -309,6 +332,7 @@ public SwitchParameter UseSsl public ImpersonationType Impersonation { get { return impersonation; } + set { impersonation = value; @@ -316,6 +340,7 @@ public ImpersonationType Impersonation base.SetParameter(value, nameImpersonation); } } + private ImpersonationType impersonation; private bool impersonationSet = false; @@ -328,6 +353,7 @@ public ImpersonationType Impersonation public SwitchParameter PacketIntegrity { get { return packetintegrity; } + set { packetintegrity = value; @@ -335,6 +361,7 @@ public SwitchParameter PacketIntegrity base.SetParameter(value, namePacketIntegrity); } } + private SwitchParameter packetintegrity; private bool packetintegritySet = false; @@ -347,6 +374,7 @@ public SwitchParameter PacketIntegrity public SwitchParameter PacketPrivacy { get { return packetprivacy; } + set { packetprivacy = value; @@ -354,12 +382,13 @@ public SwitchParameter PacketPrivacy base.SetParameter(value, namePacketPrivacy); } } + private SwitchParameter packetprivacy; private bool packetprivacySet = false; /// /// The following is the definition of the input parameter "Protocol". - /// Switch indicating if to encode Port In Service Principal Name + /// Switch indicating if to encode Port In Service Principal Name. /// [Parameter( Mandatory = true, @@ -369,36 +398,42 @@ public SwitchParameter PacketPrivacy public ProtocolType Protocol { get { return protocol; } + set { protocol = value; base.SetParameter(value, nameProtocol); } } + private ProtocolType protocol; /// /// The following is the definition of the input parameter "UICulture". - /// Specifies the UI Culture to use. i.e. en-us, ar-sa + /// Specifies the UI Culture to use. i.e. en-us, ar-sa. /// [Parameter(ValueFromPipelineByPropertyName = true)] public CultureInfo UICulture { get { return uiculture; } + set { uiculture = value; } } + private CultureInfo uiculture; /// /// The following is the definition of the input parameter "Culture". - /// Specifies the culture to use. i.e. en-us, ar-sa + /// Specifies the culture to use. i.e. en-us, ar-sa. /// [Parameter(ValueFromPipelineByPropertyName = true)] public CultureInfo Culture { get { return culture; } + set { culture = value; } } + private CultureInfo culture; #endregion @@ -412,7 +447,7 @@ protected override void BeginProcessing() { this.CmdletOperation = new CmdletOperationBase(this); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -427,11 +462,13 @@ protected override void ProcessRecord() { options = CreateWSMANSessionOptions(); } + break; case DcomParameterSet: { options = CreateDComSessionOptions(); } + break; case ProtocolNameParameterSet: switch (Protocol) @@ -444,36 +481,40 @@ protected override void ProcessRecord() options = CreateWSMANSessionOptions(); break; } + break; default: return; } + if (options != null) { if (this.Culture != null) { options.Culture = this.Culture; } + if (this.UICulture != null) { options.UICulture = this.UICulture; } + this.WriteObject(options); } - }//End ProcessRecord() + } /// /// EndProcessing method. /// protected override void EndProcessing() { - }//End EndProcessing() + } #endregion #region helper functions /// - /// Create DComSessionOptions + /// Create DComSessionOptions. /// /// internal DComSessionOptions CreateDComSessionOptions() @@ -488,6 +529,7 @@ internal DComSessionOptions CreateDComSessionOptions() { dcomoptions.Impersonation = ImpersonationType.Impersonate; } + if (this.packetintegritySet) { dcomoptions.PacketIntegrity = this.packetintegrity; @@ -497,6 +539,7 @@ internal DComSessionOptions CreateDComSessionOptions() { dcomoptions.PacketIntegrity = true; } + if (this.packetprivacySet) { dcomoptions.PacketPrivacy = this.PacketPrivacy; @@ -506,11 +549,12 @@ internal DComSessionOptions CreateDComSessionOptions() { dcomoptions.PacketPrivacy = true; } + return dcomoptions; } /// - /// Create WSMANSessionOptions + /// Create WSMANSessionOptions. /// /// internal WSManSessionOptions CreateWSMANSessionOptions() @@ -525,6 +569,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.NoEncryption = false; } + if (this.skipCACheckSet) { wsmanoptions.CertCACheck = false; @@ -534,6 +579,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.CertCACheck = true; } + if (this.skipCNCheckSet) { wsmanoptions.CertCNCheck = false; @@ -543,6 +589,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.CertCNCheck = true; } + if (this.skipRevocationCheckSet) { wsmanoptions.CertRevocationCheck = false; @@ -552,6 +599,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.CertRevocationCheck = true; } + if (this.encodeportinserviceprincipalnameSet) { wsmanoptions.EncodePortInServicePrincipalName = this.EncodePortInServicePrincipalName; @@ -561,6 +609,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.EncodePortInServicePrincipalName = false; } + if (this.encodingSet) { wsmanoptions.PacketEncoding = this.Encoding; @@ -569,10 +618,12 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.PacketEncoding = PacketEncoding.Utf8; } + if (this.HttpPrefix != null) { wsmanoptions.HttpUrlPrefix = this.HttpPrefix; } + if (this.maxenvelopesizekbSet) { wsmanoptions.MaxEnvelopeSize = this.MaxEnvelopeSizeKB; @@ -581,11 +632,13 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.MaxEnvelopeSize = 0; } - if (!String.IsNullOrWhiteSpace(this.ProxyCertificateThumbprint)) + + if (!string.IsNullOrWhiteSpace(this.ProxyCertificateThumbprint)) { CimCredential credentials = new CimCredential(CertificateAuthenticationMechanism.Default, this.ProxyCertificateThumbprint); wsmanoptions.AddProxyCredentials(credentials); } + if (this.proxyauthenticationSet) { this.proxyauthenticationSet = false; @@ -605,6 +658,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() } } } + if (this.proxytypeSet) { wsmanoptions.ProxyType = this.ProxyType; @@ -614,6 +668,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.ProxyType = Options.ProxyType.WinHttp; } + if (this.usesslSet) { wsmanoptions.UseSsl = this.UseSsl; @@ -623,6 +678,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { wsmanoptions.UseSsl = false; } + wsmanoptions.DestinationPort = 0; return wsmanoptions; } @@ -651,7 +707,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -752,7 +808,7 @@ internal WSManSessionOptions CreateWSMANSessionOptions() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -761,5 +817,5 @@ internal WSManSessionOptions CreateWSMANSessionOptions() { CimBaseCommand.WSManParameterSet, new ParameterSetEntry(0) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/RegisterCimIndicationCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/RegisterCimIndicationCommand.cs index 39ce6cfcd627..17da1ae330a9 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/RegisterCimIndicationCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/RegisterCimIndicationCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -11,7 +9,6 @@ using Microsoft.PowerShell.Commands; #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -37,12 +34,14 @@ public class RegisterCimIndicationCommand : ObjectEventRegistrationBase /// /// [Parameter] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; } } - private String nameSpace; + + private string nameSpace; /// /// The following is the definition of the input parameter "ClassName". @@ -55,16 +54,18 @@ public String Namespace [Parameter(Mandatory = true, Position = 0, ParameterSetName = CimBaseCommand.ClassNameComputerSet)] - public String ClassName + public string ClassName { get { return className; } + set { className = value; this.SetParameter(value, nameClassName); } } - private String className; + + private string className; /// /// The following is the definition of the input parameter "Query". @@ -78,16 +79,18 @@ public String ClassName Mandatory = true, Position = 0, ParameterSetName = CimBaseCommand.QueryExpressionComputerSet)] - public String Query + public string Query { get { return query; } + set { query = value; this.SetParameter(value, nameQuery); } } - private String query; + + private string query; /// /// @@ -98,16 +101,18 @@ public String Query /// [Parameter(ParameterSetName = CimBaseCommand.QueryExpressionComputerSet)] [Parameter(ParameterSetName = CimBaseCommand.QueryExpressionSessionSet)] - public String QueryDialect + public string QueryDialect { get { return queryDialect; } + set { queryDialect = value; this.SetParameter(value, nameQueryDialect); } } - private String queryDialect; + + private string queryDialect; /// /// The following is the definition of the input parameter "OperationTimeoutSec". @@ -119,8 +124,10 @@ public String QueryDialect public UInt32 OperationTimeoutSec { get { return operationTimeout; } + set { operationTimeout = value; } } + private UInt32 operationTimeout; /// @@ -136,12 +143,14 @@ public UInt32 OperationTimeoutSec public CimSession CimSession { get { return cimSession; } + set { cimSession = value; this.SetParameter(value, nameCimSession); } } + private CimSession cimSession; /// @@ -152,23 +161,25 @@ public CimSession CimSession [Alias(CimBaseCommand.AliasCN, CimBaseCommand.AliasServerName)] [Parameter(ParameterSetName = CimBaseCommand.QueryExpressionComputerSet)] [Parameter(ParameterSetName = CimBaseCommand.ClassNameComputerSet)] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; this.SetParameter(value, nameComputerName); } } - private String computername; + + private string computername; #endregion /// - /// Returns the object that generates events to be monitored + /// Returns the object that generates events to be monitored. /// - protected override Object GetSourceObject() + protected override object GetSourceObject() { CimIndicationWatcher watcher = null; string parameterSetName = null; @@ -180,6 +191,7 @@ protected override Object GetSourceObject() { this.parameterBinder.reset(); } + string tempQueryExpression = string.Empty; switch (parameterSetName) { @@ -191,9 +203,10 @@ protected override Object GetSourceObject() case CimBaseCommand.ClassNameComputerSet: // validate the classname this.CheckArgument(); - tempQueryExpression = String.Format(CultureInfo.CurrentCulture, "Select * from {0}", this.ClassName); + tempQueryExpression = string.Format(CultureInfo.CurrentCulture, "Select * from {0}", this.ClassName); break; } + switch (parameterSetName) { case CimBaseCommand.QueryExpressionSessionSet: @@ -201,25 +214,29 @@ protected override Object GetSourceObject() { watcher = new CimIndicationWatcher(this.CimSession, this.Namespace, this.QueryDialect, tempQueryExpression, this.OperationTimeoutSec); } + break; case CimBaseCommand.QueryExpressionComputerSet: case CimBaseCommand.ClassNameComputerSet: { watcher = new CimIndicationWatcher(this.ComputerName, this.Namespace, this.QueryDialect, tempQueryExpression, this.OperationTimeoutSec); } + break; } + if (watcher != null) { watcher.SetCmdlet(this); } + return watcher; } /// - /// Returns the event name to be monitored on the input object + /// Returns the event name to be monitored on the input object. /// - protected override String GetSourceObjectEventName() + protected override string GetSourceObjectEventName() { return "CimIndicationArrived"; } @@ -241,7 +258,7 @@ protected override void EndProcessing() DebugHelper.WriteLog("RegisterCimIndicationCommand::EndProcessing subscribe to Unsubscribed event", 4); newSubscriber.Unsubscribed += new PSEventUnsubscribedEventHandler(newSubscriber_Unsubscribed); } - }//End EndProcessing() + } /// /// @@ -264,7 +281,7 @@ protected override void EndProcessing() #region private members /// - /// check argument value + /// Check argument value. /// private void CheckArgument() { @@ -272,13 +289,13 @@ private void CheckArgument() } /// - /// Parameter binder used to resolve parameter set name + /// Parameter binder used to resolve parameter set name. /// private ParameterBinder parameterBinder = new ParameterBinder( parameters, parameterSets); /// - /// Set the parameter + /// Set the parameter. /// /// private void SetParameter(object value, string parameterName) @@ -287,6 +304,7 @@ private void SetParameter(object value, string parameterName) { return; } + this.parameterBinder.SetParameter(parameterName, true); } @@ -299,7 +317,7 @@ private void SetParameter(object value, string parameterName) #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -336,7 +354,7 @@ private void SetParameter(object value, string parameterName) }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -347,5 +365,5 @@ private void SetParameter(object value, string parameterName) }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimInstanceCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimInstanceCommand.cs index 6544f9d44272..c542499906de 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimInstanceCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimInstanceCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -12,7 +10,6 @@ #endregion - namespace Microsoft.Management.Infrastructure.CimCmdlets { /// @@ -29,7 +26,7 @@ public class RemoveCimInstanceCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public RemoveCimInstanceCommand() : base(parameters, parameterSets) @@ -56,14 +53,15 @@ public RemoveCimInstanceCommand() public CimSession[] CimSession { get { return cimSession; } + set { cimSession = value; base.SetParameter(value, nameCimSession); } } - private CimSession[] cimSession; + private CimSession[] cimSession; /// /// @@ -78,12 +76,14 @@ public CimSession[] CimSession public Uri ResourceUri { get { return resourceUri; } + set { this.resourceUri = value; base.SetParameter(value, nameResourceUri); } } + private Uri resourceUri; /// @@ -96,16 +96,18 @@ public Uri ResourceUri [Parameter( ParameterSetName = CimBaseCommand.CimInstanceComputerSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computername; } + set { computername = value; base.SetParameter(value, nameComputerName); } } - private String[] computername; + + private string[] computername; /// /// The following is the definition of the input parameter "Namespace". @@ -119,16 +121,18 @@ public String[] ComputerName Position = 1, ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QueryComputerSet)] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; base.SetParameter(value, nameNamespace); } } - private String nameSpace; + + private string nameSpace; /// /// The following is the definition of the input parameter "OperationTimeoutSec". @@ -140,8 +144,10 @@ public String Namespace public UInt32 OperationTimeoutSec { get { return operationTimeout;} + set { operationTimeout = value; } } + private UInt32 operationTimeout; /// @@ -162,6 +168,7 @@ public UInt32 OperationTimeoutSec public CimInstance InputObject { get { return cimInstance; } + set { cimInstance = value; @@ -170,12 +177,13 @@ public CimInstance InputObject } /// - /// Property for internal usage purpose + /// Property for internal usage purpose. /// internal CimInstance CimInstance { get { return cimInstance; } } + private CimInstance cimInstance; /// @@ -191,16 +199,18 @@ internal CimInstance CimInstance Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QuerySessionSet)] - public String Query + public string Query { get { return query;} + set { query = value; base.SetParameter(value, nameQuery); } } - private String query; + + private string query; /// /// The following is the definition of the input parameter "QueryDialect". @@ -211,16 +221,18 @@ public String Query ParameterSetName = CimBaseCommand.QuerySessionSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QueryComputerSet)] - public String QueryDialect + public string QueryDialect { get { return querydialect;} + set { querydialect = value; base.SetParameter(value, nameQueryDialect); } } - private String querydialect; + + private string querydialect; #endregion @@ -236,9 +248,10 @@ protected override void BeginProcessing() { cimRemoveInstance = CreateOperationAgent(); } + this.CmdletOperation = new CmdletOperationRemoveCimInstance(this, cimRemoveInstance); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -249,7 +262,7 @@ protected override void ProcessRecord() CimRemoveCimInstance cimRemoveInstance = this.GetOperationAgent(); cimRemoveInstance.RemoveCimInstance(this); cimRemoveInstance.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -261,7 +274,7 @@ protected override void EndProcessing() { cimRemoveInstance.ProcessRemainActions(this.CmdletOperation); } - }//End EndProcessing() + } #endregion @@ -307,7 +320,7 @@ CimRemoveCimInstance CreateOperationAgent() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -356,7 +369,7 @@ CimRemoveCimInstance CreateOperationAgent() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -366,5 +379,5 @@ CimRemoveCimInstance CreateOperationAgent() { CimBaseCommand.QuerySessionSet, new ParameterSetEntry(2) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimSessionCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimSessionCommand.cs index 97194b95247d..b84795884069 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimSessionCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/RemoveCimSessionCommand.cs @@ -1,6 +1,6 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; @@ -29,7 +29,7 @@ public sealed class RemoveCimSessionCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public RemoveCimSessionCommand() : base(parameters, parameterSets) @@ -55,12 +55,14 @@ public RemoveCimSessionCommand() public CimSession[] CimSession { get { return cimsession;} + set { cimsession = value; base.SetParameter(value, nameCimSession); } } + private CimSession[] cimsession; /// @@ -77,16 +79,18 @@ public CimSession[] CimSession ValueFromPipelineByPropertyName = true, ParameterSetName = ComputerNameSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computername; } + set { computername = value; base.SetParameter(value, nameComputerName); } } - private String[] computername; + + private string[] computername; /// /// The following is the definition of the input parameter "Id". @@ -101,12 +105,14 @@ public String[] ComputerName public UInt32[] Id { get { return id;} + set { id = value; base.SetParameter(value, nameId); } } + private UInt32[] id; /// @@ -122,12 +128,14 @@ public UInt32[] Id public Guid[] InstanceId { get { return instanceid;} + set { instanceid = value; base.SetParameter(value, nameInstanceId); } } + private Guid[] instanceid; /// @@ -140,16 +148,18 @@ public Guid[] InstanceId ValueFromPipelineByPropertyName = true, ParameterSetName = NameSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Name + public string[] Name { get { return name;} + set { name = value; base.SetParameter(value, nameName); } } - private String[] name; + + private string[] name; #endregion @@ -160,7 +170,7 @@ protected override void BeginProcessing() { this.cimRemoveSession = new CimRemoveSession(); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -169,12 +179,12 @@ protected override void ProcessRecord() { base.CheckParameterSet(); this.cimRemoveSession.RemoveCimSession(this); - }//End ProcessRecord() + } #region private members /// /// object used to remove the session from - /// session cache + /// session cache. /// private CimRemoveSession cimRemoveSession; @@ -187,7 +197,7 @@ protected override void ProcessRecord() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -219,7 +229,7 @@ protected override void ProcessRecord() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -230,5 +240,5 @@ protected override void ProcessRecord() { CimBaseCommand.NameSet, new ParameterSetEntry(1) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/SetCimInstanceCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/SetCimInstanceCommand.cs index 3ff061400c5f..abad4702e8b2 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/SetCimInstanceCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/SetCimInstanceCommand.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; @@ -30,7 +28,7 @@ public class SetCimInstanceCommand : CimBaseCommand #region constructor /// - /// constructor + /// Constructor. /// public SetCimInstanceCommand() : base(parameters, parameterSets) @@ -56,12 +54,14 @@ public SetCimInstanceCommand() public CimSession[] CimSession { get { return cimSession; } + set { cimSession = value; base.SetParameter(value, nameCimSession); } } + private CimSession[] cimSession; /// @@ -74,16 +74,18 @@ public CimSession[] CimSession [Parameter( ParameterSetName = CimBaseCommand.CimInstanceComputerSet)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName + public string[] ComputerName { get { return computername; } + set { computername = value; base.SetParameter(value, nameComputerName); } } - private String[] computername; + + private string[] computername; /// /// @@ -98,12 +100,14 @@ public String[] ComputerName public Uri ResourceUri { get { return resourceUri; } + set { this.resourceUri = value; base.SetParameter(value, nameResourceUri); } } + private Uri resourceUri; /// @@ -114,16 +118,18 @@ public Uri ResourceUri ParameterSetName = CimBaseCommand.QuerySessionSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QueryComputerSet)] - public String Namespace + public string Namespace { get { return nameSpace; } + set { nameSpace = value; base.SetParameter(value, nameNamespace); } } - private String nameSpace; + + private string nameSpace; /// /// The following is the definition of the input parameter "OperationTimeoutSec". @@ -135,8 +141,10 @@ public String Namespace public UInt32 OperationTimeoutSec { get { return operationTimeout; } + set { operationTimeout = value; } } + private UInt32 operationTimeout; /// @@ -157,6 +165,7 @@ public UInt32 OperationTimeoutSec public CimInstance InputObject { get { return cimInstance; } + set { cimInstance = value; @@ -165,12 +174,13 @@ public CimInstance InputObject } /// - /// Property for internal usage purpose + /// Property for internal usage purpose. /// internal CimInstance CimInstance { get { return cimInstance; } } + private CimInstance cimInstance; /// @@ -186,16 +196,18 @@ internal CimInstance CimInstance Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QuerySessionSet)] - public String Query + public string Query { get { return query; } + set { query = value; base.SetParameter(value, nameQuery); } } - private String query; + + private string query; /// /// The following is the definition of the input parameter "QueryDialect". @@ -206,16 +218,18 @@ public String Query ParameterSetName = CimBaseCommand.QuerySessionSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = CimBaseCommand.QueryComputerSet)] - public String QueryDialect + public string QueryDialect { get { return querydialect; } + set { querydialect = value; base.SetParameter(value, nameQueryDialect); } } - private String querydialect; + + private string querydialect; /// /// @@ -242,12 +256,14 @@ public String QueryDialect public IDictionary Property { get { return property; } + set { property = value; base.SetParameter(value, nameProperty); } } + private IDictionary property; /// @@ -266,11 +282,13 @@ public SwitchParameter PassThru { this.passThru = value; } + get { return this.passThru; } } + private SwitchParameter passThru; #endregion @@ -287,9 +305,10 @@ protected override void BeginProcessing() { cimSetCimInstance = CreateOperationAgent(); } + this.CmdletOperation = new CmdletOperationSetCimInstance(this, cimSetCimInstance); this.AtBeginProcess = false; - }//End BeginProcessing() + } /// /// ProcessRecord method. @@ -300,7 +319,7 @@ protected override void ProcessRecord() CimSetCimInstance cimSetCimInstance = this.GetOperationAgent(); cimSetCimInstance.SetCimInstance(this); cimSetCimInstance.ProcessActions(this.CmdletOperation); - }//End ProcessRecord() + } /// /// EndProcessing method. @@ -312,7 +331,7 @@ protected override void EndProcessing() { cimSetCimInstance.ProcessRemainActions(this.CmdletOperation); } - }//End EndProcessing() + } #endregion @@ -359,7 +378,7 @@ CimSetCimInstance CreateOperationAgent() #endregion /// - /// static parameter definition entries + /// Static parameter definition entries. /// static Dictionary> parameters = new Dictionary> { @@ -416,7 +435,7 @@ CimSetCimInstance CreateOperationAgent() }; /// - /// static parameter set entries + /// Static parameter set entries. /// static Dictionary parameterSets = new Dictionary { @@ -426,5 +445,5 @@ CimSetCimInstance CreateOperationAgent() { CimBaseCommand.CimInstanceComputerSet, new ParameterSetEntry(1, true) }, }; #endregion - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/Utils.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/Utils.cs index 66828f9b611b..b2c59c6afa69 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/Utils.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/Utils.cs @@ -1,7 +1,5 @@ -/*============================================================================ - * Copyright (c) Microsoft Corporation. All rights reserved. - *============================================================================ - */ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. // #define LOGENABLE // uncomment this line to enable the log, // create c:\temp\cim.log before invoking cimcmdlets @@ -67,7 +65,7 @@ internal static class ConstValue internal static string DefaultQueryDialect = @"WQL"; /// - /// Name of the note property that controls if "PSComputerName" column is shown + /// Name of the note property that controls if "PSComputerName" column is shown. /// internal static string ShowComputerNameNoteProperty = "PSShowComputerName"; @@ -80,7 +78,7 @@ internal static class ConstValue /// internal static bool IsDefaultComputerName(string computerName) { - return String.IsNullOrEmpty(computerName); + return string.IsNullOrEmpty(computerName); } /// @@ -96,7 +94,7 @@ internal static IEnumerable GetComputerNames(IEnumerable compute } /// - /// Get computer name, if it is null then return default one + /// Get computer name, if it is null then return default one. /// /// /// @@ -146,36 +144,38 @@ internal static class DebugHelper internal static bool GenerateLog { get { return generateLog; } + set { generateLog = value; } } /// - /// Whether the log been initialized + /// Whether the log been initialized. /// private static bool logInitialized = false; /// - /// Flag used to control generating message into powershell + /// Flag used to control generating message into powershell. /// private static bool generateVerboseMessage = true; internal static bool GenerateVerboseMessage { get { return generateVerboseMessage; } + set { generateVerboseMessage = value; } } /// - /// Flag used to control generating message into powershell + /// Flag used to control generating message into powershell. /// internal static string logFile = @"c:\temp\Cim.log"; /// - /// Indent space string + /// Indent space string. /// internal static string space = @" "; /// - /// Indent space strings array + /// Indent space strings array. /// internal static string[] spaces = { string.Empty, @@ -187,7 +187,7 @@ internal static bool GenerateVerboseMessage }; /// - /// Lock the log file + /// Lock the log file. /// internal static object logLock = new object(); @@ -216,14 +216,15 @@ internal static string GetSourceCodeInformation(bool withFileName, int depth) { StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(depth); - //if (withFileName) - //{ + // if (withFileName) + // { // return string.Format(CultureInfo.CurrentUICulture, "{0}#{1}:{2}:", frame.GetFileName()., frame.GetFileLineNumber(), frame.GetMethod().Name); - //} - //else - //{ + // } + // else + // { // return string.Format(CultureInfo.CurrentUICulture, "{0}:", frame.GetMethod()); - //} + // } + return string.Format(CultureInfo.CurrentUICulture, "{0}::{1} ", frame.GetMethod().DeclaringType.Name, frame.GetMethod().Name); @@ -231,7 +232,7 @@ internal static string GetSourceCodeInformation(bool withFileName, int depth) #endregion /// - /// Write message to log file named @logFile + /// Write message to log file named @logFile. /// /// internal static void WriteLog(string message) @@ -240,7 +241,7 @@ internal static void WriteLog(string message) } /// - /// Write blank line to log file named @logFile + /// Write blank line to log file named @logFile. /// /// internal static void WriteEmptyLine() @@ -249,18 +250,18 @@ internal static void WriteEmptyLine() } /// - /// Write message to log file named @logFile with args + /// Write message to log file named @logFile with args. /// /// internal static void WriteLog(string message, int indent, params object[] args) { - String outMessage = String.Empty; + string outMessage = string.Empty; FormatLogMessage(ref outMessage, message, args); WriteLog(outMessage, indent); } /// - /// Write message to log file w/o arguments + /// Write message to log file w/o arguments. /// /// /// @@ -270,19 +271,19 @@ internal static void WriteLog(string message, int indent) } /// - /// Write message to log file named @logFile with args + /// Write message to log file named @logFile with args. /// /// internal static void WriteLogEx(string message, int indent, params object[] args) { - String outMessage = String.Empty; + string outMessage = string.Empty; WriteLogInternal(string.Empty, 0, -1); FormatLogMessage(ref outMessage, message, args); WriteLogInternal(outMessage, indent, 3); } /// - /// Write message to log file w/o arguments + /// Write message to log file w/o arguments. /// /// /// @@ -293,7 +294,7 @@ internal static void WriteLogEx(string message, int indent) } /// - /// Write message to log file w/o arguments + /// Write message to log file w/o arguments. /// /// /// @@ -304,15 +305,15 @@ internal static void WriteLogEx() } /// - /// Format the message + /// Format the message. /// /// /// /// [Conditional("LOGENABLE")] - private static void FormatLogMessage(ref String outMessage, string message, params object[] args) + private static void FormatLogMessage(ref string outMessage, string message, params object[] args) { - outMessage = String.Format(CultureInfo.CurrentCulture, message, args); + outMessage = string.Format(CultureInfo.CurrentCulture, message, args); } /// @@ -342,10 +343,12 @@ private static void WriteLogInternal(string message, int indent, int depth) { indent = 0; } + if (indent > 5) { indent = 5; } + string sourceInformation = string.Empty; if (depth != -1) { @@ -358,6 +361,7 @@ private static void WriteLogInternal(string message, int indent, int depth) DateTime.Now.Second, GetSourceCodeInformation(true, depth)); } + lock (logLock) { using (FileStream fs = new FileStream(logFile,FileMode.OpenOrCreate)) @@ -379,7 +383,7 @@ private static void WriteLogInternal(string message, int indent, int depth) internal static class ValidationHelper { /// - /// Validate the argument is not null + /// Validate the argument is not null. /// /// /// @@ -392,13 +396,13 @@ public static void ValidateNoNullArgument(object obj, string argumentName) } /// - /// Validate the argument is not null and not whitespace + /// Validate the argument is not null and not whitespace. /// /// /// public static void ValidateNoNullorWhiteSpaceArgument(string obj, string argumentName) { - if (String.IsNullOrWhiteSpace(obj)) + if (string.IsNullOrWhiteSpace(obj)) { throw new ArgumentException(argumentName); } @@ -406,12 +410,12 @@ public static void ValidateNoNullorWhiteSpaceArgument(string obj, string argumen /// /// Validate that given classname/propertyname is a valid name compliance with DMTF standard. - /// Only for verifying ClassName and PropertyName argument + /// Only for verifying ClassName and PropertyName argument. /// /// /// /// - /// Throw if the given value is not a valid name (class name or property name) + /// Throw if the given value is not a valid name (class name or property name). public static string ValidateArgumentIsValidName(string parameterName, string value) { DebugHelper.WriteLogEx(); @@ -427,8 +431,9 @@ public static string ValidateArgumentIsValidName(string parameterName, string va return trimed; } } + DebugHelper.WriteLogEx("An invalid name: {0}={1}", 0, parameterName, value); - throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Strings.InvalidParameterValue, value, parameterName)); + throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.InvalidParameterValue, value, parameterName)); } /// @@ -438,21 +443,23 @@ public static string ValidateArgumentIsValidName(string parameterName, string va /// /// /// - /// Throw if the given value contains any invalid name (class name or property name) - public static String[] ValidateArgumentIsValidName(string parameterName, String[] value) + /// Throw if the given value contains any invalid name (class name or property name). + public static string[] ValidateArgumentIsValidName(string parameterName, string[] value) { if (value != null) { foreach (string propertyName in value) { // * is wild char supported in select properties - if ((propertyName != null) && (String.Compare(propertyName.Trim(), "*", StringComparison.OrdinalIgnoreCase) == 0)) + if ((propertyName != null) && (string.Compare(propertyName.Trim(), "*", StringComparison.OrdinalIgnoreCase) == 0)) { continue; } + ValidationHelper.ValidateArgumentIsValidName(parameterName, propertyName); } } + return value; } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs index 8ee3e95903d1..cda3502764e0 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs @@ -1,151 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections; using System.Diagnostics; using System.Globalization; +using System.Reflection; +using System.Resources; using System.Runtime.InteropServices; using System.Text; -using System.Resources; -using System.Reflection; - -#if CORECLR -using System.ComponentModel; -#else -using System.Threading; -#endif namespace Microsoft.PowerShell.Commands.Diagnostics.Common { internal static class CommonUtilities { - // - // StringArrayToString helper converts a string array into a comma-separated string. - // Note this has only limited use, individual strings cannot have commas. - // - public static string StringArrayToString(IEnumerable input) - { - string ret = ""; - foreach (string element in input) - { - ret += element + ", "; - } - - ret = ret.TrimEnd(); - ret = ret.TrimEnd(','); - - return ret; - } - -#if CORECLR - private const string LibraryLoadDllName = "api-ms-win-core-libraryloader-l1-2-0.dll"; - private const string LocalizationDllName = "api-ms-win-core-localization-l1-2-1.dll"; - private const string SysInfoDllName = "api-ms-win-core-sysinfo-l1-2-1.dll"; - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct OSVERSIONINFOEX - { - public int OSVersionInfoSize; - public int MajorVersion; - public int MinorVersion; - public int BuildNumber; - public int PlatformId; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] - public string CSDVersion; - public ushort ServicePackMajor; - public ushort ServicePackMinor; - public short SuiteMask; - public byte ProductType; - public byte Reserved; - } - - [DllImport(SysInfoDllName, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool GetVersionEx(ref OSVERSIONINFOEX osVerEx); -#else - private const string LibraryLoadDllName = "kernel32.dll"; - private const string LocalizationDllName = "kernel32.dll"; -#endif - - private const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; - private const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; - private const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; - private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; - private const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800; - - [DllImport(LocalizationDllName, SetLastError = true, CharSet = CharSet.Unicode)] - private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, - uint dwMessageId, uint dwLanguageId, - [MarshalAs(UnmanagedType.LPWStr)] - StringBuilder lpBuffer, - uint nSize, IntPtr Arguments); - - [DllImport(LibraryLoadDllName, SetLastError = true, CharSet = CharSet.Unicode)] - private static extern IntPtr LoadLibraryEx( - [MarshalAs(UnmanagedType.LPWStr)] string lpFileName, - IntPtr hFile, - uint dwFlags - ); - - [DllImport(LibraryLoadDllName)] - private static extern bool FreeLibrary(IntPtr hModule); - - - [DllImport(LocalizationDllName, EntryPoint = "GetUserDefaultLangID", CallingConvention = CallingConvention.Winapi, SetLastError = true)] - private static extern ushort GetUserDefaultLangID(); - - - public static uint FormatMessageFromModule(uint lastError, string moduleName, out String msg) - { - Debug.Assert(!string.IsNullOrEmpty(moduleName)); - - uint formatError = 0; - msg = String.Empty; - IntPtr moduleHandle = IntPtr.Zero; - - moduleHandle = LoadLibraryEx(moduleName, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); - if (moduleHandle == IntPtr.Zero) - { - return (uint)Marshal.GetLastWin32Error(); - } - - try - { - uint dwFormatFlags = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE; - uint LANGID = (uint)GetUserDefaultLangID(); - uint langError = (uint)Marshal.GetLastWin32Error(); - if (langError != 0) - { - LANGID = 0; // neutral - } - - StringBuilder outStringBuilder = new StringBuilder(1024); - uint nChars = FormatMessage(dwFormatFlags, - moduleHandle, - lastError, - LANGID, - outStringBuilder, - (uint)outStringBuilder.Capacity, - IntPtr.Zero); - - if (nChars == 0) - { - formatError = (uint)Marshal.GetLastWin32Error(); - //Console.WriteLine("Win32FormatMessage", String.Format(null, "Error formatting message: {0}", formatError)); - } - else - { - msg = outStringBuilder.ToString(); - if (msg.EndsWith(Environment.NewLine, StringComparison.Ordinal)) - { - msg = msg.Substring(0, msg.Length - 2); - } - } - } - finally - { - FreeLibrary(moduleHandle); - } - return formatError; - } - public static ResourceManager GetResourceManager() { // this naming pattern is dictated by the dotnet cli diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CoreCLR/Stubs.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CoreCLR/Stubs.cs index 88b3a6f134f7..5ea3041de9ef 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/CoreCLR/Stubs.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CoreCLR/Stubs.cs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #if CORECLR using System.ComponentModel; diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs index 858f5f0b6ff0..87c629b93965 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs @@ -1,13 +1,12 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// +// Licensed under the MIT License. using System; using System.Collections; -using System.Collections.Specialized; using System.Collections.Generic; -using System.Diagnostics; +using System.Collections.Specialized; using System.ComponentModel; +using System.Diagnostics; namespace Microsoft.PowerShell.Commands.GetCounter { @@ -31,6 +30,7 @@ public DateTime OldestRecord return _oldestRecord; } } + private DateTime _oldestRecord = DateTime.MinValue; public DateTime NewestRecord @@ -40,6 +40,7 @@ public DateTime NewestRecord return _newestRecord; } } + private DateTime _newestRecord = DateTime.MaxValue; public UInt32 SampleCount @@ -49,6 +50,7 @@ public UInt32 SampleCount return _sampleCount; } } + private UInt32 _sampleCount = 0; } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSample.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSample.cs index 4ba65b3c8ea2..c2dbb2b21307 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSample.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSample.cs @@ -1,18 +1,16 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// - +// Licensed under the MIT License. using System; -using System.Reflection; using System.Collections.Generic; -using System.Diagnostics; using System.ComponentModel; -using System.Resources; -using Microsoft.Powershell.Commands.GetCounter.PdhNative; -using System.Globalization; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Resources; +using Microsoft.Powershell.Commands.GetCounter.PdhNative; namespace Microsoft.PowerShell.Commands.GetCounter { @@ -52,88 +50,109 @@ internal PerformanceCounterSample() public string Path { get { return _path; } + set { _path = value; } } - private string _path = ""; + private string _path = string.Empty; public string InstanceName { get { return _instanceName; } + set { _instanceName = value; } } - private string _instanceName = ""; + private string _instanceName = string.Empty; public double CookedValue { get { return _cookedValue; } + set { _cookedValue = value; } } + private double _cookedValue = 0; public UInt64 RawValue { get { return _rawValue; } + set { _rawValue = value; } } + private UInt64 _rawValue = 0; public UInt64 SecondValue { get { return _secondValue; } + set { _secondValue = value; } } + private UInt64 _secondValue = 0; public uint MultipleCount { get { return _multiCount; } + set { _multiCount = value; } } + private uint _multiCount = 0; public PerformanceCounterType CounterType { get { return _counterType; } + set { _counterType = value; } } + private PerformanceCounterType _counterType = 0; public DateTime Timestamp { get { return _timeStamp; } + set { _timeStamp = value; } } - private DateTime _timeStamp = DateTime.MinValue; + private DateTime _timeStamp = DateTime.MinValue; public UInt64 Timestamp100NSec { get { return _timeStamp100nSec; } + set { _timeStamp100nSec = value; } } + private UInt64 _timeStamp100nSec = 0; public UInt32 Status { get { return _status; } + set { _status = value; } } + private UInt32 _status = 0; public UInt32 DefaultScale { get { return _defaultScale; } + set { _defaultScale = value; } } + private UInt32 _defaultScale = 0; public UInt64 TimeBase { get { return _timeBase; } + set { _timeBase = value; } } + private UInt64 _timeBase = 0; } @@ -155,8 +174,10 @@ internal PerformanceCounterSampleSet() public DateTime Timestamp { get { return _timeStamp; } + set { _timeStamp = value; } } + private DateTime _timeStamp = DateTime.MinValue; [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", @@ -166,8 +187,10 @@ public DateTime Timestamp public PerformanceCounterSample[] CounterSamples { get { return _counterSamples; } + set { _counterSamples = value; } } + private PerformanceCounterSample[] _counterSamples = null; private ResourceManager _resourceMgr = null; diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSet.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSet.cs index fb7edd1ac92f..acbfc7e9fb30 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSet.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterSet.cs @@ -1,13 +1,12 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// +// Licensed under the MIT License. using System; using System.Collections; -using System.Collections.Specialized; using System.Collections.Generic; -using System.Diagnostics; +using System.Collections.Specialized; using System.ComponentModel; +using System.Diagnostics; namespace Microsoft.PowerShell.Commands.GetCounter { @@ -32,6 +31,7 @@ public class CounterSet _machineName = @"\\" + _machineName; } } + _counterSetType = categoryType; _description = setHelp; _counterInstanceMapping = counterInstanceMapping; @@ -44,7 +44,8 @@ public string CounterSetName return _counterSetName; } } - private string _counterSetName = ""; + + private string _counterSetName = string.Empty; public string MachineName { @@ -53,6 +54,7 @@ public string MachineName return _machineName; } } + private string _machineName = "."; public PerformanceCounterCategoryType CounterSetType @@ -62,8 +64,8 @@ public PerformanceCounterCategoryType CounterSetType return _counterSetType; } } - private PerformanceCounterCategoryType _counterSetType; + private PerformanceCounterCategoryType _counterSetType; public string Description { @@ -72,7 +74,8 @@ public string Description return _description; } } - private string _description = ""; + + private string _description = string.Empty; internal Dictionary CounterInstanceMapping { @@ -81,6 +84,7 @@ public string Description return _counterInstanceMapping; } } + private Dictionary _counterInstanceMapping; public StringCollection Paths @@ -103,6 +107,7 @@ public StringCollection Paths ("\\" + _counterSetName + "\\" + counterName) : (_machineName + "\\" + _counterSetName + "\\" + counterName); } + retColl.Add(path); } @@ -125,6 +130,7 @@ public StringCollection PathsWithInstances retColl.Add(path); } } + return retColl; } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs index 9a7e138b521b..fc0183466ad1 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs @@ -1,32 +1,30 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// - +// Licensed under the MIT License. using System; -using System.Text; -using System.IO; -using System.Xml; -using System.Net; -using System.Management.Automation; -using System.ComponentModel; -using System.Reflection; -using System.Globalization; -using System.Management.Automation.Runspaces; using System.Collections; -using System.Collections.Specialized; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Runspaces; +using System.Net; +using System.Reflection; +using System.Resources; using System.Security; using System.Security.Principal; -using System.Resources; +using System.Text; using System.Threading; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Powershell.Commands.GetCounter.PdhNative; -using Microsoft.PowerShell.Commands.GetCounter; -using Microsoft.PowerShell.Commands.Diagnostics.Common; +using System.Xml; +using Microsoft.PowerShell.Commands.Diagnostics.Common; +using Microsoft.PowerShell.Commands.GetCounter; +using Microsoft.Powershell.Commands.GetCounter.PdhNative; namespace Microsoft.PowerShell.Commands { @@ -49,12 +47,13 @@ public sealed class ExportCounterCommand : PSCmdlet public string Path { get { return _path; } + set { _path = value; } } + private string _path; private string _resolvedPath; - // // Format parameter. // Valid strings are "blg", "csv", "tsv" (case-insensitive). @@ -69,11 +68,11 @@ public string Path public string FileFormat { get { return _format; } + set { _format = value; } } - private string _format = "blg"; - + private string _format = "blg"; // // MaxSize parameter @@ -84,10 +83,11 @@ public string FileFormat public UInt32 MaxSize { get { return _maxSize; } + set { _maxSize = value; } } - private UInt32 _maxSize = 0; + private UInt32 _maxSize = 0; // // InputObject parameter @@ -105,10 +105,11 @@ public UInt32 MaxSize public PerformanceCounterSampleSet[] InputObject { get { return _counterSampleSets; } + set { _counterSampleSets = value; } } - private PerformanceCounterSampleSet[] _counterSampleSets = new PerformanceCounterSampleSet[0]; + private PerformanceCounterSampleSet[] _counterSampleSets = new PerformanceCounterSampleSet[0]; // // Force switch @@ -118,8 +119,10 @@ public PerformanceCounterSampleSet[] InputObject public SwitchParameter Force { get { return _force; } + set { _force = value; } } + private SwitchParameter _force; // @@ -130,11 +133,11 @@ public SwitchParameter Force public SwitchParameter Circular { get { return _circular; } + set { _circular = value; } } - private SwitchParameter _circular; - + private SwitchParameter _circular; private ResourceManager _resourceMgr = null; @@ -159,7 +162,7 @@ protected override void BeginProcessing() throw new PlatformNotSupportedException(); } - // PowerShell Core requires at least Windows 7, + // PowerShell 7 requires at least Windows 7, // so no version test is needed _pdhHelper = new PdhHelper(false); #else @@ -213,7 +216,6 @@ protected override void EndProcessing() _pdhHelper.Dispose(); } - /// /// Handle Control-C /// @@ -247,6 +249,7 @@ protected override void ProcessRecord() { res = _pdhHelper.AddRelogCountersPreservingPaths(_counterSampleSets[0]); } + if (res != 0) { ReportPdhError(res, true); @@ -279,7 +282,6 @@ protected override void ProcessRecord() _queryInitialized = true; } - foreach (PerformanceCounterSampleSet set in _counterSampleSets) { _pdhHelper.ResetRelogValues(); @@ -299,6 +301,7 @@ protected override void ProcessRecord() ReportPdhError(res, true); } } + res = _pdhHelper.WriteRelogSample(set.Timestamp); if (res != 0) { @@ -365,6 +368,7 @@ private void ReportPdhError(uint res, bool bTerminate) { msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterApiError"), res); } + Exception exc = new Exception(msg); if (bTerminate) { diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs index 29da31a48bd4..0889cdc7f4b6 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs @@ -1,32 +1,30 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// - +// Licensed under the MIT License. using System; -using System.Text; -using System.IO; -using System.Xml; -using System.Net; -using System.Management.Automation; -using System.ComponentModel; -using System.Reflection; -using System.Globalization; -using System.Management.Automation.Runspaces; using System.Collections; -using System.Collections.Specialized; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Runspaces; +using System.Net; +using System.Reflection; +using System.Resources; using System.Security; using System.Security.Principal; -using System.Resources; +using System.Text; using System.Threading; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Powershell.Commands.GetCounter.PdhNative; -using Microsoft.PowerShell.Commands.GetCounter; -using Microsoft.PowerShell.Commands.Diagnostics.Common; +using System.Xml; +using Microsoft.PowerShell.Commands.Diagnostics.Common; +using Microsoft.PowerShell.Commands.GetCounter; +using Microsoft.Powershell.Commands.GetCounter.PdhNative; namespace Microsoft.PowerShell.Commands { @@ -55,10 +53,11 @@ public sealed class GetCounterCommand : PSCmdlet public string[] ListSet { get { return _listSet; } + set { _listSet = value; } } - private string[] _listSet = { "*" }; + private string[] _listSet = { "*" }; // // Counter parameter @@ -77,12 +76,14 @@ public string[] ListSet public string[] Counter { get { return _counter; } + set { _counter = value; _defaultCounters = false; } } + private string[] _counter = {@"\network interface(*)\bytes total/sec", @"\processor(_total)\% processor time", @"\memory\% committed bytes in use", @@ -93,7 +94,6 @@ public string[] Counter private List _accumulatedCounters = new List(); - // // SampleInterval parameter. // Defaults to 1 second. @@ -107,10 +107,11 @@ public string[] Counter public int SampleInterval { get { return _sampleInterval; } + set { _sampleInterval = value; } } - private int _sampleInterval = 1; + private int _sampleInterval = 1; // // MaxSamples parameter @@ -125,16 +126,17 @@ public int SampleInterval public Int64 MaxSamples { get { return _maxSamples; } + set { _maxSamples = value; _maxSamplesSpecified = true; } } + private Int64 _maxSamples = 1; private bool _maxSamplesSpecified = false; - // // Continuous switch // @@ -142,10 +144,11 @@ public Int64 MaxSamples public SwitchParameter Continuous { get { return _continuous; } + set { _continuous = value; } } - private bool _continuous = false; + private bool _continuous = false; // // ComputerName parameter @@ -165,9 +168,11 @@ public SwitchParameter Continuous public string[] ComputerName { get { return _computerName; } + set { _computerName = value; } } - private string[] _computerName = new string[0]; + + private string[] _computerName = Array.Empty(); private ResourceManager _resourceMgr = null; @@ -213,7 +218,7 @@ protected override void BeginProcessing() throw new PlatformNotSupportedException(); } - // PowerShell Core requires at least Windows 7, + // PowerShell 7 requires at least Windows 7, // so no version test is needed _pdhHelper = new PdhHelper(false); #else @@ -228,7 +233,6 @@ protected override void BeginProcessing() return; } - if (Continuous.IsPresent && _maxSamplesSpecified) { Exception exc = new Exception(string.Format(CultureInfo.CurrentCulture, _resourceMgr.GetString("CounterContinuousOrMaxSamples"))); @@ -249,7 +253,6 @@ protected override void EndProcessing() _pdhHelper.Dispose(); } - // // Handle Control-C // @@ -323,7 +326,7 @@ private void ProcessListSetPerMachine(string machine) uint res = _pdhHelper.EnumObjects(machine, ref counterSets); if (res != 0) { - //add an error message + // add an error message string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("NoCounterSetsOnComputer"), machine, res); Exception exc = new Exception(msg); WriteError(new ErrorRecord(exc, "NoCounterSetsOnComputer", ErrorCategory.InvalidResult, machine)); @@ -405,7 +408,7 @@ private void ProcessListSetPerMachine(string machine) { categoryType = PerformanceCounterCategoryType.MultiInstance; } - else //if (counterSetInstances.Count == 1) //??? + else // if (counterSetInstances.Count == 1) //??? { categoryType = PerformanceCounterCategoryType.SingleInstance; } @@ -449,7 +452,6 @@ private void ProcessGetCounter() _cultureAndSpecialCharacterMap.TryGetValue(culture.Name, out characterReplacementList); } - StringCollection allExpandedPaths = new StringCollection(); foreach (string path in paths) { @@ -493,9 +495,11 @@ private void ProcessGetCounter() continue; } + allExpandedPaths.Add(expandedPath); } } + if (allExpandedPaths.Count == 0) { return; @@ -506,6 +510,7 @@ private void ProcessGetCounter() { ReportPdhError(res, false); } + res = _pdhHelper.AddCounters(ref allExpandedPaths, true); if (res != 0) { @@ -531,14 +536,14 @@ private void ProcessGetCounter() if (res == 0) { - //Display valid data + // Display valid data if (!bSkip) { WriteSampleSetObject(nextSet); sampleReads++; } - //Don't need to skip anymore + // Don't need to skip anymore bSkip = false; } else if (res == PdhResults.PDH_NO_DATA || res == PdhResults.PDH_INVALID_DATA) @@ -586,6 +591,7 @@ private void ReportPdhError(uint res, bool bTerminate) { msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterApiError"), res); } + Exception exc = new Exception(msg); if (bTerminate) { @@ -597,7 +603,6 @@ private void ReportPdhError(uint res, bool bTerminate) } } - // // CombineMachinesAndCounterPaths() helper. // For paths that do not contain machine names, creates a path for each machine in machineNames. @@ -615,7 +620,7 @@ private List CombineMachinesAndCounterPaths() foreach (string path in _accumulatedCounters) { - if (path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase)) //NOTE: can we do anything smarter here? + if (path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase)) // NOTE: can we do anything smarter here? { retColl.Add(path); } @@ -655,6 +660,7 @@ private void WriteSampleSetObject(PerformanceCounterSampleSet set) break; } } + WriteObject(set); } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs index f23a6da9ad00..378f20147dbe 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs @@ -1,22 +1,21 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// +// Licensed under the MIT License. using System; -using System.Xml; -using System.Net; -using System.Management.Automation; -using System.Reflection; -using System.Globalization; using System.Collections; -using System.Collections.Specialized; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Eventing.Reader; -using System.Security.Principal; +using System.Globalization; +using System.Management.Automation; +using System.Net; +using System.Reflection; using System.Resources; -using System.Diagnostics.CodeAnalysis; +using System.Security.Principal; using System.Text; +using System.Xml; [assembly: CLSCompliant(false)] @@ -29,7 +28,7 @@ namespace Microsoft.PowerShell.Commands public sealed class GetWinEventCommand : PSCmdlet { /// - /// ListLog parameter + /// ListLog parameter. /// [Parameter( Position = 0, @@ -48,12 +47,14 @@ public sealed class GetWinEventCommand : PSCmdlet public string[] ListLog { get { return _listLog; } + set { _listLog = value; } } + private string[] _listLog = { "*" }; /// - /// GetLog parameter + /// GetLog parameter. /// [Parameter( Position = 0, @@ -69,13 +70,14 @@ public string[] ListLog public string[] LogName { get { return _logName; } + set { _logName = value; } } - private string[] _logName = { "*" }; + private string[] _logName = { "*" }; /// - /// ListProvider parameter + /// ListProvider parameter. /// [Parameter( Position = 0, @@ -95,13 +97,14 @@ public string[] LogName public string[] ListProvider { get { return _listProvider; } + set { _listProvider = value; } } - private string[] _listProvider = { "*" }; + private string[] _listProvider = { "*" }; /// - /// ProviderName parameter + /// ProviderName parameter. /// [Parameter( Position = 0, @@ -119,13 +122,14 @@ public string[] ListProvider public string[] ProviderName { get { return _providerName; } + set { _providerName = value; } } - private string[] _providerName; + private string[] _providerName; /// - /// Path parameter + /// Path parameter. /// [Parameter( Position = 0, @@ -143,13 +147,14 @@ public string[] ProviderName public string[] Path { get { return _path; } + set { _path = value; } } - private string[] _path; + private string[] _path; /// - /// MaxEvents parameter + /// MaxEvents parameter. /// [Parameter( ParameterSetName = "FileSet", @@ -185,12 +190,14 @@ public string[] Path public Int64 MaxEvents { get { return _maxEvents; } + set { _maxEvents = value; } } + private Int64 _maxEvents = -1; /// - /// ComputerName parameter + /// ComputerName parameter. /// [Parameter( ParameterSetName = "ListProviderSet", @@ -222,12 +229,14 @@ public Int64 MaxEvents public string ComputerName { get { return _computerName; } + set { _computerName = value; } } + private string _computerName = string.Empty; /// - /// Credential parameter + /// Credential parameter. /// [Parameter(ParameterSetName = "ListProviderSet")] [Parameter(ParameterSetName = "GetProviderSet")] @@ -240,13 +249,14 @@ public string ComputerName public PSCredential Credential { get { return _credential; } + set { _credential = value; } } - private PSCredential _credential = PSCredential.Empty; + private PSCredential _credential = PSCredential.Empty; /// - /// FilterXPath parameter + /// FilterXPath parameter. /// [Parameter( ParameterSetName = "FileSet", @@ -267,12 +277,14 @@ public PSCredential Credential public string FilterXPath { get { return _filter; } + set { _filter = value; } } + private string _filter = "*"; /// - /// FilterXml parameter + /// FilterXml parameter. /// [Parameter( Position = 0, @@ -290,13 +302,14 @@ public string FilterXPath public XmlDocument FilterXml { get { return _xmlQuery; } + set { _xmlQuery = value; } } - private XmlDocument _xmlQuery = null; + private XmlDocument _xmlQuery = null; /// - /// FilterHashtable parameter + /// FilterHashtable parameter. /// [Parameter( Position = 0, @@ -314,12 +327,14 @@ public XmlDocument FilterXml public Hashtable[] FilterHashtable { get { return _selector; } + set { _selector = value; } } + private Hashtable[] _selector; /// - /// Force switch + /// Force switch. /// [Parameter(ParameterSetName = "ListLogSet")] [Parameter(ParameterSetName = "GetProviderSet")] @@ -329,12 +344,14 @@ public Hashtable[] FilterHashtable public SwitchParameter Force { get { return _force; } + set { _force = value; } } + private SwitchParameter _force; /// - /// Oldest switch + /// Oldest switch. /// [Parameter(ParameterSetName = "FileSet")] [Parameter(ParameterSetName = "GetProviderSet")] @@ -345,10 +362,11 @@ public SwitchParameter Force public SwitchParameter Oldest { get { return _oldest; } + set { _oldest = value; } } - private bool _oldest = false; + private bool _oldest = false; // // Query builder constant strings @@ -404,18 +422,16 @@ public SwitchParameter Oldest private const string hashkey_data_lc = "data"; private const string hashkey_supress_lc = "suppresshashfilter"; - /// - /// BeginProcessing() is invoked once per pipeline: we will load System.Core.dll here + /// BeginProcessing() is invoked once per pipeline: we will load System.Core.dll here. /// protected override void BeginProcessing() { _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager(); } - /// - /// EndProcessing() is invoked once per pipeline + /// EndProcessing() is invoked once per pipeline. /// protected override void EndProcessing() { @@ -438,7 +454,6 @@ protected override void EndProcessing() } } - /// /// ProcessRecord() override. /// This is the main entry point for the cmdlet. @@ -481,7 +496,6 @@ protected override void ProcessRecord() } } - // // AccumulatePipelineCounters() accumulates log names in the pipeline scenario: // we do not want to construct a query until all the log names are supplied. @@ -533,6 +547,7 @@ private void ProcessGetLog() { logQuery = new EventLogQuery(_logNamesMatchingWildcard[0], PathType.LogName, _filter); } + logQuery.Session = eventLogSession; logQuery.ReverseDirection = !_oldest; @@ -540,7 +555,6 @@ private void ProcessGetLog() } } - // // Process GetProviderSet parameter set // @@ -558,7 +572,6 @@ private void ProcessGetProvider() return; } - EventLogQuery logQuery = null; if (_providersByLogMap.Count > 1) { @@ -577,6 +590,7 @@ private void ProcessGetProvider() WriteVerbose(string.Format(CultureInfo.InvariantCulture, "Log {0} will be queried", log)); } } + logQuery.Session = eventLogSession; logQuery.ReverseDirection = !_oldest; ; @@ -584,7 +598,6 @@ private void ProcessGetProvider() } } - // // Process ListLog parameter set // @@ -595,11 +608,10 @@ private void ProcessListLog() foreach (string logPattern in _listLog) { bool bMatchFound = false; + WildcardPattern wildLogPattern = new WildcardPattern(logPattern, WildcardOptions.IgnoreCase); foreach (string logName in eventLogSession.GetLogNames()) { - WildcardPattern wildLogPattern = new WildcardPattern(logPattern, WildcardOptions.IgnoreCase); - if (((!WildcardPattern.ContainsWildcardCharacters(logPattern)) && string.Equals(logPattern, logName, StringComparison.CurrentCultureIgnoreCase)) || @@ -645,6 +657,7 @@ private void ProcessListLog() } } } + if (!bMatchFound) { string msg = _resourceMgr.GetString("NoMatchingLogsFound"); @@ -665,11 +678,10 @@ private void ProcessListProvider() foreach (string provPattern in _listProvider) { bool bMatchFound = false; + WildcardPattern wildProvPattern = new WildcardPattern(provPattern, WildcardOptions.IgnoreCase); foreach (string provName in eventLogSession.GetProviderNames()) { - WildcardPattern wildProvPattern = new WildcardPattern(provPattern, WildcardOptions.IgnoreCase); - if (((!WildcardPattern.ContainsWildcardCharacters(provPattern)) && string.Equals(provPattern, provName, StringComparison.CurrentCultureIgnoreCase)) || @@ -746,7 +758,6 @@ private void ProcessFilterXml() } } - // // Process FileSet parameter set // @@ -783,6 +794,7 @@ private void ProcessFile() { logQuery = new EventLogQuery(_resolvedPaths[0], PathType.FilePath, _filter); } + logQuery.Session = eventLogSession; logQuery.ReverseDirection = !_oldest; @@ -799,7 +811,6 @@ private void ProcessHashQuery() using (EventLogSession eventLogSession = CreateSession()) { - string query = BuildStructuredQuery(eventLogSession); if (query.Length == 0) { @@ -852,12 +863,11 @@ private EventLogSession CreateSession() // // Force the destruction of cached password // - netCred.Password = ""; + netCred.Password = string.Empty; return eventLogSession; } - // // ReadEvents helper. // @@ -879,10 +889,12 @@ private void ReadEvents(EventLogQuery logQuery) WriteError(new ErrorRecord(exc, exc.Message, ErrorCategory.NotSpecified, null)); continue; } + if (evtObj == null) { break; } + if (_maxEvents != -1 && numEvents >= _maxEvents) { break; @@ -899,8 +911,8 @@ private void ReadEvents(EventLogQuery logQuery) { WriteError(new ErrorRecord(exc, exc.Message, ErrorCategory.NotSpecified, null)); } - outputObj.Properties.Add(new PSNoteProperty("Message", evtMessage)); + outputObj.Properties.Add(new PSNoteProperty("Message", evtMessage)); // // Enumerate the object one level to get to event payload @@ -918,8 +930,6 @@ private void ReadEvents(EventLogQuery logQuery) } } - - // // BuildStructuredQuery() builds a structured query from cmdlet arguments. // @@ -945,8 +955,10 @@ private string BuildStructuredQuery(EventLogSession eventLogSession) string providerFilter = AddProviderPredicatesToFilter(_providersByLogMap[log]); result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, log, providerFilter }); } + result.Append(queryListClose); } + break; case "GetLogSet": @@ -957,8 +969,10 @@ private string BuildStructuredQuery(EventLogSession eventLogSession) { result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, log, _filter }); } + result.Append(queryListClose); } + break; case "FileSet": @@ -970,8 +984,10 @@ private string BuildStructuredQuery(EventLogSession eventLogSession) string properFilePath = filePrefix + filePath; result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, properFilePath, _filter }); } + result.Append(queryListClose); } + break; case "HashQuerySet": @@ -993,12 +1009,12 @@ private string BuildStructuredQuery(EventLogSession eventLogSession) // private string BuildXPathFromHashTable(Hashtable hash) { - StringBuilder xpathString = new StringBuilder(""); + StringBuilder xpathString = new StringBuilder(string.Empty); bool bDateTimeHandled = false; foreach (string key in hash.Keys) { - string added = ""; + string added = string.Empty; switch (key.ToLowerInvariant()) { @@ -1057,8 +1073,8 @@ private string BuildXPathFromHashTable(Hashtable hash) // // Fix Issue #2327 added = HandleNamedDataHashValue(key, hash[key]); - } + break; } @@ -1068,9 +1084,9 @@ private string BuildXPathFromHashTable(Hashtable hash) { xpathString.Append(" and "); } + xpathString.Append(added); } - } return xpathString.ToString(); @@ -1082,7 +1098,7 @@ private string BuildXPathFromHashTable(Hashtable hash) // private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession) { - StringBuilder result = new StringBuilder(""); + StringBuilder result = new StringBuilder(string.Empty); result.Append(queryListOpen); @@ -1090,8 +1106,8 @@ private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession foreach (Hashtable hash in _selector) { - string xpathString = ""; - string xpathStringSuppress = ""; + string xpathString = string.Empty; + string xpathStringSuppress = string.Empty; CheckHashTableForQueryPathPresence(hash); @@ -1138,6 +1154,7 @@ private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, logName)); } } + if (hash.ContainsKey(hashkey_path_lc)) { if (hash[hashkey_path_lc] is Array) @@ -1166,6 +1183,7 @@ private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession } } } + if (hash.ContainsKey(hashkey_providername_lc)) { List provPatterns = new List(); @@ -1274,7 +1292,7 @@ private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession string query = queriedLogsQueryMap[keyLogName]; result.Append(query); - if (query.EndsWith("*", StringComparison.OrdinalIgnoreCase)) + if (query.EndsWith('*')) { // // No provider predicate: just add the XPath string @@ -1293,6 +1311,7 @@ private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession { result.Append(" and ").Append(xpathString); } + result.Append(propClose); } @@ -1309,8 +1328,7 @@ private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession result.Append(queryCloser); } - } //end foreach hashtable - + } result.Append(queryListClose); @@ -1336,6 +1354,7 @@ private string HandleEventIdHashValue(Object value) ret.Append(" or "); } } + ret.Append(")"); } else @@ -1365,6 +1384,7 @@ private string HandleLevelHashValue(Object value) ret.Append(" or "); } } + ret.Append(")"); } else @@ -1399,8 +1419,9 @@ private string HandleKeywordHashValue(Object value) { if (!KeywordStringToInt64(value.ToString(), ref keywordLong)) { - return ""; + return string.Empty; } + keywordsMask |= keywordLong; } @@ -1437,14 +1458,13 @@ private string HandleContextHashValue(Object value) string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("InvalidContext"), value.ToString()); Exception outerExc = new Exception(msg, exc); WriteError(new ErrorRecord(outerExc, "InvalidContext", ErrorCategory.InvalidArgument, null)); - return ""; + return string.Empty; } } return string.Format(CultureInfo.InvariantCulture, SystemSecurityTemplate, sidCandidate.ToString()); } - // // HandleStartTimeHashValue helper for hashtable structured query builder. // Constructs and returns TimeCreated XPath portion as a string. @@ -1456,7 +1476,7 @@ private string HandleStartTimeHashValue(Object value, Hashtable hash) DateTime startTime = new DateTime(); if (!StringToDateTime(value.ToString(), ref startTime)) { - return ""; + return string.Empty; } startTime = startTime.ToUniversalTime(); @@ -1467,7 +1487,7 @@ private string HandleStartTimeHashValue(Object value, Hashtable hash) DateTime endTime = new DateTime(); if (!StringToDateTime(hash[hashkey_endtime_lc].ToString(), ref endTime)) { - return ""; + return string.Empty; } endTime = endTime.ToUniversalTime(); @@ -1488,7 +1508,6 @@ private string HandleStartTimeHashValue(Object value, Hashtable hash) return ret.ToString(); } - // // HandleEndTimeHashValue helper for hashtable structured query builder. // Constructs and returns TimeCreated XPath portion as a string. @@ -1500,7 +1519,7 @@ private string HandleEndTimeHashValue(Object value, Hashtable hash) DateTime endTime = new DateTime(); if (!StringToDateTime(value.ToString(), ref endTime)) { - return ""; + return string.Empty; } endTime = endTime.ToUniversalTime(); @@ -1512,7 +1531,7 @@ private string HandleEndTimeHashValue(Object value, Hashtable hash) DateTime startTime = new DateTime(); if (!StringToDateTime(hash[hashkey_starttime_lc].ToString(), ref startTime)) { - return ""; + return string.Empty; } startTime = startTime.ToUniversalTime(); @@ -1553,6 +1572,7 @@ private string HandleDataHashValue(Object value) ret.Append(" or "); } } + ret.Append(")"); } else @@ -1563,13 +1583,12 @@ private string HandleDataHashValue(Object value) return ret.ToString(); } - // // HandleNamedDataHashValue helper for hashtable structured query builder. // Constructs and returns named event data field XPath portion as a string. // Fix Issue #2327 // - private string HandleNamedDataHashValue(String key, Object value) + private string HandleNamedDataHashValue(String key, object value) { StringBuilder ret = new StringBuilder(); Array dataArray = value as Array; @@ -1586,6 +1605,7 @@ private string HandleNamedDataHashValue(String key, Object value) ret.Append(" or "); } } + ret.Append(")"); } else @@ -1598,7 +1618,6 @@ private string HandleNamedDataHashValue(String key, Object value) return ret.ToString(); } - // // Helper checking whether at least one of log, _path, provider is specified. // It will ThrowTerminatingError in case none of those keys are present. @@ -1661,6 +1680,7 @@ private bool ValidateLogName(string logName, EventLogSession eventLogSession) WriteError(new ErrorRecord(outerExc, "LogInfoUnavailable", ErrorCategory.NotSpecified, null)); return false; } + if (!Oldest.IsPresent) { if (logObj.LogType == EventLogType.Debug || logObj.LogType == EventLogType.Analytical) @@ -1670,10 +1690,10 @@ private bool ValidateLogName(string logName, EventLogSession eventLogSession) ThrowTerminatingError(new ErrorRecord(exc, "SpecifyOldestForLog", ErrorCategory.InvalidArgument, logName)); } } + return true; } - // // KeywordStringToInt64 helper converts a string to Int64. // Returns true and keyLong ref if successful. @@ -1735,27 +1755,27 @@ private StringCollection ValidateAndResolveFilePath(string path) } catch (PSNotSupportedException notSupported) { - WriteError(new ErrorRecord(notSupported, "", ErrorCategory.ObjectNotFound, path)); + WriteError(new ErrorRecord(notSupported, string.Empty, ErrorCategory.ObjectNotFound, path)); return retColl; } catch (System.Management.Automation.DriveNotFoundException driveNotFound) { - WriteError(new ErrorRecord(driveNotFound, "", ErrorCategory.ObjectNotFound, path)); + WriteError(new ErrorRecord(driveNotFound, string.Empty, ErrorCategory.ObjectNotFound, path)); return retColl; } catch (ProviderNotFoundException providerNotFound) { - WriteError(new ErrorRecord(providerNotFound, "", ErrorCategory.ObjectNotFound, path)); + WriteError(new ErrorRecord(providerNotFound, string.Empty, ErrorCategory.ObjectNotFound, path)); return retColl; } catch (ItemNotFoundException pathNotFound) { - WriteError(new ErrorRecord(pathNotFound, "", ErrorCategory.ObjectNotFound, path)); + WriteError(new ErrorRecord(pathNotFound, string.Empty, ErrorCategory.ObjectNotFound, path)); return retColl; } catch (Exception exc) { - WriteError(new ErrorRecord(exc, "", ErrorCategory.ObjectNotFound, path)); + WriteError(new ErrorRecord(exc, string.Empty, ErrorCategory.ObjectNotFound, path)); return retColl; } @@ -1787,6 +1807,7 @@ private StringCollection ValidateAndResolveFilePath(string path) Exception exc = new Exception(string.Format(CultureInfo.InvariantCulture, msg, pi.ProviderPath)); WriteError(new ErrorRecord(exc, "NotALogFile", ErrorCategory.InvalidArgument, path)); } + continue; } @@ -1809,7 +1830,7 @@ private void CheckHashTablesForNullValues() { foreach (string key in hash.Keys) { - Object value = hash[key]; + object value = hash[key]; if (value == null) { string msg = _resourceMgr.GetString("NullNotAllowedInHashtable"); @@ -1876,7 +1897,6 @@ private string AddProviderPredicatesToFilter(StringCollection providers) return ret; } - // // BuildProvidersPredicate() builds a predicate expression like: // "System/Provider[@Name='a' or @Name='b']" @@ -1886,7 +1906,7 @@ private string BuildProvidersPredicate(StringCollection providers) { if (providers.Count == 0) { - return ""; + return string.Empty; } StringBuilder predicate = new StringBuilder("System/Provider["); @@ -1898,12 +1918,12 @@ private string BuildProvidersPredicate(StringCollection providers) predicate.Append(" or "); } } + predicate.Append("]"); return predicate.ToString(); } - // // BuildAllProvidersPredicate() builds a predicate expression like: // "System/Provider[@Name='a' or @Name='b']" @@ -1915,7 +1935,7 @@ private string BuildAllProvidersPredicate() { if (_providersByLogMap.Count == 0) { - return ""; + return string.Empty; } StringBuilder predicate = new StringBuilder("System/Provider["); @@ -1948,7 +1968,6 @@ private string BuildAllProvidersPredicate() return predicate.ToString(); } - // // AddLogsForProviderToInternalMap helper. // Retrieves log names to which _providerName writes. @@ -2038,10 +2057,10 @@ private void FindLogNamesMatchingWildcards(EventLogSession eventLogSession, IEnu foreach (string logPattern in logPatterns) { bool bMatched = false; + WildcardPattern wildLogPattern = new WildcardPattern(logPattern, WildcardOptions.IgnoreCase); + foreach (string actualLogName in eventLogSession.GetLogNames()) { - WildcardPattern wildLogPattern = new WildcardPattern(logPattern, WildcardOptions.IgnoreCase); - if (((!WildcardPattern.ContainsWildcardCharacters(logPattern)) && (logPattern.Equals(actualLogName, StringComparison.CurrentCultureIgnoreCase))) || @@ -2080,9 +2099,11 @@ private void FindLogNamesMatchingWildcards(EventLogSession eventLogSession, IEnu { _logNamesMatchingWildcard.Add(actualLogName.ToLowerInvariant()); } + bMatched = true; } } + if (!bMatched) { string msg = _resourceMgr.GetString("NoMatchingLogsFound"); @@ -2105,10 +2126,10 @@ private void FindProvidersByLogForWildcardPatterns(EventLogSession eventLogSessi foreach (string provPattern in providerPatterns) { bool bMatched = false; + WildcardPattern wildProvPattern = new WildcardPattern(provPattern, WildcardOptions.IgnoreCase); + foreach (string provName in eventLogSession.GetProviderNames()) { - WildcardPattern wildProvPattern = new WildcardPattern(provPattern, WildcardOptions.IgnoreCase); - if (((!WildcardPattern.ContainsWildcardCharacters(provPattern)) && (provPattern.Equals(provName, StringComparison.CurrentCultureIgnoreCase))) || @@ -2119,6 +2140,7 @@ private void FindProvidersByLogForWildcardPatterns(EventLogSession eventLogSessi bMatched = true; } } + if (!bMatched) { string msg = _resourceMgr.GetString("NoMatchingProvidersFound"); @@ -2130,4 +2152,3 @@ private void FindProvidersByLogForWildcardPatterns(EventLogSession eventLogSessi } } - diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventSnapin.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventSnapin.cs index 6aa23f2eca7a..5debeaef1766 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventSnapin.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventSnapin.cs @@ -1,13 +1,11 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// - +// Licensed under the MIT License. using System; using System.Collections.Generic; -using System.Text; -using System.Management.Automation; using System.ComponentModel; +using System.Management.Automation; +using System.Text; namespace Microsoft.PowerShell.Commands { @@ -92,6 +90,7 @@ public override string[] Types return _types; } } + private string[] _types = new string[] { "getevent.types.ps1xml" }; /// diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs index d8635b38b5d8..fc08bcd96c4c 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs @@ -1,32 +1,30 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// - +// Licensed under the MIT License. using System; -using System.Text; -using System.IO; -using System.Xml; -using System.Net; -using System.Management.Automation; -using System.ComponentModel; -using System.Reflection; -using System.Globalization; -using System.Management.Automation.Runspaces; using System.Collections; -using System.Collections.Specialized; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Runspaces; +using System.Net; +using System.Reflection; +using System.Resources; using System.Security; using System.Security.Principal; -using System.Resources; +using System.Text; using System.Threading; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Powershell.Commands.GetCounter.PdhNative; -using Microsoft.PowerShell.Commands.GetCounter; -using Microsoft.PowerShell.Commands.Diagnostics.Common; +using System.Xml; +using Microsoft.PowerShell.Commands.Diagnostics.Common; +using Microsoft.PowerShell.Commands.GetCounter; +using Microsoft.Powershell.Commands.GetCounter.PdhNative; namespace Microsoft.PowerShell.Commands { @@ -54,15 +52,16 @@ public sealed class ImportCounterCommand : PSCmdlet public string[] Path { get { return _path; } + set { _path = value; } } + private string[] _path; private StringCollection _resolvedPaths = new StringCollection(); private List _accumulatedFileNames = new List(); - // // ListSet parameter // @@ -80,10 +79,11 @@ public string[] Path public string[] ListSet { get { return _listSet; } + set { _listSet = value; } } - private string[] _listSet = new string[0]; + private string[] _listSet = Array.Empty(); // // StartTime parameter @@ -96,10 +96,11 @@ public string[] ListSet public DateTime StartTime { get { return _startTime; } + set { _startTime = value; } } - private DateTime _startTime = DateTime.MinValue; + private DateTime _startTime = DateTime.MinValue; // // EndTime parameter @@ -112,10 +113,11 @@ public DateTime StartTime public DateTime EndTime { get { return _endTime; } + set { _endTime = value; } } - private DateTime _endTime = DateTime.MaxValue; + private DateTime _endTime = DateTime.MaxValue; // // Counter parameter @@ -133,9 +135,11 @@ public DateTime EndTime public string[] Counter { get { return _counter; } + set { _counter = value; } } - private string[] _counter = new string[0]; + + private string[] _counter = Array.Empty(); // // Summary switch @@ -144,8 +148,10 @@ public string[] Counter public SwitchParameter Summary { get { return _summary; } + set { _summary = value; } } + private SwitchParameter _summary; // @@ -161,10 +167,11 @@ public SwitchParameter Summary public Int64 MaxSamples { get { return _maxSamples; } + set { _maxSamples = value; } } - private Int64 _maxSamples = KEEP_ON_SAMPLING; + private Int64 _maxSamples = KEEP_ON_SAMPLING; private ResourceManager _resourceMgr = null; @@ -172,7 +179,6 @@ public Int64 MaxSamples private bool _stopping = false; - // // AccumulatePipelineFileNames() accumulates counter file paths in the pipeline scenario: // we do not want to construct a Pdh query until all the file names are supplied. @@ -182,7 +188,6 @@ private void AccumulatePipelineFileNames() _accumulatedFileNames.AddRange(_path); } - // // BeginProcessing() is invoked once per pipeline // @@ -196,7 +201,7 @@ protected override void BeginProcessing() throw new PlatformNotSupportedException(); } - // PowerShell Core requires at least Windows 7, + // PowerShell 7 requires at least Windows 7, // so no version test is needed _pdhHelper = new PdhHelper(false); #else @@ -217,6 +222,7 @@ protected override void EndProcessing() { return; } + ValidateFilePaths(); switch (ParameterSetName) @@ -241,7 +247,6 @@ protected override void EndProcessing() _pdhHelper.Dispose(); } - // // Handle Control-C // @@ -251,7 +256,6 @@ protected override void StopProcessing() _pdhHelper.Dispose(); } - // // ProcessRecord() override. // This is the main entry point for the cmdlet. @@ -331,7 +335,6 @@ private void ProcessListSet() continue; } - StringCollection counterSetCounters = new StringCollection(); StringCollection counterSetInstances = new StringCollection(); @@ -360,7 +363,7 @@ private void ProcessListSet() { categoryType = PerformanceCounterCategoryType.MultiInstance; } - else //if (counterSetInstances.Count == 1) //??? + else // if (counterSetInstances.Count == 1) //??? { categoryType = PerformanceCounterCategoryType.SingleInstance; } @@ -371,6 +374,7 @@ private void ProcessListSet() WriteObject(setObj); bMatched = true; } + if (!bMatched) { string msg = _resourceMgr.GetString("NoMatchingCounterSetsInFile"); @@ -432,9 +436,11 @@ private void ProcessGetCounter() continue; } + validPaths.Add(expandedPath); } } + if (validPaths.Count == 0) { return; @@ -488,6 +494,7 @@ private void ProcessGetCounter() { break; } + if (res != 0 && res != PdhResults.PDH_INVALID_DATA) { ReportPdhError(res, false); @@ -508,7 +515,6 @@ private void ProcessGetCounter() } } - // // ValidateFilePaths() helper. // Validates the _resolvedPaths: present for all parametersets. @@ -525,9 +531,9 @@ private void ValidateFilePaths() WriteVerbose(fileName); string curExtension = System.IO.Path.GetExtension(fileName); - if (!curExtension.Equals(".blg", StringComparison.CurrentCultureIgnoreCase) - && !curExtension.Equals(".csv", StringComparison.CurrentCultureIgnoreCase) - && !curExtension.Equals(".tsv", StringComparison.CurrentCultureIgnoreCase)) + if (!curExtension.Equals(".blg", StringComparison.OrdinalIgnoreCase) + && !curExtension.Equals(".csv", StringComparison.OrdinalIgnoreCase) + && !curExtension.Equals(".tsv", StringComparison.OrdinalIgnoreCase)) { string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterNotALogFile"), fileName); Exception exc = new Exception(msg); @@ -535,7 +541,7 @@ private void ValidateFilePaths() return; } - if (!curExtension.Equals(firstExt, StringComparison.CurrentCultureIgnoreCase)) + if (!curExtension.Equals(firstExt, StringComparison.OrdinalIgnoreCase)) { string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterNoMixedLogTypes"), fileName); Exception exc = new Exception(msg); @@ -544,7 +550,7 @@ private void ValidateFilePaths() } } - if (firstExt.Equals(".blg", StringComparison.CurrentCultureIgnoreCase)) + if (firstExt.Equals(".blg", StringComparison.OrdinalIgnoreCase)) { if (_resolvedPaths.Count > 32) { @@ -563,7 +569,6 @@ private void ValidateFilePaths() } } - // // ResolveFilePath helper. // Returns a string collection of resolved file paths. @@ -583,27 +588,27 @@ private bool ResolveFilePaths() } catch (PSNotSupportedException notSupported) { - WriteError(new ErrorRecord(notSupported, "", ErrorCategory.ObjectNotFound, origPath)); + WriteError(new ErrorRecord(notSupported, string.Empty, ErrorCategory.ObjectNotFound, origPath)); continue; } catch (System.Management.Automation.DriveNotFoundException driveNotFound) { - WriteError(new ErrorRecord(driveNotFound, "", ErrorCategory.ObjectNotFound, origPath)); + WriteError(new ErrorRecord(driveNotFound, string.Empty, ErrorCategory.ObjectNotFound, origPath)); continue; } catch (ProviderNotFoundException providerNotFound) { - WriteError(new ErrorRecord(providerNotFound, "", ErrorCategory.ObjectNotFound, origPath)); + WriteError(new ErrorRecord(providerNotFound, string.Empty, ErrorCategory.ObjectNotFound, origPath)); continue; } catch (ItemNotFoundException pathNotFound) { - WriteError(new ErrorRecord(pathNotFound, "", ErrorCategory.ObjectNotFound, origPath)); + WriteError(new ErrorRecord(pathNotFound, string.Empty, ErrorCategory.ObjectNotFound, origPath)); continue; } catch (Exception exc) { - WriteError(new ErrorRecord(exc, "", ErrorCategory.ObjectNotFound, origPath)); + WriteError(new ErrorRecord(exc, string.Empty, ErrorCategory.ObjectNotFound, origPath)); continue; } @@ -635,6 +640,7 @@ private void ReportPdhError(uint res, bool bTerminate) { msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterApiError"), res); } + Exception exc = new Exception(msg); if (bTerminate) { @@ -674,4 +680,3 @@ private void WriteSampleSetObject(PerformanceCounterSampleSet set, bool firstSet } } - diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index a0b008be9e52..09a7c3545226 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -1,7 +1,7 @@  - PowerShell Core's Microsoft.PowerShell.Commands.Diagnostics project + PowerShell's Microsoft.PowerShell.Commands.Diagnostics project $(NoWarn);CS1591 Microsoft.PowerShell.Commands.Diagnostics @@ -27,16 +27,9 @@ - - portable - - - - $(DefineConstants);UNIX - - - - full - + + + + diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs index ec064f0d8be2..3f2bfa4ec41b 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs @@ -1,18 +1,17 @@ -// // Copyright (c) Microsoft Corporation. All rights reserved. -// +// Licensed under the MIT License. using System; -using System.Management.Automation; -using System.Globalization; -using System.Reflection; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Eventing; using System.Diagnostics.Eventing.Reader; +using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Reflection; using System.Resources; -using System.Diagnostics.CodeAnalysis; -using System.Collections.Generic; using System.Xml; -using System.IO; namespace Microsoft.PowerShell.Commands { @@ -30,9 +29,8 @@ public sealed class NewWinEventCommand : PSCmdlet private const string DataTag = "data"; private ResourceManager _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager(); - /// - /// ProviderName + /// ProviderName. /// [Parameter( Position = 0, @@ -44,11 +42,13 @@ public string ProviderName { return _providerName; } + set { _providerName = value; } } + private string _providerName; /// @@ -64,16 +64,17 @@ public int Id { return _id; } + set { _id = value; _idSpecified = true; } } + private int _id; private bool _idSpecified = false; - /// /// Version (event version) /// @@ -86,18 +87,19 @@ public byte Version { return _version; } + set { _version = value; _versionSpecified = true; } } + private byte _version; private bool _versionSpecified = false; - /// - /// Event Payload + /// Event Payload. /// [Parameter( Position = 2, @@ -113,15 +115,17 @@ public object[] Payload { return _payload; } + set { _payload = value; } } + private object[] _payload; /// - /// BeginProcessing + /// BeginProcessing. /// protected override void BeginProcessing() { @@ -153,6 +157,7 @@ private void LoadProvider() string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("ProviderMetadataUnavailable"), providerName, exc.Message); throw new Exception(msg, exc); } + break; } } @@ -204,6 +209,7 @@ private void LoadEventDescriptor() break; } } + if (matchedEvent == null) { string msg = string.Format(CultureInfo.InvariantCulture, @@ -246,9 +252,7 @@ private bool VerifyTemplate(EventMetadata emd) IgnoreProcessingInstructions = true, MaxCharactersInDocument = 0, // no limit ConformanceLevel = ConformanceLevel.Fragment, -#if !CORECLR - XmlResolver = null, -#endif + XmlResolver = null }; int definedParameterCount = 0; @@ -274,6 +278,7 @@ private bool VerifyTemplate(EventMetadata emd) return false; } } + return true; } @@ -304,7 +309,7 @@ private static EventDescriptor CreateEventDescriptor(ProviderMetadata providerMe } /// - /// ProcessRecord + /// ProcessRecord. /// protected override void ProcessRecord() { @@ -321,6 +326,7 @@ protected override void ProcessRecord() _payload[i] = string.Empty; } } + provider.WriteEvent(ref ed, _payload); } else @@ -328,11 +334,12 @@ protected override void ProcessRecord() provider.WriteEvent(ref ed); } } + base.ProcessRecord(); } /// - /// EndProcessing + /// EndProcessing. /// protected override void EndProcessing() { @@ -353,4 +360,4 @@ internal EventWriteException(string msg) : base(msg) { } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs index ce1eea08e91c..0814e1b67882 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs @@ -1,15 +1,15 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.InteropServices; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; + using Microsoft.PowerShell.Commands.GetCounter; using Microsoft.Win32; @@ -105,8 +105,6 @@ internal static class PdhResults public const long PDH_QUERY_PERF_DATA_TIMEOUT = 0xC0000BFEL; } - - internal static class PerfDetail { public const uint PERF_DETAIL_NOVICE = 100; // The uninformed can understand it @@ -203,7 +201,6 @@ public PdhHelper(bool isPreVista) _isPreVista = isPreVista; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct PDH_COUNTER_PATH_ELEMENTS { @@ -232,11 +229,11 @@ private struct PDH_FMT_COUNTERVALUE_LARGE public Int64 largeValue; - //[FieldOffset (4), MarshalAs(UnmanagedType.LPStr)] - //public string AnsiStringValue; + // [FieldOffset (4), MarshalAs(UnmanagedType.LPStr)] + // public string AnsiStringValue; - //[FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)] - //public string WideStringValue; + // [FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)] + // public string WideStringValue; }; [StructLayout(LayoutKind.Sequential)] @@ -274,7 +271,6 @@ private struct PDH_TIME_INFO public UInt32 SampleCount; } - /* // // This is the structure returned by PdhGetCounterInfo(). @@ -304,7 +300,6 @@ struct PDH_COUNTER_INFO { [FieldOffset(104)]public IntPtr DataBuffer; }*/ - [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhBindInputDataSource(out PdhSafeDataSourceHandle phDataSource, string szLogFileNameList); @@ -314,13 +309,13 @@ struct PDH_COUNTER_INFO { [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhAddCounter(PdhSafeQueryHandle queryHandle, string counterPath, IntPtr userData, out IntPtr counterHandle); - //Win7+ only + // Win7+ only [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhAddRelogCounter(PdhSafeQueryHandle queryHandle, string counterPath, UInt32 counterType, UInt32 counterDefaultScale, UInt64 timeBase, out IntPtr counterHandle); - //not on XP + // not on XP [DllImport("pdh.dll")] private static extern uint PdhCollectQueryDataWithTime(PdhSafeQueryHandle queryHandle, ref Int64 pllTimeStamp); @@ -343,19 +338,18 @@ struct PDH_COUNTER_INFO { out PdhSafeLogHandle phLog ); - //Win7+ only + // Win7+ only [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern void PdhResetRelogCounterValues(PdhSafeLogHandle LogHandle); - - //Win7+ only + // Win7+ only [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhSetCounterValue(IntPtr CounterHandle, ref PDH_RAW_COUNTER Value, /*PPDH_RAW_COUNTER */ string InstanceName ); - //Win7+ only + // Win7+ only [DllImport("pdh.dll")] private static extern uint PdhWriteRelogSample(PdhSafeLogHandle LogHandle, Int64 Timestamp @@ -392,11 +386,10 @@ Int64 Timestamp [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhParseCounterPath(string szFullPathBuffer, - IntPtr pCounterPathElements, //PDH_COUNTER_PATH_ELEMENTS + IntPtr pCounterPathElements, // PDH_COUNTER_PATH_ELEMENTS ref IntPtr pdwBufferSize, uint dwFlags); - [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhExpandWildCardPathH(PdhSafeDataSourceHandle hDataSource, string szWildCardPath, @@ -404,15 +397,15 @@ Int64 Timestamp ref IntPtr pcchPathListLength, uint dwFlags); - //not available on XP + // not available on XP [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhValidatePathEx(PdhSafeDataSourceHandle hDataSource, string szFullPathBuffer); [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhValidatePath(string szFullPathBuffer); - //not available on XP - [DllImport("pdh.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)] //private export + // not available on XP + [DllImport("pdh.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)] // private export private static extern IntPtr PdhGetExplainText(string szMachineName, string szObjectName, string szCounterName); [DllImport("pdh.dll", CharSet = CharSet.Unicode)] @@ -427,11 +420,9 @@ Int64 Timestamp [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhSetQueryTimeRange(PdhSafeQueryHandle hQuery, ref PDH_TIME_INFO pInfo); - [DllImport("pdh.dll", CharSet = CharSet.Unicode)] private static extern uint PdhLookupPerfNameByIndex(string szMachineName, UInt32 dwNameIndex, IntPtr szNameBuffer, ref int pcchNameBufferSize); - private PdhSafeDataSourceHandle _hDataSource = null; private PdhSafeQueryHandle _hQuery = null; @@ -468,7 +459,6 @@ public void Dispose() // private Dictionary _consumerPathToHandleAndInstanceMap = new Dictionary(); - // // m_ReloggerPathToHandleAndInstanceMap map is used for writing relog counters. // @@ -485,7 +475,7 @@ private void ReadPdhMultiString(ref IntPtr strNative, Int32 strSize, ref StringC { Debug.Assert(strSize >= 2); int offset = 0; - string allSubstringsWithNulls = ""; + string allSubstringsWithNulls = string.Empty; while (offset <= ((strSize * sizeof(char)) - 4)) { Int32 next4 = Marshal.ReadInt32(strNative, offset); @@ -504,8 +494,6 @@ private void ReadPdhMultiString(ref IntPtr strNative, Int32 strSize, ref StringC strColl.AddRange(allSubstringsWithNulls.Split('\0')); } - - private uint GetCounterInfoPlus(IntPtr hCounter, out UInt32 counterType, out UInt32 defaultScale, out UInt64 timeBase) { uint res = 0; @@ -530,7 +518,7 @@ private uint GetCounterInfoPlus(IntPtr hCounter, out UInt32 counterType, out UIn res = PdhGetCounterInfo(hCounter, false, ref pBufferSize, bufCounterInfo); if (res == 0 && bufCounterInfo != IntPtr.Zero) { - //PDH_COUNTER_INFO pdhCounterInfo = (PDH_COUNTER_INFO)Marshal.PtrToStructure(bufCounterInfo, typeof(PDH_COUNTER_INFO)); + // PDH_COUNTER_INFO pdhCounterInfo = (PDH_COUNTER_INFO)Marshal.PtrToStructure(bufCounterInfo, typeof(PDH_COUNTER_INFO)); counterType = (uint)Marshal.ReadInt32(bufCounterInfo, 4); defaultScale = (uint)Marshal.ReadInt32(bufCounterInfo, 20); @@ -560,7 +548,7 @@ public uint ConnectToDataSource() uint res = PdhHelper.PdhBindInputDataSource(out _hDataSource, null); if (res != 0) { - //Console.WriteLine("error in PdhBindInputDataSource: " + res); + // Console.WriteLine("error in PdhBindInputDataSource: " + res); return res; } @@ -581,12 +569,12 @@ public uint ConnectToDataSource(string dataSourceName) uint res = PdhHelper.PdhBindInputDataSource(out _hDataSource, dataSourceName); if (res != 0) { - //Console.WriteLine("error in PdhBindInputDataSource: " + res); + // Console.WriteLine("error in PdhBindInputDataSource: " + res); } + return res; } - public uint ConnectToDataSource(StringCollection blgFileNames) { if (blgFileNames.Count == 1) @@ -594,7 +582,7 @@ public uint ConnectToDataSource(StringCollection blgFileNames) return ConnectToDataSource(blgFileNames[0]); } - string doubleNullTerminated = ""; + string doubleNullTerminated = string.Empty; foreach (string fileName in blgFileNames) { doubleNullTerminated += fileName + '\0'; @@ -611,8 +599,9 @@ public uint OpenQuery() if (res != 0) { - //Console.WriteLine("error in PdhOpenQueryH: " + res); + // Console.WriteLine("error in PdhOpenQueryH: " + res); } + return res; } @@ -635,7 +624,6 @@ public uint OpenLogForWriting(string logName, PdhLogFileType logFileType, bool b return res; } - public uint SetQueryTimeRange(DateTime startTime, DateTime endTime) { Debug.Assert(_hQuery != null); @@ -647,12 +635,14 @@ public uint SetQueryTimeRange(DateTime startTime, DateTime endTime) { startTime = new DateTime(startTime.Ticks, DateTimeKind.Utc); } + pTimeInfo.StartTime = (startTime == DateTime.MinValue) ? 0 : startTime.ToFileTimeUtc(); if (endTime != DateTime.MaxValue && endTime.Kind == DateTimeKind.Local) { endTime = new DateTime(endTime.Ticks, DateTimeKind.Utc); } + pTimeInfo.EndTime = (endTime == DateTime.MaxValue) ? Int64.MaxValue : endTime.ToFileTimeUtc(); pTimeInfo.SampleCount = 0; @@ -669,7 +659,7 @@ public uint EnumBlgFilesMachines(ref StringCollection machineNames) return res; } - Int32 cChars = MachineListTcharSizePtr.ToInt32(); //should be ok on 64 bit + Int32 cChars = MachineListTcharSizePtr.ToInt32(); // should be ok on 64 bit IntPtr strMachineList = Marshal.AllocHGlobal(cChars * sizeof(char)); try @@ -728,23 +718,23 @@ public uint EnumObjectItems(string machineName, string objectName, ref StringCol if (res == PdhResults.PDH_CSTATUS_NO_INSTANCE) { instanceNames.Clear(); - return 0; //masking the error + return 0; // masking the error } else if (res == PdhResults.PDH_CSTATUS_NO_OBJECT) { counterNames.Clear(); - return 0; //masking the error + return 0; // masking the error } else if (res != PdhResults.PDH_MORE_DATA) { - //Console.WriteLine("error in PdhEnumObjectItemsH 1st call: " + res); + // Console.WriteLine("error in PdhEnumObjectItemsH 1st call: " + res); return res; } Int32 cChars = pCounterBufferSize.ToInt32(); IntPtr strCountersList = (cChars > 0) ? Marshal.AllocHGlobal((cChars) * sizeof(char)) : IntPtr.Zero; - //re-set count to 0 if it is lte 2 + // re-set count to 0 if it is lte 2 if (cChars < 0) { pCounterBufferSize = new IntPtr(0); @@ -754,7 +744,7 @@ public uint EnumObjectItems(string machineName, string objectName, ref StringCol IntPtr strInstancesList = (cChars > 0) ? Marshal.AllocHGlobal((cChars) * sizeof(char)) : IntPtr.Zero; - //re-set count to 0 if it is lte 2 + // re-set count to 0 if it is lte 2 if (cChars < 0) { pInstanceBufferSize = new IntPtr(0); @@ -768,7 +758,7 @@ public uint EnumObjectItems(string machineName, string objectName, ref StringCol PerfDetail.PERF_DETAIL_WIZARD, 0); if (res != 0) { - //Console.WriteLine("error in PdhEnumObjectItemsH 2nd call: " + res + "\n Counter buffer size is " + // Console.WriteLine("error in PdhEnumObjectItemsH 2nd call: " + res + "\n Counter buffer size is " // + pCounterBufferSize.ToInt32() + "\n Instance buffer size is " + pInstanceBufferSize.ToInt32()); } else @@ -786,6 +776,7 @@ public uint EnumObjectItems(string machineName, string objectName, ref StringCol { Marshal.FreeHGlobal(strCountersList); } + if (strInstancesList != IntPtr.Zero) { Marshal.FreeHGlobal(strInstancesList); @@ -799,7 +790,6 @@ public uint GetValidPathsFromFiles(ref StringCollection validPaths) { Debug.Assert(_hDataSource != null && !_hDataSource.IsInvalid, "Call ConnectToDataSource before GetValidPathsFromFiles"); - StringCollection machineNames = new StringCollection(); uint res = this.EnumBlgFilesMachines(ref machineNames); if (res != 0) @@ -818,7 +808,7 @@ public uint GetValidPathsFromFiles(ref StringCollection validPaths) foreach (string counterSet in counterSets) { - //Console.WriteLine("Counter set " + counterSet); + // Console.WriteLine("Counter set " + counterSet); StringCollection counterSetCounters = new StringCollection(); StringCollection counterSetInstances = new StringCollection(); @@ -836,13 +826,14 @@ public uint GetValidPathsFromFiles(ref StringCollection validPaths) } } } + return res; } private bool IsPathValid(ref PDH_COUNTER_PATH_ELEMENTS pathElts, out string outPath) { bool ret = false; - outPath = ""; + outPath = string.Empty; IntPtr pPathBufferSize = new IntPtr(0); uint res = PdhMakeCounterPath(ref pathElts, IntPtr.Zero, ref pPathBufferSize, 0); @@ -894,10 +885,9 @@ public bool IsPathValid(string path) } } - private uint MakePath(PDH_COUNTER_PATH_ELEMENTS pathElts, out string outPath, bool bWildcardInstances) { - outPath = ""; + outPath = string.Empty; IntPtr pPathBufferSize = new IntPtr(0); if (bWildcardInstances) @@ -947,7 +937,6 @@ private uint MakeAllInstancePath(string origPath, out string unifiedPath) return MakePath(elts, out unifiedPath, true); } - private uint ParsePath(string fullPath, ref PDH_COUNTER_PATH_ELEMENTS pCounterPathElements) { IntPtr bufSize = new IntPtr(0); @@ -958,7 +947,7 @@ private uint ParsePath(string fullPath, ref PDH_COUNTER_PATH_ELEMENTS pCounterPa 0); if (res != PdhResults.PDH_MORE_DATA && res != 0) { - //Console.WriteLine("error in PdhParseCounterPath: " + res); + // Console.WriteLine("error in PdhParseCounterPath: " + res); return res; } @@ -1002,7 +991,7 @@ private uint ParsePath(string fullPath, ref PDH_COUNTER_PATH_ELEMENTS pCounterPa public uint TranslateLocalCounterPath(string englishPath, out string localizedPath) { uint res = 0; - localizedPath = ""; + localizedPath = string.Empty; PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS(); res = ParsePath(englishPath, ref pathElts); if (res != 0) @@ -1022,7 +1011,6 @@ public uint TranslateLocalCounterPath(string englishPath, out string localizedPa RegistryKey rootKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"); string[] regCounters = (string[])rootKey.GetValue("Counter"); - // NOTE: 1-based enumeration because the name strings follow index strings in the array Int32 counterIndex = -1; Int32 objIndex = -1; @@ -1051,6 +1039,7 @@ public uint TranslateLocalCounterPath(string englishPath, out string localizedPa return (uint)PdhResults.PDH_INVALID_PATH; } } + if (counterIndex != -1 && objIndex != -1) { break; @@ -1062,7 +1051,6 @@ public uint TranslateLocalCounterPath(string englishPath, out string localizedPa return (uint)PdhResults.PDH_INVALID_PATH; } - // Now, call retrieve the localized names of the object and the counter by index: string objNameLocalized; res = LookupPerfNameByIndex(pathElts.MachineName, (uint)objIndex, out objNameLocalized); @@ -1070,8 +1058,8 @@ public uint TranslateLocalCounterPath(string englishPath, out string localizedPa { return res; } - pathElts.ObjectName = objNameLocalized; + pathElts.ObjectName = objNameLocalized; string ctrNameLocalized; res = LookupPerfNameByIndex(pathElts.MachineName, (uint)counterIndex, out ctrNameLocalized); @@ -1079,17 +1067,16 @@ public uint TranslateLocalCounterPath(string englishPath, out string localizedPa { return res; } + pathElts.CounterName = ctrNameLocalized; // Assemble the path back by using the translated object and counter names: res = MakePath(pathElts, out localizedPath, false); - return res; } - public uint LookupPerfNameByIndex(string machineName, uint index, out string locName) { // @@ -1100,7 +1087,7 @@ public uint LookupPerfNameByIndex(string machineName, uint index, out string loc int strSize = 256; IntPtr localizedPathPtr = Marshal.AllocHGlobal(strSize * sizeof(char)); - locName = ""; + locName = string.Empty; uint res = 0; try { @@ -1111,6 +1098,7 @@ public uint LookupPerfNameByIndex(string machineName, uint index, out string loc localizedPathPtr = Marshal.AllocHGlobal(strSize * sizeof(char)); res = PdhLookupPerfNameByIndex(machineName, index, localizedPathPtr, ref strSize); } + if (res == 0) { locName = Marshal.PtrToStringUni(localizedPathPtr); @@ -1124,8 +1112,6 @@ public uint LookupPerfNameByIndex(string machineName, uint index, out string loc return res; } - - public uint GetValidPaths(string machineName, string objectName, ref StringCollection counters, @@ -1165,10 +1151,10 @@ public uint LookupPerfNameByIndex(string machineName, uint index, out string loc } } } + return res; } - public uint AddCounters(ref StringCollection validPaths, bool bFlushOldCounters) { Debug.Assert(_hQuery != null && !_hQuery.IsInvalid); @@ -1210,7 +1196,6 @@ public uint AddCounters(ref StringCollection validPaths, bool bFlushOldCounters) return bAtLeastOneAdded ? 0 : res; } - // // AddRelogCounters combines instances and adds counters to m_hQuery. // The counter handles and full paths @@ -1254,7 +1239,7 @@ public uint AddRelogCounters(PerformanceCounterSampleSet sampleSet) prefixInstanceMap.Add(lcPathMinusInstance, newList); } - //Console.WriteLine ("Added path " + sample.Path + " to the 1ist map with prefix " + lcPathMinusInstance); + // Console.WriteLine ("Added path " + sample.Path + " to the 1ist map with prefix " + lcPathMinusInstance); } // @@ -1292,7 +1277,7 @@ public uint AddRelogCounters(PerformanceCounterSampleSet sampleSet) continue; } - //now, add all actual paths to m_ReloggerPathToHandleAndInstanceMap + // now, add all actual paths to m_ReloggerPathToHandleAndInstanceMap foreach (PerformanceCounterSample sample in prefixInstanceMap[prefix]) { PDH_COUNTER_PATH_ELEMENTS pathElts = new PDH_COUNTER_PATH_ELEMENTS(); @@ -1315,18 +1300,16 @@ public uint AddRelogCounters(PerformanceCounterSampleSet sampleSet) if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLowerInvariant())) { _reloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLowerInvariant(), chi); - //Console.WriteLine ("added map path:" + sample.Path ); + // Console.WriteLine ("added map path:" + sample.Path ); } } } - //TODO: verify that all counters are in the map + // TODO: verify that all counters are in the map return (_reloggerPathToHandleAndInstanceMap.Keys.Count > 0) ? 0 : res; } - - // // AddRelogCountersPreservingPaths preserves all paths and adds as relog counters to m_hQuery. // The counter handles and full paths are added to m_ReloggerPathToHandleAndInstanceMap @@ -1386,6 +1369,7 @@ public string GetCounterSetHelp(string szMachineName, string szObjectName) { return string.Empty; } + IntPtr retString = PdhGetExplainText(szMachineName, szObjectName, null); return Marshal.PtrToStringUni(retString); } @@ -1400,6 +1384,7 @@ public uint ReadNextSetPreVista(out PerformanceCounterSampleSet nextSet, bool bS { return res; } + if (res != 0 && res != PdhResults.PDH_NO_DATA) { return res; @@ -1425,14 +1410,14 @@ public uint ReadNextSetPreVista(out PerformanceCounterSampleSet nextSet, bool bS res = GetCounterInfoPlus(hCounter, out counterType, out defaultScale, out timeBase); if (res != 0) { - //Console.WriteLine ("GetCounterInfoPlus for " + path + " failed with " + res); + // Console.WriteLine ("GetCounterInfoPlus for " + path + " failed with " + res); } PDH_RAW_COUNTER rawValue; res = PdhGetRawCounterValue(hCounter, out counterTypePtr, out rawValue); if (res == PdhResults.PDH_INVALID_DATA || res == PdhResults.PDH_NO_DATA) { - //Console.WriteLine ("PdhGetRawCounterValue returned " + res); + // Console.WriteLine ("PdhGetRawCounterValue returned " + res); samplesArr[sampleIndex++] = new PerformanceCounterSample(path, _consumerPathToHandleAndInstanceMap[path].InstanceName, 0, @@ -1473,7 +1458,7 @@ public uint ReadNextSetPreVista(out PerformanceCounterSampleSet nextSet, bool bS out fmtValueDouble); if (res == PdhResults.PDH_INVALID_DATA || res == PdhResults.PDH_NO_DATA) { - //Console.WriteLine ("PdhGetFormattedCounterValue returned " + res); + // Console.WriteLine ("PdhGetFormattedCounterValue returned " + res); samplesArr[sampleIndex++] = new PerformanceCounterSample(path, _consumerPathToHandleAndInstanceMap[path].InstanceName, 0, @@ -1493,7 +1478,7 @@ public uint ReadNextSetPreVista(out PerformanceCounterSampleSet nextSet, bool bS } else if (res != 0) { - //Console.WriteLine ("PdhGetFormattedCounterValue returned " + res); + // Console.WriteLine ("PdhGetFormattedCounterValue returned " + res); return res; } @@ -1534,7 +1519,6 @@ public uint ReadNextSetPreVista(out PerformanceCounterSampleSet nextSet, bool bS return res; } - public uint ReadNextSet(out PerformanceCounterSampleSet nextSet, bool bSkipReading) { Debug.Assert(_hQuery != null && !_hQuery.IsInvalid); @@ -1554,6 +1538,7 @@ public uint ReadNextSet(out PerformanceCounterSampleSet nextSet, bool bSkipReadi { return res; } + if (res != 0 && res != PdhResults.PDH_NO_DATA) { return res; @@ -1589,7 +1574,7 @@ public uint ReadNextSet(out PerformanceCounterSampleSet nextSet, bool bSkipReadi res = GetCounterInfoPlus(hCounter, out counterType, out defaultScale, out timeBase); if (res != 0) { - //Console.WriteLine ("GetCounterInfoPlus for " + path + " failed with " + res); + // Console.WriteLine ("GetCounterInfoPlus for " + path + " failed with " + res); } PDH_RAW_COUNTER rawValue; @@ -1658,7 +1643,6 @@ public uint ReadNextSet(out PerformanceCounterSampleSet nextSet, bool bSkipReadi fmtValueDouble.CStatus); } - nextSet = new PerformanceCounterSampleSet(batchStamp, samplesArr, _firstReading); _firstReading = false; @@ -1677,7 +1661,6 @@ public uint ReadNextSet(out PerformanceCounterSampleSet nextSet, bool bSkipReadi return res; } - public uint GetFilesSummary(out CounterFileInfo summary) { IntPtr pNumEntries = new IntPtr(0); @@ -1770,7 +1753,6 @@ public uint SetCounterValue(PerformanceCounterSample sample, out bool bUnknownPa rawStruct.TimeStamp.dwLowDateTime = (int)(new DateTime(sample.Timestamp.Ticks, DateTimeKind.Utc).ToFileTimeUtc() & 0xFFFFFFFFL); rawStruct.CStatus = sample.Status; - return PdhSetCounterValue(_reloggerPathToHandleAndInstanceMap[lcPath].hCounter, ref rawStruct, /*PPDH_RAW_COUNTER */ _reloggerPathToHandleAndInstanceMap[lcPath].InstanceName); diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs index b2adb0112683..c77e9f10f5e9 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Runtime.InteropServices; @@ -21,7 +20,6 @@ public override bool IsInvalid } } - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { @@ -29,9 +27,6 @@ protected override bool ReleaseHandle() } } - - - internal sealed class PdhSafeQueryHandle : SafeHandle { private PdhSafeQueryHandle() : base(IntPtr.Zero, true) { } @@ -44,7 +39,6 @@ public override bool IsInvalid } } - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { @@ -64,7 +58,6 @@ public override bool IsInvalid } } - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.txt b/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.txt index 6e004d457d8c..4605fbe008ce 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.txt +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.txt @@ -1,7 +1,7 @@ #Copyright (c) Microsoft Corporation. All rights reserved. Vendor=Microsoft -Description=This Windows PowerShell snap-in contains Windows Eventing and Performance Counter cmdlets. +Description=This PowerShell snap-in contains Windows Eventing and Performance Counter cmdlets. NoMatchingEventsFound=No events were found that match the specified selection criteria. NoMatchingLogsFound=There is not an event log on the {0} computer that matches "{1}". @@ -56,4 +56,4 @@ CounterCircularNoMaxSize=The Circular parameter will be ignored unless the MaxSi ExportCtrWin7Required=This cmdlet can be run only on Microsoft Windows 7 and above. FileOpenFailed=Unable to open the {0} file for writing. FileCreateFailed=Unable to create the {0} file. Verify that the path is valid. -ExportDestPathAmbiguous=The following export destination path is ambiguous: {0}. \ No newline at end of file +ExportDestPathAmbiguous=The following export destination path is ambiguous: {0}. diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 7f0bb98cc6b4..1d851a24af40 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -1,7 +1,7 @@  - PowerShell Core's Microsoft.PowerShell.Commands.Management project + PowerShell's Microsoft.PowerShell.Commands.Management project $(NoWarn);CS1570 Microsoft.PowerShell.Commands.Management @@ -55,20 +55,9 @@ - - portable - - - - $(DefineConstants);UNIX - - - - full - - - + + diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/SessionBasedWrapper.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/SessionBasedWrapper.cs index 793bb0e6ba87..470b7b42be42 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/SessionBasedWrapper.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/SessionBasedWrapper.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -38,7 +37,7 @@ internal SessionBasedCmdletAdapter() private bool _disposed; /// - /// Releases resources associated with this object + /// Releases resources associated with this object. /// public void Dispose() { @@ -47,7 +46,7 @@ public void Dispose() } /// - /// Releases resources associated with this object + /// Releases resources associated with this object. /// protected virtual void Dispose(bool disposing) { @@ -61,6 +60,7 @@ protected virtual void Dispose(bool disposing) _parentJob = null; } } + _disposed = true; } } @@ -70,12 +70,13 @@ protected virtual void Dispose(bool disposing) #region Common parameters (AsJob, ThrottleLimit, Session) /// - /// Session to operate on + /// Session to operate on. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] protected TSession[] Session { - get { return _session ?? (_session = new TSession[] {this.DefaultSession}); } + get { return _session ?? (_session = new TSession[] { this.DefaultSession }); } + set { if (value == null) @@ -87,18 +88,21 @@ protected TSession[] Session _sessionWasSpecified = true; } } + private TSession[] _session; private bool _sessionWasSpecified; /// - /// Whether to wrap and emit the whole operation as a background job + /// Whether to wrap and emit the whole operation as a background job. /// [Parameter] public SwitchParameter AsJob { get { return _asJob; } + set { _asJob = value; } } + private bool _asJob; /// @@ -114,8 +118,8 @@ public SwitchParameter AsJob /// /// Creates a object that performs a query against the wrapped object model. /// - /// Remote session to query - /// Query parameters + /// Remote session to query. + /// Query parameters. /// /// /// This method shouldn't do any processing or interact with the remote session. @@ -163,10 +167,10 @@ private StartableJob DoCreateQueryJob(TSession sessionForJob, QueryBuilder query /// /// Creates a object that invokes an instance method in the wrapped object model. /// - /// Remote session to invoke the method in - /// The object on which to invoke the method - /// Method invocation details - /// true if successful method invocations should emit downstream the being operated on + /// Remote session to invoke the method in. + /// The object on which to invoke the method. + /// Method invocation details. + /// true if successful method invocations should emit downstream the being operated on. /// /// /// This method shouldn't do any processing or interact with the remote session. @@ -200,8 +204,8 @@ private StartableJob DoCreateInstanceMethodInvocationJob(TSession sessionForJob, /// /// Creates a object that invokes a static method in the wrapped object model. /// - /// Remote session to invoke the method in - /// Method invocation details + /// Remote session to invoke the method in. + /// Method invocation details. /// /// /// This method shouldn't do any processing or interact with the remote session. @@ -284,7 +288,7 @@ internal virtual TSession GetSessionOfOriginFromInstance(TObjectInstance instanc /// /// Returns default sessions to use when the user doesn't specify the -Session cmdlet parameter. /// - /// Default sessions to use when the user doesn't specify the -Session cmdlet parameter + /// Default sessions to use when the user doesn't specify the -Session cmdlet parameter. protected abstract TSession DefaultSession { get; } /// @@ -320,6 +324,7 @@ private enum JobOutputs NonPipelineResults = Output | Error | Warning | Verbose | Debug | Progress, PipelineResults = Results, } + private static void DiscardJobOutputs(Job job, JobOutputs jobOutputsToDiscard) { if (JobOutputs.Output == (jobOutputsToDiscard & JobOutputs.Output)) @@ -367,8 +372,8 @@ private static void DiscardJobOutputs(Job job, JobOutputs jobOutputsToDiscard) /// /// Queries for object instances in the object model. /// - /// Query parameters - /// A lazy evaluated collection of object instances + /// Query parameters. + /// A lazy evaluated collection of object instances. public override void ProcessRecord(QueryBuilder query) { _parentJob.DisableFlowControlForPendingCmdletActionsQueue(); @@ -390,11 +395,11 @@ public override void ProcessRecord(QueryBuilder query) } /// - /// Queries for instance and invokes an instance method + /// Queries for instance and invokes an instance method. /// - /// Query parameters - /// Method invocation details - /// true if successful method invocations should emit downstream the object instance being operated on + /// Query parameters. + /// Method invocation details. + /// true if successful method invocations should emit downstream the object instance being operated on. public override void ProcessRecord(QueryBuilder query, MethodInvocationInfo methodInvocationInfo, bool passThru) { _parentJob.DisableFlowControlForPendingJobsQueue(); @@ -524,6 +529,7 @@ private IEnumerable GetSessionsToActAgainst(MethodInvocationInfo metho associatedSessions.Add(associatedSession); } } + if (associatedSessions.Count == 1) { return associatedSessions; @@ -570,9 +576,9 @@ private TSession GetImpliedSession() /// /// Invokes an instance method in the object model. /// - /// The object on which to invoke the method - /// Method invocation details - /// true if successful method invocations should emit downstream the being operated on + /// The object on which to invoke the method. + /// Method invocation details. + /// true if successful method invocations should emit downstream the being operated on. public override void ProcessRecord(TObjectInstance objectInstance, MethodInvocationInfo methodInvocationInfo, bool passThru) { if (objectInstance == null) throw new ArgumentNullException("objectInstance"); @@ -598,7 +604,7 @@ public override void ProcessRecord(TObjectInstance objectInstance, MethodInvocat /// /// Invokes a static method in the object model. /// - /// Method invocation details + /// Method invocation details. public override void ProcessRecord(MethodInvocationInfo methodInvocationInfo) { if (methodInvocationInfo == null) throw new ArgumentNullException("methodInvocationInfo"); @@ -637,6 +643,7 @@ public override void BeginProcessing() { conflictingParameter = "Confirm"; } + if (conflictingParameter != null) { string errorMessage = string.Format( diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs index 0854414a4409..12331bd9cd4f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs @@ -1,18 +1,19 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Globalization; using System.Management.Automation; using System.Runtime.Serialization; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Represents an error during execution of a CIM job + /// Represents an error during execution of a CIM job. /// [Serializable] public class CimJobException : SystemException, IContainsErrorRecord @@ -126,6 +127,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont errorId: "CimJob_" + inner.GetType().Name, errorCategory: ErrorCategory.NotSpecified); } + return cimJobException; } @@ -268,57 +270,57 @@ private static ErrorCategory ConvertCimNativeErrorCodeToErrorCategory(NativeErro case NativeErrorCode.Ok: return ErrorCategory.NotSpecified; case NativeErrorCode.Failed: - return ErrorCategory.NotSpecified; ; + return ErrorCategory.NotSpecified; case NativeErrorCode.AccessDenied: - return ErrorCategory.PermissionDenied; ; + return ErrorCategory.PermissionDenied; case NativeErrorCode.InvalidNamespace: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.InvalidParameter: - return ErrorCategory.InvalidArgument; ; + return ErrorCategory.InvalidArgument; case NativeErrorCode.InvalidClass: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.NotFound: - return ErrorCategory.ObjectNotFound; ; + return ErrorCategory.ObjectNotFound; case NativeErrorCode.NotSupported: - return ErrorCategory.NotImplemented; ; + return ErrorCategory.NotImplemented; case NativeErrorCode.ClassHasChildren: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.ClassHasInstances: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.InvalidSuperClass: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.AlreadyExists: - return ErrorCategory.ResourceExists; ; + return ErrorCategory.ResourceExists; case NativeErrorCode.NoSuchProperty: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.TypeMismatch: - return ErrorCategory.InvalidType; ; + return ErrorCategory.InvalidType; case NativeErrorCode.QueryLanguageNotSupported: - return ErrorCategory.NotImplemented; ; + return ErrorCategory.NotImplemented; case NativeErrorCode.InvalidQuery: - return ErrorCategory.InvalidArgument; ; + return ErrorCategory.InvalidArgument; case NativeErrorCode.MethodNotAvailable: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.MethodNotFound: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.NamespaceNotEmpty: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.InvalidEnumerationContext: - return ErrorCategory.MetadataError; ; + return ErrorCategory.MetadataError; case NativeErrorCode.InvalidOperationTimeout: - return ErrorCategory.InvalidArgument; ; + return ErrorCategory.InvalidArgument; case NativeErrorCode.PullHasBeenAbandoned: - return ErrorCategory.OperationStopped; ; + return ErrorCategory.OperationStopped; case NativeErrorCode.PullCannotBeAbandoned: - return ErrorCategory.CloseError; ; + return ErrorCategory.CloseError; case NativeErrorCode.FilteredEnumerationNotSupported: - return ErrorCategory.NotImplemented; ; + return ErrorCategory.NotImplemented; case NativeErrorCode.ContinuationOnErrorNotSupported: - return ErrorCategory.NotImplemented; ; + return ErrorCategory.NotImplemented; case NativeErrorCode.ServerLimitsExceeded: - return ErrorCategory.ResourceBusy; ; + return ErrorCategory.ResourceBusy; case NativeErrorCode.ServerIsShuttingDown: - return ErrorCategory.ResourceUnavailable; ; + return ErrorCategory.ResourceUnavailable; default: return ErrorCategory.NotSpecified; } @@ -353,6 +355,7 @@ public ErrorRecord ErrorRecord { get { return _errorRecord; } } + private ErrorRecord _errorRecord; internal bool IsTerminatingError diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs index 93bb4f7932b5..4690a729e1a1 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs @@ -1,15 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job wrapping invocation of a CreateInstance intrinsic CIM method + /// Job wrapping invocation of a CreateInstance intrinsic CIM method. /// internal class CreateInstanceJob : PropertySettingJob { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs index 58b981c0ce56..6caf4146d209 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs @@ -1,15 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job wrapping invocation of a DeleteInstance intrinsic CIM method + /// Job wrapping invocation of a DeleteInstance intrinsic CIM method. /// internal class DeleteInstanceJob : MethodInvocationJobBase { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs index 2ed6c186d067..440594322f61 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs @@ -1,17 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Globalization; using System.Management.Automation; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job that handles executing a WQL (in the future CQL?) query on a remote CIM server + /// Job that handles executing a WQL (in the future CQL?) query on a remote CIM server. /// internal class EnumerateAssociatedInstancesJob : QueryJobBase { @@ -90,6 +91,7 @@ internal override void WriteObject(object outputObject) PSObject pso = PSObject.AsPSObject(outputObject); AddShowComputerNameMarker(pso); } + base.WriteObject(outputObject); } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ExtrinsicMethodInvocationJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ExtrinsicMethodInvocationJob.cs index 366f31a76ae0..13c75586f31f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ExtrinsicMethodInvocationJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ExtrinsicMethodInvocationJob.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -8,14 +7,16 @@ using System.Globalization; using System.Linq; using System.Management.Automation; + using Microsoft.Management.Infrastructure; using Microsoft.PowerShell.Cim; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job wrapping invocation of an extrinsic CIM method + /// Job wrapping invocation of an extrinsic CIM method. /// internal abstract class ExtrinsicMethodInvocationJob : MethodInvocationJobBase { @@ -131,6 +132,7 @@ private void OnNext(CimMethodResult methodResult) var tmp = new PSNoteProperty(element.Key, element.Value.Value); propertyBag.Properties.Add(tmp); } + this.WriteObject(propertyBag); } } @@ -180,6 +182,7 @@ private void WriteObject(object cmdletOutput, MethodParameter methodParameter) pso.TypeNames.Insert(0, methodParameter.ParameterTypeName); } } + this.WriteObject(cmdletOutput); } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs index 86adf0750e65..b1c8873d29f8 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs @@ -1,16 +1,17 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; + using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure.Options; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job wrapping invocation of an extrinsic CIM method + /// Job wrapping invocation of an extrinsic CIM method. /// internal class InstanceMethodInvocationJob : ExtrinsicMethodInvocationJob { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/MethodInvocationJobBase.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/MethodInvocationJobBase.cs index db81ea379366..edb6b2c991ac 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/MethodInvocationJobBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/MethodInvocationJobBase.cs @@ -1,21 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Management.Automation; + using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure.Options; using Microsoft.PowerShell.Cim; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job wrapping invocation of an extrinsic CIM method + /// Job wrapping invocation of an extrinsic CIM method. /// internal abstract class MethodInvocationJobBase : CimChildJobBase { @@ -59,6 +60,7 @@ private IEnumerable GetMethodInputParametersCore(Func - /// Job wrapping invocation of a ModifyInstance intrinsic CIM method + /// Job wrapping invocation of a ModifyInstance intrinsic CIM method. /// internal class ModifyInstanceJob : PropertySettingJob { @@ -66,6 +67,7 @@ internal override object PassThruObject PSObject pso = PSObject.AsPSObject(_resultFromModifyInstance); AddShowComputerNameMarker(pso); } + _resultFromModifyInstanceHasBeenPassedThru = true; return _resultFromModifyInstance; } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/PropertySettingJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/PropertySettingJob.cs index c51085292a2a..f5cc8a862e7c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/PropertySettingJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/PropertySettingJob.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using Microsoft.Management.Infrastructure; using Microsoft.PowerShell.Cim; @@ -8,7 +7,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job wrapping invocation of a CreateInstance or ModifyInstance intrinsic CIM method + /// Job wrapping invocation of a CreateInstance or ModifyInstance intrinsic CIM method. /// internal abstract class PropertySettingJob : MethodInvocationJobBase { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs index 734f87e7e1ba..d7648ce809a9 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs @@ -1,17 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Globalization; using System.Text; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job that handles executing a WQL (in the future CQL?) query on a remote CIM server + /// Job that handles executing a WQL (in the future CQL?) query on a remote CIM server. /// internal class QueryInstancesJob : QueryJobBase { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJobBase.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJobBase.cs index 662d890b69ce..c05d9991fda1 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJobBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJobBase.cs @@ -1,15 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Base job for queries + /// Base job for queries. /// internal abstract class QueryJobBase : CimChildJobBase { @@ -37,6 +38,7 @@ public override void OnNext(CimInstance item) { return; } + this.WriteObject(item); }); } @@ -53,6 +55,7 @@ public override void OnCompleted() { errorId = errorId + "_" + notFoundError.PropertyName; } + CimJobException cimJobException = CimJobException.CreateWithFullControl( this.JobContext, notFoundError.ErrorMessageGenerator(this.Description, this.JobContext.ClassName), @@ -62,6 +65,7 @@ public override void OnCompleted() { cimJobException.ErrorRecord.SetTargetObject(notFoundError.PropertyValue); } + this.WriteError(cimJobException.ErrorRecord); } }); diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs index f19fadc66788..a025ef77d6be 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; + using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure.Options; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Job wrapping invocation of a static CIM method + /// Job wrapping invocation of a static CIM method. /// internal class StaticMethodInvocationJob : ExtrinsicMethodInvocationJob { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/TerminatingErrorTracker.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/TerminatingErrorTracker.cs index 67035a15e2d8..15c5d5099d17 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/TerminatingErrorTracker.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/TerminatingErrorTracker.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -10,13 +9,15 @@ using System.Management.Automation.Remoting; using System.Runtime.CompilerServices; using System.Threading; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Tracks (per-session) terminating errors in a given cmdlet invocation + /// Tracks (per-session) terminating errors in a given cmdlet invocation. /// internal class TerminatingErrorTracker { @@ -48,6 +49,7 @@ private static int GetNumberOfSessions(InvocationInfo invocationInfo) // - this translates into potentially unlimited number of CimSession we will work with return int.MaxValue; } + int maxNumberOfSessionsIndicatedByCimInstanceArguments = 1; foreach (object cmdletArgument in invocationInfo.BoundParameters.Values) { @@ -63,6 +65,7 @@ private static int GetNumberOfSessions(InvocationInfo invocationInfo) numberOfSessionsAssociatedWithArgument); } } + return maxNumberOfSessionsIndicatedByCimInstanceArguments; } @@ -111,6 +114,7 @@ internal bool DidSessionAlreadyPassedConnectivityTest(CimSession session) { return alreadyPassedConnectivityTest; } + return false; } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs index cf2a78ca39ec..84c001262385 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Concurrent; @@ -10,15 +9,17 @@ using System.Management.Automation.Remoting; using System.Management.Automation.Remoting.Internal; using System.Threading; + using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure.Options; using Microsoft.PowerShell.Cim; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// Base class for all child jobs that wrap CIM operations + /// Base class for all child jobs that wrap CIM operations. /// internal abstract class CimChildJobBase : StartableJob, @@ -35,6 +36,7 @@ internal CimJobContext JobContext return _jobContext; } } + private readonly CimJobContext _jobContext; internal CimChildJobBase(CimJobContext jobContext) @@ -54,7 +56,7 @@ internal CimChildJobBase(CimJobContext jobContext) _jobSpecificCustomOptions = new Lazy(this.CalculateJobSpecificCustomOptions); } - private CimSensitiveValueConverter _cimSensitiveValueConverter = new CimSensitiveValueConverter(); + private readonly CimSensitiveValueConverter _cimSensitiveValueConverter = new CimSensitiveValueConverter(); internal CimSensitiveValueConverter CimSensitiveValueConverter { get { return _cimSensitiveValueConverter; } } internal abstract IObservable GetCimOperation(); @@ -102,6 +104,7 @@ private static bool IsWsManQuotaReached(Exception exception) { return false; } + if (errorCodeProperty.CimType != CimType.UInt32) { return false; @@ -173,15 +176,18 @@ private void SleepAndRetry_OnWakeup(object state) _sleepAndRetryTimer.Dispose(); _sleepAndRetryTimer = null; } + if (_jobWasStopped) { this.SetCompletedJobState(JobState.Stopped, null); return; } } + this.StartJob(); }); } + private void SleepAndRetry() { int tmpRandomDelay = _random.Next(0, _sleepAndRetryDelayRangeMs); @@ -219,7 +225,7 @@ private void SleepAndRetry() } /// - /// Indicates a location where this job is running + /// Indicates a location where this job is running. /// public override string Location { @@ -239,7 +245,7 @@ public override string Location } /// - /// Status message associated with the Job + /// Status message associated with the Job. /// public override string StatusMessage { @@ -326,6 +332,7 @@ internal string GetDescription() } internal abstract string Description { get; } + internal abstract string FailSafeDescription { get; } internal void ExceptionSafeWrapper(Action action) @@ -359,10 +366,12 @@ internal void ExceptionSafeWrapper(Action action) { everythingIsOk = true; } + if (_alreadyReachedCompletedState && _jobHadErrors) { everythingIsOk = true; } + if (!everythingIsOk) { Dbg.Assert(false, "PSInvalidOperationException should only happen in certain job states"); @@ -398,7 +407,6 @@ internal CimOperationOptions CreateOperationOptions() operationOptions.SetOption("__MI_OPERATIONOPTIONS_IMPROVEDPERF_STREAMING", 1); - operationOptions.Flags |= this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.SchemaConformanceLevel; if (this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.ResourceUri != null) @@ -494,6 +502,7 @@ internal CimOperationOptions CreateOperationOptions() this.JobContext.CmdletizationModuleVersion, CimSensitiveValueConverter); } + CimOperationOptionsHelper.SetCustomOption( operationOptions, "MI_OPERATIONOPTIONS_POWERSHELL_CMDLETNAME", @@ -524,7 +533,6 @@ private CimCustomOptionsDictionary GetJobSpecificCustomOptions() return _jobSpecificCustomOptions.Value; } - #endregion #region Controlling job state @@ -542,6 +550,7 @@ public override void StopJob() { return; } + _jobWasStopped = true; if (!_jobWasStarted) @@ -559,6 +568,7 @@ public override void StopJob() this.SetJobState(JobState.Stopping); } } + _cancellationTokenSource.Cancel(); } @@ -596,6 +606,7 @@ internal void ReportJobFailure(IContainsErrorRecord exception) out sessionWasAlreadyTerminated); } } + if (brokenSessionException != null) { string brokenSessionMessage = string.Format( @@ -752,6 +763,7 @@ private void WriteProgressCallback(string activity, string currentOperation, str { activity = this.GetDescription(); } + if (string.IsNullOrEmpty(statusDescription)) { statusDescription = this.StatusMessage; @@ -982,6 +994,7 @@ private CimResponseType PromptUserCallback(string message, CimPromptType promptT { _userRespondedYesToAtLeastOneShouldProcess = true; } + return result; } @@ -995,6 +1008,7 @@ internal static bool IsShowComputerNameMarkerPresent(CimInstance cimInstance) { return false; } + return true.Equals(psShowComputerNameProperty.Value); } @@ -1025,17 +1039,20 @@ internal override void WriteObject(object outputObject) { cimInstance = outputObject as CimInstance; } + if (cimInstance != null) { CimCmdletAdapter.AssociateSessionOfOriginWithInstance(cimInstance, this.JobContext.Session); CimCustomOptionsDictionary.AssociateCimInstanceWithCustomOptions(cimInstance, this.GetJobSpecificCustomOptions()); } + if (this.JobContext.ShowComputerName) { if (pso == null) { pso = PSObject.AsPSObject(outputObject); } + AddShowComputerNameMarker(pso); if (cimInstance == null) { @@ -1055,11 +1072,13 @@ protected override void Dispose(bool disposing) { isCompleted = _alreadyReachedCompletedState; } + if (!isCompleted) { this.StopJob(); this.Finished.WaitOne(); } + _cimSensitiveValueConverter.Dispose(); } } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs index 50b4d4869753..a7fb3465b69b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs @@ -1,11 +1,11 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Globalization; using System.Management.Automation; + using Microsoft.Management.Infrastructure.Options; namespace Microsoft.PowerShell.Cmdletization.Cim @@ -27,9 +27,13 @@ internal class CimCmdletDefinitionContext } public string CmdletizationClassName { get; private set; } + public string CmdletizationClassVersion { get; private set; } + public Version CmdletizationModuleVersion { get; private set; } + public bool SupportsShouldProcess { get; private set; } + private readonly IDictionary _privateData; private const string QueryLanguageKey = "QueryDialect"; @@ -48,8 +52,10 @@ public bool UseEnumerateInstancesInsteadOfWql { newValue = true; } + _useEnumerateInstancesInsteadOfWql = newValue; } + return _useEnumerateInstancesInsteadOfWql.Value; } } @@ -123,6 +129,7 @@ public Uri ResourceUri _resourceUriHasBeenCalculated = true; } + return _resourceUri; } } @@ -165,6 +172,7 @@ public CimOperationFlags SchemaConformanceLevel _schemaConformanceLevel = newSchemaConformanceLevel; } + return _schemaConformanceLevel.Value; } } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs index 75866b49e368..f5bb541c0121 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs @@ -1,10 +1,11 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim @@ -83,11 +84,17 @@ internal class CimCmdletInvocationContext public CimCmdletDefinitionContext CmdletDefinitionContext { get; private set; } public InvocationInfo CmdletInvocationInfo { get; private set; } + public MshCommandRuntime.ShouldProcessPossibleOptimization ShouldProcessOptimization { get; private set; } + public ActionPreference ErrorActionPreference { get; private set; } + public ActionPreference WarningActionPreference { get; private set; } + public ActionPreference VerboseActionPreference { get; private set; } + public ActionPreference DebugActionPreference { get; private set; } + public string NamespaceOverride { get; private set; } public bool IsRunningInBackground diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs index 9c6679697c1e..abcb5d33f6cc 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -11,13 +10,15 @@ using System.Net.Mail; using System.Net.NetworkInformation; using System.Reflection; +using System.Runtime.InteropServices; using System.Security; using System.Security.AccessControl; using System.Security.Cryptography.X509Certificates; using System.Xml; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; -using System.Runtime.InteropServices; // TODO/FIXME: Move this class to src/cimSupport/other directory (to map to the namespace it lives in and functionality it implements [cmdletization independent]) @@ -53,15 +54,18 @@ private unsafe void Copy(char* source, int offset, int charsToCopy) { throw new ArgumentOutOfRangeException("offset"); } + if (offset + charsToCopy > _string.Length) { throw new ArgumentOutOfRangeException("charsToCopy"); } fixed (char* target = _string) - for (int i = 0; i < charsToCopy; i++) { - target[offset + i] = source[i]; + for (int i = 0; i < charsToCopy; i++) + { + target[offset + i] = source[i]; + } } } @@ -98,7 +102,7 @@ internal void Copy(SecureString source, int offset) } /// - /// Releases resources associated with this object + /// Releases resources associated with this object. /// public void Dispose() { @@ -107,7 +111,7 @@ public void Dispose() } /// - /// Releases resources associated with this object + /// Releases resources associated with this object. /// private void Dispose(bool disposing) { @@ -128,7 +132,7 @@ private void Dispose(bool disposing) private readonly List _trackedDisposables = new List(); /// - /// Releases resources associated with this object + /// Releases resources associated with this object. /// public void Dispose() { @@ -137,7 +141,7 @@ public void Dispose() } /// - /// Releases resources associated with this object + /// Releases resources associated with this object. /// private void Dispose(bool disposing) { @@ -147,6 +151,7 @@ private void Dispose(bool disposing) { d.Dispose(); } + _trackedDisposables.Clear(); } } @@ -172,6 +177,7 @@ internal object ConvertFromDotNetToCim(object dotNetObject) var sensitiveString = new SensitiveString(escapedUsername.Length + PSCredentialDelimiter.Length + credential.Password.Length); lock (_trackedDisposables) { _trackedDisposables.Add(sensitiveString); } + sensitiveString.Copy(escapedUsername, 0); sensitiveString.Copy(PSCredentialDelimiter, escapedUsername.Length); sensitiveString.Copy(credential.Password, escapedUsername.Length + PSCredentialDelimiter.Length); @@ -183,6 +189,7 @@ internal object ConvertFromDotNetToCim(object dotNetObject) SecureString secureString = (SecureString)psObject.BaseObject; var sensitiveString = new SensitiveString(secureString.Length); lock (_trackedDisposables) { _trackedDisposables.Add(sensitiveString); } + sensitiveString.Copy(secureString, 0); return sensitiveString.Value; } @@ -200,6 +207,7 @@ internal object ConvertFromDotNetToCim(object dotNetObject) object cimElement = ConvertFromDotNetToCim(dotNetArray.GetValue(i)); cimArray.SetValue(cimElement, i); } + return cimArray; } } @@ -225,7 +233,7 @@ internal static Type GetCimType(Type dotNetType) internal static class CimValueConverter { - /// The only kind of exception this method can throw + /// The only kind of exception this method can throw. internal static object ConvertFromDotNetToCim(object dotNetObject) { if (dotNetObject == null) @@ -243,10 +251,12 @@ internal static object ConvertFromDotNetToCim(object dotNetObject) { return psObject.BaseObject; } + if (typeof(CimInstance).IsAssignableFrom(dotNetType)) { return psObject.BaseObject; } + if (typeof(PSReference).IsAssignableFrom(dotNetType)) { PSReference psReference = (PSReference)psObject.BaseObject; @@ -274,6 +284,7 @@ internal static object ConvertFromDotNetToCim(object dotNetObject) object cimElement = ConvertFromDotNetToCim(dotNetArray.GetValue(i)); cimArray.SetValue(cimElement, i); } + return cimArray; } } @@ -338,7 +349,7 @@ internal static object ConvertFromDotNetToCim(object dotNetObject) CmdletizationResources.CimConversion_CimIntrinsicValue); } - /// The only kind of exception this method can throw + /// The only kind of exception this method can throw. internal static object ConvertFromCimToDotNet(object cimObject, Type expectedDotNetType) { if (expectedDotNetType == null) { throw new ArgumentNullException("expectedDotNetType"); } @@ -357,6 +368,7 @@ internal static object ConvertFromCimToDotNet(object cimObject, Type expectedDot { return LanguagePrimitives.ConvertTo(cimObject, expectedDotNetType, CultureInfo.InvariantCulture); } + if (expectedDotNetType == typeof(CimInstance)) { return LanguagePrimitives.ConvertTo(cimObject, expectedDotNetType, CultureInfo.InvariantCulture); @@ -374,6 +386,7 @@ internal static object ConvertFromCimToDotNet(object cimObject, Type expectedDot object dotNetElement = ConvertFromCimToDotNet(cimArray.GetValue(i), dotNetElementType); dotNetArray.SetValue(dotNetElement, i); } + return dotNetArray; } } @@ -483,6 +496,7 @@ internal static CimType GetCimTypeEnum(Type dotNetType) { return CimType.Reference; } + if (typeof(PSReference[]).IsAssignableFrom(dotNetType)) { return CimType.ReferenceArray; @@ -509,10 +523,12 @@ internal static Type GetCimType(Type dotNetType) { return dotNetType; } + if (dotNetType == typeof(CimInstance)) { return dotNetType; } + if (dotNetType == typeof(PSReference)) { return dotNetType; @@ -569,7 +585,7 @@ internal static Type GetCimType(Type dotNetType) } /// - /// Returns a type of CIM representation if conversion from/to CIM can be done purely with LanguagePrimitives.ConvertTo + /// Returns a type of CIM representation if conversion from/to CIM can be done purely with LanguagePrimitives.ConvertTo. /// /// /// @@ -614,6 +630,7 @@ internal static Type GetElementType(Type arrayType) { return null; } + Type elementType = arrayType.GetElementType(); if (elementType.IsArray) { @@ -666,4 +683,4 @@ internal static void AssertIntrinsicCimType(Type type) "Caller should verify that type is an intrinsic CIM type"); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs index 2cee2f22a881..3603b3395940 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs @@ -1,10 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Globalization; using System.Management.Automation; + using Microsoft.Management.Infrastructure; namespace Microsoft.PowerShell.Cmdletization.Cim @@ -25,6 +25,7 @@ internal class CimJobContext public CimCmdletInvocationContext CmdletInvocationContext { get; private set; } public CimSession Session { get; private set; } + public object TargetObject { get; private set; } public string ClassName @@ -43,6 +44,7 @@ public string ClassNameOrNullIfResourceUriIsUsed { return null; } + return this.ClassName; } } @@ -55,6 +57,7 @@ public string Namespace { return this.CmdletInvocationContext.NamespaceOverride; } + return GetCimNamespace(this.CmdletInvocationContext.CmdletDefinitionContext.CmdletizationClassName); } } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimOperationOptionsHelper.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimOperationOptionsHelper.cs index 528dac6cdabe..f6eb6b994031 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimOperationOptionsHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimOperationOptionsHelper.cs @@ -1,14 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; + using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure.Options; using Microsoft.PowerShell.Cim; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim @@ -105,6 +106,7 @@ internal static CimCustomOptionsDictionary MergeOptions(CimCustomOptionsDictiona result = MergeOptions(result, instanceRelatedToThisOperation); } } + return result; } @@ -115,7 +117,7 @@ internal void Apply(CimOperationOptions cimOperationOptions, CimSensitiveValueCo } /// - /// CimQuery supports building of queries against CIM object model + /// CimQuery supports building of queries against CIM object model. /// internal static class CimOperationOptionsHelper { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs index 4878cf51bf7a..4e10fc94517e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -17,7 +16,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// CimQuery supports building of queries against CIM object model + /// CimQuery supports building of queries against CIM object model. /// internal class CimQuery : QueryBuilder, ISessionBoundQueryBuilder { @@ -53,7 +52,7 @@ private static string ObjectToWqlLiteral(object o) { if (LanguagePrimitives.IsNull(o)) { - return "null"; // based on an example at http://msdn.microsoft.com/en-us/library/aa394054(VS.85).aspx + return "null"; // based on an example at https://msdn.microsoft.com/library/aa394054(VS.85).aspx } o = CimValueConverter.ConvertFromDotNetToCim(o); @@ -96,9 +95,10 @@ private static string ObjectToWqlLiteral(object o) { if ((bool)LanguagePrimitives.ConvertTo(o, typeof(bool), CultureInfo.InvariantCulture)) { - return "TRUE"; // based on http://msdn.microsoft.com/en-us/library/aa394054(VS.85).aspx + return "TRUE"; // based on https://msdn.microsoft.com/library/aa394054(VS.85).aspx } - return "FALSE"; // based on http://msdn.microsoft.com/en-us/library/aa394054(VS.85).aspx + + return "FALSE"; // based on https://msdn.microsoft.com/library/aa394054(VS.85).aspx } throw CimValueConverter.GetInvalidCastException( @@ -191,10 +191,10 @@ private static string GetMatchCondition(string propertyName, IEnumerable propert #region Public inputs from cmdletization /// - /// Modifies the query, so that it only returns objects with a given property value + /// Modifies the query, so that it only returns objects with a given property value. /// - /// Property name to query on - /// Property values to accept in the query + /// Property name to query on. + /// Property values to accept in the query. /// /// true if should be treated as a containing a wildcard pattern; /// false otherwise @@ -214,10 +214,10 @@ public override void FilterByProperty(string propertyName, IEnumerable allowedPr } /// - /// Modifies the query, so that it does not return objects with a given property value + /// Modifies the query, so that it does not return objects with a given property value. /// - /// Property name to query on - /// Property values to reject in the query + /// Property name to query on. + /// Property values to reject in the query. /// /// true if should be treated as a containing a wildcard pattern; /// false otherwise @@ -241,10 +241,10 @@ public override void ExcludeByProperty(string propertyName, IEnumerable excluded } /// - /// Modifies the query, so that it returns only objects that have a property value greater than or equal to a threshold + /// Modifies the query, so that it returns only objects that have a property value greater than or equal to a threshold. /// - /// Property name to query on - /// Minimum property value + /// Property name to query on. + /// Minimum property value. /// /// Describes how to handle filters that didn't match any objects /// @@ -265,10 +265,10 @@ public override void FilterByMinPropertyValue(string propertyName, object minPro } /// - /// Modifies the query, so that it returns only objects that have a property value less than or equal to a threshold + /// Modifies the query, so that it returns only objects that have a property value less than or equal to a threshold. /// - /// Property name to query on - /// Maximum property value + /// Property name to query on. + /// Maximum property value. /// /// Describes how to handle filters that didn't match any objects /// @@ -291,10 +291,10 @@ public override void FilterByMaxPropertyValue(string propertyName, object maxPro /// /// Modifies the query, so that it returns only objects associated with /// - /// object that query results have to be associated with - /// name of the association - /// name of the role that has in the association - /// name of the role that query results have in the association + /// Object that query results have to be associated with. + /// Name of the association. + /// Name of the role that has in the association. + /// Name of the role that query results have in the association. /// /// Describes how to handle filters that didn't match any objects /// @@ -308,7 +308,7 @@ public override void FilterByAssociatedInstance(object associatedInstance, strin } /// - /// Sets a query option + /// Sets a query option. /// /// /// @@ -318,6 +318,7 @@ public override void AddQueryOption(string optionName, object optionValue) { throw new ArgumentNullException("optionName"); } + if (optionValue == null) { throw new ArgumentNullException("optionValue"); @@ -361,13 +362,14 @@ CimSession ISessionBoundQueryBuilder.GetTargetSession() { return CimCmdletAdapter.GetSessionOfOriginFromCimInstance(_associatedObject); } + return null; } /// - /// Returns a string that represents the current CIM query + /// Returns a string that represents the current CIM query. /// - /// A string that represents the current CIM query + /// A string that represents the current CIM query. public override string ToString() { return _wqlCondition.ToString(); diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs index 8a7bfa882a59..ad37e321aa1b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.ObjectModel; @@ -9,13 +8,15 @@ using System.Management.Automation; using System.Runtime.CompilerServices; using System.Threading; + using Microsoft.Management.Infrastructure; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// - /// CIM-specific ObjectModelWrapper + /// CIM-specific ObjectModelWrapper. /// public sealed class CimCmdletAdapter : SessionBasedCmdletAdapter, @@ -32,7 +33,7 @@ public sealed class CimCmdletAdapter : #region Changing Session parameter to CimSession /// - /// CimSession to operate on + /// CimSession to operate on. /// [Parameter] [ValidateNotNullOrEmpty] @@ -44,6 +45,7 @@ public CimSession[] CimSession { return base.Session; } + set { base.Session = value; @@ -65,12 +67,14 @@ public override int ThrottleLimit return this.CmdletDefinitionContext.DefaultThrottleLimit; } + set { base.ThrottleLimit = value; _throttleLimitIsSetExplicitly = true; } } + private bool _throttleLimitIsSetExplicitly; #endregion @@ -78,9 +82,9 @@ public override int ThrottleLimit #region ObjectModelWrapper overrides /// - /// Creates a query builder for CIM OM + /// Creates a query builder for CIM OM. /// - /// Query builder for CIM OM + /// Query builder for CIM OM. public override QueryBuilder GetQueryBuilder() { return new CimQuery(); @@ -97,6 +101,7 @@ internal CimCmdletInvocationContext CmdletInvocationContext this.GetDynamicNamespace())); } } + private CimCmdletInvocationContext _cmdletInvocationContext; internal CimCmdletDefinitionContext CmdletDefinitionContext @@ -112,9 +117,11 @@ internal CimCmdletDefinitionContext CmdletDefinitionContext this.Cmdlet.CommandInfo.CommandMetadata.SupportsShouldProcess, this.PrivateData); } + return _cmdletDefinitionContext; } } + private CimCmdletDefinitionContext _cmdletDefinitionContext; internal InvocationInfo CmdletInvocationInfo @@ -131,7 +138,7 @@ internal InvocationInfo CmdletInvocationInfo /// /// Returns a new job name to use for the parent job that handles throttling of the child jobs that actually perform querying and method invocation. /// - /// Job name + /// Job name. protected override string GenerateParentJobName() { return "CimJob" + Interlocked.Increment(ref CimCmdletAdapter.s_jobNumber).ToString(CultureInfo.InvariantCulture); @@ -140,7 +147,7 @@ protected override string GenerateParentJobName() /// /// Returns default sessions to use when the user doesn't specify the -Session cmdlet parameter. /// - /// Default sessions to use when the user doesn't specify the -Session cmdlet parameter + /// Default sessions to use when the user doesn't specify the -Session cmdlet parameter. protected override CimSession DefaultSession { get @@ -160,9 +167,9 @@ private CimJobContext CreateJobContext(CimSession session, object targetObject) /// /// Creates a object that performs a query against the wrapped object model. /// - /// Remote session to query - /// Query parameters - /// object that performs a query against the wrapped object model + /// Remote session to query. + /// Query parameters. + /// object that performs a query against the wrapped object model. internal override StartableJob CreateQueryJob(CimSession session, QueryBuilder baseQuery) { CimQuery query = baseQuery as CimQuery; @@ -176,6 +183,7 @@ internal override StartableJob CreateQueryJob(CimSession session, QueryBuilder b { return null; } + if (!IsSupportedSession(session, tracker)) { return null; @@ -190,10 +198,10 @@ internal override StartableJob CreateQueryJob(CimSession session, QueryBuilder b /// /// Creates a object that invokes an instance method in the wrapped object model. /// - /// Remote session to invoke the method in - /// The object on which to invoke the method - /// Method invocation details - /// true if successful method invocations should emit downstream the being operated on + /// Remote session to invoke the method in. + /// The object on which to invoke the method. + /// Method invocation details. + /// true if successful method invocations should emit downstream the being operated on. /// internal override StartableJob CreateInstanceMethodInvocationJob(CimSession session, CimInstance objectInstance, MethodInvocationInfo methodInvocationInfo, bool passThru) { @@ -202,6 +210,7 @@ internal override StartableJob CreateInstanceMethodInvocationJob(CimSession sess { return null; } + if (!IsSupportedSession(session, tracker)) { return null; @@ -293,8 +302,8 @@ private bool IsSupportedSession(CimSession cimSession, TerminatingErrorTracker t /// (of the class named by ) /// in the wrapped object model. /// - /// Remote session to invoke the method in - /// Method invocation details + /// Remote session to invoke the method in. + /// Method invocation details. internal override StartableJob CreateStaticMethodInvocationJob(CimSession session, MethodInvocationInfo methodInvocationInfo) { TerminatingErrorTracker tracker = TerminatingErrorTracker.GetTracker(this.CmdletInvocationInfo, isStaticCmdlet: true); @@ -302,6 +311,7 @@ internal override StartableJob CreateStaticMethodInvocationJob(CimSession sessio { return null; } + if (!IsSupportedSession(session, tracker)) { return null; @@ -345,6 +355,7 @@ internal static CimSession GetSessionOfOriginFromCimInstance(CimInstance instanc { s_cimInstanceToSessionOfOrigin.TryGetValue(instance, out result); } + return result; } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs index 683384b5a8d8..e27387f9cbef 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -8,8 +7,10 @@ using System.Globalization; using System.Linq; using System.Management.Automation; + using Microsoft.Management.Infrastructure; using Microsoft.PowerShell.Cim; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim @@ -55,7 +56,9 @@ public NotFoundError(string propertyName, object propertyValue, bool wildcardsEn } public string PropertyName { get; private set; } + public object PropertyValue { get; private set; } + public Func ErrorMessageGenerator { get; private set; } private static string GetErrorMessageForNotFound(string queryDescription, string className) @@ -152,6 +155,7 @@ private abstract class CimInstancePropertyBasedFilter : CimInstanceFilterBase { private readonly List _propertyValueFilters = new List(); protected IEnumerable PropertyValueFilters { get { return _propertyValueFilters; } } + protected void AddPropertyValueFilter(PropertyValueFilter propertyValueFilter) { _propertyValueFilters.Add(propertyValueFilter); @@ -171,6 +175,7 @@ protected override bool IsMatchCore(CimInstance cimInstance) } } } + return isMatch; } } @@ -346,9 +351,11 @@ public BehaviorOnNoMatch BehaviorOnNoMatch { _behaviorOnNoMatch = this.GetDefaultBehaviorWhenNoMatchesFound(this.CimTypedExpectedPropertyValue); } + return _behaviorOnNoMatch; } } + protected abstract BehaviorOnNoMatch GetDefaultBehaviorWhenNoMatchesFound(object cimTypedExpectedPropertyValue); private BehaviorOnNoMatch _behaviorOnNoMatch; @@ -372,6 +379,7 @@ public bool IsMatch(CimInstance o) { return false; } + object actualPropertyValue = propertyInfo.Value; if (CimTypedExpectedPropertyValue == null) @@ -423,6 +431,7 @@ private static bool IsSameType(object actualPropertyValue, object expectedProper { return true; } + if (expectedPropertyValue == null) { return true; @@ -492,6 +501,7 @@ private static bool NonWildcardEqual(string propertyName, object actualPropertyV expectedPropertyValue = expectedPropertyValue.ToString(); actualPropertyValue = actualPropertyValue.ToString(); } + var expectedPropertyValueAsString = expectedPropertyValue as string; if (expectedPropertyValueAsString != null) { @@ -511,10 +521,12 @@ private static bool WildcardEqual(string propertyName, object actualPropertyValu { return false; } + if (!LanguagePrimitives.TryConvertTo(expectedPropertyValue, out expectedPropertyValueAsString)) { return false; } + return WildcardPattern.Get(expectedPropertyValueAsString, WildcardOptions.IgnoreCase).IsMatch(actualPropertyValueAsString); } } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/AddContentCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/AddContentCommand.cs index f9784f9f5e0a..25377c7a7453 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/AddContentCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/AddContentCommand.cs @@ -1,11 +1,11 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Management.Automation; using System.Management.Automation.Internal; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -23,15 +23,12 @@ public class AddContentCommand : WriteContentCommandBase /// Seeks to the end of the writer stream in each of the writers in the /// content holders. /// - /// /// /// The content holders that contain the writers to be moved. /// - /// /// /// If calling Seek on the content writer throws an exception. /// - /// internal override void SeekContentPosition(List contentHolders) { foreach (ContentHolder holder in contentHolders) @@ -52,7 +49,6 @@ internal override void SeekContentPosition(List contentHolders) holder.PathInfo.Path, e); - // Log a provider health event MshLog.LogProviderHealthEvent( @@ -65,20 +61,17 @@ internal override void SeekContentPosition(List contentHolders) } } } - } // SeekContentPosition + } /// /// Makes the call to ShouldProcess with appropriate action and target strings. /// - /// /// /// The path to the item on which the content will be added. /// - /// /// /// True if the action should continue or false otherwise. /// - /// internal override bool CallShouldProcess(string path) { string action = NavigationResources.AddContentAction; @@ -89,6 +82,6 @@ internal override bool CallShouldProcess(string path) } #endregion protected members - } // AddContentCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs index ad56f989ae7f..f642cfab6f79 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Collections.Generic; using System.Reflection; @@ -247,11 +250,11 @@ internal static class CIMExtensions /// /// An "overload" of the /// .QueryInstances - /// method that takes only the namespace and query string as a parameters + /// method that takes only the namespace and query string as a parameters. /// - /// The CimSession to be queried - /// A string containing the namespace to run the query against - /// A string containing the query to be run + /// The CimSession to be queried. + /// A string containing the namespace to run the query against. + /// A string containing the query to be run. /// /// An IEnumerable interface that can be used to enumerate the instances /// @@ -263,9 +266,9 @@ internal static IEnumerable QueryInstances(this CimSession session, /// /// Execute a CIM query and return only the first instance in the result. /// - /// The CimSession to be queried - /// A string containing the namespace to run the query against - /// A string containing the query to be run + /// The CimSession to be queried. + /// A string containing the namespace to run the query against. + /// A string containing the query to be run. /// /// A object /// representing the first instance in a query result if successful, null @@ -292,8 +295,8 @@ internal static CimInstance QueryFirstInstance(this CimSession session, string n /// /// Execute a CIM query and return only the first instance in the result. /// - /// The CimSession to be queried - /// A string containing the query to be run + /// The CimSession to be queried. + /// A string containing the query to be run. /// /// A object /// representing the first instance in a query result if successful, null diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearContentCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearContentCommand.cs index f0e57fc3e447..b9086b99ba3b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearContentCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearContentCommand.cs @@ -1,8 +1,8 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -62,11 +62,11 @@ protected override void ProcessRecord() pathNotFound)); } } - } // ProcessRecord + } #endregion Command code /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// protected override bool ProviderSupportsShouldProcess @@ -77,22 +77,18 @@ protected override bool ProviderSupportsShouldProcess } } - /// /// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) @@ -102,7 +98,7 @@ internal override object GetDynamicParameters(CmdletProviderContext context) } return InvokeProvider.Content.ClearContentDynamicParameters(".", context); - } // GetDynamicParameters - } // ClearContentCommand -} // namespace Microsoft.PowerShell.Commands + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearPropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearPropertyCommand.cs index b752936ac116..c42c3fa199ab 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearPropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearPropertyCommand.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Collections.ObjectModel; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// A command to clear the value of a property of an item at a specified path + /// A command to clear the value of a property of an item at a specified path. /// [Cmdlet(VerbsCommon.Clear, "ItemProperty", DefaultParameterSetName = "Path", SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113284")] @@ -18,7 +18,7 @@ public class ClearItemPropertyCommand : PassThroughItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -27,67 +27,63 @@ public string[] Path get { return paths; - } // get + } set { paths = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return paths; - } // get + } set { base.SuppressWildcardExpansion = true; paths = value; - } // set - } // LiteralPath + } + } /// - /// The properties to clear from the item + /// The properties to clear from the item. /// - /// [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string Name { get { return _property; - } // get + } set { _property = value; } - } // Name + } /// /// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { Collection propertyCollection = new Collection(); @@ -102,11 +98,12 @@ internal override object GetDynamicParameters(CmdletProviderContext context) propertyCollection, context); } + return InvokeProvider.Property.ClearPropertyDynamicParameters( ".", propertyCollection, context); - } // GetDynamicParameters + } #endregion Parameters @@ -122,7 +119,7 @@ internal override object GetDynamicParameters(CmdletProviderContext context) #region Command code /// - /// Clears the properties of an item at the specified path + /// Clears the properties of an item at the specified path. /// protected override void ProcessRecord() { @@ -170,9 +167,8 @@ protected override void ProcessRecord() pathNotFound)); } } - } // ProcessRecord + } #endregion Command code - - } // ClearItemPropertyCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearRecycleBinCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearRecycleBinCommand.cs index 183c3712fbc8..f07356c287b0 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearRecycleBinCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ClearRecycleBinCommand.cs @@ -1,11 +1,14 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; using System.Management.Automation; using System.Runtime.InteropServices; -using System.IO; -using System.Globalization; -using System.ComponentModel; using System.Text.RegularExpressions; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.PowerShell.Commands { @@ -30,6 +33,7 @@ public class ClearRecycleBinCommand : PSCmdlet public string[] DriveLetter { get { return _drivesList; } + set { _drivesList = value; } } @@ -43,6 +47,7 @@ public SwitchParameter Force { return _force; } + set { _force = value; @@ -72,7 +77,7 @@ protected override void ProcessRecord() { WriteError(new ErrorRecord( new ArgumentException( - String.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.InvalidDriveNameFormat, "C", "C:", "C:\\")), + string.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.InvalidDriveNameFormat, "C", "C:", "C:\\")), "InvalidDriveNameFormat", ErrorCategory.InvalidArgument, drive)); @@ -106,7 +111,7 @@ private bool ValidDrivePath(string drivePath) { foreach (DriveInfo drive in _availableDrives) { - if (String.Compare(drive.Name, drivePath, StringComparison.OrdinalIgnoreCase) == 0) + if (string.Compare(drive.Name, drivePath, StringComparison.OrdinalIgnoreCase) == 0) { actualDrive = drive; break; @@ -119,7 +124,7 @@ private bool ValidDrivePath(string drivePath) { WriteError(new ErrorRecord( new System.IO.DriveNotFoundException( - String.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.DriveNotFound, drivePath, "Get-Volume")), + string.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.DriveNotFound, drivePath, "Get-Volume")), "DriveNotFound", ErrorCategory.InvalidArgument, drivePath)); @@ -131,13 +136,15 @@ private bool ValidDrivePath(string drivePath) // The drive path exists, and the drive is 'fixed'. return true; } + WriteError(new ErrorRecord( new ArgumentException( - String.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.InvalidDriveType, drivePath, "Get-Volume")), + string.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.InvalidDriveType, drivePath, "Get-Volume")), "InvalidDriveType", ErrorCategory.InvalidArgument, drivePath)); } + return false; } @@ -164,7 +171,7 @@ private string GetDrivePath(string driveName) { drivePath = driveName; } - else if (driveName.EndsWith(":", StringComparison.OrdinalIgnoreCase)) + else if (driveName.EndsWith(':')) { drivePath = driveName + "\\"; } @@ -172,6 +179,7 @@ private string GetDrivePath(string driveName) { drivePath = driveName + ":\\"; } + return drivePath; } @@ -199,16 +207,16 @@ private void EmptyRecycleBin(string drivePath) { // If driveName is null, then clear the recyclebin for all drives; otherwise, just for the specified driveName. - string activity = String.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.ClearRecycleBinProgressActivity); + string activity = string.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.ClearRecycleBinProgressActivity); string statusDescription; if (drivePath == null) { - statusDescription = String.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.ClearRecycleBinStatusDescriptionForAllDrives); + statusDescription = string.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.ClearRecycleBinStatusDescriptionForAllDrives); } else { - statusDescription = String.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.ClearRecycleBinStatusDescriptionByDrive, drivePath); + statusDescription = string.Format(CultureInfo.InvariantCulture, ClearRecycleBinResources.ClearRecycleBinStatusDescriptionByDrive, drivePath); } ProgressRecord progress = new ProgressRecord(0, activity, statusDescription); @@ -248,7 +256,8 @@ internal enum RecycleFlags : uint SHERB_NOPROGRESSUI = 0x00000002, SHERB_NOSOUND = 0x00000004 } + [DllImport("Shell32.dll", CharSet = CharSet.Unicode)] internal static extern uint SHEmptyRecycleBin(IntPtr hwnd, string pszRootPath, RecycleFlags dwFlags); } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs index a1fd4a9ee471..1b89f0be1de8 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs @@ -1,11 +1,11 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; using System.Collections.ObjectModel; using System.Management.Automation; +using System.Text; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -21,14 +21,14 @@ public class JoinPathCommand : CoreCommandWithCredentialsBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [Alias("PSPath")] public string[] Path { get; set; } /// - /// Gets or sets the childPath parameter to the command + /// Gets or sets the childPath parameter to the command. /// [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)] [AllowNull] @@ -42,10 +42,10 @@ public class JoinPathCommand : CoreCommandWithCredentialsBase [AllowNull] [AllowEmptyString] [AllowEmptyCollection] - public string[] AdditionalChildPath { get; set; } = Utils.EmptyArray(); + public string[] AdditionalChildPath { get; set; } = Array.Empty(); /// - /// Determines if the path should be resolved after being joined + /// Determines if the path should be resolved after being joined. /// /// [Parameter] @@ -204,7 +204,7 @@ protected override void ProcessRecord() pathNotFound)); continue; } - } // for each path + } } else { @@ -214,10 +214,9 @@ protected override void ProcessRecord() } } } - } // ProcessRecord + } #endregion Command code - - } // JoinPathCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs index a23aa040ed9e..32eeb4438489 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs @@ -1,8 +1,8 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -14,7 +14,7 @@ namespace Microsoft.PowerShell.Commands public class CompleteTransactionCommand : PSCmdlet { /// - /// Commits the current transaction + /// Commits the current transaction. /// protected override void EndProcessing() { @@ -26,6 +26,6 @@ protected override void EndProcessing() this.Context.TransactionManager.Commit(); } } - } // CommitTransactionCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs index 744849d3d995..97785dab993f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs @@ -1,8 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #if !UNIX -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ using System; using System.Collections; using System.Collections.Generic; @@ -27,7 +27,6 @@ using Microsoft.Management.Infrastructure.Options; using System.Linq; using Dbg = System.Management.Automation; -using Microsoft.PowerShell.CoreClr.Stubs; // FxCop suppressions for resource strings: [module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "ComputerResources.resources", MessageId = "unjoined")] @@ -35,16 +34,16 @@ namespace Microsoft.PowerShell.Commands { -#region Restart-Computer + #region Restart-Computer /// - /// This exception is thrown when the timeout expires before a computer finishes restarting + /// This exception is thrown when the timeout expires before a computer finishes restarting. /// [Serializable] public sealed class RestartComputerTimeoutException : RuntimeException { /// - /// Name of the computer that is restarting + /// Name of the computer that is restarting. /// public string ComputerName { get; private set; } @@ -70,41 +69,36 @@ internal RestartComputerTimeoutException(string computerName, int timeout, strin } /// - /// Construct a RestartComputerTimeoutException + /// Construct a RestartComputerTimeoutException. /// public RestartComputerTimeoutException() : base() { } /// - /// Constructs a RestartComputerTimeoutException + /// Constructs a RestartComputerTimeoutException. /// - /// /// /// The message used in the exception. /// public RestartComputerTimeoutException(string message) : base(message) { } /// - /// Constructs a RestartComputerTimeoutException + /// Constructs a RestartComputerTimeoutException. /// - /// /// /// The message used in the exception. /// - /// /// /// An exception that led to this exception. /// public RestartComputerTimeoutException(string message, Exception innerException) : base(message, innerException) { } -#region Serialization + #region Serialization /// - /// Serialization constructor for class RestartComputerTimeoutException + /// Serialization constructor for class RestartComputerTimeoutException. /// - /// /// /// serialization information /// - /// /// /// streaming context /// @@ -123,11 +117,9 @@ private RestartComputerTimeoutException(SerializationInfo info, StreamingContext /// /// Serializes the RestartComputerTimeoutException. /// - /// /// /// serialization information /// - /// /// /// streaming context /// @@ -143,45 +135,45 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("ComputerName", ComputerName); info.AddValue("Timeout", Timeout); } -#endregion Serialization + #endregion Serialization } /// - /// Defines the services that Restart-Computer can wait on + /// Defines the services that Restart-Computer can wait on. /// [SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags")] public enum WaitForServiceTypes { /// - /// Wait for the WMI service to be ready + /// Wait for the WMI service to be ready. /// Wmi = 0x0, /// - /// Wait for the WinRM service to be ready + /// Wait for the WinRM service to be ready. /// WinRM = 0x1, /// - /// Wait for the PowerShell to be ready + /// Wait for the PowerShell to be ready. /// PowerShell = 0x2, } /// - /// Restarts the computer + /// Restarts the computer. /// [Cmdlet(VerbsLifecycle.Restart, "Computer", SupportsShouldProcess = true, DefaultParameterSetName = DefaultParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135253", RemotingCapability = RemotingCapability.OwnedByCommand)] public class RestartComputerCommand : PSCmdlet, IDisposable { -#region "Parameters and PrivateData" + #region "Parameters and PrivateData" private const string DefaultParameterSet = "DefaultSet"; - private const int forcedReboot = 6; // see https://msdn.microsoft.com/en-us/library/aa394058(v=vs.85).aspx + private const int forcedReboot = 6; // see https://msdn.microsoft.com/library/aa394058(v=vs.85).aspx /// - /// The authentication options for CIM_WSMan connection + /// The authentication options for CIM_WSMan connection. /// [Parameter(ParameterSetName = DefaultParameterSet)] [ValidateSet( @@ -205,7 +197,7 @@ public class RestartComputerCommand : PSCmdlet, IDisposable [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Alias("CN", "__SERVER", "Server", "IPAddress")] - public String[] ComputerName { get; set; } = new string[] { "." }; + public string[] ComputerName { get; set; } = new string[] { "." }; private List _validatedComputerNames = new List(); private readonly List _waitOnComputers = new List(); @@ -215,7 +207,7 @@ public class RestartComputerCommand : PSCmdlet, IDisposable /// The following is the definition of the input parameter "Credential". /// Specifies a user account that has permission to perform this action. Type a /// user-name, such as "User01" or "Domain01\User01", or enter a PSCredential - /// object, such as one from the Get-Credential cmdlet + /// object, such as one from the Get-Credential cmdlet. /// [Parameter(Position = 1)] [ValidateNotNullOrEmpty] @@ -231,7 +223,7 @@ public class RestartComputerCommand : PSCmdlet, IDisposable public SwitchParameter Force { get; set; } /// - /// Specify the Wait parameter. Prompt will be blocked is the Timeout is not 0 + /// Specify the Wait parameter. Prompt will be blocked is the Timeout is not 0. /// [Parameter(ParameterSetName = DefaultParameterSet)] public SwitchParameter Wait { get; set; } @@ -247,12 +239,14 @@ public class RestartComputerCommand : PSCmdlet, IDisposable public int Timeout { get { return _timeout; } + set { _timeout = value; _timeoutSpecified = true; } } + private int _timeout = -1; private bool _timeoutSpecified = false; @@ -264,12 +258,14 @@ public int Timeout public WaitForServiceTypes For { get { return _waitFor; } + set { _waitFor = value; _waitForSpecified = true; } } + private WaitForServiceTypes _waitFor = WaitForServiceTypes.PowerShell; private bool _waitForSpecified = false; @@ -282,17 +278,19 @@ public WaitForServiceTypes For public Int16 Delay { get { return (Int16)_delay; } + set { _delay = value; _delaySpecified = true; } } + private int _delay = 5; private bool _delaySpecified = false; /// - /// Script to test if the PowerShell is ready + /// Script to test if the PowerShell is ready. /// private const string TestPowershellScript = @" $array = @($input) @@ -303,25 +301,28 @@ public Int16 Delay $arguments = @{ ComputerName = $computerName ScriptBlock = { $true } + SessionOption = NewPSSessionOption -NoMachineProfile ErrorAction = 'SilentlyContinue' } + if ( $null -ne $array[0] ) { $arguments['Credential'] = $array[0] } + $result[$computerName] = (Invoke-Command @arguments) -as [bool] } $result "; /// - /// The indicator to use when show progress + /// The indicator to use when show progress. /// private string[] _indicator = { "|", "/", "-", "\\" }; /// - /// The activity id + /// The activity id. /// private int _activityId; @@ -332,12 +333,12 @@ public Int16 Delay private const int SecondsToWaitForRestartToBegin = 25; /// - /// Actual time out in seconds + /// Actual time out in seconds. /// private int _timeoutInMilliseconds; /// - /// Indicate to exit + /// Indicate to exit. /// private bool _exit, _timeUp; private readonly CancellationTokenSource _cancel = new CancellationTokenSource(); @@ -348,11 +349,11 @@ public Int16 Delay private readonly ManualResetEventSlim _waitHandler = new ManualResetEventSlim(false); private readonly Dictionary _computerInfos = new Dictionary(StringComparer.OrdinalIgnoreCase); - // CLR 4.0 Port note - use https://msdn.microsoft.com/en-us/library/system.net.networkinformation.ipglobalproperties.hostname(v=vs.110).aspx + // CLR 4.0 Port note - use https://msdn.microsoft.com/library/system.net.networkinformation.ipglobalproperties.hostname(v=vs.110).aspx private readonly string _shortLocalMachineName = Dns.GetHostName(); // And for this, use PsUtils.GetHostname() - private readonly string _fullLocalMachineName = Dns.GetHostEntryAsync("").Result.HostName; + private readonly string _fullLocalMachineName = Dns.GetHostEntryAsync(string.Empty).Result.HostName; private int _percent; private string _status; @@ -365,12 +366,12 @@ public Int16 Delay private const string WinrmConnectionTest = "WinRM"; private const string PowerShellConnectionTest = "PowerShell"; -#endregion "parameters and PrivateData" + #endregion "parameters and PrivateData" -#region "IDisposable Members" + #region "IDisposable Members" /// - /// Dispose Method + /// Dispose Method. /// public void Dispose() { @@ -402,9 +403,9 @@ public void Dispose(bool disposing) } } -#endregion "IDisposable Members" + #endregion "IDisposable Members" -#region "Private Methods" + #region "Private Methods" /// /// Validate parameters for 'DefaultSet' @@ -426,6 +427,7 @@ private void ValidateComputerNames() { WriteError(error); } + continue; } @@ -441,7 +443,7 @@ private void ValidateComputerNames() } // Force wait with a test hook even if we're on the local computer - if (! InternalTestHooks.TestWaitStopComputer && Wait && containLocalhost) + if (!InternalTestHooks.TestWaitStopComputer && Wait && containLocalhost) { // The local machine will be ignored, and an error will be emitted. InvalidOperationException ex = new InvalidOperationException(ComputerResources.CannotWaitLocalComputer); @@ -458,7 +460,7 @@ private void ValidateComputerNames() } /// - /// Write out progress + /// Write out progress. /// /// /// @@ -473,7 +475,7 @@ private void WriteProgress(string activity, string status, int percent, Progress } /// - /// Calculate the progress percentage + /// Calculate the progress percentage. /// /// /// @@ -500,7 +502,7 @@ private int CalculateProgressPercentage(string currentStage) } /// - /// Event handler for the timer + /// Event handler for the timer. /// /// private void OnTimedEvent(object s) @@ -535,7 +537,8 @@ private List TestRestartStageUsingWsman(IEnumerable computerName try { if (token.IsCancellationRequested) { break; } - using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, Credential, WsmanAuthentication, token, this)) + + using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, Credential, WsmanAuthentication, isLocalHost: false, token, this)) { bool itemRetrieved = false; IEnumerable mCollection = cimSession.QueryInstances( @@ -591,7 +594,7 @@ private List SetUpComputerInfoUsingWsman(IEnumerable computerNam { try { - using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, Credential, WsmanAuthentication, token, this)) + using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, Credential, WsmanAuthentication, isLocalHost: false, token, this)) { bool itemRetrieved = false; IEnumerable mCollection = cimSession.QueryInstances( @@ -650,15 +653,16 @@ private void WriteOutTimeoutError(IEnumerable computerNames) string errorMsg = StringUtil.Format(ComputerResources.RestartcomputerFailed, computer, ComputerResources.TimeoutError); var exception = new RestartComputerTimeoutException(computer, Timeout, errorMsg, errorId); var error = new ErrorRecord(exception, errorId, ErrorCategory.OperationTimeout, computer); - if (! InternalTestHooks.TestWaitStopComputer ) { - WriteError(error); + if (!InternalTestHooks.TestWaitStopComputer) + { + WriteError(error); } } } -#endregion "Private Methods" + #endregion "Private Methods" -#region "Internal Methods" + #region "Internal Methods" internal static List TestWmiConnectionUsingWsman(List computerNames, List nextTestList, CancellationToken token, PSCredential credential, string wsmanAuthentication, PSCmdlet cmdlet) { @@ -675,7 +679,8 @@ internal static List TestWmiConnectionUsingWsman(List computerNa try { if (token.IsCancellationRequested) { break; } - using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, credential, wsmanAuthentication, token, cmdlet)) + + using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, credential, wsmanAuthentication, isLocalHost: false, token, cmdlet)) { bool itemRetrieved = false; IEnumerable mCollection = cimSession.QueryInstances( @@ -716,7 +721,7 @@ internal static List TestWmiConnectionUsingWsman(List computerNa } /// - /// Test the PowerShell state for the restarting computer + /// Test the PowerShell state for the restarting computer. /// /// /// @@ -771,9 +776,9 @@ internal static List TestPowerShell(List computerNames, List /// BeginProcessing method. @@ -843,7 +848,7 @@ protected override void ProcessRecord() bool isLocal = false; string compname; - if (computer.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) + if (computer.Equals("localhost", StringComparison.OrdinalIgnoreCase)) { compname = _shortLocalMachineName; isLocal = true; @@ -873,7 +878,7 @@ protected override void ProcessRecord() { _waitOnComputers.Add(computer); } - }//end foreach + } if (_waitOnComputers.Count > 0) { @@ -931,6 +936,7 @@ protected override void ProcessRecord() // We check if the target machine has already rebooted by querying the LastBootUpTime from the Win32_OperatingSystem object. // So after this step, we are sure that both the Network and the WMI or WinRM service have already come up. if (_exit) { break; } + if (restartStageTestList.Count > 0) { if (_waitOnComputers.Count == 1) @@ -939,12 +945,14 @@ protected override void ProcessRecord() _percent = CalculateProgressPercentage(StageVerification); WriteProgress(_indicator[(indicatorIndex++) % 4] + _activity, _status, _percent, ProgressRecordType.Processing); } + List nextTestList = (isForWmi || isForPowershell) ? wmiTestList : winrmTestList; restartStageTestList = TestRestartStageUsingWsman(restartStageTestList, nextTestList, _cancel.Token); } // Test WMI service if (_exit) { break; } + if (wmiTestList.Count > 0) { // This statement block executes for both CLRs. @@ -956,13 +964,16 @@ protected override void ProcessRecord() _percent = CalculateProgressPercentage(WmiConnectionTest); WriteProgress(_indicator[(indicatorIndex++) % 4] + _activity, _status, _percent, ProgressRecordType.Processing); } + wmiTestList = TestWmiConnectionUsingWsman(wmiTestList, winrmTestList, _cancel.Token, Credential, WsmanAuthentication, this); } } + if (isForWmi) { break; } // Test WinRM service if (_exit) { break; } + if (winrmTestList.Count > 0) { // This statement block executes for both CLRs. @@ -991,10 +1002,12 @@ protected override void ProcessRecord() } } } + if (isForWinRm) { break; } // Test PowerShell if (_exit) { break; } + if (psTestList.Count > 0) { if (_waitOnComputers.Count == 1) @@ -1003,6 +1016,7 @@ protected override void ProcessRecord() _percent = CalculateProgressPercentage(PowerShellConnectionTest); WriteProgress(_indicator[(indicatorIndex++) % 4] + _activity, _status, _percent, ProgressRecordType.Processing); } + psTestList = TestPowerShell(psTestList, allDoneList, _powershell, this.Credential); } } while (false); @@ -1036,6 +1050,7 @@ protected override void ProcessRecord() WriteProgress(_indicator[indicatorIndex % 4] + _activity, _status, 100, ProgressRecordType.Completed); _timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); } + break; } @@ -1044,8 +1059,7 @@ protected override void ProcessRecord() _status = StringUtil.Format(ComputerResources.WaitForMultipleComputers, machineCompleteRestart, _waitOnComputers.Count); _percent = machineCompleteRestart * 100 / _waitOnComputers.Count; } - }// end while(true) - + } if (_timeUp) { @@ -1053,24 +1067,26 @@ protected override void ProcessRecord() do { if (restartStageTestList.Count > 0) { WriteOutTimeoutError(restartStageTestList); } + if (wmiTestList.Count > 0) { WriteOutTimeoutError(wmiTestList); } // Wait for WMI. All computers that finished restarting are put in "winrmTestList" if (isForWmi) { break; } // Wait for WinRM. All computers that finished restarting are put in "psTestList" if (winrmTestList.Count > 0) { WriteOutTimeoutError(winrmTestList); } + if (isForWinRm) { break; } if (psTestList.Count > 0) { WriteOutTimeoutError(psTestList); } // Wait for PowerShell. All computers that finished restarting are put in "allDoneList" } while (false); } - }// end if(waitOnComputer.Count > 0) - }//end DefaultParameter - }//End Processrecord + } + } + } /// - /// to implement ^C + /// To implement ^C. /// protected override void StopProcessing() { @@ -1090,31 +1106,31 @@ protected override void StopProcessing() } } -#endregion "Overrides" + #endregion "Overrides" } -#endregion Restart-Computer + #endregion Restart-Computer -#region Stop-Computer + #region Stop-Computer /// - /// cmdlet to stop computer + /// Cmdlet to stop computer. /// [Cmdlet(VerbsLifecycle.Stop, "Computer", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135263", RemotingCapability = RemotingCapability.SupportedByCommand)] public sealed class StopComputerCommand : PSCmdlet, IDisposable { -#region Private Members + #region Private Members private readonly CancellationTokenSource _cancel = new CancellationTokenSource(); - private const int forcedShutdown = 5; // See https://msdn.microsoft.com/en-us/library/aa394058(v=vs.85).aspx + private const int forcedShutdown = 5; // See https://msdn.microsoft.com/library/aa394058(v=vs.85).aspx -#endregion + #endregion -#region "Parameters" + #region "Parameters" /// - /// The authentication options for CIM_WSMan connection + /// The authentication options for CIM_WSMan connection. /// [Parameter] [ValidateSet( @@ -1137,14 +1153,13 @@ public sealed class StopComputerCommand : PSCmdlet, IDisposable [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Alias("CN", "__SERVER", "Server", "IPAddress")] - public String[] ComputerName { get; set; } = new string[] { "." }; - + public string[] ComputerName { get; set; } = new string[] { "." }; /// /// The following is the definition of the input parameter "Credential". /// Specifies a user account that has permission to perform this action. Type a /// user-name, such as "User01" or "Domain01\User01", or enter a PSCredential - /// object, such as one from the Get-Credential cmdlet + /// object, such as one from the Get-Credential cmdlet. /// [Parameter(Position = 1)] [ValidateNotNullOrEmpty] @@ -1152,17 +1167,17 @@ public sealed class StopComputerCommand : PSCmdlet, IDisposable public PSCredential Credential { get; set; } /// - /// Force the operation to take place if possible + /// Force the operation to take place if possible. /// [Parameter] public SwitchParameter Force { get; set; } = false; #endregion "parameters" -#region "IDisposable Members" + #region "IDisposable Members" /// - /// Dispose Method + /// Dispose Method. /// public void Dispose() { @@ -1173,12 +1188,12 @@ public void Dispose() catch (ObjectDisposedException) { } } -#endregion "IDisposable Members" + #endregion "IDisposable Members" -#region "Overrides" + #region "Overrides" /// - /// ProcessRecord + /// ProcessRecord. /// [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] protected override void ProcessRecord() @@ -1188,10 +1203,10 @@ protected override void ProcessRecord() flags[0] = forcedShutdown; ProcessWSManProtocol(flags); - }//End Processrecord + } /// - /// to implement ^C + /// To implement ^C. /// protected override void StopProcessing() { @@ -1203,9 +1218,9 @@ protected override void StopProcessing() catch (AggregateException) { } } -#endregion "Overrides" + #endregion "Overrides" -#region Private Methods + #region Private Methods private void ProcessWSManProtocol(object[] flags) { @@ -1217,7 +1232,7 @@ private void ProcessWSManProtocol(object[] flags) if (_cancel.Token.IsCancellationRequested) { break; } - if ((computer.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) || (computer.Equals(".", StringComparison.OrdinalIgnoreCase))) + if ((computer.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || (computer.Equals(".", StringComparison.OrdinalIgnoreCase))) { compname = Dns.GetHostName(); strLocal = "localhost"; @@ -1248,12 +1263,12 @@ private void ProcessWSManProtocol(object[] flags) } } -#endregion + #endregion } -#endregion + #endregion -#region Rename-Computer + #region Rename-Computer /// /// Renames a domain computer and its corresponding domain account or a @@ -1265,20 +1280,20 @@ private void ProcessWSManProtocol(object[] flags) HelpUri = "https://go.microsoft.com/fwlink/?LinkID=219990", RemotingCapability = RemotingCapability.SupportedByCommand)] public class RenameComputerCommand : PSCmdlet { -#region Private Members + #region Private Members private bool _containsLocalHost = false; private string _newNameForLocalHost = null; private readonly string _shortLocalMachineName = Dns.GetHostName(); - private readonly string _fullLocalMachineName = Dns.GetHostEntryAsync("").Result.HostName; + private readonly string _fullLocalMachineName = Dns.GetHostEntryAsync(string.Empty).Result.HostName; -#endregion + #endregion -#region Parameters + #region Parameters /// - /// Target computers to rename + /// Target computers to rename. /// [Parameter(ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] @@ -1287,12 +1302,12 @@ public class RenameComputerCommand : PSCmdlet /// /// Emit the output. /// - //[Alias("Restart")] + // [Alias("Restart")] [Parameter] public SwitchParameter PassThru { get; set; } /// - /// The domain credential of the domain the target computer joined + /// The domain credential of the domain the target computer joined. /// [Parameter] [ValidateNotNullOrEmpty] @@ -1300,7 +1315,7 @@ public class RenameComputerCommand : PSCmdlet public PSCredential DomainCredential { get; set; } /// - /// The administrator credential of the target computer + /// The administrator credential of the target computer. /// [Parameter] [ValidateNotNullOrEmpty] @@ -1308,36 +1323,40 @@ public class RenameComputerCommand : PSCmdlet public PSCredential LocalCredential { get; set; } /// - /// New names for the target computers + /// New names for the target computers. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] public string NewName { get; set; } /// - /// Suppress the ShouldContinue + /// Suppress the ShouldContinue. /// [Parameter] public SwitchParameter Force { get { return _force; } + set { _force = value; } } + private bool _force; /// - /// To restart the target computer after rename it + /// To restart the target computer after rename it. /// [Parameter] public SwitchParameter Restart { get { return _restart; } + set { _restart = value; } } + private bool _restart; /// - /// The authentication options for CIM_WSMan connection + /// The authentication options for CIM_WSMan connection. /// [Parameter] [ValidateSet( @@ -1350,12 +1369,12 @@ public SwitchParameter Restart [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] public string WsmanAuthentication { get; set; } = "Default"; -#endregion + #endregion -#region "Private Methods" + #region "Private Methods" /// - /// Check to see if the target computer is the local machine + /// Check to see if the target computer is the local machine. /// private string ValidateComputerName() { @@ -1368,6 +1387,7 @@ private string ValidateComputerName() { WriteError(targetError); } + return null; } @@ -1420,13 +1440,13 @@ private void DoRenameComputerWsman(string computer, string computerName, string try { using (CancellationTokenSource cancelTokenSource = new CancellationTokenSource()) - using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, credToUse, WsmanAuthentication, cancelTokenSource.Token, this)) + using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(computer, credToUse, WsmanAuthentication, isLocalhost, cancelTokenSource.Token, this)) { var operationOptions = new CimOperationOptions { Timeout = TimeSpan.FromMilliseconds(10000), CancellationToken = cancelTokenSource.Token, - //This prefix works against all versions of the WinRM server stack, both win8 and win7 + // This prefix works against all versions of the WinRM server stack, both win8 and win7 ResourceUriPrefix = new Uri(ComputerWMIHelper.CimUriPrefix) }; @@ -1481,7 +1501,7 @@ private void DoRenameComputerWsman(string computer, string computerName, string Microsoft.Management.Infrastructure.CimType.String, (dPassword == null) ? CimFlags.NullValue : CimFlags.None)); - if ( ! InternalTestHooks.TestRenameComputer ) + if (!InternalTestHooks.TestRenameComputer) { CimMethodResult result = cimSession.InvokeMethod( ComputerWMIHelper.CimOperatingSystemNamespace, @@ -1536,8 +1556,8 @@ private void DoRenameComputerWsman(string computer, string computerName, string WriteWarning(StringUtil.Format(ComputerResources.RestartNeeded, null, computerName)); } } - } // end foreach - } // end using + } + } } catch (CimException ex) { @@ -1555,9 +1575,9 @@ private void DoRenameComputerWsman(string computer, string computerName, string } } -#endregion "Private Methods" + #endregion "Private Methods" -#region "Override Methods" + #region "Override Methods" /// /// ProcessRecord method. @@ -1581,7 +1601,7 @@ protected override void ProcessRecord() } /// - /// EndProcessing method + /// EndProcessing method. /// protected override void EndProcessing() { @@ -1590,12 +1610,12 @@ protected override void EndProcessing() DoRenameComputerAction("localhost", _newNameForLocalHost, true); } -#endregion "Override Methods" + #endregion "Override Methods" } -#endregion Rename-Computer + #endregion Rename-Computer -#region "Public API" + #region "Public API" /// /// The object returned by SAM Computer cmdlets representing the status of the target machine. /// @@ -1604,7 +1624,7 @@ public sealed class ComputerChangeInfo private const string MatchFormat = "{0}:{1}"; /// - /// The HasSucceeded which shows the operation was success or not + /// The HasSucceeded which shows the operation was success or not. /// public bool HasSucceeded { get; set; } @@ -1677,9 +1697,9 @@ private string FormatLine(string HasSucceeded, string newcomputername, string ol return StringUtil.Format(MatchFormat, HasSucceeded, newcomputername, oldcomputername); } } -#endregion "Public API" + #endregion "Public API" -#region Helper + #region Helper /// /// Helper Class used by Stop-Computer,Restart-Computer and Test-Connection /// Also Contain constants used by System Restore related Cmdlets. @@ -1687,27 +1707,27 @@ private string FormatLine(string HasSucceeded, string newcomputername, string ol internal static class ComputerWMIHelper { /// - /// The maximum length of a valid NetBIOS name + /// The maximum length of a valid NetBIOS name. /// internal const int NetBIOSNameMaxLength = 15; /// - /// System Restore Class used by Cmdlets + /// System Restore Class used by Cmdlets. /// internal const string WMI_Class_SystemRestore = "SystemRestore"; /// - /// OperatingSystem WMI class used by Cmdlets + /// OperatingSystem WMI class used by Cmdlets. /// internal const string WMI_Class_OperatingSystem = "Win32_OperatingSystem"; /// - /// Service WMI class used by Cmdlets + /// Service WMI class used by Cmdlets. /// internal const string WMI_Class_Service = "Win32_Service"; /// - /// Win32_ComputerSystem WMI class used by Cmdlets + /// Win32_ComputerSystem WMI class used by Cmdlets. /// internal const string WMI_Class_ComputerSystem = "Win32_ComputerSystem"; @@ -1717,12 +1737,12 @@ internal static class ComputerWMIHelper internal const string WMI_Class_PingStatus = "Win32_PingStatus"; /// - /// CIMV2 path + /// CIMV2 path. /// internal const string WMI_Path_CIM = "\\root\\cimv2"; /// - /// Default path + /// Default path. /// internal const string WMI_Path_Default = "\\root\\default"; @@ -1737,43 +1757,42 @@ internal static class ComputerWMIHelper internal const int ErrorCode_Service = 1056; /// - /// The name of the privilege to shutdown a local system + /// The name of the privilege to shutdown a local system. /// internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; /// - /// The name of the privilege to shutdown a remote system + /// The name of the privilege to shutdown a remote system. /// internal const string SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege"; /// - /// CimUriPrefix + /// CimUriPrefix. /// internal const string CimUriPrefix = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2"; /// - /// CimOperatingSystemNamespace + /// CimOperatingSystemNamespace. /// internal const string CimOperatingSystemNamespace = "root/cimv2"; /// - /// CimOperatingSystemShutdownMethod + /// CimOperatingSystemShutdownMethod. /// internal const string CimOperatingSystemShutdownMethod = "Win32shutdown"; /// - /// CimQueryDialect + /// CimQueryDialect. /// internal const string CimQueryDialect = "WQL"; /// - /// Local host name + /// Local host name. /// internal const string localhostStr = "localhost"; - /// - /// Get the local admin user name from a local NetworkCredential + /// Get the local admin user name from a local NetworkCredential. /// /// /// @@ -1789,7 +1808,7 @@ internal static string GetLocalAdminUserName(string computerName, PSCredential p } else { - int dotIndex = computerName.IndexOf(".", StringComparison.OrdinalIgnoreCase); + int dotIndex = computerName.IndexOf('.'); if (dotIndex == -1) { localUserName = computerName + "\\" + psLocalCredential.UserName; @@ -1804,7 +1823,7 @@ internal static string GetLocalAdminUserName(string computerName, PSCredential p } /// - /// Generate a random password + /// Generate a random password. /// /// /// @@ -1827,8 +1846,7 @@ internal static string GetRandomPassword(int passwordLength) } /// - /// Gets the Scope - /// + /// Gets the Scope. /// /// /// @@ -1836,7 +1854,7 @@ internal static string GetRandomPassword(int passwordLength) internal static string GetScopeString(string computer, string namespaceParameter) { StringBuilder returnValue = new StringBuilder("\\\\"); - if (computer.Equals("::1", StringComparison.CurrentCultureIgnoreCase) || computer.Equals("[::1]", StringComparison.CurrentCultureIgnoreCase)) + if (computer.Equals("::1", StringComparison.OrdinalIgnoreCase) || computer.Equals("[::1]", StringComparison.OrdinalIgnoreCase)) { returnValue.Append("localhost"); } @@ -1844,6 +1862,7 @@ internal static string GetScopeString(string computer, string namespaceParameter { returnValue.Append(computer); } + returnValue.Append(namespaceParameter); return returnValue.ToString(); } @@ -1864,6 +1883,7 @@ internal static bool IsValidDrive(string drive) return true; } } + return false; } @@ -1878,20 +1898,21 @@ internal static bool ContainsSystemDrive(string[] drives, string sysdrive) string driveApp; foreach (string drive in drives) { - if (!drive.EndsWith("\\", StringComparison.CurrentCultureIgnoreCase)) + if (!drive.EndsWith('\\')) { - driveApp = String.Concat(drive, "\\"); + driveApp = string.Concat(drive, "\\"); } else driveApp = drive; - if (driveApp.Equals(sysdrive, StringComparison.CurrentCultureIgnoreCase)) + if (driveApp.Equals(sysdrive, StringComparison.OrdinalIgnoreCase)) return true; } + return false; } /// - /// Returns the given computernames in a string + /// Returns the given computernames in a string. /// /// internal static string GetMachineNames(string[] computerNames) @@ -1921,7 +1942,7 @@ internal static string GetMachineNames(string[] computerNames) i++; } - if ((computer.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) || (computer.Equals(".", StringComparison.OrdinalIgnoreCase))) + if ((computer.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || (computer.Equals(".", StringComparison.OrdinalIgnoreCase))) { compname = Dns.GetHostName(); } @@ -1948,6 +1969,7 @@ internal static ComputerChangeInfo GetComputerStatusObject(int errorcode, string { computerchangeinfo.HasSucceeded = true; } + return computerchangeinfo; } @@ -1964,25 +1986,26 @@ internal static RenameComputerChangeInfo GetRenameComputerStatusObject(int error { renamecomputerchangeinfo.HasSucceeded = true; } + return renamecomputerchangeinfo; } - internal static void WriteNonTerminatingError(int errorcode, PSCmdlet cmdlet, string computername) { Win32Exception ex = new Win32Exception(errorcode); - string additionalmessage = String.Empty; + string additionalmessage = string.Empty; if (ex.NativeErrorCode.Equals(0x00000035)) { additionalmessage = StringUtil.Format(ComputerResources.NetworkPathNotFound, computername); } + string message = StringUtil.Format(ComputerResources.OperationFailed, ex.Message, computername, additionalmessage); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, computername); cmdlet.WriteError(er); } /// - /// Check whether the new computer name is valid + /// Check whether the new computer name is valid. /// /// /// @@ -2034,6 +2057,7 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) cmdlet.WriteError(er); retValue = true; } + return retValue; } @@ -2042,16 +2066,16 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) /// over a CIMSession. The flags parameter determines the type of shutdown operation /// such as shutdown, reboot, force etc. /// - /// Cmdlet host for reporting errors - /// True if local host computer - /// Target computer - /// Win32Shutdown flags - /// Optional credential - /// Optional authentication - /// Error message format string that takes two parameters - /// Fully qualified error Id - /// Cancel token - /// True on success + /// Cmdlet host for reporting errors. + /// True if local host computer. + /// Target computer. + /// Win32Shutdown flags. + /// Optional credential. + /// Optional authentication. + /// Error message format string that takes two parameters. + /// Fully qualified error Id. + /// Cancel token. + /// True on success. internal static bool InvokeWin32ShutdownUsingWsman( PSCmdlet cmdlet, bool isLocalhost, @@ -2074,7 +2098,7 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) { Timeout = TimeSpan.FromMilliseconds(10000), CancellationToken = cancelToken, - //This prefix works against all versions of the WinRM server stack, both win8 and win7 + // This prefix works against all versions of the WinRM server stack, both win8 and win7 ResourceUriPrefix = new Uri(ComputerWMIHelper.CimUriPrefix) }; @@ -2091,7 +2115,7 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) return false; } - using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(targetMachine, credInUse, authInUse, cancelToken, cmdlet)) + using (CimSession cimSession = RemoteDiscoveryHelper.CreateCimSession(targetMachine, credInUse, authInUse, isLocalhost, cancelToken, cmdlet)) { var methodParameters = new CimMethodParametersCollection(); int retVal; @@ -2107,14 +2131,31 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) Microsoft.Management.Infrastructure.CimType.SInt32, CimFlags.None)); - if ( ! InternalTestHooks.TestStopComputer ) + if (!InternalTestHooks.TestStopComputer) { - CimMethodResult result = cimSession.InvokeMethod( - ComputerWMIHelper.CimOperatingSystemNamespace, - ComputerWMIHelper.WMI_Class_OperatingSystem, - ComputerWMIHelper.CimOperatingSystemShutdownMethod, - methodParameters, - operationOptions); + CimMethodResult result = null; + + if (isLocalhost) + { + // Win32_ComputerSystem is a singleton hence FirstOrDefault() return the only instance returned by EnumerateInstances. + var computerSystem = cimSession.EnumerateInstances(ComputerWMIHelper.CimOperatingSystemNamespace, ComputerWMIHelper.WMI_Class_OperatingSystem).FirstOrDefault(); + + result = cimSession.InvokeMethod( + ComputerWMIHelper.CimOperatingSystemNamespace, + computerSystem, + ComputerWMIHelper.CimOperatingSystemShutdownMethod, + methodParameters, + operationOptions); + } + else + { + result = cimSession.InvokeMethod( + ComputerWMIHelper.CimOperatingSystemNamespace, + ComputerWMIHelper.WMI_Class_OperatingSystem, + ComputerWMIHelper.CimOperatingSystemShutdownMethod, + methodParameters, + operationOptions); + } retVal = Convert.ToInt32(result.ReturnValue.Value, CultureInfo.CurrentCulture); } @@ -2164,11 +2205,11 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) /// /// Returns valid computer name or null on failure. /// - /// Computer name to validate + /// Computer name to validate. /// /// /// - /// Valid computer name + /// Valid computer name. internal static string ValidateComputerName( string nameToCheck, string shortLocalMachineName, @@ -2223,6 +2264,7 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) return null; } + validatedComputerName = nameToCheck; } } @@ -2230,8 +2272,7 @@ internal static bool SkipSystemRestoreOperationForARMPlatform(PSCmdlet cmdlet) return validatedComputerName; } } -#endregion Helper - -}//End namespace + #endregion Helper +} #endif diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs index 87a325631614..5dbe8fcc9189 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -8,33 +7,35 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Management.Automation.Provider; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// The base class for the */content commands + /// The base class for the */content commands. /// public class ContentCommandBase : CoreCommandWithCredentialsBase, IDisposable { #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipelineByPropertyName = true)] public string[] Path { get; set; } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return Path; } + set { base.SuppressWildcardExpansion = true; @@ -43,39 +44,41 @@ public string[] LiteralPath } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { get { return base.Filter; } + set { base.Filter = value; } } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { get { return base.Include; } + set { base.Include = value; } } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { get { return base.Exclude; } + set { base.Exclude = value; } } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -85,11 +88,11 @@ public override string[] Exclude /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { get { return base.Force; } + set { base.Force = value; } } @@ -105,29 +108,23 @@ public override SwitchParameter Force /// An array of content holder objects that contain the path information /// and content readers/writers for the item represented by the path information. /// - /// internal List contentStreams = new List(); /// - /// Wraps the content into a PSObject and adds context information as notes + /// Wraps the content into a PSObject and adds context information as notes. /// - /// /// /// The content being written out. /// - /// /// /// The number of blocks that have been read so far. /// - /// /// /// The context the content was retrieved from. /// - /// /// /// The context the command is being run under. /// - /// internal void WriteContentObject(object content, long readCount, PathInfo pathInfo, CmdletProviderContext context) { Dbg.Diagnostics.Assert( @@ -154,7 +151,7 @@ internal void WriteContentObject(object content, long readCount, PathInfo pathIn if (_currentContentItem != null && ((_currentContentItem.PathInfo == pathInfo) || ( - String.Compare( + string.Compare( pathInfo.Path, _currentContentItem.PathInfo.Path, StringComparison.OrdinalIgnoreCase) == 0) @@ -188,8 +185,9 @@ internal void WriteContentObject(object content, long readCount, PathInfo pathIn } else { - parentPath = SessionState.Path.ParseParent(pathInfo.Path, String.Empty, context); + parentPath = SessionState.Path.ParseParent(pathInfo.Path, string.Empty, context); } + note = new PSNoteProperty("PSParentPath", parentPath); result.Properties.Add(note, true); tracer.WriteLine("Attaching {0} = {1}", "PSParentPath", parentPath); @@ -233,7 +231,7 @@ internal void WriteContentObject(object content, long readCount, PathInfo pathIn result.Properties.Add(note, true); WriteObject(result); - } // WriteContentObject + } /// /// A cache of the notes that get added to the content items as they are written @@ -251,11 +249,9 @@ internal class ContentPathsCache /// /// Constructs a content cache item. /// - /// /// /// The path information for which the cache will be bound. /// - /// public ContentPathsCache(PathInfo pathInfo) { PathInfo = pathInfo; @@ -264,51 +260,42 @@ public ContentPathsCache(PathInfo pathInfo) /// /// The path information for the cached item. /// - /// public PathInfo PathInfo { get; } /// /// The cached PSPath of the item. /// - /// - public String PSPath { get; set; } + public string PSPath { get; set; } /// /// The cached parent path of the item. /// - /// - public String ParentPath { get; set; } + public string ParentPath { get; set; } /// /// The cached drive for the item. /// - /// public PSDriveInfo Drive { get; set; } /// /// The cached provider of the item. /// - /// public ProviderInfo Provider { get; set; } /// /// The cached child name of the item. /// - /// - public String ChildName { get; set; } + public string ChildName { get; set; } /// /// Attaches the cached notes to the specified PSObject. /// - /// /// /// The PSObject to attached the cached notes to. /// - /// /// /// The PSObject that was passed in with the cached notes added. /// - /// public PSObject AttachNotes(PSObject content) { // Construct a provider qualified path as the Path note @@ -345,15 +332,13 @@ public PSObject AttachNotes(PSObject content) tracer.WriteLine("Attaching {0} = {1}", "PSProvider", Provider); return content; - } // AttachNotes - } // ContentPathsCache - + } + } /// /// A struct to hold the path information and the content readers/writers /// for an item. /// - /// internal struct ContentHolder { internal ContentHolder( @@ -369,17 +354,17 @@ internal struct ContentHolder PathInfo = pathInfo; Reader = reader; Writer = writer; - } // constructor + } internal PathInfo PathInfo { get; } internal IContentReader Reader { get; } internal IContentWriter Writer { get; } - } // struct ContentHolder + } /// - /// Closes the content readers and writers in the content holder array + /// Closes the content readers and writers in the content holder array. /// internal void CloseContent(List contentHolders, bool disposing) { @@ -410,7 +395,6 @@ internal void CloseContent(List contentHolders, bool disposing) holder.PathInfo.Path, e); - // Log a provider health event MshLog.LogProviderHealthEvent( @@ -448,7 +432,6 @@ internal void CloseContent(List contentHolders, bool disposing) holder.PathInfo.Path, e); - // Log a provider health event MshLog.LogProviderHealthEvent( @@ -466,22 +449,19 @@ internal void CloseContent(List contentHolders, bool disposing) } } } - } // CloseContent + } /// /// Overridden by derived classes to support ShouldProcess with /// the appropriate information. /// - /// /// /// The path to the item from which the content writer will be /// retrieved. /// - /// /// /// True if the action should continue or false otherwise. /// - /// internal virtual bool CallShouldProcess(string path) { return true; @@ -490,11 +470,9 @@ internal virtual bool CallShouldProcess(string path) /// /// Gets the IContentReaders for the current path(s) /// - /// /// /// An array of IContentReaders for the current path(s) /// - /// internal List GetContentReaders( string[] readerPaths, CmdletProviderContext currentCommandContext) @@ -568,36 +546,30 @@ internal virtual bool CallShouldProcess(string path) results.Add(holder); } } - } // foreach pathInfo in pathInfos + } return results; - } // GetContentReaders + } /// - /// Resolves the specified paths to PathInfo objects + /// Resolves the specified paths to PathInfo objects. /// - /// /// /// The paths to be resolved. Each path may contain glob characters. /// - /// /// /// If true, resolves the path even if it doesn't exist. /// - /// /// /// If true, allows a wildcard that returns no results. /// - /// /// /// The context under which the command is running. /// - /// /// /// An array of PathInfo objects that are the resolved paths for the /// parameter. /// - /// internal Collection ResolvePaths( string[] pathsToResolve, bool allowNonexistingPaths, @@ -696,7 +668,7 @@ internal virtual bool CallShouldProcess(string path) if (pathNotFoundErrorRecord == null) { // Detect if the path resolution failed to resolve to a file. - String error = StringUtil.Format(NavigationResources.ItemNotFound, Path); + string error = StringUtil.Format(NavigationResources.ItemNotFound, Path); Exception e = new Exception(error); pathNotFoundErrorRecord = new ErrorRecord( @@ -712,7 +684,7 @@ internal virtual bool CallShouldProcess(string path) } return results; - } // ResolvePaths + } #endregion protected members @@ -728,7 +700,7 @@ internal void Dispose(bool isDisposing) } /// - /// Dispose method in IDisposable + /// Dispose method in IDisposable. /// public void Dispose() { @@ -737,7 +709,7 @@ public void Dispose() } /// - /// Finalizer + /// Finalizer. /// ~ContentCommandBase() { @@ -745,5 +717,5 @@ public void Dispose() } #endregion IDisposable - } // ContentCommandBase -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs index 5950e80b0f46..c2798b03f51b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs @@ -1,52 +1,53 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using Microsoft.Win32; -using System; using System.Management.Automation; using System.Management.Automation.Internal; -using System.Collections.Generic; + +using Microsoft.Win32; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Commands { /// - /// Represent a control panel item + /// Represent a control panel item. /// public sealed class ControlPanelItem { /// - /// Control panel applet name + /// Control panel applet name. /// public string Name { get; } /// - /// Control panel applet canonical name + /// Control panel applet canonical name. /// public string CanonicalName { get; } /// - /// Control panel applet category + /// Control panel applet category. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] Category { get; } /// - /// Control panel applet description + /// Control panel applet description. /// public string Description { get; } /// - /// Control panel applet path + /// Control panel applet path. /// internal string Path { get; } /// - /// Internal constructor for ControlPanelItem + /// Internal constructor for ControlPanelItem. /// /// /// @@ -63,7 +64,7 @@ internal ControlPanelItem(string name, string canonicalName, string[] category, } /// - /// ToString method + /// ToString method. /// /// public override string ToString() @@ -73,7 +74,7 @@ public override string ToString() } /// - /// This class implements the base for ControlPanelItem commands + /// This class implements the base for ControlPanelItem commands. /// public abstract class ControlPanelItemBaseCommand : PSCmdlet { @@ -112,7 +113,7 @@ public abstract class ControlPanelItemBaseCommand : PSCmdlet internal ControlPanelItem[] ControlPanelItems = new ControlPanelItem[0]; /// - /// Get all executable control panel items + /// Get all executable control panel items. /// internal List AllControlPanelItems { @@ -141,6 +142,7 @@ internal List AllControlPanelItems break; } } + if (match) continue; } @@ -149,15 +151,17 @@ internal List AllControlPanelItems _allControlPanelItems.Add(item); } } + return _allControlPanelItems; } } + private List _allControlPanelItems; #region Cmdlet Overrides /// - /// Does the preprocessing for ControlPanelItem cmdlets + /// Does the preprocessing for ControlPanelItem cmdlets. /// protected override void BeginProcessing() { @@ -182,7 +186,7 @@ protected override void BeginProcessing() #endregion /// - /// Test if an item can be invoked + /// Test if an item can be invoked. /// /// /// @@ -192,7 +196,7 @@ private bool ContainVerbOpen(ShellFolderItem item) FolderItemVerbs verbs = item.Verbs(); foreach (FolderItemVerb verb in verbs) { - if (!String.IsNullOrEmpty(verb.Name) && + if (!string.IsNullOrEmpty(verb.Name) && (verb.Name.Equals(ControlPanelResources.VerbActionOpen, StringComparison.OrdinalIgnoreCase) || CompareVerbActionOpen(verb.Name))) { @@ -200,6 +204,7 @@ private bool ContainVerbOpen(ShellFolderItem item) break; } } + return result; } @@ -221,8 +226,8 @@ private static bool CompareVerbActionOpen(string verbActionName) foreach (ShellFolderItem item in allItems) { string canonicalName = (string)item.ExtendedProperty("System.ApplicationName"); - canonicalName = !String.IsNullOrEmpty(canonicalName) - ? canonicalName.Substring(0, canonicalName.IndexOf("\0", StringComparison.OrdinalIgnoreCase)) + canonicalName = !string.IsNullOrEmpty(canonicalName) + ? canonicalName.Substring(0, canonicalName.IndexOf('\0')) : null; if (canonicalName != null && canonicalName.Equals(RegionCanonicalName, StringComparison.OrdinalIgnoreCase)) @@ -254,7 +259,7 @@ private bool IsServerCoreOrHeadLessServer() { Dbg.Assert(installation != null, "the CurrentVersion subkey should exist"); - string installationType = (string)installation.GetValue("InstallationType", ""); + string installationType = (string)installation.GetValue("InstallationType", string.Empty); if (installationType.Equals("Server Core")) { @@ -265,7 +270,7 @@ private bool IsServerCoreOrHeadLessServer() using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) { ps.AddScript(TestHeadlessServerScript); - Collection psObjectCollection = ps.Invoke(new object[0]); + Collection psObjectCollection = ps.Invoke(Array.Empty()); Dbg.Assert(psObjectCollection != null && psObjectCollection.Count == 1, "invoke should never return null, there should be only one return item"); if (LanguagePrimitives.IsTrue(PSObject.Base(psObjectCollection[0]))) { @@ -279,7 +284,7 @@ private bool IsServerCoreOrHeadLessServer() } /// - /// Get the category number and name map + /// Get the category number and name map. /// internal void GetCategoryMap() { @@ -302,7 +307,7 @@ internal void GetCategoryMap() } /// - /// Get control panel item by the category + /// Get control panel item by the category. /// /// /// @@ -354,7 +359,7 @@ internal List GetControlPanelItemByCategory(List - /// Get control panel item by the regular name + /// Get control panel item by the regular name. /// /// /// @@ -402,7 +407,7 @@ internal List GetControlPanelItemByName(List c } /// - /// Get control panel item by the canonical name + /// Get control panel item by the canonical name. /// /// /// @@ -430,10 +435,11 @@ internal List GetControlPanelItemByCanonicalName(List GetControlPanelItemByCanonicalName(List GetControlPanelItemByCanonicalName(List - /// Get control panel item by the ControlPanelItem instances + /// Get control panel item by the ControlPanelItem instances. /// /// /// @@ -540,7 +546,7 @@ internal List GetControlPanelItemsByInstance(List - /// Get all control panel items that is available in the "All Control Panel Items" category + /// Get all control panel items that is available in the "All Control Panel Items" category. /// [Cmdlet(VerbsCommon.Get, "ControlPanelItem", DefaultParameterSetName = RegularNameParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=219982")] [OutputType(typeof(ControlPanelItem))] @@ -552,7 +558,7 @@ public sealed class GetControlPanelItemCommand : ControlPanelItemBaseCommand #region "Parameters" /// - /// Control panel item names + /// Control panel item names. /// [Parameter(Position = 0, ParameterSetName = RegularNameParameterSet, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] @@ -560,16 +566,18 @@ public sealed class GetControlPanelItemCommand : ControlPanelItemBaseCommand public string[] Name { get { return RegularNames; } + set { RegularNames = value; _nameSpecified = true; } } + private bool _nameSpecified = false; /// - /// Canonical names of control panel items + /// Canonical names of control panel items. /// [Parameter(Mandatory = true, ParameterSetName = CanonicalNameParameterSet)] [AllowNull] @@ -577,16 +585,18 @@ public string[] Name public string[] CanonicalName { get { return CanonicalNames; } + set { CanonicalNames = value; _canonicalNameSpecified = true; } } + private bool _canonicalNameSpecified = false; /// - /// Category of control panel items + /// Category of control panel items. /// [Parameter] [ValidateNotNullOrEmpty] @@ -594,18 +604,19 @@ public string[] CanonicalName public string[] Category { get { return CategoryNames; } + set { CategoryNames = value; _categorySpecified = true; } } + private bool _categorySpecified = false; #endregion "Parameters" /// - /// /// protected override void ProcessRecord() { @@ -629,7 +640,7 @@ protected override void ProcessRecord() string description = (string)item.ExtendedProperty("InfoTip"); string canonicalName = (string)item.ExtendedProperty("System.ApplicationName"); canonicalName = canonicalName != null - ? canonicalName.Substring(0, canonicalName.IndexOf("\0", StringComparison.OrdinalIgnoreCase)) + ? canonicalName.Substring(0, canonicalName.IndexOf('\0')) : null; int[] categories = (int[])item.ExtendedProperty("System.ControlPanel.Category"); string[] cateStrings = new string[categories.Length]; @@ -672,7 +683,7 @@ private static int CompareControlPanelItems(ControlPanelItem x, ControlPanelItem } /// - /// Show the specified control panel applet + /// Show the specified control panel applet. /// [Cmdlet(VerbsCommon.Show, "ControlPanelItem", DefaultParameterSetName = RegularNameParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=219983")] public sealed class ShowControlPanelItemCommand : ControlPanelItemBaseCommand @@ -684,7 +695,7 @@ public sealed class ShowControlPanelItemCommand : ControlPanelItemBaseCommand #region "Parameters" /// - /// Control panel item names + /// Control panel item names. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = RegularNameParameterSet, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] @@ -692,11 +703,12 @@ public sealed class ShowControlPanelItemCommand : ControlPanelItemBaseCommand public string[] Name { get { return RegularNames; } + set { RegularNames = value; } } /// - /// Canonical names of control panel items + /// Canonical names of control panel items. /// [Parameter(Mandatory = true, ParameterSetName = CanonicalNameParameterSet)] [AllowNull] @@ -704,11 +716,12 @@ public string[] Name public string[] CanonicalName { get { return CanonicalNames; } + set { CanonicalNames = value; } } /// - /// Control panel items returned by Get-ControlPanelItem + /// Control panel items returned by Get-ControlPanelItem. /// [Parameter(Position = 0, ParameterSetName = ControlPanelItemParameterSet, ValueFromPipeline = true)] [ValidateNotNullOrEmpty] @@ -716,13 +729,13 @@ public string[] CanonicalName public ControlPanelItem[] InputObject { get { return ControlPanelItems; } + set { ControlPanelItems = value; } } #endregion "Parameters" /// - /// /// protected override void ProcessRecord() { diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs index ef093e91071c..19cd92cec61b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ConvertPathCommand.cs @@ -1,9 +1,9 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Collections.ObjectModel; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -20,7 +20,7 @@ public class ConvertPathCommand : CoreCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -29,40 +29,40 @@ public string[] Path get { return _paths; - } // get + } set { _paths = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return _paths; - } // get + } set { base.SuppressWildcardExpansion = true; _paths = value; - } // set - } // LiteralPath + } + } #endregion Parameters #region parameter data /// - /// The path(s) to the item(s) to convert + /// The path(s) to the item(s) to convert. /// private string[] _paths; @@ -123,10 +123,9 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord + } #endregion Command code - - } // ConvertPathCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/CopyPropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/CopyPropertyCommand.cs index a5392a7cafea..627f038776b7 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/CopyPropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/CopyPropertyCommand.cs @@ -1,8 +1,8 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -17,25 +17,27 @@ public class CopyItemPropertyCommand : PassThroughItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { get { return paths; } + set { paths = value; } } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return paths; } + set { base.SuppressWildcardExpansion = true; @@ -44,9 +46,8 @@ public string[] LiteralPath } /// - /// The name of the property to create on the item + /// The name of the property to create on the item. /// - /// [Parameter(Position = 2, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Alias("PSProperty")] public string Name { get; set; } @@ -54,7 +55,6 @@ public string[] LiteralPath /// /// The path to the destination item to copy the property to. /// - /// [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)] public string Destination { get; set; } @@ -63,16 +63,13 @@ public string[] LiteralPath /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) @@ -84,13 +81,14 @@ internal override object GetDynamicParameters(CmdletProviderContext context) Name, context); } + return InvokeProvider.Property.CopyPropertyDynamicParameters( ".", Name, Destination, Name, context); - } // GetDynamicParameters + } #endregion Parameters @@ -101,7 +99,7 @@ internal override object GetDynamicParameters(CmdletProviderContext context) #region Command code /// - /// Copies the property from one item to another + /// Copies the property from one item to another. /// protected override void ProcessRecord() { @@ -149,9 +147,8 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord + } #endregion Command code - - } // CopyItemPropertyCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs index 86194f41fe50..b0366872ce29 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -15,7 +14,7 @@ namespace Microsoft.PowerShell.Commands { #region GetEventLogCommand /// - /// This class implements the Get-EventLog command + /// This class implements the Get-EventLog command. /// /// /// The CLR EventLogEntryCollection class has problems with managing @@ -35,28 +34,28 @@ namespace Microsoft.PowerShell.Commands /// [Cmdlet(VerbsCommon.Get, "EventLog", DefaultParameterSetName = "LogName", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113314", RemotingCapability = RemotingCapability.SupportedByCommand)] - [OutputType(typeof(EventLog), typeof(EventLogEntry), typeof(String))] + [OutputType(typeof(EventLog), typeof(EventLogEntry), typeof(string))] public sealed class GetEventLogCommand : PSCmdlet { #region Parameters /// - /// Read eventlog entries from this log + /// Read eventlog entries from this log. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "LogName")] [Alias("LN")] public string LogName { get; set; } /// - /// Read eventlog entries from this computer + /// Read eventlog entries from this computer. /// [Parameter()] [ValidateNotNullOrEmpty()] [Alias("Cn")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public string[] ComputerName { get; set; } = new string[0]; + public string[] ComputerName { get; set; } = Array.Empty(); /// - /// Read only this number of entries + /// Read only this number of entries. /// [Parameter(ParameterSetName = "LogName")] [ValidateRange(0, Int32.MaxValue)] @@ -70,6 +69,7 @@ public sealed class GetEventLogCommand : PSCmdlet public DateTime After { get { return _after; } + set { _after = value; @@ -77,6 +77,7 @@ public DateTime After _isFilterSpecified = true; } } + private DateTime _after; /// @@ -87,6 +88,7 @@ public DateTime After public DateTime Before { get { return _before; } + set { _before = value; @@ -94,6 +96,7 @@ public DateTime Before _isFilterSpecified = true; } } + private DateTime _before; /// @@ -102,20 +105,22 @@ public DateTime Before [Parameter(ParameterSetName = "LogName")] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] UserName + public string[] UserName { get { return _username; } + set { _username = value; _isFilterSpecified = true; } } - private String[] _username; + + private string[] _username; /// - /// match eventlog entries by the InstanceIds - /// gets or sets an array of instanceIds + /// Match eventlog entries by the InstanceIds + /// gets or sets an array of instanceIds. /// [Parameter(Position = 1, ParameterSetName = "LogName")] [ValidateNotNullOrEmpty()] @@ -124,18 +129,19 @@ public String[] UserName public long[] InstanceId { get { return _instanceIds; } + set { _instanceIds = value; _isFilterSpecified = true; } } - private long[] _instanceIds = null; + private long[] _instanceIds = null; /// - /// match eventlog entries by the Index - /// gets or sets an array of indexes + /// Match eventlog entries by the Index + /// gets or sets an array of indexes. /// [Parameter(ParameterSetName = "LogName")] [ValidateNotNullOrEmpty()] @@ -144,18 +150,19 @@ public long[] InstanceId public int[] Index { get { return _indexes; } + set { _indexes = value; _isFilterSpecified = true; } } - private int[] _indexes = null; + private int[] _indexes = null; /// - /// match eventlog entries by the EntryType - /// gets or sets an array of EntryTypes + /// Match eventlog entries by the EntryType + /// gets or sets an array of EntryTypes. /// [Parameter(ParameterSetName = "LogName")] [ValidateNotNullOrEmpty()] @@ -165,16 +172,18 @@ public int[] Index public string[] EntryType { get { return _entryTypes; } + set { _entryTypes = value; _isFilterSpecified = true; } } + private string[] _entryTypes = null; /// - /// get or sets an array of Source + /// Get or sets an array of Source. /// [Parameter(ParameterSetName = "LogName")] [ValidateNotNullOrEmpty()] @@ -184,16 +193,18 @@ public string[] Source { get { return _sources; } + set { _sources = value; _isFilterSpecified = true; } } + private string[] _sources; /// - /// Get or Set Message string to searched in EventLog + /// Get or Set Message string to searched in EventLog. /// [Parameter(ParameterSetName = "LogName")] [ValidateNotNullOrEmpty()] @@ -204,29 +215,30 @@ public string Message { return _message; } + set { _message = value; _isFilterSpecified = true; } } + private string _message; /// - /// returns Log Entry as base object + /// Returns Log Entry as base object. /// [Parameter(ParameterSetName = "LogName")] public SwitchParameter AsBaseObject { get; set; } /// - /// Return the Eventlog objects rather than the log contents + /// Return the Eventlog objects rather than the log contents. /// [Parameter(ParameterSetName = "List")] public SwitchParameter List { get; set; } - /// - /// Return the log names rather than the EventLog objects + /// Return the log names rather than the EventLog objects. /// [Parameter(ParameterSetName = "List")] public SwitchParameter AsString @@ -235,25 +247,27 @@ public SwitchParameter AsString { return _asString; } + set { _asString = value; } } + private bool _asString /* = false */; #endregion Parameters #region Overrides /// - /// Sets true when Filter is Specified + /// Sets true when Filter is Specified. /// private bool _isFilterSpecified = false; private bool _isDateSpecified = false; private bool _isThrowError = true; /// - /// Process the specified logs + /// Process the specified logs. /// protected override void BeginProcessing() { @@ -311,7 +325,7 @@ protected override void BeginProcessing() } } } - } // ProcessRecord + } #endregion Overrides #region Private @@ -407,7 +421,8 @@ private void Process(EventLog log) + ": " + e.Message); throw; } - if ((null != entry) && + + if ((entry != null) && ((lastindex == Int32.MinValue || lastindex - entry.Index == 1))) { @@ -417,11 +432,12 @@ private void Process(EventLog log) if (!FiltersMatch(entry)) continue; } + if (!AsBaseObject) { - //wrapping in PSobject to insert into PStypesnames + // wrapping in PSobject to insert into PStypesnames PSObject logentry = new PSObject(entry); - //inserting at zero position in reverse order + // inserting at zero position in reverse order logentry.TypeNames.Insert(0, logentry.ImmediateBaseObject + "#" + log.Log + "/" + entry.Source); logentry.TypeNames.Insert(0, logentry.ImmediateBaseObject + "#" + log.Log + "/" + entry.Source + "/" + entry.InstanceId); WriteObject(logentry); @@ -432,18 +448,18 @@ private void Process(EventLog log) WriteObject(entry); matchesfound = true; } + processed++; } } + if (!matchesfound && _isThrowError) { - Exception Ex = new ArgumentException(StringUtil.Format(EventlogResources.NoEntriesFound, log.Log, "")); + Exception Ex = new ArgumentException(StringUtil.Format(EventlogResources.NoEntriesFound, log.Log, string.Empty)); WriteError(new ErrorRecord(Ex, "GetEventLogNoEntriesFound", ErrorCategory.ObjectNotFound, null)); } } - - private bool FiltersMatch(EventLogEntry entry) { if (_indexes != null) @@ -453,6 +469,7 @@ private bool FiltersMatch(EventLogEntry entry) return false; } } + if (_instanceIds != null) { if (!((IList)_instanceIds).Contains(entry.InstanceId)) @@ -460,19 +477,22 @@ private bool FiltersMatch(EventLogEntry entry) return false; } } + if (_entryTypes != null) { bool entrymatch = false; foreach (string type in _entryTypes) { - if (type.Equals(entry.EntryType.ToString(), StringComparison.CurrentCultureIgnoreCase)) + if (type.Equals(entry.EntryType.ToString(), StringComparison.OrdinalIgnoreCase)) { entrymatch = true; break; } } + if (!entrymatch) return entrymatch; } + if (_sources != null) { bool sourcematch = false; @@ -482,6 +502,7 @@ private bool FiltersMatch(EventLogEntry entry) { _isThrowError = false; } + WildcardPattern wildcardpattern = WildcardPattern.Get(source, WildcardOptions.IgnoreCase); if (wildcardpattern.IsMatch(entry.Source)) { @@ -489,20 +510,24 @@ private bool FiltersMatch(EventLogEntry entry) break; } } + if (!sourcematch) return sourcematch; } + if (_message != null) { if (WildcardPattern.ContainsWildcardCharacters(_message)) { _isThrowError = false; } + WildcardPattern wildcardpattern = WildcardPattern.Get(_message, WildcardOptions.IgnoreCase); if (!wildcardpattern.IsMatch(entry.Message)) { return false; } } + if (_username != null) { bool usernamematch = false; @@ -519,8 +544,10 @@ private bool FiltersMatch(EventLogEntry entry) } } } + if (!usernamematch) return usernamematch; } + if (_isDateSpecified) { _isThrowError = false; @@ -554,10 +581,13 @@ private bool FiltersMatch(EventLogEntry entry) } } } + if (!datematch) return datematch; } + return true; } + private List GetMatchingLogs(string pattern) { WildcardPattern wildcardPattern = WildcardPattern.Get(pattern, WildcardOptions.IgnoreCase); @@ -588,16 +618,16 @@ private List GetMatchingLogs(string pattern) return matchingLogs; } - //private string ErrorBase = "EventlogResources"; + // private string ErrorBase = "EventlogResources"; private DateTime _initial = new DateTime(); #endregion Private - }//GetEventLogCommand + } #endregion GetEventLogCommand #region ClearEventLogCommand /// - /// This class implements the Clear-EventLog command + /// This class implements the Clear-EventLog command. /// [Cmdlet(VerbsCommon.Clear, "EventLog", SupportsShouldProcess = true, @@ -614,7 +644,6 @@ public sealed class ClearEventLogCommand : PSCmdlet [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] LogName { get; set; } - /// /// Clear eventlog entries from these Computers. /// @@ -629,14 +658,14 @@ public sealed class ClearEventLogCommand : PSCmdlet #region Overrides /// - /// Does the processing + /// Does the processing. /// protected override void BeginProcessing() { string computer = string.Empty; foreach (string compName in ComputerName) { - if ((compName.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) || (compName.Equals(".", StringComparison.OrdinalIgnoreCase))) + if ((compName.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || (compName.Equals(".", StringComparison.OrdinalIgnoreCase))) { computer = "localhost"; } @@ -644,6 +673,7 @@ protected override void BeginProcessing() { computer = compName; } + foreach (string eventString in LogName) { try @@ -654,10 +684,12 @@ protected override void BeginProcessing() WriteError(er); continue; } + if (!ShouldProcess(StringUtil.Format(EventlogResources.ClearEventLogWarning, eventString, computer))) { continue; } + EventLog Log = new EventLog(eventString, compName); Log.Clear(); } @@ -683,15 +715,15 @@ protected override void BeginProcessing() } } - //beginprocessing + // beginprocessing #endregion Overrides - }//ClearEventLogCommand + } #endregion ClearEventLogCommand #region WriteEventLogCommand /// - /// This class implements the Write-EventLog command + /// This class implements the Write-EventLog command. /// [Cmdlet(VerbsCommunications.Write, "EventLog", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135281", RemotingCapability = RemotingCapability.SupportedByCommand)] @@ -699,14 +731,13 @@ public sealed class WriteEventLogCommand : PSCmdlet { #region Parameters /// - /// Write eventlog entries in this log + /// Write eventlog entries in this log. /// [Parameter(Position = 0, Mandatory = true)] [Alias("LN")] [ValidateNotNullOrEmpty] public string LogName { get; set; } - /// /// The source by which the application is registered on the specified computer. /// @@ -748,9 +779,8 @@ public sealed class WriteEventLogCommand : PSCmdlet [ValidateLength(0, 32766)] public string Message { get; set; } - /// - /// Write eventlog entries of this log + /// Write eventlog entries of this log. /// [Parameter] [Alias("RD")] @@ -759,7 +789,7 @@ public sealed class WriteEventLogCommand : PSCmdlet public byte[] RawData { get; set; } /// - /// Write eventlog entries of this log + /// Write eventlog entries of this log. /// [Parameter] [Alias("CN")] @@ -768,7 +798,7 @@ public sealed class WriteEventLogCommand : PSCmdlet public string ComputerName { get; set; } = "."; #endregion Parameters - # region private + #region private private void WriteNonTerminatingError(Exception exception, string errorId, string errorMessage, ErrorCategory category) @@ -781,12 +811,12 @@ public sealed class WriteEventLogCommand : PSCmdlet #region Overrides /// - /// Does the processing + /// Does the processing. /// protected override void BeginProcessing() { string _computerName = string.Empty; - if ((ComputerName.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) || (ComputerName.Equals(".", StringComparison.OrdinalIgnoreCase))) + if ((ComputerName.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || (ComputerName.Equals(".", StringComparison.OrdinalIgnoreCase))) { _computerName = "localhost"; } @@ -794,6 +824,7 @@ protected override void BeginProcessing() { _computerName = ComputerName; } + try { if (!(EventLog.SourceExists(Source, ComputerName))) @@ -831,15 +862,15 @@ protected override void BeginProcessing() { WriteNonTerminatingError(ex, "PathDoesNotExist", StringUtil.Format(EventlogResources.PathDoesNotExist, null, ComputerName, null), ErrorCategory.InvalidOperation); } - }//beginprocessing + } #endregion Overrides - }//WriteEventLogCommand + } #endregion WriteEventLogCommand #region LimitEventLogCommand /// - /// This class implements the Limit-EventLog command + /// This class implements the Limit-EventLog command. /// [Cmdlet(VerbsData.Limit, "EventLog", SupportsShouldProcess = true, @@ -875,12 +906,14 @@ public sealed class LimitEventLogCommand : PSCmdlet public Int32 RetentionDays { get { return _retention; } + set { _retention = value; _retentionSpecified = true; } } + private Int32 _retention; private bool _retentionSpecified = false; /// @@ -894,12 +927,14 @@ public Int32 RetentionDays public System.Diagnostics.OverflowAction OverflowAction { get { return _overflowaction; } + set { _overflowaction = value; _overflowSpecified = true; } } + private System.Diagnostics.OverflowAction _overflowaction; private bool _overflowSpecified = false; /// @@ -910,17 +945,19 @@ public System.Diagnostics.OverflowAction OverflowAction public Int64 MaximumSize { get { return _maximumKilobytes; } + set { _maximumKilobytes = value; _maxkbSpecified = true; } } + private Int64 _maximumKilobytes; private bool _maxkbSpecified = false; #endregion Parameters - # region private + #region private private void WriteNonTerminatingError(Exception exception, string resourceId, string errorId, ErrorCategory category, string _logName, string _compName) { @@ -933,7 +970,7 @@ public Int64 MaximumSize #region Overrides /// - /// Does the processing + /// Does the processing. /// protected override void @@ -942,7 +979,7 @@ protected override string computer = string.Empty; foreach (string compname in ComputerName) { - if ((compname.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) || (compname.Equals(".", StringComparison.OrdinalIgnoreCase))) + if ((compname.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || (compname.Equals(".", StringComparison.OrdinalIgnoreCase))) { computer = "localhost"; } @@ -950,6 +987,7 @@ protected override { computer = compname; } + foreach (string logname in LogName) { try @@ -1001,6 +1039,7 @@ protected override { newLog.ModifyOverflowPolicy(_overflowaction, _minRetention); } + if (_maxkbSpecified) { int kiloByte = 1024; @@ -1030,19 +1069,20 @@ protected override { WriteNonTerminatingError(ex, EventlogResources.ValueOutofRange, "ValueOutofRange", ErrorCategory.InvalidData, null, null); } + continue; } } } } - # endregion override + #endregion override } #endregion LimitEventLogCommand #region ShowEventLogCommand /// - /// This class implements the Show-EventLog command + /// This class implements the Show-EventLog command. /// [Cmdlet(VerbsCommon.Show, "EventLog", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135257", RemotingCapability = RemotingCapability.SupportedByCommand)] @@ -1051,7 +1091,7 @@ public sealed class ShowEventLogCommand : PSCmdlet #region Parameters /// - /// show eventviewer of this computer. + /// Show eventviewer of this computer. /// [Parameter(Position = 0)] [Alias("CN")] @@ -1064,7 +1104,7 @@ public sealed class ShowEventLogCommand : PSCmdlet #region Overrides /// - /// Does the processing + /// Does the processing. /// protected override void @@ -1097,11 +1137,11 @@ protected override WriteError(er); } } - # endregion override + #endregion override } #endregion ShowEventLogCommand - # region NewEventLogCommand + #region NewEventLogCommand /// /// This cmdlet creates the new event log .This cmdlet can also be used to /// configure a new source for writing entries to an event log on the local @@ -1125,75 +1165,74 @@ protected override [Cmdlet(VerbsCommon.New, "EventLog", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135235", RemotingCapability = RemotingCapability.SupportedByCommand)] public class NewEventLogCommand : PSCmdlet { - # region Parameter + #region Parameter /// /// The following is the definition of the input parameter "CategoryResourceFile". /// Specifies the path of the resource file that contains category strings for /// the source - /// Resource File is expected to be present in Local/Remote Machines + /// Resource File is expected to be present in Local/Remote Machines. /// [Parameter] [ValidateNotNullOrEmpty] [Alias("CRF")] - public String CategoryResourceFile { get; set; } + public string CategoryResourceFile { get; set; } /// /// The following is the definition of the input parameter "ComputerName". - /// Specify the Computer Name. The default is local computer + /// Specify the Computer Name. The default is local computer. /// [Parameter(Position = 2)] [ValidateNotNullOrEmpty] [Alias("CN")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName { get; set; } = { "." }; + public string[] ComputerName { get; set; } = { "." }; /// /// The following is the definition of the input parameter "LogName". - /// Specifies the name of the log - /// + /// Specifies the name of the log. /// [Parameter(Mandatory = true, Position = 0)] [ValidateNotNullOrEmpty] [Alias("LN")] - public String LogName { get; set; } + public string LogName { get; set; } /// /// The following is the definition of the input parameter "MessageResourceFile". /// Specifies the path of the message resource file that contains message /// formatting strings for the source - /// Resource File is expected to be present in Local/Remote Machines + /// Resource File is expected to be present in Local/Remote Machines. /// [Parameter] [ValidateNotNullOrEmpty] [Alias("MRF")] - public String MessageResourceFile { get; set; } + public string MessageResourceFile { get; set; } /// /// The following is the definition of the input parameter "ParameterResourceFile". /// Specifies the path of the resource file that contains message parameter /// strings for the source - /// Resource File is expected to be present in Local/Remote Machines + /// Resource File is expected to be present in Local/Remote Machines. /// [Parameter] [ValidateNotNullOrEmpty] [Alias("PRF")] - public String ParameterResourceFile { get; set; } + public string ParameterResourceFile { get; set; } /// /// The following is the definition of the input parameter "Source". - /// Specifies the Source of the EventLog + /// Specifies the Source of the EventLog. /// [Parameter(Mandatory = true, Position = 1)] [ValidateNotNullOrEmpty] [Alias("SRC")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Source { get; set; } + public string[] Source { get; set; } - # endregion Parameter + #endregion Parameter - # region private + #region private private void WriteNonTerminatingError(Exception exception, string resourceId, string errorId, ErrorCategory category, string _logName, string _compName, string _source, string _resourceFile) { @@ -1201,9 +1240,9 @@ public class NewEventLogCommand : PSCmdlet WriteError(new ErrorRecord(ex, errorId, category, null)); } - # endregion private + #endregion private - # region override + #region override /// /// BeginProcessing method. /// @@ -1212,7 +1251,7 @@ protected override void BeginProcessing() string computer = string.Empty; foreach (string compname in ComputerName) { - if ((compname.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) || (compname.Equals(".", StringComparison.OrdinalIgnoreCase))) + if ((compname.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || (compname.Equals(".", StringComparison.OrdinalIgnoreCase))) { computer = "localhost"; } @@ -1220,6 +1259,7 @@ protected override void BeginProcessing() { computer = compname; } + try { foreach (string _sourceName in Source) @@ -1228,11 +1268,11 @@ protected override void BeginProcessing() { EventSourceCreationData newEventSource = new EventSourceCreationData(_sourceName, LogName); newEventSource.MachineName = compname; - if (!String.IsNullOrEmpty(MessageResourceFile)) + if (!string.IsNullOrEmpty(MessageResourceFile)) newEventSource.MessageResourceFile = MessageResourceFile; - if (!String.IsNullOrEmpty(ParameterResourceFile)) + if (!string.IsNullOrEmpty(ParameterResourceFile)) newEventSource.ParameterResourceFile = ParameterResourceFile; - if (!String.IsNullOrEmpty(CategoryResourceFile)) + if (!string.IsNullOrEmpty(CategoryResourceFile)) newEventSource.CategoryResourceFile = CategoryResourceFile; EventLog.CreateEventSource(newEventSource); } @@ -1262,9 +1302,9 @@ protected override void BeginProcessing() } } } - //End BeginProcessing() + // End BeginProcessing() #endregion override - }//End Class + } #endregion NewEventLogCommand #region RemoveEventLogCommand @@ -1281,18 +1321,18 @@ public class RemoveEventLogCommand : PSCmdlet { /// /// The following is the definition of the input parameter "ComputerName". - /// Specifies the Computer Name + /// Specifies the Computer Name. /// [Parameter(Position = 1)] [ValidateNotNull] [ValidateNotNullOrEmpty] [Alias("CN")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ComputerName { get; set; } = { "." }; + public string[] ComputerName { get; set; } = { "." }; /// /// The following is the definition of the input parameter "LogName". - /// Specifies the Event Log Name + /// Specifies the Event Log Name. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "Default")] @@ -1300,7 +1340,7 @@ public class RemoveEventLogCommand : PSCmdlet [ValidateNotNullOrEmpty] [Alias("LN")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] LogName { get; set; } + public string[] LogName { get; set; } /// /// The following is the definition of the input parameter "RemoveSource". @@ -1316,8 +1356,7 @@ public class RemoveEventLogCommand : PSCmdlet [ValidateNotNullOrEmpty] [Alias("SRC")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Source { get; set; } - + public string[] Source { get; set; } /// /// BeginProcessing method. @@ -1329,7 +1368,7 @@ protected override void BeginProcessing() string computer = string.Empty; foreach (string compName in ComputerName) { - if ((compName.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) || (compName.Equals(".", StringComparison.OrdinalIgnoreCase))) + if ((compName.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || (compName.Equals(".", StringComparison.OrdinalIgnoreCase))) { computer = "localhost"; } @@ -1337,6 +1376,7 @@ protected override void BeginProcessing() { computer = compName; } + if (ParameterSetName.Equals("Default")) { foreach (string log in LogName) @@ -1349,6 +1389,7 @@ protected override void BeginProcessing() { continue; } + EventLog.Delete(log, compName); } else @@ -1378,11 +1419,12 @@ protected override void BeginProcessing() { continue; } + EventLog.DeleteEventSource(src, compName); } else { - ErrorRecord er = new ErrorRecord(new InvalidOperationException(StringUtil.Format(EventlogResources.SourceDoesNotExist, "", computer, src)), null, ErrorCategory.InvalidOperation, null); + ErrorRecord er = new ErrorRecord(new InvalidOperationException(StringUtil.Format(EventlogResources.SourceDoesNotExist, string.Empty, computer, src)), null, ErrorCategory.InvalidOperation, null); WriteError(er); continue; } @@ -1402,9 +1444,9 @@ protected override void BeginProcessing() ErrorRecord er = new ErrorRecord(ex, "NewEventlogException", ErrorCategory.SecurityError, null); WriteError(er); } - }//End BeginProcessing() - }//End Class + } + } #endregion RemoveEventLogCommand -}//Microsoft.PowerShell.Commands +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetChildrenCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetChildrenCommand.cs index 695648a18294..14f64cea422e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetChildrenCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetChildrenCommand.cs @@ -1,21 +1,19 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// /// The get-childitem command class. - /// This command lists the contents of a container + /// This command lists the contents of a container. /// - /// /// /// - /// [Cmdlet(VerbsCommon.Get, "ChildItem", DefaultParameterSetName = "Items", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113308")] public class GetChildItemCommand : CoreCommandBase { @@ -33,7 +31,7 @@ public class GetChildItemCommand : CoreCommandBase #region Command parameters /// - /// Gets or sets the path for the operation + /// Gets or sets the path for the operation. /// [Parameter(Position = 0, ParameterSetName = childrenSet, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -43,6 +41,7 @@ public string[] Path { return _paths; } + set { _paths = value; @@ -50,27 +49,27 @@ public string[] Path } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = literalChildrenSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return _paths; - } // get + } set { base.SuppressWildcardExpansion = true; _paths = value; - } // set - } // LiteralPath + } + } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter(Position = 1)] public override string Filter @@ -79,6 +78,7 @@ public override string Filter { return base.Filter; } + set { base.Filter = value; @@ -86,7 +86,7 @@ public override string Filter } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include @@ -94,16 +94,16 @@ public override string[] Include get { return base.Include; - } // get + } set { base.Include = value; - } // set - } // Include + } + } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude @@ -111,16 +111,16 @@ public override string[] Exclude get { return base.Exclude; - } // get + } set { base.Exclude = value; - } // set - } // Exclude + } + } /// - /// Gets or sets the recurse switch + /// Gets or sets the recurse switch. /// [Parameter] [Alias("s")] @@ -130,6 +130,7 @@ public SwitchParameter Recurse { return _recurse; } + set { _recurse = value; @@ -149,6 +150,7 @@ public uint Depth { return _depth; } + set { _depth = value; @@ -157,9 +159,8 @@ public uint Depth } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -169,7 +170,6 @@ public uint Depth /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { @@ -177,14 +177,15 @@ public override SwitchParameter Force { return base.Force; } + set { base.Force = value; } - } // Force + } /// - /// Gets or sets the names switch + /// Gets or sets the names switch. /// [Parameter] public SwitchParameter Name @@ -193,6 +194,7 @@ public SwitchParameter Name { return _childNames; } + set { _childNames = value; @@ -204,20 +206,17 @@ public SwitchParameter Name /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { object result = null; - string path = String.Empty; + string path = string.Empty; if (_paths != null && _paths.Length > 0) { @@ -240,14 +239,16 @@ internal override object GetDynamicParameters(CmdletProviderContext context) { result = InvokeProvider.ChildItem.GetChildItemsDynamicParameters(path, Recurse, context); } + break; default: result = InvokeProvider.ChildItem.GetChildItemsDynamicParameters(path, Recurse, context); break; } + return result; - } // GetDynamicParameters + } #endregion Command parameters @@ -272,13 +273,12 @@ internal override object GetDynamicParameters(CmdletProviderContext context) private uint _depth = uint.MaxValue; /// - /// The flag that specifies whether to retrieve the child names or the child items + /// The flag that specifies whether to retrieve the child names or the child items. /// private bool _childNames = false; #endregion command data - #region command code /// @@ -290,7 +290,7 @@ protected override void ProcessRecord() if (_paths == null || _paths.Length == 0) { - _paths = new string[] { String.Empty }; + _paths = new string[] { string.Empty }; } foreach (string path in _paths) @@ -360,9 +360,9 @@ protected override void ProcessRecord() break; } } - } // ProcessRecord + } #endregion command code - } // class GetChildrenCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs index 176ee347211a..f033b13100bc 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs @@ -1,16 +1,19 @@ -using System; -using System.Management.Automation; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Collections.Generic; -using System.Windows.Forms; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Drawing; using System.Globalization; using System.IO; using System.Linq; -using System.Drawing; +using System.Management.Automation; using System.Media; using System.Runtime.InteropServices; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Collections.Specialized; +using System.Windows.Forms; namespace Microsoft.PowerShell.Commands { @@ -38,11 +41,11 @@ public enum ClipboardFormat /// [Cmdlet(VerbsCommon.Get, "Clipboard", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526219")] [Alias("gcb")] - [OutputType(typeof(String), typeof(FileInfo), typeof(Image), typeof(Stream))] + [OutputType(typeof(string), typeof(FileInfo), typeof(Image), typeof(Stream))] public class GetClipboardCommand : PSCmdlet { /// - /// Property that sets clipboard type. This will return the required format from clipboard + /// Property that sets clipboard type. This will return the required format from clipboard. /// [Parameter] public ClipboardFormat Format { get; set; } @@ -55,12 +58,14 @@ public class GetClipboardCommand : PSCmdlet public TextDataFormat TextFormatType { get { return _textFormat; } + set { _isTextFormatTypeSet = true; _textFormat = value; } } + private TextDataFormat _textFormat = TextDataFormat.UnicodeText; private bool _isTextFormatTypeSet = false; @@ -71,17 +76,19 @@ public TextDataFormat TextFormatType public SwitchParameter Raw { get { return _raw; } + set { _isRawSet = true; _raw = value; } } + private bool _raw; private bool _isRawSet = false; /// - /// This method implements the ProcessRecord method for Get-Clipboard command + /// This method implements the ProcessRecord method for Get-Clipboard command. /// protected override void BeginProcessing() { @@ -89,7 +96,7 @@ protected override void BeginProcessing() if (Format != ClipboardFormat.Text && _isTextFormatTypeSet) { ThrowTerminatingError(new ErrorRecord(new InvalidOperationException( - String.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidTypeCombine)), + string.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidTypeCombine)), "FailedToGetClipboard", ErrorCategory.InvalidOperation, "Clipboard")); } @@ -97,7 +104,7 @@ protected override void BeginProcessing() if (Format != ClipboardFormat.Text && Format != ClipboardFormat.FileDropList && _isRawSet) { ThrowTerminatingError(new ErrorRecord(new InvalidOperationException( - String.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidRawCombine)), + string.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidRawCombine)), "FailedToGetClipboard", ErrorCategory.InvalidOperation, "Clipboard")); } @@ -137,6 +144,7 @@ private List GetClipboardContentAsText(TextDataFormat textFormat) { return null; } + List result = new List(); // TextFormat default value is Text, by default it is same as Clipboard.GetText() @@ -150,6 +158,7 @@ private List GetClipboardContentAsText(TextDataFormat textFormat) string[] splitSymbol = { Environment.NewLine }; result.AddRange(textContent.Split(splitSymbol, StringSplitOptions.None)); } + return result; } @@ -163,12 +172,14 @@ private List GetClipboardContentAsFileList() { return null; } + List result = new List(); foreach (string filePath in Clipboard.GetFileDropList()) { FileInfo file = new FileInfo(filePath); result.Add(WrapOutputInPSObject(file, filePath)); } + return result; } @@ -196,6 +207,7 @@ private List GetClipboardContentAsFileList() string childName = item.Name; result.AddOrSetProperty("PSChildName", childName); } + return result; } } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs index a4a0e4ff1224..0ecf80085dbd 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs @@ -1,16 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #if !UNIX using System; using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Reflection; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Linq.Expressions; using System.Management.Automation; -using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.InteropServices; using Microsoft.Management.Infrastructure; using Microsoft.Win32; @@ -67,7 +67,7 @@ private class DeviceGuardInfo private class MiscInfoGroup { - public UInt64? physicallyInstalledMemory; + public ulong? physicallyInstalledMemory; public string timeZone; public string logonServer; public FirmwareType? firmwareType; @@ -86,7 +86,6 @@ private class MiscInfoGroup #region Instance Data private string _machineName = localMachineName; // we might need to have cmdlet work on another machine - private ProgressRecord _progress = null; /// /// Collection of property names from the Property parameter, @@ -101,7 +100,7 @@ private class MiscInfoGroup /// The Property parameter contains the names of properties to be retrieved. /// If this parameter is given, the cmdlet returns a PSCustomObject /// containing only the requested properties. - /// Wild-card patterns may be provided + /// Wild-card patterns may be provided. /// /// /// @@ -124,7 +123,7 @@ private class MiscInfoGroup #region Cmdlet Overrides /// - /// Perform any first-stage processing + /// Perform any first-stage processing. /// protected override void BeginProcessing() { @@ -144,7 +143,7 @@ protected override void BeginProcessing() } /// - /// Performs the cmdlet's work + /// Performs the cmdlet's work. /// protected override void ProcessRecord() { @@ -199,13 +198,13 @@ protected override void ProcessRecord() systemInfo.networkAdapters = GetNetworkAdapters(session); UpdateProgress(null); // close the progress bar - } // end of using(CimSession...) + } var infoOutput = CreateFullOutputObject(systemInfo, osInfo, miscInfo); if (_namedProperties != null) { - //var output = CreateCustomOutputObject(namedProperties, systemInfo, osInfo, miscInfo); + // var output = CreateCustomOutputObject(namedProperties, systemInfo, osInfo, miscInfo); var output = CreateCustomOutputObject(infoOutput, _namedProperties); WriteObject(output); @@ -219,24 +218,17 @@ protected override void ProcessRecord() #region Private Methods /// - /// Display progress + /// Display progress. /// /// /// Text to be displayed in status bar /// private void UpdateProgress(string status) { - if (_progress != null) - { - _progress.RecordType = ProgressRecordType.Completed; - WriteProgress(_progress); - } + ProgressRecord progress = new ProgressRecord(0, activity, status ?? ComputerResources.ProgressStatusCompleted); + progress.RecordType = status == null ? ProgressRecordType.Completed : ProgressRecordType.Processing; - if (status != null) - { - _progress = new ProgressRecord(0, activity, status); - WriteProgress(_progress); - } + WriteProgress(progress); } /// @@ -295,7 +287,7 @@ private static NetworkAdapter[] GetNetworkAdapters(CimSession session) if (adapters != null && configs != null) { - var configDict = new Dictionary(); + var configDict = new Dictionary(); foreach (var config in configs) { @@ -412,11 +404,12 @@ private static bool CheckDeviceGuardLicense() // consider there to be no license. } } + return false; } /// - /// Retrieve information related to Device Guard + /// Retrieve information related to Device Guard. /// /// /// A object representing @@ -436,12 +429,14 @@ private static DeviceGuardInfo GetDeviceGuard(CimSession session) var wmiGuard = session.GetFirst(CIMHelper.DeviceGuardNamespace, CIMHelper.ClassNames.DeviceGuard); - if (wmiGuard != null) { + if (wmiGuard != null) + { var smartStatus = EnumConverter.Convert((int?)wmiGuard.VirtualizationBasedSecurityStatus ?? 0); if (smartStatus != null) { status = (DeviceGuardSmartStatus)smartStatus; } + guard = wmiGuard.AsOutputType; } } @@ -479,7 +474,7 @@ private static DeviceGuardInfo GetDeviceGuard(CimSession session) } /// - /// Retrieve information related to HyperVisor + /// Retrieve information related to HyperVisor. /// /// /// A object representing @@ -533,7 +528,7 @@ private static HyperVInfo GetHyperVisorInfo(CimSession session) } /// - /// Retrieve miscellaneous system information + /// Retrieve miscellaneous system information. /// /// /// A object representing @@ -550,7 +545,7 @@ private static MiscInfoGroup GetOtherInfo(CimSession session) // get platform role try { - //TODO: Local machine only. Check for that? + // TODO: Local machine only. Check for that? uint powerRole = Native.PowerDeterminePlatformRoleEx(Native.POWER_PLATFORM_ROLE_V2); if (powerRole >= (uint)PowerPlatformRole.MaximumEnumValue) rv.powerPlatformRole = PowerPlatformRole.Unspecified; @@ -564,14 +559,13 @@ private static MiscInfoGroup GetOtherInfo(CimSession session) } // get secure-boot info - //TODO: Local machine only? Check for that? + // TODO: Local machine only? Check for that? rv.firmwareType = GetFirmwareType(); // get amount of memory physically installed - //TODO: Local machine only. Check for that? + // TODO: Local machine only. Check for that? rv.physicallyInstalledMemory = GetPhysicallyInstalledSystemMemory(); - // get time zone // we'll use .Net's TimeZoneInfo for now. systeminfo uses Caption from Win32_TimeZone var tzi = TimeZoneInfo.Local; @@ -616,7 +610,7 @@ private static MiscInfoGroup GetOtherInfo(CimSession session) /// null if unsuccessful, otherwise FirmwareType enum specifying /// the firmware type. /// - private static Nullable GetFirmwareType() + private static FirmwareType? GetFirmwareType() { try { @@ -640,11 +634,11 @@ private static Nullable GetFirmwareType() /// /// null if unsuccessful, otherwise the amount of physically installed memory. /// - private static Nullable GetPhysicallyInstalledSystemMemory() + private static ulong? GetPhysicallyInstalledSystemMemory() { try { - UInt64 memory; + ulong memory; if (Native.GetPhysicallyInstalledSystemMemory(out memory)) return memory; } @@ -889,14 +883,13 @@ private static ComputerInfo CreateFullOutputObject(SystemInfoGroup systemInfo, O if (otherInfo.keyboards.Length > 0) { - //TODO: handle multiple keyboards? + // TODO: handle multiple keyboards? // there might be several keyboards found. For the moment // we display info for only one string layout = otherInfo.keyboards[0].Layout; - var culture = Conversion.MakeLocale(layout); - output.KeyboardLayout = culture == null ? layout : culture.Name; + output.KeyboardLayout = Conversion.GetLocaleName(layout); } if (otherInfo.hyperV != null) @@ -933,7 +926,7 @@ private static ComputerInfo CreateFullOutputObject(SystemInfoGroup systemInfo, O /// /// Create a new PSObject, containing only those properties named in the - /// namedProperties parameter + /// namedProperties parameter. /// /// /// A containing all the acquired system information @@ -988,7 +981,7 @@ private static List GetComputerInfoPropertyNames() } /// - /// Expand any wild-card patterns into known property names + /// Expand any wild-card patterns into known property names. /// /// /// List of known property names @@ -1051,7 +1044,7 @@ private static List CollectPropertyNames(string[] requestedProperties) { return string.Compare(s, name, - StringComparison.CurrentCultureIgnoreCase) == 0; + StringComparison.OrdinalIgnoreCase) == 0; }; var propertyName = availableProperties.Find(pred); @@ -1104,29 +1097,6 @@ internal static bool TryParseHex(string hexString, out uint value) } } - public static string LocaleIdToLocaleName(uint localeID) - { - // CoreCLR's System.Globalization.Culture does not appear to have a constructor - // that accepts an integer LocalID (LCID) value, so we'll PInvoke native code - // to get a locale name from an LCID value - - try - { - var sbName = new System.Text.StringBuilder(Native.LOCALE_NAME_MAX_LENGTH); - var len = Native.LCIDToLocaleName(localeID, sbName, sbName.Capacity, 0); - - if (len > 0 && sbName.Length > 0) - return sbName.ToString(); - } - catch (Exception) - { - // Probably failed to load the DLL or to file the function entry point. - // Fail silently - } - - return null; - } - /// /// Attempt to create a /// object from a locale string as retrieved from WMI. @@ -1143,38 +1113,36 @@ public static string LocaleIdToLocaleName(uint localeID) /// Failing that it attempts to retrieve the CultureInfo object /// using the locale string as passed. /// - internal static System.Globalization.CultureInfo MakeLocale(string locale) + internal static string GetLocaleName(string locale) { - System.Globalization.CultureInfo culture = null; + CultureInfo culture = null; if (locale != null) { try { - uint localeNum; - - if (TryParseHex(locale, out localeNum)) + // The "locale" must contain a hexadecimal value, with no + // base-indication prefix. For example, the string "0409" will be + // parsed into the base-10 integer value 1033, while the string "0x0409" + // will fail to parse due to the "0x" base-indication prefix. + if (UInt32.TryParse(locale, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint localeNum)) { - string localeName = LocaleIdToLocaleName(localeNum); - - if (localeName != null) - culture = new System.Globalization.CultureInfo(localeName); + culture = CultureInfo.GetCultureInfo((int)localeNum); } if (culture == null) { - // either the TryParseHex failed, or the LocaleIdToLocaleName - // failed, so we'll try using the original string - culture = new System.Globalization.CultureInfo(locale); + // If TryParse failed we'll try using the original string as culture name + culture = CultureInfo.GetCultureInfo(locale); } } - catch (Exception/* ex*/) + catch (Exception) { culture = null; } } - return culture; + return culture == null ? null : culture.Name; } /// @@ -1218,7 +1186,7 @@ internal static class EnumConverter where T : struct, IConvertible private static readonly Func s_convert = MakeConverter(); /// - /// Convert an integer to a Nullable enum of type T + /// Convert an integer to a Nullable enum of type T. /// /// /// The integer value to be converted to the specified enum type. @@ -1343,7 +1311,7 @@ internal abstract class WmiClassBase /// /// Get a language name from a language identifier. /// - /// + /// /// A nullable integer containing the language ID for the desired language. /// /// @@ -1351,10 +1319,18 @@ internal abstract class WmiClassBase /// the language parameter. If the language parameter is null or has a /// value that is not a valid language ID, the method returns null. /// - protected static string GetLanguageName(UInt32? language) + protected static string GetLanguageName(uint? lcid) { - if (language != null) - return Conversion.LocaleIdToLocaleName(language.Value); + if (lcid != null && lcid >= 0) + { + try + { + return CultureInfo.GetCultureInfo((int)lcid.Value).Name; + } + catch + { + } + } return null; } @@ -1406,7 +1382,7 @@ internal class WmiBios : WmiClassBase public byte? EmbeddedControllerMajorVersion; public byte? EmbeddedControllerMinorVersion; public string IdentificationCode; - public UInt16? InstallableLanguages; + public ushort? InstallableLanguages; public DateTime? InstallDate; public string LanguageEdition; public string[] ListOfLanguages; @@ -1417,65 +1393,65 @@ internal class WmiBios : WmiClassBase public DateTime? ReleaseDate; public string SerialNumber; public string SMBIOSBIOSVersion; - public UInt16? SMBIOSMajorVersion; - public UInt16? SMBIOSMinorVersion; + public ushort? SMBIOSMajorVersion; + public ushort? SMBIOSMinorVersion; public bool? SMBIOSPresent; - public UInt16? SoftwareElementState; + public ushort? SoftwareElementState; public string Status; public byte? SystemBiosMajorVersion; public byte? SystemBiosMinorVersion; - public UInt16? TargetOperatingSystem; + public ushort? TargetOperatingSystem; public string Version; } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] internal class WmiComputerSystem { - public UInt16? AdminPasswordStatus; + public ushort? AdminPasswordStatus; public bool? AutomaticManagedPagefile; public bool? AutomaticResetBootOption; public bool? AutomaticResetCapability; - public UInt16? BootOptionOnLimit; - public UInt16? BootOptionOnWatchDog; + public ushort? BootOptionOnLimit; + public ushort? BootOptionOnWatchDog; public bool? BootROMSupported; public string BootupState; public UInt16[] BootStatus; public string Caption; - public UInt16? ChassisBootupState; + public ushort? ChassisBootupState; public string ChassisSKUNumber; public Int16? CurrentTimeZone; public bool? DaylightInEffect; public string Description; public string DNSHostName; public string Domain; - public UInt16? DomainRole; + public ushort? DomainRole; public bool? EnableDaylightSavingsTime; - public UInt16? FrontPanelResetStatus; + public ushort? FrontPanelResetStatus; public bool? HypervisorPresent; public bool? InfraredSupported; public string InitialLoadInfo; public DateTime? InstallDate; - public UInt16? KeyboardPasswordStatus; + public ushort? KeyboardPasswordStatus; public string LastLoadInfo; public string Manufacturer; public string Model; public string Name; public bool? NetworkServerModeEnabled; - public UInt32? NumberOfLogicalProcessors; - public UInt32? NumberOfProcessors; + public uint? NumberOfLogicalProcessors; + public uint? NumberOfProcessors; public string[] OEMStringArray; public bool? PartOfDomain; public Int64? PauseAfterReset; - public UInt16? PCSystemType; - public UInt16? PCSystemTypeEx; + public ushort? PCSystemType; + public ushort? PCSystemTypeEx; public UInt16[] PowerManagementCapabilities; public bool? PowerManagementSupported; - public UInt16? PowerOnPasswordStatus; - public UInt16? PowerState; - public UInt16? PowerSupplyState; + public ushort? PowerOnPasswordStatus; + public ushort? PowerState; + public ushort? PowerSupplyState; public string PrimaryOwnerContact; public string PrimaryOwnerName; - public UInt16? ResetCapability; + public ushort? ResetCapability; public Int16? ResetCount; public Int16? ResetLimit; public string[] Roles; @@ -1484,10 +1460,10 @@ internal class WmiComputerSystem public string SystemFamily; public string SystemSKUNumber; public string SystemType; - public UInt16? ThermalState; - public UInt64? TotalPhysicalMemory; + public ushort? ThermalState; + public ulong? TotalPhysicalMemory; public string UserName; - public UInt16? WakeUpType; + public ushort? WakeUpType; public string Workgroup; public PowerManagementCapabilities[] GetPowerManagementCapabilities() @@ -1515,12 +1491,12 @@ public PowerManagementCapabilities[] GetPowerManagementCapabilities() internal class WmiDeviceGuard { public UInt32[] AvailableSecurityProperties; - public UInt32? CodeIntegrityPolicyEnforcementStatus; - public UInt32? UsermodeCodeIntegrityPolicyEnforcementStatus; + public uint? CodeIntegrityPolicyEnforcementStatus; + public uint? UsermodeCodeIntegrityPolicyEnforcementStatus; public UInt32[] RequiredSecurityProperties; public UInt32[] SecurityServicesConfigured; public UInt32[] SecurityServicesRunning; - public UInt32? VirtualizationBasedSecurityStatus; + public uint? VirtualizationBasedSecurityStatus; public DeviceGuard AsOutputType { @@ -1539,6 +1515,7 @@ public DeviceGuard AsOutputType if (temp != null) listHardware.Add(temp.Value); } + guard.RequiredSecurityProperties = listHardware.ToArray(); listHardware.Clear(); @@ -1549,6 +1526,7 @@ public DeviceGuard AsOutputType if (temp != null) listHardware.Add(temp.Value); } + guard.AvailableSecurityProperties = listHardware.ToArray(); var listSoftware = new List(); @@ -1559,6 +1537,7 @@ public DeviceGuard AsOutputType if (temp != null) listSoftware.Add(temp.Value); } + guard.SecurityServicesConfigured = listSoftware.ToArray(); listSoftware.Clear(); @@ -1569,6 +1548,7 @@ public DeviceGuard AsOutputType if (temp != null) listSoftware.Add(temp.Value); } + guard.SecurityServicesRunning = listSoftware.ToArray(); } @@ -1585,9 +1565,9 @@ public DeviceGuard AsOutputType [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] internal class WmiKeyboard { - public UInt16? Availability; + public ushort? Availability; public string Caption; - public UInt32? ConfigManagerErrorCode; + public uint? ConfigManagerErrorCode; public bool? ConfigManagerUserConfig; public string Description; public string DeviceID; @@ -1595,16 +1575,16 @@ internal class WmiKeyboard public string ErrorDescription; public DateTime? InstallDate; public bool? IsLocked; - public UInt32? LastErrorCode; + public uint? LastErrorCode; public string Layout; public string Name; - public UInt16? NumberOfFunctionKeys; - public UInt16? Password; + public ushort? NumberOfFunctionKeys; + public ushort? Password; public string PNPDeviceID; public UInt16[] PowerManagementCapabilities; public bool? PowerManagementSupported; public string Status; - public UInt16? StatusInfo; + public ushort? StatusInfo; public string SystemCreationClassName; public string SystemName; } @@ -1612,8 +1592,8 @@ internal class WmiKeyboard [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] internal class WMiLogicalMemory { - //TODO: fill this in!!! - public UInt32? TotalPhysicalMemory; + // TODO: fill this in!!! + public uint? TotalPhysicalMemory; } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] @@ -1624,76 +1604,76 @@ internal class WmiMsftNetAdapter public DateTime? InstallDate; public string Name; public string Status; - public UInt16? Availability; - public UInt32? ConfigManagerErrorCode; + public ushort? Availability; + public uint? ConfigManagerErrorCode; public bool? ConfigManagerUserConfig; public string DeviceID; public bool? ErrorCleared; public string ErrorDescription; - public UInt32? LastErrorCode; + public uint? LastErrorCode; public string PNPDeviceID; public UInt16[] PowerManagementCapabilities; public bool? PowerManagementSupported; - public UInt16? StatusInfo; + public ushort? StatusInfo; public string SystemCreationClassName; public string SystemName; - public UInt64? Speed; - public UInt64? MaxSpeed; - public UInt64? RequestedSpeed; - public UInt16? UsageRestriction; - public UInt16? PortType; + public ulong? Speed; + public ulong? MaxSpeed; + public ulong? RequestedSpeed; + public ushort? UsageRestriction; + public ushort? PortType; public string OtherPortType; public string OtherNetworkPortType; - public UInt16? PortNumber; - public UInt16? LinkTechnology; + public ushort? PortNumber; + public ushort? LinkTechnology; public string OtherLinkTechnology; public string PermanentAddress; public string[] NetworkAddresses; public bool? FullDuplex; public bool? AutoSense; - public UInt64? SupportedMaximumTransmissionUnit; - public UInt64? ActiveMaximumTransmissionUnit; + public ulong? SupportedMaximumTransmissionUnit; + public ulong? ActiveMaximumTransmissionUnit; public string InterfaceDescription; public string InterfaceName; - public UInt64? NetLuid; + public ulong? NetLuid; public string InterfaceGuid; - public UInt32? InterfaceIndex; + public uint? InterfaceIndex; public string DeviceName; - public UInt32? NetLuidIndex; + public uint? NetLuidIndex; public bool? Virtual; public bool? Hidden; public bool? NotUserRemovable; public bool? IMFilter; - public UInt32? InterfaceType; + public uint? InterfaceType; public bool? HardwareInterface; public bool? WdmInterface; public bool? EndPointInterface; public bool? iSCSIInterface; - public UInt32? State; - public UInt32? NdisMedium; - public UInt32? NdisPhysicalMedium; - public UInt32? InterfaceOperationalStatus; + public uint? State; + public uint? NdisMedium; + public uint? NdisPhysicalMedium; + public uint? InterfaceOperationalStatus; public bool? OperationalStatusDownDefaultPortNotAuthenticated; public bool? OperationalStatusDownMediaDisconnected; public bool? OperationalStatusDownInterfacePaused; public bool? OperationalStatusDownLowPowerState; - public UInt32? InterfaceAdminStatus; - public UInt32? MediaConnectState; - public UInt32? MtuSize; - public UInt16? VlanID; - public UInt64? TransmitLinkSpeed; - public UInt64? ReceiveLinkSpeed; + public uint? InterfaceAdminStatus; + public uint? MediaConnectState; + public uint? MtuSize; + public ushort? VlanID; + public ulong? TransmitLinkSpeed; + public ulong? ReceiveLinkSpeed; public bool? PromiscuousMode; public bool? DeviceWakeUpEnable; public bool? ConnectorPresent; - public UInt32? MediaDuplexState; + public uint? MediaDuplexState; public string DriverDate; - public UInt64? DriverDateData; + public ulong? DriverDateData; public string DriverVersionString; public string DriverName; public string DriverDescription; - public UInt16? MajorDriverVersion; - public UInt16? MinorDriverVersion; + public ushort? MajorDriverVersion; + public ushort? MinorDriverVersion; public byte? DriverMajorNdisVersion; public byte? DriverMinorNdisVersion; public string PnPDeviceID; @@ -1708,29 +1688,29 @@ internal class WmiMsftNetAdapter internal class WmiNetworkAdapter { public string AdapterType; - public UInt16? AdapterTypeID; + public ushort? AdapterTypeID; public bool? AutoSense; - public UInt16? Availability; + public ushort? Availability; public string Caption; - public UInt32? ConfigManagerErrorCode; + public uint? ConfigManagerErrorCode; public bool? ConfigManagerUserConfig; public string Description; public string DeviceID; public bool? ErrorCleared; public string ErrorDescription; public string GUID; - public UInt32? Index; + public uint? Index; public DateTime? InstallDate; public bool? Installed; - public UInt32? InterfaceIndex; - public UInt32? LastErrorCode; + public uint? InterfaceIndex; + public uint? LastErrorCode; public string MACAddress; public string Manufacturer; - public UInt32? MaxNumberControlled; - public UInt64? MaxSpeed; + public uint? MaxNumberControlled; + public ulong? MaxSpeed; public string Name; public string NetConnectionID; - public UInt16? NetConnectionStatus; + public ushort? NetConnectionStatus; public bool? NetEnabled; public string[] NetworkAddresses; public string PermanentAddress; @@ -1740,9 +1720,9 @@ internal class WmiNetworkAdapter public bool? PowerManagementSupported; public string ProductName; public string ServiceName; - public UInt64? Speed; + public ulong? Speed; public string Status; - public UInt16? StatusInfo; + public ushort? StatusInfo; public string SystemCreationClassName; public string SystemName; public DateTime? TimeOfLastReset; @@ -1770,14 +1750,14 @@ internal class WmiNetworkAdapterConfiguration public string DNSHostName; public string[] DNSServerSearchOrder; public bool? DomainDNSRegistrationEnabled; - public UInt32? ForwardBufferMemory; + public uint? ForwardBufferMemory; public bool? FullDNSRegistrationEnabled; public UInt16[] GatewayCostMetric; public byte? IGMPLevel; - public UInt32? Index; - public UInt32? InterfaceIndex; + public uint? Index; + public uint? InterfaceIndex; public string[] IPAddress; - public UInt32? IPConnectionMetric; + public uint? IPConnectionMetric; public bool? IPEnabled; public bool? IPFilterSecurityEnabled; public bool? IPPortSecurityEnabled; @@ -1789,24 +1769,24 @@ internal class WmiNetworkAdapterConfiguration public string IPXAddress; public bool? IPXEnabled; public UInt32[] IPXFrameType; - public UInt32? IPXMediaType; + public uint? IPXMediaType; public string[] IPXNetworkNumber; public string IPXVirtualNetNumber; - public UInt32? KeepAliveInterval; - public UInt32? KeepAliveTime; + public uint? KeepAliveInterval; + public uint? KeepAliveTime; public string MACAddress; - public UInt32? MTU; - public UInt32? NumForwardPackets; + public uint? MTU; + public uint? NumForwardPackets; public bool? PMTUBHDetectEnabled; public bool? PMTUDiscoveryEnabled; public string ServiceName; public string SettingID; - public UInt32? TcpipNetbiosOptions; - public UInt32? TcpMaxConnectRetransmissions; - public UInt32? TcpMaxDataRetransmissions; - public UInt32? TcpNumConnections; + public uint? TcpipNetbiosOptions; + public uint? TcpMaxConnectRetransmissions; + public uint? TcpMaxDataRetransmissions; + public uint? TcpNumConnections; public bool? TcpUseRFC1122UrgentPointer; - public UInt16? TcpWindowSize; + public ushort? TcpWindowSize; public bool? WINSEnableLMHostsLookup; public string WINSHostLookupFile; public string WINSPrimaryServer; @@ -1834,47 +1814,47 @@ internal class WmiOperatingSystem : WmiClassBase public bool? Debug; public string Description; public bool? Distributed; - public UInt32? EncryptionLevel; + public uint? EncryptionLevel; public byte? ForegroundApplicationBoost; - public UInt64? FreePhysicalMemory; - public UInt64? FreeSpaceInPagingFiles; - public UInt64? FreeVirtualMemory; + public ulong? FreePhysicalMemory; + public ulong? FreeSpaceInPagingFiles; + public ulong? FreeVirtualMemory; public DateTime? InstallDate; public DateTime? LastBootUpTime; public DateTime? LocalDateTime; public string Locale; public string Manufacturer; - public UInt32? MaxNumberOfProcesses; - public UInt64? MaxProcessMemorySize; + public uint? MaxNumberOfProcesses; + public ulong? MaxProcessMemorySize; public string[] MUILanguages; public string Name; - public UInt32? NumberOfLicensedUsers; - public UInt32? NumberOfProcesses; - public UInt32? NumberOfUsers; - public UInt32? OperatingSystemSKU; + public uint? NumberOfLicensedUsers; + public uint? NumberOfProcesses; + public uint? NumberOfUsers; + public uint? OperatingSystemSKU; public string Organization; public string OSArchitecture; - public UInt32? OSLanguage; - public UInt32? OSProductSuite; - public UInt16? OSType; + public uint? OSLanguage; + public uint? OSProductSuite; + public ushort? OSType; public string OtherTypeDescription; public bool? PAEEnabled; public bool? PortableOperatingSystem; public bool? Primary; - public UInt32? ProductType; + public uint? ProductType; public string RegisteredUser; public string SerialNumber; - public UInt16? ServicePackMajorVersion; - public UInt16? ServicePackMinorVersion; - public UInt64? SizeStoredInPagingFiles; + public ushort? ServicePackMajorVersion; + public ushort? ServicePackMinorVersion; + public ulong? SizeStoredInPagingFiles; public string Status; - public UInt32? SuiteMask; + public uint? SuiteMask; public string SystemDevice; public string SystemDirectory; public string SystemDrive; - public UInt64? TotalSwapSpaceSize; - public UInt64? TotalVirtualMemorySize; - public UInt64? TotalVisibleMemorySize; + public ulong? TotalSwapSpaceSize; + public ulong? TotalVirtualMemorySize; + public ulong? TotalVisibleMemorySize; public string Version; public string WindowsDirectory; #endregion Fields @@ -1899,17 +1879,12 @@ public OSProductSuite[] Suites #region Public Methods public string GetLocale() { - System.Globalization.CultureInfo culture = null; - - if (Locale != null) - culture = Conversion.MakeLocale(Locale); - - return culture == null ? null : culture.Name; + return Conversion.GetLocaleName(Locale); } #endregion Public Methods #region Private Methods - private OSProductSuite[] MakeProductSuites(UInt32? suiteMask) + private OSProductSuite[] MakeProductSuites(uint? suiteMask) { if (suiteMask == null) return null; @@ -1929,13 +1904,13 @@ private OSProductSuite[] MakeProductSuites(UInt32? suiteMask) [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] internal class WmiPageFileUsage { - public UInt32? AllocatedBaseSize; + public uint? AllocatedBaseSize; public string Caption; - public UInt32? CurrentUsage; + public uint? CurrentUsage; public string Description; public DateTime? InstallDate; public string Name; - public UInt32? PeakUsage; + public uint? PeakUsage; public string Status; public bool? TempPageFile; } @@ -1943,61 +1918,61 @@ internal class WmiPageFileUsage [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] internal class WmiProcessor { - public UInt16? AddressWidth; - public UInt16? Architecture; + public ushort? AddressWidth; + public ushort? Architecture; public string AssetTag; - public UInt16? Availability; + public ushort? Availability; public string Caption; - public UInt32? Characteristics; - public UInt32? ConfigManagerErrorCode; + public uint? Characteristics; + public uint? ConfigManagerErrorCode; public bool? ConfigManagerUserConfig; - public UInt16? CpuStatus; - public UInt32? CurrentClockSpeed; - public UInt16? CurrentVoltage; - public UInt16? DataWidth; + public ushort? CpuStatus; + public uint? CurrentClockSpeed; + public ushort? CurrentVoltage; + public ushort? DataWidth; public string Description; public string DeviceID; public bool? ErrorCleared; public string ErrorDescription; - public UInt32? ExtClock; - public UInt16? Family; + public uint? ExtClock; + public ushort? Family; public DateTime? InstallDate; - public UInt32? L2CacheSize; - public UInt32? L2CacheSpeed; - public UInt32? L3CacheSize; - public UInt32? L3CacheSpeed; - public UInt32? LastErrorCode; - public UInt16? Level; - public UInt16? LoadPercentage; + public uint? L2CacheSize; + public uint? L2CacheSpeed; + public uint? L3CacheSize; + public uint? L3CacheSpeed; + public uint? LastErrorCode; + public ushort? Level; + public ushort? LoadPercentage; public string Manufacturer; - public UInt32? MaxClockSpeed; + public uint? MaxClockSpeed; public string Name; - public UInt32? NumberOfCores; - public UInt32? NumberOfEnabledCore; - public UInt32? NumberOfLogicalProcessors; + public uint? NumberOfCores; + public uint? NumberOfEnabledCore; + public uint? NumberOfLogicalProcessors; public string OtherFamilyDescription; public string PartNumber; public string PNPDeviceID; public UInt16[] PowerManagementCapabilities; public bool? PowerManagementSupported; public string ProcessorId; - public UInt16? ProcessorType; - public UInt16? Revision; + public ushort? ProcessorType; + public ushort? Revision; public string Role; public bool? SecondLevelAddressTranslationExtensions; public string SerialNumber; public string SocketDesignation; public string Status; - public UInt16? StatusInfo; + public ushort? StatusInfo; public string Stepping; public string SystemName; - public UInt32? ThreadCount; + public uint? ThreadCount; public string UniqueId; - public UInt16? UpgradeMethod; + public ushort? UpgradeMethod; public string Version; public bool? VirtualizationFirmwareEnabled; public bool? VMMonitorModeExtensions; - public UInt32? VoltageCaps; + public uint? VoltageCaps; } #pragma warning restore 649 @@ -2024,43 +1999,43 @@ internal class RegWinNtCurrentVersion #region Output components #region Classes comprising the output object /// - /// Provides information about Device Guard + /// Provides information about Device Guard. /// public class DeviceGuard { /// - /// Array of required security properties + /// Array of required security properties. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardHardwareSecure[] RequiredSecurityProperties { get; internal set; } /// - /// Array of available security properties + /// Array of available security properties. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardHardwareSecure[] AvailableSecurityProperties { get; internal set; } /// - /// Indicates which security services have been configured + /// Indicates which security services have been configured. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardSoftwareSecure[] SecurityServicesConfigured { get; internal set; } /// - /// Indicates which security services are running + /// Indicates which security services are running. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardSoftwareSecure[] SecurityServicesRunning { get; internal set; } /// - /// Indicates the status of the Device Guard Code Integrity policy + /// Indicates the status of the Device Guard Code Integrity policy. /// public DeviceGuardConfigCodeIntegrityStatus? CodeIntegrityPolicyEnforcementStatus { get; internal set; } /// - /// Indicates the status of the Device Guard user mode Code Integrity policy + /// Indicates the status of the Device Guard user mode Code Integrity policy. /// public DeviceGuardConfigCodeIntegrityStatus? UserModeCodeIntegrityPolicyEnforcementStatus { get; internal set; } } /// - /// Describes a Quick-Fix Engineering update + /// Describes a Quick-Fix Engineering update. /// public class HotFix { @@ -2075,7 +2050,7 @@ public string HotFixID } /// - /// Description of the update + /// Description of the update. /// public string Description { @@ -2085,7 +2060,7 @@ public string Description } /// - /// String containing the date that the update was installed + /// String containing the date that the update was installed. /// public string InstalledOn { @@ -2095,7 +2070,7 @@ public string InstalledOn } /// - /// Additional comments that relate to the update + /// Additional comments that relate to the update. /// public string FixComments { @@ -2106,30 +2081,30 @@ public string FixComments } /// - /// Provides information about a network adapter + /// Provides information about a network adapter. /// public class NetworkAdapter { /// - /// Description of the network adapter + /// Description of the network adapter. /// public string Description { get; internal set; } /// /// Name of the network connection as it appears in the Network - /// Connections Control Panel program + /// Connections Control Panel program. /// public string ConnectionID { get; internal set; } /// /// Indicates whether the DHCP server automatically assigns an IP address - /// to the computer system when establishing a network connection + /// to the computer system when establishing a network connection. /// public bool? DHCPEnabled { get; internal set; } /// - /// IP Address of the DHCP server + /// IP Address of the DHCP server. /// public string DHCPServer { get; internal set; } /// - /// State of the network adapter connection to the network + /// State of the network adapter connection to the network. /// public NetConnectionStatus ConnectionStatus { get; internal set; } /// @@ -2140,49 +2115,49 @@ public class NetworkAdapter } /// - /// Describes a processor on the computer + /// Describes a processor on the computer. /// public class Processor { /// - /// Name of the processor + /// Name of the processor. /// public string Name { get; internal set; } /// - /// Name of the processor manufacturer + /// Name of the processor manufacturer. /// public string Manufacturer { get; internal set; } /// - /// Description of the processor + /// Description of the processor. /// public string Description { get; internal set; } /// - /// Processor architecture used by the platform + /// Processor architecture used by the platform. /// public CpuArchitecture? Architecture { get; internal set; } /// - /// Address width of the processor + /// Address width of the processor. /// - public UInt16? AddressWidth { get; internal set; } + public ushort? AddressWidth { get; internal set; } /// - /// Data width of the processor + /// Data width of the processor. /// - public UInt16? DataWidth { get; internal set; } + public ushort? DataWidth { get; internal set; } /// - /// Maximum speed of the processor, in MHz + /// Maximum speed of the processor, in MHz. /// - public UInt32? MaxClockSpeed { get; internal set; } + public uint? MaxClockSpeed { get; internal set; } /// - /// Current speed of the processor, in MHz + /// Current speed of the processor, in MHz. /// - public UInt32? CurrentClockSpeed { get; internal set; } + public uint? CurrentClockSpeed { get; internal set; } /// /// Number of cores for the current instance of the processor. /// /// /// A core is a physical processor on the integrated circuit /// - public UInt32? NumberOfCores { get; internal set; } + public uint? NumberOfCores { get; internal set; } /// /// Number of logical processors for the current instance of the processor. /// @@ -2190,7 +2165,7 @@ public class Processor /// For processors capable of hyperthreading, this value includes only the /// processors which have hyperthreading enabled /// - public UInt32? NumberOfLogicalProcessors { get; internal set; } + public uint? NumberOfLogicalProcessors { get; internal set; } /// /// Processor information that describes the processor features. /// @@ -2206,35 +2181,35 @@ public class Processor /// public string ProcessorID { get; internal set; } /// - /// Type of chip socket used on the circuit + /// Type of chip socket used on the circuit. /// public string SocketDesignation { get; internal set; } /// - /// Primary function of the processor + /// Primary function of the processor. /// public ProcessorType? ProcessorType { get; internal set; } /// - /// Role of the processor + /// Role of the processor. /// public string Role { get; internal set; } /// - /// Current status of the processor + /// Current status of the processor. /// public string Status { get; internal set; } /// /// Current status of the processor. /// Status changes indicate processor usage, but not the physical - /// condition of the processor + /// condition of the processor. /// public CpuStatus? CpuStatus { get; internal set; } /// - /// Availability and status of the processor + /// Availability and status of the processor. /// public CpuAvailability? Availability { get; internal set; } } /// - /// The ComputerInfo class is output to the PowerShell pipeline. + /// The ComputerInfo class is output to the PowerShell pipeline. /// public class ComputerInfo { @@ -2303,7 +2278,7 @@ public class ComputerInfo #region BIOS /// /// Array of BIOS characteristics supported by the system as defined by - /// the System Management BIOS Reference Specification + /// the System Management BIOS Reference Specification. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public UInt16[] BiosCharacteristics { get; internal set; } @@ -2311,13 +2286,13 @@ public class ComputerInfo /// /// Array of the complete system BIOS information. In many computers /// there can be several version strings that are stored in the registry - /// and represent the system BIOS information + /// and represent the system BIOS information. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] BiosBIOSVersion { get; internal set; } /// - /// Internal identifier for this compilation of the BIOS firmware + /// Internal identifier for this compilation of the BIOS firmware. /// public string BiosBuildNumber { get; internal set; } @@ -2327,27 +2302,27 @@ public class ComputerInfo public string BiosCaption { get; internal set; } /// - /// Code set used by the BIOS + /// Code set used by the BIOS. /// public string BiosCodeSet { get; internal set; } /// - /// Name of the current BIOS language + /// Name of the current BIOS language. /// public string BiosCurrentLanguage { get; internal set; } /// - /// Description of the BIOS + /// Description of the BIOS. /// public string BiosDescription { get; internal set; } /// - /// Major version of the embedded controller firmware + /// Major version of the embedded controller firmware. /// public Int16? BiosEmbeddedControllerMajorVersion { get; internal set; } /// - /// Minor version of the embedded controller firmware + /// Minor version of the embedded controller firmware. /// public Int16? BiosEmbeddedControllerMinorVersion { get; internal set; } @@ -2361,43 +2336,43 @@ public class ComputerInfo /// /// Manufacturer's identifier for this software element. - /// Often this will be a stock keeping unit (SKU) or a part number + /// Often this will be a stock keeping unit (SKU) or a part number. /// public string BiosIdentificationCode { get; internal set; } /// /// Number of languages available for installation on this system. - /// Language may determine properties such as the need for Unicode and bidirectional text + /// Language may determine properties such as the need for Unicode and bidirectional text. /// - public UInt16? BiosInstallableLanguages { get; internal set; } + public ushort? BiosInstallableLanguages { get; internal set; } /// /// Date and time the object was installed. /// - //TODO: do we want this? On my system this is null + // TODO: do we want this? On my system this is null public DateTime? BiosInstallDate { get; internal set; } /// /// Language edition of the BIOS firmware. /// The language codes defined in ISO 639 should be used. /// Where the software element represents a multilingual or international - /// version of a product, the string "multilingual" should be used + /// version of a product, the string "multilingual" should be used. /// public string BiosLanguageEdition { get; internal set; } /// - /// Array of names of available BIOS-installable languages + /// Array of names of available BIOS-installable languages. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] BiosListOfLanguages { get; internal set; } /// - /// Manufacturer of the BIOS + /// Manufacturer of the BIOS. /// public string BiosManufacturer { get; internal set; } /// - /// Name used to identify the BIOS + /// Name used to identify the BIOS. /// public string BiosName { get; internal set; } @@ -2406,139 +2381,141 @@ public class ComputerInfo /// the BiosTargetOperatingSystem property has a value of 1 (Other). /// When TargetOperatingSystem has a value of 1, BiosOtherTargetOS must /// have a nonnull value. For all other values of BiosTargetOperatingSystem, - /// BiosOtherTargetOS is NULL + /// BiosOtherTargetOS is NULL. /// public string BiosOtherTargetOS { get; internal set; } /// - /// If true, this is the primary BIOS of the computer system + /// If true, this is the primary BIOS of the computer system. /// public bool? BiosPrimaryBIOS { get; internal set; } /// - /// Release date of the Windows BIOS + /// Release date of the Windows BIOS. /// public DateTime? BiosReleaseDate { get; internal set; } /// - /// Assigned serial number of the BIOS + /// Assigned serial number of the BIOS. /// public string BiosSerialNumber { get; internal set; } /// - /// BIOS version as reported by SMBIOS + /// BIOS version as reported by SMBIOS. /// public string BiosSMBIOSBIOSVersion { get; internal set; } /// - /// SMBIOS major version number. This property is null if SMBIOS is not found + /// SMBIOS major version number. This property is null if SMBIOS is not found. /// - public UInt16? BiosSMBIOSMajorVersion { get; internal set; } + public ushort? BiosSMBIOSMajorVersion { get; internal set; } /// - /// SMBIOS minor version number. This property is null if SMBIOS is not found + /// SMBIOS minor version number. This property is null if SMBIOS is not found. /// - public UInt16? BiosSMBIOSMinorVersion { get; internal set; } + public ushort? BiosSMBIOSMinorVersion { get; internal set; } /// - /// If true, the SMBIOS is available on this computer system + /// If true, the SMBIOS is available on this computer system. /// public bool? BiosSMBIOSPresent { get; internal set; } /// - /// State of a BIOS software element + /// State of a BIOS software element. /// public SoftwareElementState? BiosSoftwareElementState { get; internal set; } /// - /// Status of the BIOS + /// Status of the BIOS. /// public string BiosStatus { get; internal set; } /// - /// Major elease of the System BIOS + /// Major elease of the System BIOS. /// - public UInt16? BiosSystemBiosMajorVersion { get; internal set; } + public ushort? BiosSystemBiosMajorVersion { get; internal set; } /// - /// Minor release of the System BIOS + /// Minor release of the System BIOS. /// - public UInt16? BiosSystemBiosMinorVersion { get; internal set; } + public ushort? BiosSystemBiosMinorVersion { get; internal set; } /// - /// Target operating system + /// Target operating system. /// - public UInt16? BiosTargetOperatingSystem { get; internal set; } + public ushort? BiosTargetOperatingSystem { get; internal set; } /// /// Version of the BIOS. - /// This string is created by the BIOS manufacturer + /// This string is created by the BIOS manufacturer. /// public string BiosVersion { get; internal set; } #endregion BIOS #region Computer System /// - /// System hardware security settings for administrator password status + /// System hardware security settings for administrator password status. /// - //public AdminPasswordStatus? CsAdminPasswordStatus { get; internal set; } + // public AdminPasswordStatus? CsAdminPasswordStatus { get; internal set; } + public HardwareSecurity? CsAdminPasswordStatus { get; internal set; } /// - /// If true, the system manages the page file + /// If true, the system manages the page file. /// public bool? CsAutomaticManagedPagefile { get; internal set; } /// - /// If True, the automatic reset boot option is enabled + /// If True, the automatic reset boot option is enabled. /// public bool? CsAutomaticResetBootOption { get; internal set; } /// - /// If True, the automatic reset is enabled + /// If True, the automatic reset is enabled. /// public bool? CsAutomaticResetCapability { get; internal set; } /// /// Boot option limit is ON. Identifies the system action when the - /// CsResetLimit value is reached + /// CsResetLimit value is reached. /// public BootOptionAction? CsBootOptionOnLimit { get; internal set; } /// - /// Type of reboot action after the time on the watchdog timer is elapsed + /// Type of reboot action after the time on the watchdog timer is elapsed. /// public BootOptionAction? CsBootOptionOnWatchDog { get; internal set; } /// - /// If true, indicates whether a boot ROM is supported + /// If true, indicates whether a boot ROM is supported. /// public bool? CsBootROMSupported { get; internal set; } /// - /// Status and Additional Data fields that identify the boot status + /// Status and Additional Data fields that identify the boot status. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public UInt16[] CsBootStatus { get; internal set; } /// - /// System is started. Fail-safe boot bypasses the user startup files—also called SafeBoot + /// System is started. Fail-safe boot bypasses the user startup files—also called SafeBoot. /// public string CsBootupState { get; internal set; } /// - /// The name of this computer + /// The name of this computer. /// - public string CsCaption { get; internal set; } //TODO: remove this? Same as CsName??? + public string CsCaption { get; internal set; } // TODO: remove this? Same as CsName??? /// - /// Boot up state of the chassis + /// Boot up state of the chassis. /// - //public ChassisBootupState? CsChassisBootupState { get; internal set; } + // public ChassisBootupState? CsChassisBootupState { get; internal set; } + public SystemElementState? CsChassisBootupState { get; internal set; } /// - /// The chassis or enclosure SKU number as a string + /// The chassis or enclosure SKU number as a string. /// public string CsChassisSKUNumber { get; internal set; } @@ -2549,17 +2526,17 @@ public class ComputerInfo public Int16? CsCurrentTimeZone { get; internal set; } /// - /// If True, the daylight savings mode is ON + /// If True, the daylight savings mode is ON. /// public bool? CsDaylightInEffect { get; internal set; } /// - /// Description of the computer system + /// Description of the computer system. /// public string CsDescription { get; internal set; } /// - /// Name of local computer according to the domain name server + /// Name of local computer according to the domain name server. /// public string CsDNSHostName { get; internal set; } @@ -2574,7 +2551,7 @@ public class ComputerInfo /// /// Role of a computer in an assigned domain workgroup. A domain workgroup /// is a collection of computers on the same network. For example, - /// a DomainRole property may show that a computer is a member workstation + /// a DomainRole property may show that a computer is a member workstation. /// public DomainRole? CsDomainRole { get; internal set; } @@ -2588,57 +2565,59 @@ public class ComputerInfo public bool? CsEnableDaylightSavingsTime { get; internal set; } /// - /// Hardware security setting for the reset button on a computer + /// Hardware security setting for the reset button on a computer. /// - //public FrontPanelResetStatus? CsFrontPanelResetStatus { get; internal set; } + // public FrontPanelResetStatus? CsFrontPanelResetStatus { get; internal set; } + public HardwareSecurity? CsFrontPanelResetStatus { get; internal set; } /// - /// If True, a hypervisor is present + /// If True, a hypervisor is present. /// public bool? CsHypervisorPresent { get; internal set; } /// - /// If True, an infrared port exists on a computer system + /// If True, an infrared port exists on a computer system. /// public bool? CsInfraredSupported { get; internal set; } /// - /// Data required to find the initial load device or boot service to request that the operating system start up + /// Data required to find the initial load device or boot service to request that the operating system start up. /// public string CsInitialLoadInfo { get; internal set; } /// - /// Object is installed. An object does not need a value to indicate that it is installed + /// Object is installed. An object does not need a value to indicate that it is installed. /// public DateTime? CsInstallDate { get; internal set; } /// - /// System hardware security setting for Keyboard Password Status + /// System hardware security setting for Keyboard Password Status. /// - //public KeyboardPasswordStatus? CsKeyboardPasswordStatus { get; internal set; } + // public KeyboardPasswordStatus? CsKeyboardPasswordStatus { get; internal set; } + public HardwareSecurity? CsKeyboardPasswordStatus { get; internal set; } /// /// Array entry of the CsInitialLoadInfo property that contains the data - /// to start the loaded operating system + /// to start the loaded operating system. /// public string CsLastLoadInfo { get; internal set; } /// - /// Name of the computer manufacturer + /// Name of the computer manufacturer. /// public string CsManufacturer { get; internal set; } /// - /// Product name that a manufacturer gives to a computer + /// Product name that a manufacturer gives to a computer. /// public string CsModel { get; internal set; } /// - /// Key of a CIM_System instance in an enterprise environment + /// Key of a CIM_System instance in an enterprise environment. /// - public string CsName { get; internal set; } //TODO: get rid of this? Is this about CIM rather than about the computer? + public string CsName { get; internal set; } /// /// An array of objects describing any @@ -2648,14 +2627,14 @@ public class ComputerInfo public NetworkAdapter[] CsNetworkAdapters { get; internal set; } /// - /// If True, the network Server Mode is enabled + /// If True, the network Server Mode is enabled. /// public bool? CsNetworkServerModeEnabled { get; internal set; } /// - /// Number of logical processors available on the computer + /// Number of logical processors available on the computer. /// - public UInt32? CsNumberOfLogicalProcessors { get; internal set; } + public uint? CsNumberOfLogicalProcessors { get; internal set; } /// /// Number of physical processors currently available on a system. @@ -2667,7 +2646,7 @@ public class ComputerInfo /// then the value of CsNumberOfProcessors is 2 and CsNumberOfLogicalProcessors /// is 4. The processors may be multicore or they may be hyperthreading processors /// - public UInt32? CsNumberOfProcessors { get; internal set; } + public uint? CsNumberOfProcessors { get; internal set; } /// /// Array of objects describing each processor on the system. @@ -2678,14 +2657,14 @@ public class ComputerInfo /// /// Array of free-form strings that an OEM defines. /// For example, an OEM defines the part numbers for system reference - /// documents, manufacturer contact information, and so on + /// documents, manufacturer contact information, and so on. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] CsOEMStringArray { get; internal set; } /// /// If True, the computer is part of a domain. - /// If the value is NULL, the computer is not in a domain or the status is unknown + /// If the value is NULL, the computer is not in a domain or the status is unknown. /// public bool? CsPartOfDomain { get; internal set; } @@ -2693,12 +2672,12 @@ public class ComputerInfo /// Time delay before a reboot is initiated, in milliseconds. /// It is used after a system power cycle, local or remote system reset, /// and automatic system reset. A value of –1 (minus one) indicates that - /// the pause value is unknown + /// the pause value is unknown. /// public Int64? CsPauseAfterReset { get; internal set; } /// - /// Type of the computer in use, such as laptop, desktop, or tablet + /// Type of the computer in use, such as laptop, desktop, or tablet. /// public PCSystemType? CsPCSystemType { get; internal set; } @@ -2708,7 +2687,7 @@ public class ComputerInfo public PCSystemTypeEx? CsPCSystemTypeEx { get; internal set; } /// - /// Array of the specific power-related capabilities of a logical device + /// Array of the specific power-related capabilities of a logical device. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public PowerManagementCapabilities[] CsPowerManagementCapabilities { get; internal set; } @@ -2725,9 +2704,10 @@ public class ComputerInfo public bool? CsPowerManagementSupported { get; internal set; } /// - /// System hardware security setting for Power-On Password Status + /// System hardware security setting for Power-On Password Status. /// - //public PowerOnPasswordStatus? CsPowerOnPasswordStatus { get; internal set; } + // public PowerOnPasswordStatus? CsPowerOnPasswordStatus { get; internal set; } + public HardwareSecurity? CsPowerOnPasswordStatus { get; internal set; } /// @@ -2736,19 +2716,20 @@ public class ComputerInfo public PowerState? CsPowerState { get; internal set; } /// - /// State of the power supply or supplies when last booted + /// State of the power supply or supplies when last booted. /// - //public PowerSupplyState? CsPowerSupplyState { get; internal set; } + // public PowerSupplyState? CsPowerSupplyState { get; internal set; } + public SystemElementState? CsPowerSupplyState { get; internal set; } /// /// Contact information for the primary system owner. - /// For example, phone number, email address, and so on + /// For example, phone number, email address, and so on. /// public string CsPrimaryOwnerContact { get; internal set; } /// - /// Name of the primary system owner + /// Name of the primary system owner. /// public string CsPrimaryOwnerName { get; internal set; } @@ -2759,30 +2740,30 @@ public class ComputerInfo /// /// Number of automatic resets since the last reset. - /// A value of –1 (minus one) indicates that the count is unknown + /// A value of –1 (minus one) indicates that the count is unknown. /// public Int16? CsResetCount { get; internal set; } /// /// Number of consecutive times a system reset is attempted. - /// A value of –1 (minus one) indicates that the limit is unknown + /// A value of –1 (minus one) indicates that the limit is unknown. /// public Int16? CsResetLimit { get; internal set; } /// /// Array that specifies the roles of a system in the information - /// technology environment + /// technology environment. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] CsRoles { get; internal set; } /// - /// Statis pf the computer system + /// Statis pf the computer system. /// public string CsStatus { get; internal set; } /// - /// Array of the support contact information for the Windows operating system + /// Array of the support contact information for the Windows operating system. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] CsSupportContactDescription { get; internal set; } @@ -2790,25 +2771,26 @@ public class ComputerInfo /// /// The family to which a particular computer belongs. /// A family refers to a set of computers that are similar but not - /// identical from a hardware or software point of view + /// identical from a hardware or software point of view. /// public string CsSystemFamily { get; internal set; } /// /// Identifies a particular computer configuration for sale. - /// It is sometimes also called a product ID or purchase order number + /// It is sometimes also called a product ID or purchase order number. /// public string CsSystemSKUNumber { get; internal set; } /// - /// System running on the Windows-based computer + /// System running on the Windows-based computer. /// public string CsSystemType { get; internal set; } /// - /// Thermal state of the system when last booted + /// Thermal state of the system when last booted. /// - //public ThermalState? CsThermalState { get; internal set; } + // public ThermalState? CsThermalState { get; internal set; } + public SystemElementState? CsThermalState { get; internal set; } /// @@ -2819,13 +2801,13 @@ public class ComputerInfo /// return an accurate value for the physical memory. For example, /// it is not accurate if the BIOS is using some of the physical memory /// - public UInt64? CsTotalPhysicalMemory { get; internal set; } + public ulong? CsTotalPhysicalMemory { get; internal set; } /// /// Size of physically installed memory, as reported by the Windows API - /// function GetPhysicallyInstalledSystemMemory + /// function GetPhysicallyInstalledSystemMemory. /// - public UInt64? CsPhysicallyInstalledMemory { get; internal set; } + public ulong? CsPhysicallyInstalledMemory { get; internal set; } /// /// Name of a user that is logged on currently. @@ -2838,83 +2820,83 @@ public class ComputerInfo public string CsUserName { get; internal set; } /// - /// Event that causes the system to power up + /// Event that causes the system to power up. /// public WakeUpType? CsWakeUpType { get; internal set; } /// - /// Name of the workgroup for this computer + /// Name of the workgroup for this computer. /// public string CsWorkgroup { get; internal set; } #endregion Computer System #region Operating System /// - /// Name of the operating system + /// Name of the operating system. /// public string OsName { get; internal set; } /// - /// Type of operating system + /// Type of operating system. /// public OSType? OsType { get; internal set; } /// - /// SKU number for the operating system + /// SKU number for the operating system. /// public OperatingSystemSKU? OsOperatingSystemSKU { get; internal set; } /// - /// Version number of the operating system + /// Version number of the operating system. /// public string OsVersion { get; internal set; } /// /// String that indicates the latest service pack installed on a computer. - /// If no service pack is installed, the string is NULL + /// If no service pack is installed, the string is NULL. /// public string OsCSDVersion { get; internal set; } /// - /// Build number of the operating system + /// Build number of the operating system. /// public string OsBuildNumber { get; internal set; } /// /// Array of objects containing information about /// any Quick-Fix Engineering patches (Hot Fixes) applied to the operating - /// system + /// system. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public HotFix[] OsHotFixes { get; internal set; } /// - /// Name of the disk drive from which the Windows operating system starts + /// Name of the disk drive from which the Windows operating system starts. /// public string OsBootDevice { get; internal set; } /// - /// Physical disk partition on which the operating system is installed + /// Physical disk partition on which the operating system is installed. /// public string OsSystemDevice { get; internal set; } /// - /// System directory of the operating system + /// System directory of the operating system. /// public string OsSystemDirectory { get; internal set; } /// - /// Letter of the disk drive on which the operating system resides + /// Letter of the disk drive on which the operating system resides. /// public string OsSystemDrive { get; internal set; } /// - /// Windows directory of the operating system + /// Windows directory of the operating system. /// public string OsWindowsDirectory { get; internal set; } /// - /// Code for the country/region that an operating system uses + /// Code for the country/region that an operating system uses. /// /// /// Values are based on international phone dialing prefixes—also @@ -2924,7 +2906,7 @@ public class ComputerInfo /// /// Number, in minutes, an operating system is offset from Greenwich - /// mean time (GMT). The number is positive, negative, or zero + /// mean time (GMT). The number is positive, negative, or zero. /// public Int16? OsCurrentTimeZone { get; internal set; } @@ -2940,70 +2922,70 @@ public class ComputerInfo public string OsLocaleID { get; internal set; } // From Win32_OperatingSystem.Locale /// - /// The culture name, such as "en-US", derived from the property + /// The culture name, such as "en-US", derived from the property. /// public string OsLocale { get; internal set; } /// - /// Operating system version of the local date and time-of-day + /// Operating system version of the local date and time-of-day. /// public DateTime? OsLocalDateTime { get; internal set; } /// - /// Date and time the operating system was last restarted + /// Date and time the operating system was last restarted. /// public DateTime? OsLastBootUpTime { get; internal set; } /// /// The interval between the time the operating system was last - /// restarted and the current time + /// restarted and the current time. /// public TimeSpan? OsUptime { get; internal set; } /// - /// Type of build used for the operating system + /// Type of build used for the operating system. /// public string OsBuildType { get; internal set; } /// - /// Code page value the operating system uses + /// Code page value the operating system uses. /// public string OsCodeSet { get; internal set; } /// - /// If true, then the data execution prevention hardware feature is available + /// If true, then the data execution prevention hardware feature is available. /// public bool? OsDataExecutionPreventionAvailable { get; internal set; } /// /// When the data execution prevention hardware feature is available, /// this property indicates that the feature is set to work for 32-bit - /// applications if true + /// applications if true. /// public bool? OsDataExecutionPrevention32BitApplications { get; internal set; } /// /// When the data execution prevention hardware feature is available, /// this property indicates that the feature is set to work for drivers - /// if true + /// if true. /// public bool? OsDataExecutionPreventionDrivers { get; internal set; } /// /// Indicates which Data Execution Prevention (DEP) setting is applied. /// The DEP setting specifies the extent to which DEP applies to 32-bit - /// applications on the system. DEP is always applied to the Windows kernel + /// applications on the system. DEP is always applied to the Windows kernel. /// public DataExecutionPreventionSupportPolicy? OsDataExecutionPreventionSupportPolicy { get; internal set; } /// - /// If true, the operating system is a checked (debug) build + /// If true, the operating system is a checked (debug) build. /// public bool? OsDebug { get; internal set; } /// /// If True, the operating system is distributed across several computer - /// system nodes. If so, these nodes should be grouped as a cluster + /// system nodes. If so, these nodes should be grouped as a cluster. /// public bool? OsDistributed { get; internal set; } @@ -3013,7 +2995,7 @@ public class ComputerInfo public OSEncryptionLevel? OsEncryptionLevel { get; internal set; } /// - /// Increased priority given to the foreground application + /// Increased priority given to the foreground application. /// public ForegroundApplicationBoost? OsForegroundApplicationBoost { get; internal set; } @@ -3026,30 +3008,30 @@ public class ComputerInfo /// physical memory, but what is reported to the operating system /// as available to it. /// - public UInt64? OsTotalVisibleMemorySize { get; internal set; } + public ulong? OsTotalVisibleMemorySize { get; internal set; } /// - /// Number, in kilobytes, of physical memory currently unused and available + /// Number, in kilobytes, of physical memory currently unused and available. /// - public UInt64? OsFreePhysicalMemory { get; internal set; } + public ulong? OsFreePhysicalMemory { get; internal set; } /// - /// Number, in kilobytes, of virtual memory + /// Number, in kilobytes, of virtual memory. /// - public UInt64? OsTotalVirtualMemorySize { get; internal set; } + public ulong? OsTotalVirtualMemorySize { get; internal set; } /// - /// Number, in kilobytes, of virtual memory currently unused and available + /// Number, in kilobytes, of virtual memory currently unused and available. /// - public UInt64? OsFreeVirtualMemory { get; internal set; } + public ulong? OsFreeVirtualMemory { get; internal set; } /// - /// Number, in kilobytes, of virtual memory currently in use + /// Number, in kilobytes, of virtual memory currently in use. /// - public UInt64? OsInUseVirtualMemory { get; internal set; } + public ulong? OsInUseVirtualMemory { get; internal set; } /// - /// Total swap space in kilobytes + /// Total swap space in kilobytes. /// /// /// This value may be NULL (unspecified) if the swap space is not @@ -3058,24 +3040,24 @@ public class ComputerInfo /// can be swapped out when the free page list falls and remains below /// a specified amount /// - public UInt64? OsTotalSwapSpaceSize { get; internal set; } + public ulong? OsTotalSwapSpaceSize { get; internal set; } /// /// Total number of kilobytes that can be stored in the operating system /// paging files—0 (zero) indicates that there are no paging files. /// Be aware that this number does not represent the actual physical - /// size of the paging file on disk + /// size of the paging file on disk. /// - public UInt64? OsSizeStoredInPagingFiles { get; internal set; } + public ulong? OsSizeStoredInPagingFiles { get; internal set; } /// /// Number, in kilobytes, that can be mapped into the operating system - /// paging files without causing any other pages to be swapped out + /// paging files without causing any other pages to be swapped out. /// - public UInt64? OsFreeSpaceInPagingFiles { get; internal set; } + public ulong? OsFreeSpaceInPagingFiles { get; internal set; } /// - /// Array of fiel paths to the operating system's paging files + /// Array of fiel paths to the operating system's paging files. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] OsPagingFiles { get; internal set; } @@ -3086,7 +3068,7 @@ public class ComputerInfo public string OsHardwareAbstractionLayer { get; internal set; } /// - /// Indicates the install date + /// Indicates the install date. /// public DateTime? OsInstallDate { get; internal set; } @@ -3097,18 +3079,18 @@ public class ComputerInfo public string OsManufacturer { get; internal set; } /// - /// Maximum number of process contexts the operating system can support + /// Maximum number of process contexts the operating system can support. /// - public UInt32? OsMaxNumberOfProcesses { get; internal set; } + public uint? OsMaxNumberOfProcesses { get; internal set; } /// - /// Maximum number, in kilobytes, of memory that can be allocated to a process + /// Maximum number, in kilobytes, of memory that can be allocated to a process. /// - public UInt64? OsMaxProcessMemorySize { get; internal set; } + public ulong? OsMaxProcessMemorySize { get; internal set; } /// /// Array of Multilingual User Interface Pack (MUI Pack) languages installed - /// on the computer + /// on the computer. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] OsMuiLanguages { get; internal set; } @@ -3116,195 +3098,195 @@ public class ComputerInfo /// /// Number of user licenses for the operating system. /// - public UInt32? OsNumberOfLicensedUsers { get; internal set; } + public uint? OsNumberOfLicensedUsers { get; internal set; } /// - /// Number of process contexts currently loaded or running on the operating system + /// Number of process contexts currently loaded or running on the operating system. /// - public UInt32? OsNumberOfProcesses { get; internal set; } + public uint? OsNumberOfProcesses { get; internal set; } /// /// Number of user sessions for which the operating system is storing - /// state information currently + /// state information currently. /// - public UInt32? OsNumberOfUsers { get; internal set; } + public uint? OsNumberOfUsers { get; internal set; } /// - /// Company name for the registered user of the operating system + /// Company name for the registered user of the operating system. /// public string OsOrganization { get; internal set; } /// - /// Architecture of the operating system, as opposed to the processor + /// Architecture of the operating system, as opposed to the processor. /// public string OsArchitecture { get; internal set; } /// - /// Language version of the operating system installed + /// Language version of the operating system installed. /// public string OsLanguage { get; internal set; } /// /// Array of objects indicating installed - /// and licensed product additions to the operating system + /// and licensed product additions to the operating system. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public OSProductSuite[] OsProductSuites { get; internal set; } /// - /// Additional description for the current operating system version + /// Additional description for the current operating system version. /// public string OsOtherTypeDescription { get; internal set; } /// /// If True, the physical address extensions (PAE) are enabled by the - /// operating system running on Intel processors + /// operating system running on Intel processors. /// public bool? OsPAEEnabled { get; internal set; } /// /// Specifies whether the operating system booted from an external USB device. /// If true, the operating system has detected it is booting on a supported - /// locally connected storage device + /// locally connected storage device. /// public bool? OsPortableOperatingSystem { get; internal set; } /// - /// Specifies whether this is the primary operating system + /// Specifies whether this is the primary operating system. /// public bool? OsPrimary { get; internal set; } /// - /// Additional system information + /// Additional system information. /// public ProductType? OsProductType { get; internal set; } /// - /// Name of the registered user of the operating system + /// Name of the registered user of the operating system. /// public string OsRegisteredUser { get; internal set; } /// - /// Operating system product serial identification number + /// Operating system product serial identification number. /// public string OsSerialNumber { get; internal set; } /// - /// Major version of the service pack installed on the computer system + /// Major version of the service pack installed on the computer system. /// - public UInt16? OsServicePackMajorVersion { get; internal set; } + public ushort? OsServicePackMajorVersion { get; internal set; } /// - /// Minor version of the service pack installed on the computer system + /// Minor version of the service pack installed on the computer system. /// - public UInt16? OsServicePackMinorVersion { get; internal set; } + public ushort? OsServicePackMinorVersion { get; internal set; } /// - /// Current status + /// Current status. /// public string OsStatus { get; internal set; } /// - /// Product suites available on the operating system + /// Product suites available on the operating system. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public OSProductSuite[] OsSuites { get; internal set; } /// - /// Server level of the operating system, if the operating system is a server + /// Server level of the operating system, if the operating system is a server. /// public ServerLevel? OsServerLevel { get; internal set; } #endregion Operating System #region Misc Info /// - /// Layout of the (first) keyboard attached to the system + /// Layout of the (first) keyboard attached to the system. /// public string KeyboardLayout { get; internal set; } /// - /// Name of the system's current time zone + /// Name of the system's current time zone. /// public string TimeZone { get; internal set; } /// - /// Path to the system's logon server + /// Path to the system's logon server. /// public string LogonServer { get; internal set; } /// - /// Power platform role + /// Power platform role. /// public PowerPlatformRole? PowerPlatformRole { get; internal set; } /// - /// If true, a HyperVisor was detected + /// If true, a HyperVisor was detected. /// public bool? HyperVisorPresent { get; internal set; } /// /// If a HyperVisor is not present, indicates the state of the - /// requirement that the Data Execution Prevention feature is available + /// requirement that the Data Execution Prevention feature is available. /// public bool? HyperVRequirementDataExecutionPreventionAvailable { get; internal set; } /// /// If a HyperVisor is not present, indicates the state of the /// requirement that the processor supports address translation - /// extensions used for virtualization + /// extensions used for virtualization. /// public bool? HyperVRequirementSecondLevelAddressTranslation { get; internal set; } /// /// If a HyperVisor is not present, indicates the state of the /// requirement that the firmware has enabled virtualization - /// extensions + /// extensions. /// public bool? HyperVRequirementVirtualizationFirmwareEnabled { get; internal set; } /// /// If a HyperVisor is not present, indicates the state of the /// requirement that the processor supports Intel or AMD Virtual - /// Machine Monitor extensions + /// Machine Monitor extensions. /// public bool? HyperVRequirementVMMonitorModeExtensions { get; internal set; } /// - /// Indicates the status of the Device Guard features + /// Indicates the status of the Device Guard features. /// public DeviceGuardSmartStatus? DeviceGuardSmartStatus { get; internal set; } /// - /// Required Device Guard security properties + /// Required Device Guard security properties. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardHardwareSecure[] DeviceGuardRequiredSecurityProperties { get; internal set; } /// - /// Available Device Guard security properties + /// Available Device Guard security properties. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardHardwareSecure[] DeviceGuardAvailableSecurityProperties { get; internal set; } /// - /// Configured Device Guard security services + /// Configured Device Guard security services. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardSoftwareSecure[] DeviceGuardSecurityServicesConfigured { get; internal set; } /// - /// Running Device Guard security services + /// Running Device Guard security services. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public DeviceGuardSoftwareSecure[] DeviceGuardSecurityServicesRunning { get; internal set; } /// - /// Status of the Device Guard Code Integrity policy enforcement + /// Status of the Device Guard Code Integrity policy enforcement. /// public DeviceGuardConfigCodeIntegrityStatus? DeviceGuardCodeIntegrityPolicyEnforcementStatus { get; internal set; } /// - /// Status of the Device Guard user mode Code Integrity policy enforcement + /// Status of the Device Guard user mode Code Integrity policy enforcement. /// public DeviceGuardConfigCodeIntegrityStatus? DeviceGuardUserModeCodeIntegrityPolicyEnforcementStatus { get; internal set; } #endregion Misc Info @@ -3313,34 +3295,34 @@ public class ComputerInfo #region Enums used in the output objects /// - /// System hardware security settings for administrator password status + /// System hardware security settings for administrator password status. /// public enum AdminPasswordStatus { /// - /// Feature is disabled + /// Feature is disabled. /// Disabled = 0, /// - /// Feature is Enabled + /// Feature is Enabled. /// Enabled = 1, /// - /// Feature is not implemented + /// Feature is not implemented. /// NotImplemented = 2, /// - /// Status is unknown + /// Status is unknown. /// Unknown = 3 } /// /// Actions related to the BootOptionOn* properties of the Win32_ComputerSystem - /// CIM class + /// CIM class. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum BootOptionAction @@ -3348,276 +3330,276 @@ public enum BootOptionAction // // This value is reserved // - //Reserved = 0, + // Reserved = 0, /// - /// Boot into operating system + /// Boot into operating system. /// OperatingSystem = 1, /// - /// Boot into system utilities + /// Boot into system utilities. /// SystemUtilities = 2, /// - /// Do not reboot + /// Do not reboot. /// DoNotReboot = 3 } /// - /// Indicates the state of a system element + /// Indicates the state of a system element. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum SystemElementState { /// - /// The element state is something other than those in this Enum + /// The element state is something other than those in this Enum. /// Other = 1, /// - /// The element state is unknown + /// The element state is unknown. /// Unknown = 2, /// - /// The element is in Safe state + /// The element is in Safe state. /// Safe = 3, /// - /// The element is in Warning state + /// The element is in Warning state. /// Warning = 4, /// - /// The element is in Critical state + /// The element is in Critical state. /// Critical = 5, /// - /// The element is in Non-Recoverable state + /// The element is in Non-Recoverable state. /// NonRecoverable = 6 } /// - /// Specifies the processor architecture + /// Specifies the processor architecture. /// public enum CpuArchitecture { /// - /// Architecture is Intel x86 + /// Architecture is Intel x86. /// x86 = 0, /// - /// Architecture is MIPS + /// Architecture is MIPS. /// MIPs = 1, /// - /// Architecture is DEC Alpha + /// Architecture is DEC Alpha. /// Alpha = 2, /// - /// Architecture is Motorola PowerPC + /// Architecture is Motorola PowerPC. /// PowerPC = 3, /// - /// Architecture is ARM + /// Architecture is ARM. /// ARM = 5, /// - /// Architecture is Itanium-based 64-bit + /// Architecture is Itanium-based 64-bit. /// ia64 = 6, /// - /// Architecture is Intel 64-bit + /// Architecture is Intel 64-bit. /// x64 = 9 } /// - /// Specifies a CPU's availability and status + /// Specifies a CPU's availability and status. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum CpuAvailability { /// - /// A state other than those specified in CpuAvailability + /// A state other than those specified in CpuAvailability. /// Other = 1, /// - /// Availability status is unknown + /// Availability status is unknown. /// Unknown = 2, /// - /// The device is running or at full power + /// The device is running or at full power. /// RunningOrFullPower = 3, /// - /// Device is in a Warning state + /// Device is in a Warning state. /// Warning = 4, /// - /// Availability status is In Test + /// Availability status is In Test. /// InTest = 5, /// - /// Status is not applicable to this device + /// Status is not applicable to this device. /// NotApplicable = 6, /// - /// The device is powered off + /// The device is powered off. /// PowerOff = 7, /// - /// Availability status is Offline + /// Availability status is Offline. /// OffLine = 8, /// - /// Availability status is Off-Duty + /// Availability status is Off-Duty. /// OffDuty = 9, /// - /// Availability status is Degraded + /// Availability status is Degraded. /// Degraded = 10, /// - /// Availability status is Not Installed + /// Availability status is Not Installed. /// NotInstalled = 11, /// - /// Availability status is Install Error + /// Availability status is Install Error. /// InstallError = 12, /// - /// The device is known to be in a power save state, but its exact status is unknown + /// The device is known to be in a power save state, but its exact status is unknown. /// PowerSaveUnknown = 13, /// /// The device is in a power save state, but is still functioning, - /// and may exhibit decreased performance + /// and may exhibit decreased performance. /// PowerSaveLowPowerMode = 14, /// - /// The device is not functioning, but can be brought to full power quickly + /// The device is not functioning, but can be brought to full power quickly. /// PowerSaveStandby = 15, /// - /// The device is in a power-cycle state + /// The device is in a power-cycle state. /// PowerCycle = 16, /// - /// The device is in a warning state, though also in a power save state + /// The device is in a warning state, though also in a power save state. /// PowerSaveWarning = 17, /// - /// The device is paused + /// The device is paused. /// Paused = 18, /// - /// The device is not ready + /// The device is not ready. /// NotReady = 19, /// - /// The device is not configured + /// The device is not configured. /// NotConfigured = 20, /// - /// The device is quiet + /// The device is quiet. /// Quiesced = 21 } /// - /// Specifies that current status of the processor + /// Specifies that current status of the processor. /// [SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags", Justification = "The underlying MOF definition is not a bit field.")] public enum CpuStatus { /// - /// CPU status is Unknown + /// CPU status is Unknown. /// Unknown = 0, /// - /// CPU status is Enabled + /// CPU status is Enabled. /// Enabled = 1, /// - /// CPU status is Disabled by User via BIOS Setup + /// CPU status is Disabled by User via BIOS Setup. /// DisabledByUser = 2, /// - /// CPU status is Disabled by BIOS + /// CPU status is Disabled by BIOS. /// DisabledByBIOS = 3, /// - /// CPU is Idle + /// CPU is Idle. /// Idle = 4, // // This value is reserved // - //Reserved_5 = 5, + // Reserved_5 = 5, // // This value is reserved // - //Reserved_6 = 6, + // Reserved_6 = 6, /// - /// CPU is in another state + /// CPU is in another state. /// Other = 7 } /// - /// Data Execution Prevention (DEP) settings + /// Data Execution Prevention (DEP) settings. /// public enum DataExecutionPreventionSupportPolicy { - //Unknown = -1, + // Unknown = -1, /// - /// DEP is turned off for all 32-bit applications on the computer with no exceptions + /// DEP is turned off for all 32-bit applications on the computer with no exceptions. /// AlwaysOff = 0, /// - /// DEP is enabled for all 32-bit applications on the computer + /// DEP is enabled for all 32-bit applications on the computer. /// AlwaysOn = 1, @@ -3626,311 +3608,311 @@ public enum DataExecutionPreventionSupportPolicy /// Windows-based services. However, it is off by default for all 32-bit /// applications. A user or administrator must explicitly choose either /// the Always On or the Opt Out setting before DEP can be applied to - /// 32-bit applications + /// 32-bit applications. /// OptIn = 2, /// /// DEP is enabled by default for all 32-bit applications. A user or /// administrator can explicitly remove support for a 32-bit - /// application by adding the application to an exceptions list + /// application by adding the application to an exceptions list. /// OptOut = 3 } /// - /// Status of the Device Guard feature + /// Status of the Device Guard feature. /// public enum DeviceGuardSmartStatus { /// - /// Device Guard is off + /// Device Guard is off. /// Off = 0, /// - /// Device Guard is Configured + /// Device Guard is Configured. /// Configured = 1, /// - /// Device Guard is Running + /// Device Guard is Running. /// Running = 2 } /// - /// Configuration status of the Device Guard Code Integrity + /// Configuration status of the Device Guard Code Integrity. /// public enum DeviceGuardConfigCodeIntegrityStatus { /// - /// Code Integrity is off + /// Code Integrity is off. /// Off = 0, /// - /// Code Integrity uses Audit mode + /// Code Integrity uses Audit mode. /// AuditMode = 1, /// - /// Code Integrity uses Enforcement mode + /// Code Integrity uses Enforcement mode. /// EnforcementMode = 2 } /// - /// Device Guard hardware security properties + /// Device Guard hardware security properties. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum DeviceGuardHardwareSecure { /// - /// Base Virtualization Support + /// Base Virtualization Support. /// BaseVirtualizationSupport = 1, /// - /// Secure Boot + /// Secure Boot. /// SecureBoot = 2, /// - /// DMA Protection + /// DMA Protection. /// DMAProtection = 3, /// - /// Secure Memory Overwrite + /// Secure Memory Overwrite. /// SecureMemoryOverwrite = 4 } /// - /// Device Guard software security properties + /// Device Guard software security properties. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum DeviceGuardSoftwareSecure { /// - /// Credential Guard + /// Credential Guard. /// CredentialGuard = 1, /// - /// Hypervisor enforced Code Integrity + /// Hypervisor enforced Code Integrity. /// HypervisorEnforcedCodeIntegrity = 2 } /// - /// Role of a computer in an assigned domain workgroup + /// Role of a computer in an assigned domain workgroup. /// public enum DomainRole { /// - /// Standalone Workstation + /// Standalone Workstation. /// StandaloneWorkstation = 0, /// - /// Member Workstation + /// Member Workstation. /// MemberWorkstation = 1, /// - /// Standalone Server + /// Standalone Server. /// StandaloneServer = 2, /// - /// Member Server + /// Member Server. /// MemberServer = 3, /// - /// Backup Domain Controller + /// Backup Domain Controller. /// BackupDomainController = 4, /// - /// Primary Domain Controller + /// Primary Domain Controller. /// PrimaryDomainController = 5 } /// - /// Specifies a firmware type + /// Specifies a firmware type. /// public enum FirmwareType { /// - /// The firmware type is unknown + /// The firmware type is unknown. /// Unknown = 0, /// - /// The computer booted in legacy BIOS mode + /// The computer booted in legacy BIOS mode. /// Bios = 1, /// - /// The computer booted in UEFI mode + /// The computer booted in UEFI mode. /// Uefi = 2, /// - /// Not implemented + /// Not implemented. /// Max = 3 } /// - /// Increase in priority given to the foreground application + /// Increase in priority given to the foreground application. /// public enum ForegroundApplicationBoost { /// - /// The system boosts the quantum length by 6 + /// The system boosts the quantum length by 6. /// None = 0, /// - /// The system boosts the quantum length by 12 + /// The system boosts the quantum length by 12. /// Minimum = 1, /// - /// The system boosts the quantum length by 18 + /// The system boosts the quantum length by 18. /// Maximum = 2 } /// - /// hardware security settings for the reset button on a computer + /// Hardware security settings for the reset button on a computer. /// public enum FrontPanelResetStatus { /// - /// Reset button is disabled + /// Reset button is disabled. /// Disabled = 0, /// - /// Reset button is enabled + /// Reset button is enabled. /// Enabled = 1, /// - /// Hardware security settings are not implement + /// Hardware security settings are not implement. /// NotImplemented = 2, /// - /// Unknown security setting + /// Unknown security setting. /// Unknown = 3 } /// - /// Indicates a hardware security setting + /// Indicates a hardware security setting. /// public enum HardwareSecurity { /// - /// Hardware security is disabled + /// Hardware security is disabled. /// Disabled = 0, /// - /// Hardware security is enabled + /// Hardware security is enabled. /// Enabled = 1, /// - /// Hardware security is not implemented + /// Hardware security is not implemented. /// NotImplemented = 2, /// - /// Hardware security setting is unknown + /// Hardware security setting is unknown. /// Unknown = 3 } /// - /// State of the network adapter connection to the network + /// State of the network adapter connection to the network. /// public enum NetConnectionStatus { /// - /// Adapter is disconnected + /// Adapter is disconnected. /// Disconnected = 0, /// - /// Adapter is connecting + /// Adapter is connecting. /// Connecting = 1, /// - /// Adapter is connected + /// Adapter is connected. /// Connected = 2, /// - /// Adapter is disconnecting + /// Adapter is disconnecting. /// Disconnecting = 3, /// - /// Adapter hardware is not present + /// Adapter hardware is not present. /// HardwareNotPresent = 4, /// - /// Adapter hardware is disabled + /// Adapter hardware is disabled. /// HardwareDisabled = 5, /// - /// Adapter has a hardware malfunction + /// Adapter has a hardware malfunction. /// HardwareMalfunction = 6, /// - /// Media is disconnected + /// Media is disconnected. /// MediaDisconnected = 7, /// - /// Adapter is authenticating + /// Adapter is authenticating. /// Authenticating = 8, /// - /// Authentication has succeeded + /// Authentication has succeeded. /// AuthenticationSucceeded = 9, /// - /// Authentication has failed + /// Authentication has failed. /// AuthenticationFailed = 10, /// - /// Address is invalid + /// Address is invalid. /// InvalidAddress = 11, /// - /// Credentials are required + /// Credentials are required. /// CredentialsRequired = 12, /// - /// Other unspecified state + /// Other unspecified state. /// Other = 13 } @@ -3941,23 +3923,23 @@ public enum NetConnectionStatus public enum OSEncryptionLevel { /// - /// 40-bit encryption + /// 40-bit encryption. /// Encrypt40Bits = 0, /// - /// 128-bit encryption + /// 128-bit encryption. /// Encrypt128Bits = 1, /// - /// n-bit encryption + /// N-bit encryption. /// EncryptNBits = 2 } /// - /// Indicates installed and licensed system product additions to the operating system + /// Indicates installed and licensed system product additions to the operating system. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] [FlagsAttribute] @@ -3965,68 +3947,68 @@ public enum OSProductSuite { /// /// Microsoft Small Business Server was once installed, but may have - /// been upgraded to another version of Windows + /// been upgraded to another version of Windows. /// SmallBusinessServer = 0x0001, /// - /// Windows Server 2008 Enterprise is installed + /// Windows Server 2008 Enterprise is installed. /// Server2008Enterprise = 0x0002, /// - /// Windows BackOffice components are installed + /// Windows BackOffice components are installed. /// BackOfficeComponents = 0x0004, /// - /// Communication Server is installed + /// Communication Server is installed. /// CommunicationsServer = 0x0008, /// - /// Terminal Services is installed + /// Terminal Services is installed. /// TerminalServices = 0x0010, /// /// Microsoft Small Business Server is installed with the restrictive - /// client license + /// client license. /// SmallBusinessServerRestricted = 0x0020, /// - /// Windows Embedded is installed + /// Windows Embedded is installed. /// WindowsEmbedded = 0x0040, /// - /// A Datacenter edition is installed + /// A Datacenter edition is installed. /// DatacenterEdition = 0x0080, /// - /// Terminal Services is installed, but only one interactive session is supported + /// Terminal Services is installed, but only one interactive session is supported. /// TerminalServicesSingleSession = 0x0100, /// - /// Windows Home Edition is installed + /// Windows Home Edition is installed. /// HomeEdition = 0x0200, /// - /// Web Server Edition is installed + /// Web Server Edition is installed. /// WebServerEdition = 0x0400, /// - /// Storage Server Edition is installed + /// Storage Server Edition is installed. /// StorageServerEdition = 0x2000, /// - /// Compute Cluster Edition is installed + /// Compute Cluster Edition is installed. /// ComputeClusterEdition = 0x4000 } @@ -4037,147 +4019,147 @@ public enum OSProductSuite public enum OperatingSystemSKU { /// - /// The SKU is undefined + /// The SKU is undefined. /// Undefined = 0, /// - /// SKU is Ultimate Edition + /// SKU is Ultimate Edition. /// UltimateEdition = 1, /// - /// SKU is Home Basic Edition + /// SKU is Home Basic Edition. /// HomeBasicEdition = 2, /// - /// SKU is Home Premium Edition + /// SKU is Home Premium Edition. /// HomePremiumEdition = 3, /// - /// SKU is Enterprise Edition + /// SKU is Enterprise Edition. /// EnterpriseEdition = 4, /// - /// SKU is Home Basic N Edition + /// SKU is Home Basic N Edition. /// HomeBasicNEdition = 5, /// - /// SKU is Business Edition + /// SKU is Business Edition. /// BusinessEdition = 6, /// - /// SKU is Standard Server Edition + /// SKU is Standard Server Edition. /// StandardServerEdition = 7, /// - /// SKU is Datacenter Server Edition + /// SKU is Datacenter Server Edition. /// DatacenterServerEdition = 8, /// - /// SKU is Small Business Server Edition + /// SKU is Small Business Server Edition. /// SmallBusinessServerEdition = 9, /// - /// SKU is Enterprise Server Edition + /// SKU is Enterprise Server Edition. /// EnterpriseServerEdition = 10, /// - /// SKU is Starter Edition + /// SKU is Starter Edition. /// StarterEdition = 11, /// - /// SKU is Datacenter Server Core Edition + /// SKU is Datacenter Server Core Edition. /// DatacenterServerCoreEdition = 12, /// - /// SKU is Standard Server Core Edition + /// SKU is Standard Server Core Edition. /// StandardServerCoreEdition = 13, /// - /// SKU is Enterprise Server Core Edition + /// SKU is Enterprise Server Core Edition. /// EnterpriseServerCoreEdition = 14, /// - /// SKU is Enterprise Server IA64 Edition + /// SKU is Enterprise Server IA64 Edition. /// EnterpriseServerIA64Edition = 15, /// - /// SKU is Business N Edition + /// SKU is Business N Edition. /// BusinessNEdition = 16, /// - /// SKU is Web Server Edition + /// SKU is Web Server Edition. /// WebServerEdition = 17, /// - /// SKU is Cluster Server Edition + /// SKU is Cluster Server Edition. /// ClusterServerEdition = 18, /// - /// SKU is Home Server Edition + /// SKU is Home Server Edition. /// HomeServerEdition = 19, /// - /// SKU is Storage Express Server Edition + /// SKU is Storage Express Server Edition. /// StorageExpressServerEdition = 20, /// - /// SKU is Storage Standard Server Edition + /// SKU is Storage Standard Server Edition. /// StorageStandardServerEdition = 21, /// - /// SKU is Storage Workgroup Server Edition + /// SKU is Storage Workgroup Server Edition. /// StorageWorkgroupServerEdition = 22, /// - /// SKU is Storage Enterprise Server Edition + /// SKU is Storage Enterprise Server Edition. /// StorageEnterpriseServerEdition = 23, /// - /// SKU is Server For Small Business Edition + /// SKU is Server For Small Business Edition. /// ServerForSmallBusinessEdition = 24, /// - /// SKU is Small Business Server Premium Edition + /// SKU is Small Business Server Premium Edition. /// SmallBusinessServerPremiumEdition = 25, /// - /// SKU is to be determined + /// SKU is to be determined. /// TBD = 26, /// - /// SKU is Windows Enterprise + /// SKU is Windows Enterprise. /// WindowsEnterprise = 27, /// - /// SKU is Windows Ultimate + /// SKU is Windows Ultimate. /// WindowsUltimate = 28, @@ -4187,17 +4169,17 @@ public enum OperatingSystemSKU WebServerCore = 29, /// - /// SKU is Server Foundation + /// SKU is Server Foundation. /// ServerFoundation = 33, /// - /// SKU is Windows Home Server + /// SKU is Windows Home Server. /// WindowsHomeServer = 34, /// - /// SKU is Windows Server Standard without Hyper-V + /// SKU is Windows Server Standard without Hyper-V. /// WindowsServerStandardNoHyperVFull = 36, @@ -4227,7 +4209,7 @@ public enum OperatingSystemSKU WindowsServerEnterpriseNoHyperVCore = 41, /// - /// SKU is Microsoft Hyper-V Server + /// SKU is Microsoft Hyper-V Server. /// MicrosoftHyperVServer = 42, @@ -4252,7 +4234,7 @@ public enum OperatingSystemSKU StorageServerEnterpriseCore = 46, /// - /// SKU is Windows Small Business Server 2011 Essentials + /// SKU is Windows Small Business Server 2011 Essentials. /// WindowsSmallBusinessServer2011Essentials = 50, @@ -4262,597 +4244,597 @@ public enum OperatingSystemSKU SmallBusinessServerPremiumCore = 63, /// - /// SKU is Windows Server Hyper Core V + /// SKU is Windows Server Hyper Core V. /// WindowsServerHyperCoreV = 64, /// - /// SKU is Windows Thin PC + /// SKU is Windows Thin PC. /// WindowsThinPC = 87, /// - /// SKU is Windows Embedded Industry + /// SKU is Windows Embedded Industry. /// WindowsEmbeddedIndustry = 89, /// - /// SKU is Windows RT + /// SKU is Windows RT. /// WindowsRT = 97, /// - /// SKU is Windows Home + /// SKU is Windows Home. /// WindowsHome = 101, /// - /// SKU is Windows Professional with Media Center + /// SKU is Windows Professional with Media Center. /// WindowsProfessionalWithMediaCenter = 103, /// - /// SKU is Windows Mobile + /// SKU is Windows Mobile. /// WindowsMobile = 104, /// - /// SKU is Windows Embedded Handheld + /// SKU is Windows Embedded Handheld. /// WindowsEmbeddedHandheld = 118, /// - /// SKU is Windows IoT (Internet of Things) Core + /// SKU is Windows IoT (Internet of Things) Core. /// WindowsIotCore = 123 } /// - /// Type of operating system + /// Type of operating system. /// public enum OSType { /// - /// OS is unknown + /// OS is unknown. /// Unknown = 0, /// - /// OS is one other than covered by this Enum + /// OS is one other than covered by this Enum. /// Other = 1, /// - /// OS is MacOS + /// OS is MacOS. /// MACROS = 2, /// - /// OS is AT&T UNIX + /// OS is AT&T UNIX. /// ATTUNIX = 3, /// - /// OS is DG/UX + /// OS is DG/UX. /// DGUX = 4, /// - /// OS is DECNT + /// OS is DECNT. /// DECNT = 5, /// - /// OS is Digital UNIX + /// OS is Digital UNIX. /// DigitalUNIX = 6, /// - /// OS is OpenVMS + /// OS is OpenVMS. /// OpenVMS = 7, /// - /// OS is HP-UX + /// OS is HP-UX. /// HPUX = 8, /// - /// OS is AIX + /// OS is AIX. /// AIX = 9, /// - /// OS is MVS + /// OS is MVS. /// MVS = 10, /// - /// OS is OS/400 + /// OS is OS/400. /// OS400 = 11, /// - /// OS is OS/2 + /// OS is OS/2. /// OS2 = 12, /// - /// OS is Java Virtual Machine + /// OS is Java Virtual Machine. /// JavaVM = 13, /// - /// OS is MS-DOS + /// OS is MS-DOS. /// MSDOS = 14, /// - /// OS is Windows 3x + /// OS is Windows 3x. /// WIN3x = 15, /// - /// OS is Windows 95 + /// OS is Windows 95. /// WIN95 = 16, /// - /// OS is Windows 98 + /// OS is Windows 98. /// WIN98 = 17, /// - /// OS is Windows NT + /// OS is Windows NT. /// WINNT = 18, /// - /// OS is Windows CE + /// OS is Windows CE. /// WINCE = 19, /// - /// OS is NCR System 3000 + /// OS is NCR System 3000. /// NCR3000 = 20, /// - /// OS is NetWare + /// OS is NetWare. /// NetWare = 21, /// - /// OS is OSF + /// OS is OSF. /// OSF = 22, /// - /// OS is DC/OS + /// OS is DC/OS. /// DC_OS = 23, /// - /// OS is Reliant UNIX + /// OS is Reliant UNIX. /// ReliantUNIX = 24, /// - /// OS is SCO UnixWare + /// OS is SCO UnixWare. /// SCOUnixWare = 25, /// - /// OS is SCO OpenServer + /// OS is SCO OpenServer. /// SCOOpenServer = 26, /// - /// OS is Sequent + /// OS is Sequent. /// Sequent = 27, /// - /// OS is IRIX + /// OS is IRIX. /// IRIX = 28, /// - /// OS is Solaris + /// OS is Solaris. /// Solaris = 29, /// - /// OS is SunOS + /// OS is SunOS. /// SunOS = 30, /// - /// OS is U6000 + /// OS is U6000. /// U6000 = 31, /// - /// OS is ASERIES + /// OS is ASERIES. /// ASERIES = 32, /// - /// OS is Tandem NSK + /// OS is Tandem NSK. /// TandemNSK = 33, /// - /// OS is Tandem NT + /// OS is Tandem NT. /// TandemNT = 34, /// - /// OS is BS2000 + /// OS is BS2000. /// BS2000 = 35, /// - /// OS is Linux + /// OS is Linux. /// LINUX = 36, /// - /// OS is Lynx + /// OS is Lynx. /// Lynx = 37, /// - /// OS is XENIX + /// OS is XENIX. /// XENIX = 38, /// - /// OS is VM/ESA + /// OS is VM/ESA. /// VM_ESA = 39, /// - /// OS is Interactive UNIX + /// OS is Interactive UNIX. /// InteractiveUNIX = 40, /// - /// OS is BSD UNIX + /// OS is BSD UNIX. /// BSDUNIX = 41, /// - /// OS is FreeBSD + /// OS is FreeBSD. /// FreeBSD = 42, /// - /// OS is NetBSD + /// OS is NetBSD. /// NetBSD = 43, /// - /// OS is GNU Hurd + /// OS is GNU Hurd. /// GNUHurd = 44, /// - /// OS is OS 9 + /// OS is OS 9. /// OS9 = 45, /// - /// OS is Mach Kernel + /// OS is Mach Kernel. /// MACHKernel = 46, /// - /// OS is Inferno + /// OS is Inferno. /// Inferno = 47, /// - /// OS is QNX + /// OS is QNX. /// QNX = 48, /// - /// OS is EPOC + /// OS is EPOC. /// EPOC = 49, /// - /// OS is IxWorks + /// OS is IxWorks. /// IxWorks = 50, /// - /// OS is VxWorks + /// OS is VxWorks. /// VxWorks = 51, /// - /// OS is MiNT + /// OS is MiNT. /// MiNT = 52, /// - /// OS is BeOS + /// OS is BeOS. /// BeOS = 53, /// - /// OS is HP MPE + /// OS is HP MPE. /// HP_MPE = 54, /// - /// OS is NextStep + /// OS is NextStep. /// NextStep = 55, /// - /// OS is PalmPilot + /// OS is PalmPilot. /// PalmPilot = 56, /// - /// OS is Rhapsody + /// OS is Rhapsody. /// Rhapsody = 57, /// - /// OS is Windows 2000 + /// OS is Windows 2000. /// Windows2000 = 58, /// - /// OS is Dedicated + /// OS is Dedicated. /// Dedicated = 59, /// - /// OS is OS/390 + /// OS is OS/390. /// OS_390 = 60, /// - /// OS is VSE + /// OS is VSE. /// VSE = 61, /// - /// OS is TPF + /// OS is TPF. /// TPF = 62 } /// - /// Specifies the type of the computer in use, such as laptop, desktop, or Tablet + /// Specifies the type of the computer in use, such as laptop, desktop, or Tablet. /// public enum PCSystemType { /// - /// System type is unspecified + /// System type is unspecified. /// Unspecified = 0, /// - /// System is a desktop + /// System is a desktop. /// Desktop = 1, /// - /// System is a mobile device + /// System is a mobile device. /// Mobile = 2, /// - /// System is a workstation + /// System is a workstation. /// Workstation = 3, /// - /// System is an Enterprise Server + /// System is an Enterprise Server. /// EnterpriseServer = 4, /// - /// System is a Small Office and Home Office (SOHO) Server + /// System is a Small Office and Home Office (SOHO) Server. /// SOHOServer = 5, /// - /// System is an appliance PC + /// System is an appliance PC. /// AppliancePC = 6, /// - /// System is a performance server + /// System is a performance server. /// PerformanceServer = 7, /// - /// Maximum enum value + /// Maximum enum value. /// Maximum = 8 } /// /// Specifies the type of the computer in use, such as laptop, desktop, or Tablet. - /// This is an extended version of PCSystemType + /// This is an extended version of PCSystemType. /// - //TODO: conflate these two enums??? + // TODO: conflate these two enums??? public enum PCSystemTypeEx { /// - /// System type is unspecified + /// System type is unspecified. /// Unspecified = 0, /// - /// System is a desktop + /// System is a desktop. /// Desktop = 1, /// - /// System is a mobile device + /// System is a mobile device. /// Mobile = 2, /// - /// System is a workstation + /// System is a workstation. /// Workstation = 3, /// - /// System is an Enterprise Server + /// System is an Enterprise Server. /// EnterpriseServer = 4, /// - /// System is a Small Office and Home Office (SOHO) Server + /// System is a Small Office and Home Office (SOHO) Server. /// SOHOServer = 5, /// - /// System is an appliance PC + /// System is an appliance PC. /// AppliancePC = 6, /// - /// System is a performance server + /// System is a performance server. /// PerformanceServer = 7, /// - /// System is a Slate + /// System is a Slate. /// Slate = 8, /// - /// Maximum enum value + /// Maximum enum value. /// Maximum = 9 } /// - /// Specifies power-related capabilities of a logical device + /// Specifies power-related capabilities of a logical device. /// public enum PowerManagementCapabilities { /// - /// Unknown capability + /// Unknown capability. /// Unknown = 0, /// - /// Power management not supported + /// Power management not supported. /// NotSupported = 1, /// - /// Power management features are currently disabled + /// Power management features are currently disabled. /// Disabled = 2, /// /// The power management features are currently enabled, - /// but the exact feature set is unknown or the information is unavailable + /// but the exact feature set is unknown or the information is unavailable. /// Enabled = 3, /// - /// The device can change its power state based on usage or other criteria + /// The device can change its power state based on usage or other criteria. /// PowerSavingModesEnteredAutomatically = 4, /// - /// The power state may be set through the Win32_LogicalDevice class + /// The power state may be set through the Win32_LogicalDevice class. /// PowerStateSettable = 5, /// - /// Power may be done through the Win32_LogicalDevice class + /// Power may be done through the Win32_LogicalDevice class. /// PowerCyclingSupported = 6, /// - /// Timed power-on is supported + /// Timed power-on is supported. /// TimedPowerOnSupported = 7 } /// - /// Specified power states + /// Specified power states. /// public enum PowerState { /// - /// Power state is unknown + /// Power state is unknown. /// Unknown = 0, /// - /// Full power + /// Full power. /// FullPower = 1, /// - /// Power Save - Low Power mode + /// Power Save - Low Power mode. /// PowerSaveLowPowerMode = 2, /// - /// Power Save - Standby + /// Power Save - Standby. /// PowerSaveStandby = 3, /// - /// Unknown Power Save mode + /// Unknown Power Save mode. /// PowerSaveUnknown = 4, /// - /// Power Cycle + /// Power Cycle. /// PowerCycle = 5, /// - /// Power Off + /// Power Off. /// PowerOff = 6, /// - /// Power Save - Warning + /// Power Save - Warning. /// PowerSaveWarning = 7, /// - /// Power Save - Hibernate + /// Power Save - Hibernate. /// PowerSaveHibernate = 8, /// - /// Power Save - Soft off + /// Power Save - Soft off. /// PowerSaveSoftOff = 9 } /// - /// Specifies the primary function of a processor + /// Specifies the primary function of a processor. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum ProcessorType { /// - /// Processor ype is other than provided in these enumeration values + /// Processor ype is other than provided in these enumeration values. /// Other = 1, /// - /// Processor type is + /// Processor type is. /// Unknown = 2, @@ -4862,7 +4844,7 @@ public enum ProcessorType CentralProcessor = 3, /// - /// Processor is a Math processor + /// Processor is a Math processor. /// MathProcessor = 4, @@ -4872,45 +4854,45 @@ public enum ProcessorType DSPProcessor = 5, /// - /// Processor is a Video processor + /// Processor is a Video processor. /// VideoProcessor = 6 } /// - /// Specifies a computer's reset capability + /// Specifies a computer's reset capability. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum ResetCapability { /// - /// Capability is a value other than provided in these enumerated values + /// Capability is a value other than provided in these enumerated values. /// Other = 1, /// - /// Reset capability is unknown + /// Reset capability is unknown. /// Unknown = 2, /// - /// Capability is disabled + /// Capability is disabled. /// Disabled = 3, /// - /// Capability is enabled + /// Capability is enabled. /// Enabled = 4, /// - /// Capability is not implemented + /// Capability is not implemented. /// NotImplemented = 5 } /// - /// Specifies the kind of event that causes a computer to power up + /// Specifies the kind of event that causes a computer to power up. /// [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "The underlying MOF definition does not contain a zero value. The converter method will handle it appropriately.")] public enum WakeUpType @@ -4918,61 +4900,61 @@ public enum WakeUpType // // This value is reserved // - //Reserved = 0, + // Reserved = 0, /// - /// An event other than specified in this enumeration + /// An event other than specified in this enumeration. /// Other = 1, /// - /// Event type is unknown + /// Event type is unknown. /// Unknown = 2, /// - /// Event is APM timer + /// Event is APM timer. /// APMTimer = 3, /// - /// Event is a Modem Ring + /// Event is a Modem Ring. /// ModemRing = 4, /// - /// Event is a LAN Remove + /// Event is a LAN Remove. /// LANRemote = 5, /// - /// Event is a power switch + /// Event is a power switch. /// PowerSwitch = 6, /// - /// Event is a PCI PME# signal + /// Event is a PCI PME# signal. /// PCIPME = 7, /// - /// AC power was restored + /// AC power was restored. /// ACPowerRestored = 8 } /// - /// Indicates the OEM's preferred power management profile + /// Indicates the OEM's preferred power management profile. /// public enum PowerPlatformRole { /// - /// The OEM did not specify a specific role + /// The OEM did not specify a specific role. /// Unspecified = 0, /// - /// The OEM specified a desktop role + /// The OEM specified a desktop role. /// Desktop = 1, @@ -4982,120 +4964,120 @@ public enum PowerPlatformRole Mobile = 2, /// - /// The OEM specified a workstation role + /// The OEM specified a workstation role. /// Workstation = 3, /// - /// The OEM specified an enterprise server role + /// The OEM specified an enterprise server role. /// EnterpriseServer = 4, /// - /// The OEM specified a single office/home office (SOHO) server role + /// The OEM specified a single office/home office (SOHO) server role. /// SOHOServer = 5, /// - /// The OEM specified an appliance PC role + /// The OEM specified an appliance PC role. /// AppliancePC = 6, /// - /// The OEM specified a performance server role + /// The OEM specified a performance server role. /// PerformanceServer = 7, // v1 last supported /// - /// The OEM specified a tablet form factor role + /// The OEM specified a tablet form factor role. /// Slate = 8, // v2 last supported /// - /// Max enum value + /// Max enum value. /// MaximumEnumValue } /// - /// Additional system information, from Win32_OperatingSystem + /// Additional system information, from Win32_OperatingSystem. /// public enum ProductType { /// - /// Product type is unknown + /// Product type is unknown. /// Unknown = 0, // this value is not specified in Win32_OperatingSystem, but may prove useful /// - /// System is a workstation + /// System is a workstation. /// WorkStation = 1, /// - /// System is a domain controller + /// System is a domain controller. /// DomainController = 2, /// - /// System is a server + /// System is a server. /// Server = 3 } /// - /// Specifies the system server level + /// Specifies the system server level. /// public enum ServerLevel { /// - /// An unknown or unrecognized level was detected + /// An unknown or unrecognized level was detected. /// Unknown = 0, /// - /// Nano server + /// Nano server. /// NanoServer, /// - /// Server core + /// Server core. /// ServerCore, /// - /// Server core with management tools + /// Server core with management tools. /// ServerCoreWithManagementTools, /// - /// Full server + /// Full server. /// FullServer } /// - /// State of a software element + /// State of a software element. /// public enum SoftwareElementState { /// - /// Software element is deployable + /// Software element is deployable. /// Deployable = 0, /// - /// Software element is installable + /// Software element is installable. /// Installable = 1, /// - /// Software element is executable + /// Software element is executable. /// Executable = 2, /// - /// Software element is running + /// Software element is running. /// Running = 3 } @@ -5108,7 +5090,6 @@ internal static class Native private static class PInvokeDllNames { public const string GetPhysicallyInstalledSystemMemoryDllName = "api-ms-win-core-sysinfo-l1-2-1.dll"; - public const string LCIDToLocaleNameDllName = "kernelbase.dll"; public const string PowerDeterminePlatformRoleExDllName = "api-ms-win-power-base-l1-1-0.dll"; public const string GetFirmwareTypeDllName = "api-ms-win-core-kernel32-legacy-l1-1-1"; } @@ -5119,17 +5100,16 @@ private static class PInvokeDllNames public const UInt32 S_OK = 0; - /// - /// Import WINAPI function PowerDeterminePlatformRoleEx + /// Import WINAPI function PowerDeterminePlatformRoleEx. /// - /// The version of the POWER_PLATFORM_ROLE enumeration for the platform - /// POWER_PLATFORM_ROLE enumeration + /// The version of the POWER_PLATFORM_ROLE enumeration for the platform. + /// POWER_PLATFORM_ROLE enumeration. [DllImport(PInvokeDllNames.PowerDeterminePlatformRoleExDllName, EntryPoint = "PowerDeterminePlatformRoleEx", CharSet = CharSet.Ansi)] public static extern uint PowerDeterminePlatformRoleEx(uint version); /// - /// Retrieve the amount of RAM physically installed in the computer + /// Retrieve the amount of RAM physically installed in the computer. /// /// /// @@ -5138,7 +5118,7 @@ private static class PInvokeDllNames public static extern bool GetPhysicallyInstalledSystemMemory(out ulong MemoryInKilobytes); /// - /// Retrieve the firmware type of the local computer + /// Retrieve the firmware type of the local computer. /// /// /// A reference to a enumeration to contain @@ -5149,34 +5129,15 @@ private static class PInvokeDllNames [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetFirmwareType(out FirmwareType firmwareType); - /// - /// Convert a Local Identifier to a Locale name - /// - /// The Locale ID (LCID) to be converted - /// Destination of the Locale name - /// Capacity of - /// - /// - [DllImport(PInvokeDllNames.LCIDToLocaleNameDllName, SetLastError = true, CharSet = CharSet.Unicode)] - public static extern int LCIDToLocaleName(uint localeID, System.Text.StringBuilder localeName, int localeNameSize, int flags); - /// /// Gets the data specified for the passed in property name from the - /// Software Licensing API + /// Software Licensing API. /// /// Name of the licensing property to get. /// Out parameter for the value. /// An hresult indicating success or failure. [DllImport("slc.dll", CharSet = CharSet.Unicode)] internal static extern int SLGetWindowsInformationDWORD(string licenseProperty, out int propertyValue); - /* - * SLGetWindowsInformationDWORD function returns - * S_OK (0x00000000): If the method succeeds - * SL_E_RIGHT_NOT_GRANTED (0xC004F013): The caller does not have the permissions necessary to call this function. - * SL_E_DATATYPE_MISMATCHED (0xC004F013): The value portion of the name-value pair is not a DWORD. - [DllImport("Slc.dll", EntryPoint = "SLGetWindowsInformationDWORD", CharSet = CharSet.Unicode)] - public static extern UInt32 SLGetWindowsInformationDWORD(string pwszValueName, ref int pdwValue); - */ } #endregion Native } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs index dee0e3835f57..16a06ab10f8e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -9,12 +8,13 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Management.Automation.Provider; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// A command to get the content of an item at a specified path + /// A command to get the content of an item at a specified path. /// [Cmdlet(VerbsCommon.Get, "Content", DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113310")] public class GetContentCommand : ContentCommandBase @@ -27,15 +27,13 @@ public class GetContentCommand : ContentCommandBase /// at a time. To read all blocks at once, set this value /// to a negative number. /// - /// [Parameter(ValueFromPipelineByPropertyName = true)] public long ReadCount { get; set; } = 1; /// /// The number of content items to retrieve. By default this - /// value is -1 which means read all the content + /// value is -1 which means read all the content. /// - /// [Parameter(ValueFromPipelineByPropertyName = true)] [Alias("First", "Head")] public long TotalCount @@ -43,14 +41,15 @@ public long TotalCount get { return _totalCount; - } // get + } set { _totalCount = value; _totalCountSpecified = true; } - } // TotalCount + } + private bool _totalCountSpecified = false; /// @@ -65,8 +64,10 @@ public int Tail _backCount = value; _tailSpecified = true; } + get { return _backCount; } } + private int _backCount = -1; private bool _tailSpecified = false; @@ -75,24 +76,22 @@ public int Tail /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Content.GetContentReaderDynamicParameters(Path[0], context); } + return InvokeProvider.Content.GetContentReaderDynamicParameters(".", context); - } // GetDynamicParameters + } #endregion Parameters @@ -108,7 +107,7 @@ internal override object GetDynamicParameters(CmdletProviderContext context) #region Command code /// - /// Gets the content of an item at the specified path + /// Gets the content of an item at the specified path. /// protected override void ProcessRecord() { @@ -256,7 +255,7 @@ protected override void ProcessRecord() } } while (results != null && results.Count > 0 && ((TotalCount < 0) || countRead < TotalCount)); } - } // foreach holder in contentStreams + } } finally { @@ -267,10 +266,10 @@ protected override void ProcessRecord() // Empty the content holder array contentStreams = new List(); } - } // ProcessRecord + } /// - /// Scan forwards to get the tail content + /// Scan forwards to get the tail content. /// /// /// @@ -386,7 +385,7 @@ private bool ScanForwardsForTail(ContentHolder holder, CmdletProviderContext cur } /// - /// Seek position to the right place + /// Seek position to the right place. /// /// /// reader should be able to be casted to FileSystemContentReader @@ -414,7 +413,7 @@ private bool SeekPositionForTail(IContentReader reader) } /// - /// Be sure to clean up + /// Be sure to clean up. /// protected override void EndProcessing() { @@ -422,6 +421,6 @@ protected override void EndProcessing() } #endregion Command code - } // GetContentCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetPropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetPropertyCommand.cs index 7cf2b94cd7df..7079f3d55c5d 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetPropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetPropertyCommand.cs @@ -1,16 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// A command to get the property of an item at a specified path + /// A command to get the property of an item at a specified path. /// [Cmdlet(VerbsCommon.Get, "ItemProperty", DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113320")] public class GetItemPropertyCommand : ItemPropertyCommandBase @@ -18,7 +18,7 @@ public class GetItemPropertyCommand : ItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -27,38 +27,37 @@ public string[] Path get { return paths; - } // get + } set { paths = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return paths; - } // get + } set { base.SuppressWildcardExpansion = true; paths = value; - } // set - } // LiteralPath + } + } /// - /// The properties to retrieve from the item + /// The properties to retrieve from the item. /// - /// [Parameter(Position = 1)] [Alias("PSProperty")] public string[] Name @@ -66,29 +65,26 @@ public string[] Name get { return _property; - } // get + } set { _property = value; } - } // Property + } /// /// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) @@ -97,10 +93,11 @@ internal override object GetDynamicParameters(CmdletProviderContext context) Path[0], SessionStateUtilities.ConvertArrayToCollection(_property), context); } + return InvokeProvider.Property.GetPropertyDynamicParameters( ".", SessionStateUtilities.ConvertArrayToCollection(_property), context); - } // GetDynamicParameters + } #endregion Parameters @@ -116,7 +113,7 @@ internal override object GetDynamicParameters(CmdletProviderContext context) #region Command code /// - /// Gets the properties of an item at the specified path + /// Gets the properties of an item at the specified path. /// protected override void ProcessRecord() { @@ -162,10 +159,10 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord + } #endregion Command code - } // GetItemPropertyCommand + } /// /// A command to get the property value of an item at a specified path. @@ -176,7 +173,7 @@ public sealed class GetItemPropertyValueCommand : ItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = false, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] @@ -186,38 +183,37 @@ public string[] Path get { return paths; - } // get + } set { paths = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] LiteralPath { get { return paths; - } // get + } set { base.SuppressWildcardExpansion = true; paths = value; - } // set - } // LiteralPath + } + } /// - /// The properties to retrieve from the item + /// The properties to retrieve from the item. /// - /// [Parameter(Position = 1, Mandatory = true)] [Alias("PSProperty")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] @@ -226,29 +222,26 @@ public string[] Name get { return _property; - } // get + } set { _property = value; } - } // Property + } /// /// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) @@ -257,10 +250,11 @@ internal override object GetDynamicParameters(CmdletProviderContext context) Path[0], SessionStateUtilities.ConvertArrayToCollection(_property), context); } + return InvokeProvider.Property.GetPropertyDynamicParameters( ".", SessionStateUtilities.ConvertArrayToCollection(_property), context); - } // GetDynamicParameters + } #endregion Parameters @@ -284,6 +278,7 @@ protected override void ProcessRecord() { paths = new string[] { "." }; } + foreach (string path in Path) { try @@ -349,4 +344,4 @@ protected override void ProcessRecord() #endregion Command code } -} // namespace Microsoft.PowerShell.Commands +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs index f7182e46d75b..ed99d63861db 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs @@ -1,8 +1,8 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -21,6 +21,6 @@ protected override void EndProcessing() { WriteObject(this.Context.TransactionManager.GetCurrent()); } - } // GetTransactionCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs index e6b85ded55e0..b078262505f7 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs @@ -1,19 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections; using System.Globalization; -using System.Management.Automation; using System.Management; +using System.Management.Automation; using System.Text; -using System.Collections; using System.Threading; namespace Microsoft.PowerShell.Commands { /// - /// A command to get WMI Objects + /// A command to get WMI Objects. /// [Cmdlet(VerbsCommon.Get, "WmiObject", DefaultParameterSetName = "query", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113337", RemotingCapability = RemotingCapability.OwnedByCommand)] @@ -21,9 +20,8 @@ public class GetWmiObjectCommand : WmiBaseCmdlet { #region Parameters - /// - /// The WMI class to query + /// The WMI class to query. /// [Alias("ClassName")] [Parameter(Position = 0, Mandatory = true, ParameterSetName = "query")] @@ -32,30 +30,31 @@ public class GetWmiObjectCommand : WmiBaseCmdlet public string Class { get; set; } /// - /// To specify whether to get the results recursively + /// To specify whether to get the results recursively. /// [Parameter(ParameterSetName = "list")] public SwitchParameter Recurse { get; set; } = false; /// - /// The WMI properties to retrieve + /// The WMI properties to retrieve. /// [Parameter(Position = 1, ParameterSetName = "query")] [ValidateNotNullOrEmpty()] public string[] Property { get { return (string[])_property.Clone(); } + set { _property = value; } } /// - /// The filter to be used in the search + /// The filter to be used in the search. /// [Parameter(ParameterSetName = "query")] public string Filter { get; set; } /// - /// If Amended qualifier to use + /// If Amended qualifier to use. /// [Parameter] public SwitchParameter Amended { get; set; } @@ -68,13 +67,13 @@ public string[] Property public SwitchParameter DirectRead { get; set; } /// - /// The list of classes + /// The list of classes. /// [Parameter(ParameterSetName = "list")] public SwitchParameter List { get; set; } = false; /// - /// The query string to search for objects + /// The query string to search for objects. /// [Parameter(Mandatory = true, ParameterSetName = "WQLQuery")] public string Query { get; set; } @@ -90,19 +89,20 @@ public string[] Property #region Command code /// - /// Uses this.filter, this.wmiClass and this.property to retrieve the filter + /// Uses this.filter, this.wmiClass and this.property to retrieve the filter. /// internal string GetQueryString() { StringBuilder returnValue = new StringBuilder("select "); - returnValue.Append(String.Join(", ", _property)); + returnValue.Append(string.Join(", ", _property)); returnValue.Append(" from "); returnValue.Append(Class); - if (!String.IsNullOrEmpty(Filter)) + if (!string.IsNullOrEmpty(Filter)) { returnValue.Append(" where "); returnValue.Append(Filter); } + return returnValue.ToString(); } /// @@ -126,6 +126,7 @@ internal string GetFilterClassName() filterClass = filterClass.Replace('?', '_'); return filterClass; } + internal bool IsLocalizedNamespace(string sNamespace) { bool toReturn = false; @@ -133,8 +134,10 @@ internal bool IsLocalizedNamespace(string sNamespace) { toReturn = true; } + return toReturn; } + internal bool ValidateClassFormat() { string filterClass = this.Class; @@ -143,7 +146,7 @@ internal bool ValidateClassFormat() StringBuilder newClassName = new StringBuilder(); for (int i = 0; i < filterClass.Length; i++) { - if (Char.IsLetterOrDigit(filterClass[i]) || + if (char.IsLetterOrDigit(filterClass[i]) || filterClass[i].Equals('[') || filterClass[i].Equals(']') || filterClass[i].Equals('*') || filterClass[i].Equals('?') || filterClass[i].Equals('-')) @@ -158,14 +161,16 @@ internal bool ValidateClassFormat() newClassName.Append(']'); continue; } + return false; } + this.Class = newClassName.ToString(); return true; } /// - /// Gets the ManagementObjectSearcher object + /// Gets the ManagementObjectSearcher object. /// internal ManagementObjectSearcher GetObjectList(ManagementScope scope) { @@ -183,6 +188,7 @@ internal ManagementObjectSearcher GetObjectList(ManagementScope scope) queryStringBuilder.Append(filterClass); queryStringBuilder.Append("'"); } + ObjectQuery classQuery = new ObjectQuery(queryStringBuilder.ToString()); EnumerationOptions enumOptions = new EnumerationOptions(); @@ -192,7 +198,7 @@ internal ManagementObjectSearcher GetObjectList(ManagementScope scope) return searcher; } /// - /// Gets the properties of an item at the specified path + /// Gets the properties of an item at the specified path. /// protected override void BeginProcessing() { @@ -210,7 +216,7 @@ protected override void BeginProcessing() { ErrorRecord errorRecord = new ErrorRecord( new ArgumentException( - String.Format( + string.Format( Thread.CurrentThread.CurrentCulture, "Class", this.Class)), "INVALID_QUERY_IDENTIFIER", @@ -221,6 +227,7 @@ protected override void BeginProcessing() WriteError(errorRecord); return; } + foreach (string name in ComputerName) { if (this.Recurse.IsPresent) @@ -327,6 +334,7 @@ protected override void BeginProcessing() WriteError(errorRecord); continue; } + ManagementObjectSearcher searcher = this.GetObjectList(scope); if (searcher == null) continue; @@ -336,6 +344,7 @@ protected override void BeginProcessing() } } } + return; } @@ -371,19 +380,19 @@ protected override void BeginProcessing() if (e.ErrorCode.Equals(ManagementStatus.InvalidClass)) { string className = GetClassNameFromQuery(queryString); - string errorMsg = String.Format(CultureInfo.InvariantCulture, WmiResources.WmiQueryFailure, + string errorMsg = string.Format(CultureInfo.InvariantCulture, WmiResources.WmiQueryFailure, e.Message, className); errorRecord = new ErrorRecord(new ManagementException(errorMsg), "GetWMIManagementException", ErrorCategory.InvalidType, null); } else if (e.ErrorCode.Equals(ManagementStatus.InvalidQuery)) { - string errorMsg = String.Format(CultureInfo.InvariantCulture, WmiResources.WmiQueryFailure, + string errorMsg = string.Format(CultureInfo.InvariantCulture, WmiResources.WmiQueryFailure, e.Message, queryString); errorRecord = new ErrorRecord(new ManagementException(errorMsg), "GetWMIManagementException", ErrorCategory.InvalidArgument, null); } else if (e.ErrorCode.Equals(ManagementStatus.InvalidNamespace)) { - string errorMsg = String.Format(CultureInfo.InvariantCulture, WmiResources.WmiQueryFailure, + string errorMsg = string.Format(CultureInfo.InvariantCulture, WmiResources.WmiQueryFailure, e.Message, this.Namespace); errorRecord = new ErrorRecord(new ManagementException(errorMsg), "GetWMIManagementException", ErrorCategory.InvalidArgument, null); } @@ -401,12 +410,12 @@ protected override void BeginProcessing() WriteError(errorRecord); continue; } - } // foreach computerName + } } - } // BeginProcessing + } /// - /// Get the class name from a query string + /// Get the class name from a query string. /// /// /// @@ -427,6 +436,6 @@ private string GetClassNameFromQuery(string query) } #endregion Command code - } // GetWmiObjectCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs index 8f10d92d3709..d0f892d3cfe9 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs @@ -1,38 +1,37 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; -using System.Text.RegularExpressions; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; -using System.Diagnostics; // Process class using System.ComponentModel; // Win32Exception +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; // Process class using System.Globalization; -using System.Runtime.Serialization; -using System.Security.Permissions; -using System.Threading; +using System.IO; using System.Management; using System.Management.Automation; using System.Management.Automation.Internal; -using System.Diagnostics.CodeAnalysis; using System.Net; -using System.IO; +using System.Runtime.Serialization; using System.Security; -using System.Security.Principal; using System.Security.AccessControl; -using Dbg = System.Management.Automation; +using System.Security.Permissions; +using System.Security.Principal; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { #region Get-HotFix /// - /// Cmdlet for Get-Hotfix Proxy + /// Cmdlet for Get-Hotfix Proxy. /// [Cmdlet(VerbsCommon.Get, "HotFix", DefaultParameterSetName = "Default", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135217", RemotingCapability = RemotingCapability.SupportedByCommand)] @@ -51,7 +50,7 @@ public sealed class GetHotFixCommand : PSCmdlet, IDisposable public string[] Id { get; set; } /// - /// To search on description of Hotfixes + /// To search on description of Hotfixes. /// [Parameter(ParameterSetName = "Description")] [ValidateNotNullOrEmpty] @@ -59,7 +58,7 @@ public sealed class GetHotFixCommand : PSCmdlet, IDisposable public string[] Description { get; set; } /// - /// Parameter to pass the Computer Name + /// Parameter to pass the Computer Name. /// [Parameter(ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] @@ -79,7 +78,6 @@ public sealed class GetHotFixCommand : PSCmdlet, IDisposable #region Overrides - private ManagementObjectSearcher _searchProcess; private bool _inputContainsWildcard = false; @@ -106,6 +104,7 @@ protected override void BeginProcessing() if (i < Id.Length - 1) QueryString.Append(" Or "); } + QueryString.Append(")"); } else @@ -113,6 +112,7 @@ protected override void BeginProcessing() QueryString.Append("Select * from Win32_QuickFixEngineering"); foundRecord = true; } + _searchProcess = new ManagementObjectSearcher(scope, new ObjectQuery(QueryString.ToString())); foreach (ManagementObject obj in _searchProcess.Get()) { @@ -129,7 +129,7 @@ protected override void BeginProcessing() // try to translate the SID to a more friendly username // just stick with the SID if anything goes wrong string installed = (string)obj["InstalledBy"]; - if (!String.IsNullOrEmpty(installed)) + if (!string.IsNullOrEmpty(installed)) { try { @@ -142,34 +142,36 @@ protected override void BeginProcessing() catch (SystemException) // thrown by SecurityIdentifier.constr { } - //catch (ArgumentException) // thrown (indirectly) by SecurityIdentifier.constr (on XP only?) - //{ catch not needed - this is already caught as SystemException - //} - //catch (PlatformNotSupportedException) // thrown (indirectly) by SecurityIdentifier.Translate (on Win95 only?) - //{ catch not needed - this is already caught as SystemException - //} - //catch (UnauthorizedAccessException) // thrown (indirectly) by SecurityIdentifier.Translate - //{ catch not needed - this is already caught as SystemException - //} + // catch (ArgumentException) // thrown (indirectly) by SecurityIdentifier.constr (on XP only?) + // { catch not needed - this is already caught as SystemException + // } + // catch (PlatformNotSupportedException) // thrown (indirectly) by SecurityIdentifier.Translate (on Win95 only?) + // { catch not needed - this is already caught as SystemException + // } + // catch (UnauthorizedAccessException) // thrown (indirectly) by SecurityIdentifier.Translate + // { catch not needed - this is already caught as SystemException + // } } WriteObject(obj); foundRecord = true; } + if (!foundRecord && !_inputContainsWildcard) { Exception Ex = new ArgumentException(StringUtil.Format(HotFixResources.NoEntriesFound, computer)); WriteError(new ErrorRecord(Ex, "GetHotFixNoEntriesFound", ErrorCategory.ObjectNotFound, null)); } + if (_searchProcess != null) { this.Dispose(); } } - }//end of BeginProcessing method + } /// - /// to implement ^C + /// To implement ^C. /// protected override void StopProcessing() { @@ -193,6 +195,7 @@ private bool FilterMatch(ManagementObject obj) { return true; } + if (WildcardPattern.ContainsWildcardCharacters(desc)) { _inputContainsWildcard = true; @@ -203,6 +206,7 @@ private bool FilterMatch(ManagementObject obj) { return false; } + return false; } @@ -211,7 +215,7 @@ private bool FilterMatch(ManagementObject obj) #region "IDisposable Members" /// - /// Dispose Method + /// Dispose Method. /// public void Dispose() { @@ -237,6 +241,6 @@ public void Dispose(bool disposing) } #endregion "IDisposable Members" - }//end class + } #endregion -}//Microsoft.Powershell.commands +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/InvokeWMIMethodCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/InvokeWMIMethodCommand.cs index fa275c3303ab..e6204c619d0c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/InvokeWMIMethodCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/InvokeWMIMethodCommand.cs @@ -1,23 +1,22 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Management; using System.Management.Automation; using System.Management.Automation.Internal; -using System.Management; -using System.Text; using System.Management.Automation.Provider; -using System.ComponentModel; -using System.Collections; -using System.Collections.ObjectModel; -using System.Security.AccessControl; using System.Runtime.InteropServices; +using System.Security.AccessControl; +using System.Text; namespace Microsoft.PowerShell.Commands { /// - /// A command to Invoke WMI Method + /// A command to Invoke WMI Method. /// [Cmdlet(VerbsLifecycle.Invoke, "WmiMethod", DefaultParameterSetName = "class", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113346", RemotingCapability = RemotingCapability.OwnedByCommand)] @@ -25,45 +24,48 @@ public sealed class InvokeWmiMethod : WmiBaseCmdlet { #region Parameters /// - /// The WMI Object to use + /// The WMI Object to use. /// - /// [Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = "object")] public ManagementObject InputObject { get { return _inputObject; } + set { _inputObject = value; } } /// - /// The WMI Path to use + /// The WMI Path to use. /// [Parameter(ParameterSetName = "path", Mandatory = true)] public string Path { get { return _path; } + set { _path = value; } } /// - /// The WMI class to use + /// The WMI class to use. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "class")] public string Class { get { return _className; } + set { _className = value; } } /// - /// The WMI Method to execute + /// The WMI Method to execute. /// [Parameter(Position = 1, Mandatory = true)] public string Name { get { return _methodName; } + set { _methodName = value; } } /// - /// The parameters to the method specified by MethodName + /// The parameters to the method specified by MethodName. /// [Parameter(ParameterSetName = "path")] [Parameter(Position = 2, ParameterSetName = "class")] @@ -72,6 +74,7 @@ public string Name public object[] ArgumentList { get { return _argumentList; } + set { _argumentList = value; } } @@ -96,6 +99,7 @@ protected override void ProcessRecord() RunAsJob("Invoke-WMIMethod"); return; } + if (_inputObject != null) { object result = null; @@ -114,6 +118,7 @@ protected override void ProcessRecord() inParamCount--; } } + if (!ShouldProcess( StringUtil.Format(WmiResources.WmiMethodNameForConfirmation, _inputObject["__CLASS"].ToString(), @@ -122,6 +127,7 @@ protected override void ProcessRecord() { return; } + result = _inputObject.InvokeMethod(_methodName, inputParameters, null); } catch (ManagementException e) @@ -134,10 +140,12 @@ protected override void ProcessRecord() ErrorRecord errorRecord = new ErrorRecord(e, "InvokeWMICOMException", ErrorCategory.InvalidOperation, null); WriteError(errorRecord); } + if (result != null) { WriteObject(result); } + return; } else @@ -149,13 +157,13 @@ protected override void ProcessRecord() if (_path != null) { mPath = new ManagementPath(_path); - if (String.IsNullOrEmpty(mPath.NamespacePath)) + if (string.IsNullOrEmpty(mPath.NamespacePath)) { mPath.NamespacePath = this.Namespace; } else if (namespaceSpecified) { - //ThrowTerminatingError + // ThrowTerminatingError ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "NamespaceSpecifiedWithPath", @@ -165,20 +173,21 @@ protected override void ProcessRecord() if (mPath.Server != "." && serverNameSpecified) { - //ThrowTerminatingError + // ThrowTerminatingError ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "ComputerNameSpecifiedWithPath", ErrorCategory.InvalidOperation, ComputerName)); } - //If server name is specified loop through it. + // If server name is specified loop through it. if (!(mPath.Server == "." && serverNameSpecified)) { string[] serverName = new string[] { mPath.Server }; ComputerName = serverName; } } + foreach (string name in ComputerName) { result = null; @@ -197,6 +206,7 @@ protected override void ProcessRecord() ManagementObject mInstance = new ManagementObject(mPath); mObject = mInstance; } + ManagementScope mScope = new ManagementScope(mPath, options); mObject.Scope = mScope; } @@ -207,6 +217,7 @@ protected override void ProcessRecord() mObject = mClass; mObject.Scope = scope; } + ManagementBaseObject inputParameters = mObject.GetMethodParameters(_methodName); if (_argumentList != null) { @@ -224,9 +235,11 @@ protected override void ProcessRecord() { property.Value = argument; } + inParamCount--; } } + if (!ShouldProcess( StringUtil.Format(WmiResources.WmiMethodNameForConfirmation, mObject["__CLASS"].ToString(), @@ -235,6 +248,7 @@ protected override void ProcessRecord() { return; } + result = mObject.InvokeMethod(_methodName, inputParameters, null); } catch (ManagementException e) @@ -247,13 +261,14 @@ protected override void ProcessRecord() ErrorRecord errorRecord = new ErrorRecord(e, "InvokeWMICOMException", ErrorCategory.InvalidOperation, null); WriteError(errorRecord); } + if (result != null) { WriteObject(result); } } } - }//ProcessRecord + } /// /// Ensure that the argument is a collection containing no PSObjects. @@ -280,6 +295,7 @@ private static object MakeBaseObjectArray(object argument) break; } } + if (needCopy) { var copiedArgument = new object[listArgument.Count]; @@ -288,6 +304,7 @@ private static object MakeBaseObjectArray(object argument) { copiedArgument[index++] = argElement != null ? PSObject.Base(argElement) : null; } + return copiedArgument; } else @@ -297,5 +314,5 @@ private static object MakeBaseObjectArray(object argument) } #endregion Command code - }//InvokeWMIObject + } } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/MovePropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/MovePropertyCommand.cs index d51f40b7cae8..a7eacb14fd0a 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/MovePropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/MovePropertyCommand.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// A command to move a property on an item to another item + /// A command to move a property on an item to another item. /// [Cmdlet(VerbsCommon.Move, "ItemProperty", SupportsShouldProcess = true, DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113351")] @@ -18,25 +18,27 @@ public class MoveItemPropertyCommand : PassThroughItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { get { return paths; } + set { paths = value; } } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return paths; } + set { base.SuppressWildcardExpansion = true; @@ -45,20 +47,21 @@ public string[] LiteralPath } /// - /// The name of the property to create on the item + /// The name of the property to create on the item. /// - /// [Parameter(Position = 2, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Alias("PSProperty")] public string[] Name { get { return _property; } + set { if (value == null) { - value = Utils.EmptyArray(); + value = Array.Empty(); } + _property = value; } } @@ -66,7 +69,6 @@ public string[] Name /// /// The path to the destination item to copy the property to. /// - /// [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)] public string Destination { get; set; } @@ -75,19 +77,16 @@ public string[] Name /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { - string propertyName = String.Empty; + string propertyName = string.Empty; if (Name != null && Name.Length > 0) { propertyName = Name[0]; @@ -97,13 +96,14 @@ internal override object GetDynamicParameters(CmdletProviderContext context) { return InvokeProvider.Property.MovePropertyDynamicParameters(Path[0], propertyName, Destination, propertyName, context); } + return InvokeProvider.Property.MovePropertyDynamicParameters( ".", propertyName, Destination, propertyName, context); - } // GetDynamicParameters + } #endregion Parameters @@ -112,14 +112,14 @@ internal override object GetDynamicParameters(CmdletProviderContext context) /// /// The property to be created. /// - private string[] _property = new string[0]; + private string[] _property = Array.Empty(); #endregion parameter data #region Command code /// - /// Creates the property on the item + /// Creates the property on the item. /// protected override void ProcessRecord() { @@ -165,9 +165,8 @@ protected override void ProcessRecord() } } } - } // ProcessRecord + } #endregion Command code - - } // MoveItemPropertyCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs index 7378d2bf5088..b263586a002c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -8,6 +7,7 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Management.Automation.Provider; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -25,7 +25,6 @@ public abstract class CoreCommandBase : PSCmdlet, IDynamicParameters /// An instance of the PSTraceSource class used for trace output /// using "NavigationCommands" as the category. /// - /// [Dbg.TraceSourceAttribute("NavigationCommands", "The namespace navigation tracer")] internal static Dbg.PSTraceSource tracer = Dbg.PSTraceSource.GetTracer("NavigationCommands", "The namespace navigation tracer"); @@ -57,19 +56,14 @@ internal virtual CmdletProviderContext CmdletProviderContext return coreCommandContext; } - } // CmdletProviderContext + } internal virtual SwitchParameter SuppressWildcardExpansion { - get - { - return _suppressWildcardExpansion; - } - set - { - _suppressWildcardExpansion = value; - } + get => _suppressWildcardExpansion; + set => _suppressWildcardExpansion = value; } + private bool _suppressWildcardExpansion; /// @@ -77,45 +71,31 @@ internal virtual SwitchParameter SuppressWildcardExpansion /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// - internal virtual object GetDynamicParameters(CmdletProviderContext context) - { - return null; - } + internal virtual object GetDynamicParameters(CmdletProviderContext context) => null; /// /// Called by the base implementation that checks the SupportShouldProcess provider /// capability. This virtual method gives the /// derived cmdlet a chance query the CmdletProvider capabilities to determine - /// if the provider supports ShouldProcess + /// if the provider supports ShouldProcess. /// /// - protected virtual bool ProviderSupportsShouldProcess - { - get - { - return true; - } - } // ProviderSupportsShouldProcess + protected virtual bool ProviderSupportsShouldProcess => true; /// /// A helper for derived classes to call to determine if the paths specified - /// are for a provider that supports ShouldProcess + /// are for a provider that supports ShouldProcess. /// - /// /// /// The paths to check to see if the providers support ShouldProcess. /// - /// /// /// If the paths are to different providers, and any don't support /// ShouldProcess, then the return value is false. If they all @@ -152,6 +132,7 @@ protected bool DoesProviderSupportShouldProcess(string[] paths) } } } + return result; } @@ -159,19 +140,11 @@ protected bool DoesProviderSupportShouldProcess(string[] paths) /// The dynamic parameters which have already been retrieved from the provider /// and bound by the command processor. /// - /// - protected internal object RetrievedDynamicParameters - { - get - { - return _dynamicParameters; - } // get - } // RetrievedDynamicParameters + protected internal object RetrievedDynamicParameters => _dynamicParameters; /// /// The dynamic parameters for the command. They are retrieved using the /// GetDynamicParameters virtual method. /// - /// private object _dynamicParameters; #endregion Protected members @@ -183,72 +156,58 @@ protected internal object RetrievedDynamicParameters /// CmdletProviderContext to tunnel the stop message to /// the provider instance. /// - /// protected override void StopProcessing() { foreach (CmdletProviderContext stopContext in stopContextCollection) { stopContext.StopProcessing(); } - } // StopProcessing + } + internal Collection stopContextCollection = new Collection(); /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// - /// /// /// This is meant to be overridden by derived classes if /// they support the Filter parameter. This property is on /// the base class to simplify the creation of the CmdletProviderContext. /// - /// public virtual string Filter { get; set; } - /// - /// Gets or sets the include property + /// Gets or sets the include property. /// - /// /// /// This is meant to be overridden by derived classes if /// they support the Include parameter. This property is on /// the base class to simplify the creation of the CmdletProviderContext. /// - /// - public virtual string[] Include { get; -// get + public virtual string[] Include + { + get; set; -// set - } = new string[0]; - -// Include - + } = Array.Empty(); /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// - /// /// /// This is meant to be overridden by derived classes if /// they support the Exclude parameter. This property is on /// the base class to simplify the creation of the CmdletProviderContext. /// - /// - public virtual string[] Exclude { get; -// get + public virtual string[] Exclude + { + get; set; -// set - } = new string[0]; - -// Exclude - + } = Array.Empty(); /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -262,26 +221,18 @@ protected override void StopProcessing() /// they support the Force parameter. This property is on /// the base class to simplify the creation of the CmdletProviderContext. /// - /// public virtual SwitchParameter Force { - get - { - return _force; - } - set - { - _force = value; - } - } // Force - private bool _force; + get => _force; + set => _force = value; + } + private bool _force; /// /// Retrieves the dynamic parameters for the command from /// the provider. /// - /// public object GetDynamicParameters() { // Don't stream errors or Write* to the pipeline. @@ -306,22 +257,15 @@ public object GetDynamicParameters() } return _dynamicParameters; - } // GetDynamicParameters + } /// - /// Determines if the cmdlet and CmdletProvider supports ShouldProcess + /// Determines if the cmdlet and CmdletProvider supports ShouldProcess. /// - /// - public bool SupportsShouldProcess - { - get - { - return ProviderSupportsShouldProcess; - } - } // SupportsShouldProcess + public bool SupportsShouldProcess => ProviderSupportsShouldProcess; #endregion Public members - } // class CoreCommandBase + } #endregion CoreCommandBase @@ -336,9 +280,8 @@ public class CoreCommandWithCredentialsBase : CoreCommandBase #region Parameters /// - /// Gets or sets the credential parameter + /// Gets or sets the credential parameter. /// - /// [Parameter(ValueFromPipelineByPropertyName = true)] [Credential()] public PSCredential Credential { get; set; } @@ -374,10 +317,10 @@ internal override CmdletProviderContext CmdletProviderContext return coreCommandContext; } - } // CmdletProviderContext + } #endregion Protected members - } // CoreCommandWithCredentialsBase + } #endregion CoreCommandWithCredentialsBase @@ -388,54 +331,34 @@ internal override CmdletProviderContext CmdletProviderContext /// This command does things like list the contents of a container, get /// an item at a given path, get the current working directory, etc. /// - /// /// /// - /// - [Cmdlet(VerbsCommon.Get, "Location", DefaultParameterSetName = "Location", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113321")] - [OutputType(typeof(PathInfo), ParameterSetName = new string[] { "locationSet" })] - [OutputType(typeof(PathInfoStack), ParameterSetName = new string[] { "Stack" })] + [Cmdlet(VerbsCommon.Get, "Location", DefaultParameterSetName = LocationParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113321")] + [OutputType(typeof(PathInfo), ParameterSetName = new string[] { LocationParameterSet })] + [OutputType(typeof(PathInfoStack), ParameterSetName = new string[] { StackParameterSet })] public class GetLocationCommand : DriveMatchingCoreCommandBase { - /// - /// The string declaration for the Location parameter set in this command. - /// - /// - /// The "Location" parameter set includes the following parameters: - /// -location - /// - private const string locationSet = "Location"; - - /// - /// The string declaration for the Stack parameter set in this command. - /// - /// - /// The "Stack" parameter set includes the following parameters: - /// -stack - /// - private const string stackSet = "Stack"; + private const string LocationParameterSet = "Location"; + private const string StackParameterSet = "Stack"; #region Command parameters #region Location parameter set parameters - /// /// Gets or sets the provider from which to get the current location. /// - /// - [Parameter(ParameterSetName = locationSet, ValueFromPipelineByPropertyName = true)] + [Parameter(ParameterSetName = LocationParameterSet, ValueFromPipelineByPropertyName = true)] public string[] PSProvider { - get { return _provider; } - set { _provider = value ?? Utils.EmptyArray(); } + get => _provider; + set => _provider = value ?? Array.Empty(); } /// /// Gets or sets the drive from which to get the current location. /// - /// - [Parameter(ParameterSetName = locationSet, ValueFromPipelineByPropertyName = true)] + [Parameter(ParameterSetName = LocationParameterSet, ValueFromPipelineByPropertyName = true)] public string[] PSDrive { get; set; } #endregion Location parameter set parameters @@ -444,41 +367,29 @@ public string[] PSProvider /// /// Gets or sets the Stack switch parameter which is used - /// to disambiguate parameter sets + /// to disambiguate parameter sets. /// /// - [Parameter(ParameterSetName = stackSet)] + [Parameter(ParameterSetName = StackParameterSet)] public SwitchParameter Stack { - get - { - return _stackSwitch; - } - set - { - _stackSwitch = value; - } + get => _stackSwitch; + set => _stackSwitch = value; } + private bool _stackSwitch; /// /// Gets or sets the stack ID for the location stack that will /// be retrieved. /// - /// - [Parameter(ParameterSetName = stackSet, ValueFromPipelineByPropertyName = true)] + [Parameter(ParameterSetName = StackParameterSet, ValueFromPipelineByPropertyName = true)] public string[] StackName { - get - { - return _stackNames; - } // get + get => _stackNames; - set - { - _stackNames = value; - } // set - } // StackName + set => _stackNames = value; + } #endregion Stack parameter set parameters @@ -486,13 +397,12 @@ public string[] StackName #region command data - #region Location parameter set data /// /// The name of the provider from which to return the current location. /// - private string[] _provider = new string[0]; + private string[] _provider = Array.Empty(); #endregion Location parameter set data @@ -505,10 +415,8 @@ public string[] StackName #endregion Stack parameter set data - #endregion command data - #region command code /// @@ -516,7 +424,7 @@ public string[] StackName /// the parameter set that is specified, the command can do many things. /// -locationSet gets the current working directory as a Monad path /// -stackSet gets the directory stack of directories that have been - /// pushed by the push-location command + /// pushed by the push-location command. /// protected override void ProcessRecord() { @@ -524,7 +432,7 @@ protected override void ProcessRecord() // want a case sensitive comparison in the current culture. switch (ParameterSetName) { - case locationSet: + case LocationParameterSet: PathInfo result = null; if (PSDrive != null && PSDrive.Length > 0) @@ -669,9 +577,10 @@ protected override void ProcessRecord() // Get the current working directory using the core command API. WriteObject(SessionState.Path.CurrentLocation); } + break; - case stackSet: + case StackParameterSet: if (_stackNames != null) { foreach (string stackName in _stackNames) @@ -705,81 +614,60 @@ protected override void ProcessRecord() argException)); } } + break; default: - Dbg.Diagnostics.Assert(false, String.Format(System.Globalization.CultureInfo.InvariantCulture, "One of the predefined parameter sets should have been specified, instead we got: {0}", ParameterSetName)); + Dbg.Diagnostics.Assert(false, string.Format(System.Globalization.CultureInfo.InvariantCulture, "One of the predefined parameter sets should have been specified, instead we got: {0}", ParameterSetName)); break; - } // case (ParameterSetName) - } // ProcessRecord + } + } #endregion command code - } // class GetLocationCommand + } #endregion GetLocationCommand - #region SetLocationCommand /// /// The core command for setting/changing location. /// This is the equivalent of cd command. /// - [Cmdlet(VerbsCommon.Set, "Location", DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113397")] + [Cmdlet(VerbsCommon.Set, "Location", DefaultParameterSetName = PathParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113397")] [OutputType(typeof(PathInfo), typeof(PathInfoStack))] public class SetLocationCommand : CoreCommandBase { #region Command parameters + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + private const string StackParameterSet = "Stack"; /// - /// The string declaration for the Location parameter set in this command. - /// - private const string pathSet = "Path"; - - /// - /// The string declaration for the literal location parameter set in this command. - /// - private const string literalPathSet = "LiteralPath"; - - /// - /// The string declaration for the Stack parameter set in this command. - /// - private const string stackSet = "Stack"; - - /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, ParameterSetName = pathSet, + [Parameter(Position = 0, ParameterSetName = PathParameterSet, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string Path { - get - { - return _path; - } - set - { - _path = value; - } + get => _path; + set => _path = value; } /// /// Gets or sets the path path property, when bound from the pipeline. /// - [Parameter(ParameterSetName = literalPathSet, + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { - get - { - return _path; - } + get => _path; set { _path = value; base.SuppressWildcardExpansion = true; } - } // PSPath + } /// /// Gets or sets the parameter -passThru which states output from @@ -788,8 +676,8 @@ public string LiteralPath [Parameter] public SwitchParameter PassThru { - get { return _passThrough; } - set { _passThrough = value; } + get => _passThrough; + set => _passThrough = value; } /// @@ -797,7 +685,7 @@ public SwitchParameter PassThru /// to use for the push. If the parameter is missing or empty the default /// location stack is used. /// - [Parameter(ParameterSetName = stackSet, ValueFromPipelineByPropertyName = true)] + [Parameter(ParameterSetName = StackParameterSet, ValueFromPipelineByPropertyName = true)] public string StackName { get; set; } #endregion Command parameters @@ -805,9 +693,9 @@ public SwitchParameter PassThru #region Command data /// - /// The filter used when doing a dir + /// The filter used when doing a dir. /// - private string _path = String.Empty; + private string _path = string.Empty; /// /// Determines if output should be passed through for @@ -829,8 +717,8 @@ protected override void ProcessRecord() switch (ParameterSetName) { - case pathSet: - case literalPathSet: + case PathParameterSet: + case LiteralPathParameterSet: try { // Change the current working directory @@ -840,7 +728,7 @@ protected override void ProcessRecord() Path = SessionState.Internal.GetSingleProvider(Commands.FileSystemProvider.ProviderName).Home; } - result = SessionState.Path.SetLocation(Path, CmdletProviderContext); + result = SessionState.Path.SetLocation(Path, CmdletProviderContext, ParameterSetName == LiteralPathParameterSet); } catch (PSNotSupportedException notSupported) { @@ -877,9 +765,10 @@ protected override void ProcessRecord() argException.ErrorRecord, argException)); } + break; - case stackSet: + case StackParameterSet: try { @@ -907,10 +796,10 @@ protected override void ProcessRecord() { WriteObject(result); } - } // ProcessRecord + } #endregion Command code - } // SetLocationCommand + } #endregion SetLocationCommand @@ -920,48 +809,39 @@ protected override void ProcessRecord() /// The core command for setting/changing location and pushing it onto a location stack. /// This is the equivalent of the pushd command. /// - [Cmdlet(VerbsCommon.Push, "Location", DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113370")] + [Cmdlet(VerbsCommon.Push, "Location", DefaultParameterSetName = PathParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113370")] public class PushLocationCommand : CoreCommandBase { #region Command parameters + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string Path { - get - { - return _path; - } - set - { - _path = value; - } + get => _path; + set => _path = value; } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { - get - { - return _path; - } // get - + get => _path; set { base.SuppressWildcardExpansion = true; _path = value; - } // set - } // LiteralPath - + } + } /// /// Gets or sets the parameter -passThru which states output from @@ -970,15 +850,9 @@ public string LiteralPath [Parameter] public SwitchParameter PassThru { - get - { - return _passThrough; - } // get - set - { - _passThrough = value; - } //set - } // PassThru + get => _passThrough; + set => _passThrough = value; + } /// /// Gets or sets the StackName parameter which determines which location stack @@ -988,24 +862,18 @@ public SwitchParameter PassThru [Parameter(ValueFromPipelineByPropertyName = true)] public string StackName { - get - { - return _stackName; - } // get - set - { - _stackName = value; - } //set - } // StackName + get => _stackName; + set => _stackName = value; + } #endregion Command parameters #region Command data /// - /// The filter used when doing a dir + /// The filter used when doing a dir. /// - private string _path = String.Empty; + private string _path = string.Empty; /// /// Determines if output should be passed through for @@ -1085,11 +953,11 @@ protected override void ProcessRecord() argException)); return; } - } // Path != null - } // ProcessRecord + } + } #endregion Command code - } // PushLocationCommand + } #endregion PushLocationCommand @@ -1111,15 +979,9 @@ public class PopLocationCommand : CoreCommandBase [Parameter] public SwitchParameter PassThru { - get - { - return _passThrough; - } // get - set - { - _passThrough = value; - } //set - } // PassThru + get => _passThrough; + set => _passThrough = value; + } /// /// Gets or sets the StackName parameter which determines which location stack @@ -1129,15 +991,9 @@ public SwitchParameter PassThru [Parameter(ValueFromPipelineByPropertyName = true)] public string StackName { - get - { - return _stackName; - } // get - set - { - _stackName = value; - } //set - } // StackName + get => _stackName; + set => _stackName = value; + } #endregion Command parameters @@ -1156,10 +1012,8 @@ public string StackName #endregion Command data - #region Command code - /// /// Gets the top container from the location stack and sets the /// location to it. @@ -1209,10 +1063,10 @@ protected override void ProcessRecord() itemNotFound)); return; } - } // ProcessRecord + } #endregion Command code - } // PopLocationCommand + } #endregion PopLocationCommand @@ -1223,86 +1077,52 @@ protected override void ProcessRecord() /// /// Mounts a drive in the Monad namespace. /// - [Cmdlet(VerbsCommon.New, "PSDrive", SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113357")] + [Cmdlet(VerbsCommon.New, "PSDrive", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low, + SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113357")] public class NewPSDriveCommand : CoreCommandWithCredentialsBase { #region Command parameters /// - /// Gets or sets the name of the drive + /// Gets or sets the name of the drive. /// - /// [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string Name { - get { return _name; } - set - { - if (value == null) - { - throw PSTraceSource.NewArgumentNullException("value"); - } - - _name = value; - } + get => _name; + set => _name = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value)); } /// - /// Gets or sets the provider ID + /// Gets or sets the provider ID. /// - /// [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string PSProvider { - get { return _provider; } - set - { - if (value == null) - { - throw PSTraceSource.NewArgumentNullException("value"); - } - - _provider = value; - } + get => _provider; + set => _provider = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value)); } /// /// Gets or sets the root of the drive. This path should be /// a namespace specific path. /// - /// [Parameter(Position = 2, Mandatory = true, ValueFromPipelineByPropertyName = true)] [AllowEmptyString] public string Root { - get { return _root; } - set - { - if (value == null) - { - throw PSTraceSource.NewArgumentNullException("value"); - } - - _root = value; - } + get => _root; + set => _root = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value)); } /// - /// Gets or sets the description of the drive + /// Gets or sets the description of the drive. /// [Parameter(ValueFromPipelineByPropertyName = true)] public string Description { - get { return _description; } - set - { - if (value == null) - { - throw PSTraceSource.NewArgumentNullException("value"); - } - - _description = value; - } + get => _description; + set => _description = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value)); } /// @@ -1311,6 +1131,7 @@ public string Description [Parameter(ValueFromPipelineByPropertyName = true)] public string Scope { get; set; } +#if !UNIX /// /// Gets or sets the Persist Switch parameter. /// If this switch parameter is set then the created PSDrive @@ -1319,58 +1140,54 @@ public string Description [Parameter(ValueFromPipelineByPropertyName = true)] public SwitchParameter Persist { - get { return _persist; } - set { _persist = value; } + get => _persist; + set => _persist = value; } - private bool _persist = false; + private bool _persist = false; +#endif /// /// Gets the dynamic parameters for the new-psdrive cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { return SessionState.Drive.NewDriveDynamicParameters(PSProvider, context); } /// - /// new-psdrive always supports ShouldProcess + /// New-psdrive always supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get { return true; } - } + protected override bool ProviderSupportsShouldProcess => true; + #endregion Command parameters #region Command data /// - /// The name of the drive + /// The name of the drive. /// private string _name; /// - /// The provider ID for the drive + /// The provider ID for the drive. /// private string _provider; /// - /// The namespace specific path of the root of the drive + /// The namespace specific path of the root of the drive. /// private string _root; /// - /// A description for the drive + /// A description for the drive. /// private string _description; @@ -1379,7 +1196,7 @@ protected override bool ProviderSupportsShouldProcess #region Command code /// - /// Adds a new drive to the Monad namespace + /// Adds a new drive to the Monad namespace. /// protected override void ProcessRecord() { @@ -1407,7 +1224,7 @@ protected override void ProcessRecord() string resourceTemplate = NavigationResources.NewDriveConfirmResourceTemplate; string resource = - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, resourceTemplate, Name, @@ -1416,6 +1233,7 @@ protected override void ProcessRecord() if (ShouldProcess(resource, action)) { +#if !UNIX // -Persist switch parameter is supported only for FileSystem provider. if (Persist && !provider.Name.Equals(FileSystemProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { @@ -1423,6 +1241,12 @@ protected override void ProcessRecord() ThrowTerminatingError(er); } + // Trimming forward and backward slash for FileSystem provider when -Persist is used. + if (Persist && provider.Name.Equals(FileSystemProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) + { + Root = Root.TrimEnd('/', '\\'); + } + // Create the new drive PSDriveInfo newDrive = new PSDriveInfo( @@ -1432,7 +1256,17 @@ protected override void ProcessRecord() Description, Credential, Persist); - +#else + // Create the new drive + PSDriveInfo newDrive = + new PSDriveInfo( + Name, + provider, + Root, + Description, + Credential, + persist: false); +#endif try { SessionState.Drive.New(newDrive, Scope, CmdletProviderContext); @@ -1487,7 +1321,7 @@ protected override void ProcessRecord() } } } - } // ProcessRecord + } #endregion Command code } @@ -1506,37 +1340,29 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase /// Globs on both the drive name and the provider name to get a list of Drives /// that match the glob filters. /// - /// /// /// The name of the drive(s) to returned. The name can contain glob characters. /// - /// /// /// The name of the provider(s) to return. The name can contain glob characters. /// - /// /// /// The scope to get the drives from. If this parameter is null or empty all drives /// will be retrieved. /// - /// /// /// A collection of the drives that match the filters. /// - /// /// /// - /// /// /// If is less than zero, or not /// a number and not "script", "global", "local", or "private" /// - /// /// /// If is less than zero or greater than the number of currently /// active scopes. /// - /// internal List GetMatchingDrives( string driveName, string[] providerNames, @@ -1553,11 +1379,11 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase { tracer.WriteLine("ProviderName: {0}", providerName); - bool providerNameEmpty = String.IsNullOrEmpty(providerName); + bool providerNameEmpty = string.IsNullOrEmpty(providerName); bool providerNameContainsWildcardCharacters = WildcardPattern.ContainsWildcardCharacters(providerName); - bool driveNameEmpty = String.IsNullOrEmpty(driveName); + bool driveNameEmpty = string.IsNullOrEmpty(driveName); bool driveNameContainsWildcardCharacters = WildcardPattern.ContainsWildcardCharacters(driveName); @@ -1576,7 +1402,7 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase // exist. if (!driveNameEmpty && !driveNameContainsWildcardCharacters) { - if (String.IsNullOrEmpty(scope)) + if (string.IsNullOrEmpty(scope)) { SessionState.Drive.Get(driveName); } @@ -1586,7 +1412,6 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase } } - WildcardPattern providerMatcher = null; PSSnapinQualifiedName pssnapinQualifiedProviderName = null; @@ -1606,7 +1431,6 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase WildcardOptions.IgnoreCase); } - WildcardPattern nameMatcher = null; if (!driveNameEmpty) @@ -1623,12 +1447,12 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase if (base.SuppressWildcardExpansion) { - if (String.Equals(drive.Name, driveName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(drive.Name, driveName, StringComparison.OrdinalIgnoreCase)) addDrive = true; } else { - if (nameMatcher.IsMatch(drive.Name)) + if (nameMatcher != null && nameMatcher.IsMatch(drive.Name)) addDrive = true; } @@ -1639,13 +1463,14 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase { results.Add(drive); } - } // nameMatcher.IsMatch() - } // foreach Drive + } + } } + results.Sort(); return results; } - } // DriveMatchingCoreCommandBase + } #endregion DriveMatchingCoreCommandBase @@ -1654,49 +1479,42 @@ public class DriveMatchingCoreCommandBase : CoreCommandBase /// /// Removes a drive that is mounted in the Monad namespace. /// - [Cmdlet(VerbsCommon.Remove, "PSDrive", DefaultParameterSetName = "Name", SupportsShouldProcess = true, SupportsTransactions = true, + [Cmdlet(VerbsCommon.Remove, "PSDrive", DefaultParameterSetName = NameParameterSet, SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113376")] public class RemovePSDriveCommand : DriveMatchingCoreCommandBase { #region Command parameters + private const string NameParameterSet = "Name"; + private const string LiteralNameParameterSet = "LiteralName"; + /// /// Gets or sets the name of the drive to remove. /// - [Parameter(Position = 0, ParameterSetName = "Name", + [Parameter(Position = 0, ParameterSetName = NameParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [AllowNull] [AllowEmptyCollection] public string[] Name { - get - { - return _names; - } - set - { - _names = value; - } - } // Name + get => _names; + set => _names = value; + } /// - /// Gets or sets the literal name parameter to the command + /// Gets or sets the literal name parameter to the command. /// - [Parameter(Position = 0, ParameterSetName = "LiteralName", + [Parameter(Position = 0, ParameterSetName = LiteralNameParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] public string[] LiteralName { - get - { - return _names; - } // get - + get => _names; set { base.SuppressWildcardExpansion = true; _names = value; - } // set - } // LiteralName + } + } /// /// Gets or sets the name provider(s) for which the drives should be removed. @@ -1704,15 +1522,8 @@ public string[] LiteralName [Parameter(ValueFromPipelineByPropertyName = true)] public string[] PSProvider { - get { return _provider; } - set - { - if (value == null) - { - value = Utils.EmptyArray(); - } - _provider = value; - } + get => _provider; + set => _provider = value ?? Array.Empty(); } /// @@ -1728,22 +1539,18 @@ public string[] PSProvider /// Gets or sets the force property which determines if the drive /// should be removed even if there were errors. /// - /// [Parameter] public override SwitchParameter Force { - get { return base.Force; } - set { base.Force = value; } + get => base.Force; + set => base.Force = value; } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get { return true; } - } + protected override bool ProviderSupportsShouldProcess => true; #endregion Command parameters @@ -1757,7 +1564,7 @@ protected override bool ProviderSupportsShouldProcess /// /// The name of the provider(s) for which to remove all drives. /// - private string[] _provider = new string[0]; + private string[] _provider = Array.Empty(); #endregion Command data @@ -1789,7 +1596,7 @@ protected override void ProcessRecord() foreach (PSDriveInfo drive in GetMatchingDrives(driveName, PSProvider, Scope)) { string resource = - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, resourceTemplate, drive.Name, @@ -1813,6 +1620,7 @@ protected override void ProcessRecord() invalidOperation)); continue; } + SessionState.Drive.Remove(drive.Name, Force, Scope, CmdletProviderContext); } } @@ -1836,10 +1644,10 @@ protected override void ProcessRecord() WriteError(new ErrorRecord(e.ErrorRecord, e)); } } - } // ProcessRecord + } #endregion Command code - } // RemovePSDriveCommand + } #endregion RemovePSDriveCommand @@ -1849,45 +1657,40 @@ protected override void ProcessRecord() /// Gets a specified or listing of drives that are mounted in the Monad /// namespace. /// - [Cmdlet(VerbsCommon.Get, "PSDrive", DefaultParameterSetName = "Name", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113327")] + [Cmdlet(VerbsCommon.Get, "PSDrive", DefaultParameterSetName = NameParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113327")] [OutputType(typeof(PSDriveInfo))] public class GetPSDriveCommand : DriveMatchingCoreCommandBase { #region Command parameters + private const string NameParameterSet = "Name"; + private const string LiteralNameParameterSet = "LiteralName"; + /// /// Gets or sets the drive name the user is looking for. /// - /// /// /// If the drive name is left empty, all drives will be /// returned. A globing or regular expression can also be /// supplied and any drive names that match the expression /// will be returned. /// - [Parameter(Position = 0, ParameterSetName = "Name", ValueFromPipelineByPropertyName = true)] + [Parameter(Position = 0, ParameterSetName = NameParameterSet, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] public string[] Name { - get { return _name; } - set - { - if (value == null) - { - value = new string[] { "*" }; - } - _name = value; - } + get => _name; + set => _name = value ?? new string[] { "*" }; } /// - /// Gets or sets the literal name parameter to the command + /// Gets or sets the literal name parameter to the command. /// - [Parameter(Position = 0, ParameterSetName = "LiteralName", + [Parameter(Position = 0, ParameterSetName = LiteralNameParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] public string[] LiteralName { - get { return _name; } + get => _name; set { base.SuppressWildcardExpansion = true; @@ -1898,7 +1701,6 @@ public string[] LiteralName /// /// Gets or sets the scope parameter to the command. /// - /// [Parameter(ValueFromPipelineByPropertyName = true)] public string Scope { get; set; } @@ -1906,7 +1708,6 @@ public string[] LiteralName /// Gets or sets the provider name for the /// drives that should be retrieved. /// - /// /// /// If the provider is left empty, all drives will be /// returned. A globing or regular expression can also be @@ -1916,15 +1717,8 @@ public string[] LiteralName [Parameter(ValueFromPipelineByPropertyName = true)] public string[] PSProvider { - get { return _provider; } - set - { - if (value == null) - { - value = Utils.EmptyArray(); - } - _provider = value; - } + get => _provider; + set => _provider = value ?? Array.Empty(); } #endregion Command parameters @@ -1939,7 +1733,7 @@ public string[] PSProvider /// /// The provider ID for the drives you want to see. /// - private string[] _provider = new string[0]; + private string[] _provider = Array.Empty(); #endregion Command data @@ -2031,10 +1825,10 @@ protected override void ProcessRecord() argException)); } } - } // ProcessRecord + } #endregion Command code - } // GetPSDriveCommand + } #endregion GetPSDriveCommand @@ -2047,102 +1841,74 @@ protected override void ProcessRecord() /// /// Gets the specified item using the namespace providers. /// - [Cmdlet(VerbsCommon.Get, "Item", DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113319")] + [Cmdlet(VerbsCommon.Get, "Item", DefaultParameterSetName = PathParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113319")] public class GetItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + /// /// Gets or sets the path to item to get. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { - get - { - return _paths; - } - set - { - _paths = value; - } - } // Path + get => _paths; + set => _paths = value; + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get - { - return _paths; - } // get - + get => _paths; set { base.SuppressWildcardExpansion = true; _paths = value; - } // set - } // LiteralPath + } + } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { - get - { - return base.Filter; - } - set - { - base.Filter = value; - } + get => base.Filter; + set => base.Filter = value; } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { - get - { - return base.Include; - } // get - - set - { - base.Include = value; - } // set - } // Include + get => base.Include; + set => base.Include = value; + } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { - get - { - return base.Exclude; - } // get - - set - { - base.Exclude = value; - } // set - } // Exclude + get => base.Exclude; + set => base.Exclude = value; + } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -2152,41 +1918,32 @@ public override string[] Exclude /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get - { - return base.Force; - } - set - { - base.Force = value; - } - } // Force + get => base.Force; + set => base.Force = value; + } /// /// Gets the dynamic parameters for the get-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Item.GetItemDynamicParameters(Path[0], context); } + return InvokeProvider.Item.GetItemDynamicParameters(".", context); - } // GetDynamicParameters + } #endregion Command parameters @@ -2240,10 +1997,10 @@ protected override void ProcessRecord() pathNotFound)); } } - } // ProcessRecord + } #endregion Command code - } // GetItemCommand + } #endregion GetItemCommand @@ -2252,48 +2009,47 @@ protected override void ProcessRecord() /// /// Creates the specified item using the namespace providers. /// - [Cmdlet(VerbsCommon.New, "Item", DefaultParameterSetName = "pathSet", SupportsShouldProcess = true, SupportsTransactions = true, + [Cmdlet(VerbsCommon.New, "Item", DefaultParameterSetName = PathParameterSet, SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113353")] public class NewItemCommand : CoreCommandWithCredentialsBase { #region Command parameters - private const string nameSet = "nameSet"; - private const string pathSet = "pathSet"; + private const string NameParameterSet = "nameSet"; + private const string PathParameterSet = "pathSet"; /// /// Gets or sets the container path to create the item in. /// - [Parameter(Position = 0, ParameterSetName = "pathSet", Mandatory = true, ValueFromPipelineByPropertyName = true)] - [Parameter(Position = 0, ParameterSetName = "nameSet", Mandatory = false, ValueFromPipelineByPropertyName = true)] + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] + [Parameter(Position = 0, ParameterSetName = NameParameterSet, Mandatory = false, ValueFromPipelineByPropertyName = true)] public string[] Path { get; set; } /// - /// Gets or sets the name of the item to create + /// Gets or sets the name of the item to create. /// - [Parameter(ParameterSetName = "nameSet", Mandatory = true, ValueFromPipelineByPropertyName = true)] + [Parameter(ParameterSetName = NameParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [AllowNull] [AllowEmptyString] public string Name { get; set; } /// - /// Gets or sets the type of the item to create + /// Gets or sets the type of the item to create. /// [Parameter(ValueFromPipelineByPropertyName = true)] [Alias("Type")] public string ItemType { get; set; } /// - /// Gets or sets the content of the item to create + /// Gets or sets the content of the item to create. /// [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [Alias("Target")] public object Value { get; set; } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -2303,51 +2059,42 @@ public class NewItemCommand : CoreCommandWithCredentialsBase /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get { return base.Force; } - set { base.Force = value; } + get => base.Force; + set => base.Force = value; } /// /// Gets the dynamic parameters for the new-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { // Path is only globbed if Name is specified. - if (String.IsNullOrEmpty(Name)) + if (string.IsNullOrEmpty(Name)) return InvokeProvider.Item.NewItemDynamicParameters(WildcardPattern.Escape(Path[0]), ItemType, Value, context); else return InvokeProvider.Item.NewItemDynamicParameters(Path[0], ItemType, Value, context); } + return InvokeProvider.Item.NewItemDynamicParameters(".", ItemType, Value, context); } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(Path); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(Path); #endregion Command parameters @@ -2364,7 +2111,7 @@ protected override void ProcessRecord() { if (Path == null || Path.Length == 0) { - Path = new string[] { String.Empty }; + Path = new string[] { string.Empty }; } foreach (string path in Path) @@ -2402,10 +2149,10 @@ protected override void ProcessRecord() pathNotFound)); } } - } // ProcessRecord + } #endregion Command code - } // NewItemCommand + } #endregion NewItemCommand @@ -2414,37 +2161,34 @@ protected override void ProcessRecord() /// /// Sets the specified item using the namespace providers. /// - [Cmdlet(VerbsCommon.Set, "Item", SupportsShouldProcess = true, DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113395")] + [Cmdlet(VerbsCommon.Set, "Item", SupportsShouldProcess = true, DefaultParameterSetName = PathParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113395")] public class SetItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + /// /// Gets or sets the path to item to set. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string[] Path { - get - { - return _paths; - } - set - { - _paths = value; - } - } // Path + get => _paths; + set => _paths = value; + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get { return _paths; } + get => _paths; set { base.SuppressWildcardExpansion = true; @@ -2453,15 +2197,14 @@ public string[] LiteralPath } /// - /// Gets or sets the value of the item to be set + /// Gets or sets the value of the item to be set. /// [Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public object Value { get; set; } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -2471,12 +2214,11 @@ public string[] LiteralPath /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get { return base.Force; } - set { base.Force = value; } + get => base.Force; + set => base.Force = value; } /// @@ -2484,77 +2226,68 @@ public override SwitchParameter Force /// if the object that is set should be written to the pipeline. /// Defaults to false. /// - /// [Parameter] public SwitchParameter PassThru { - get { return _passThrough; } - set { _passThrough = value; } + get => _passThrough; + set => _passThrough = value; } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { - get { return base.Filter; } - set { base.Filter = value; } + get => base.Filter; + set => base.Filter = value; } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { - get { return base.Include; } - set { base.Include = value; } - } // Include + get => base.Include; + set => base.Include = value; + } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { - get { return base.Exclude; } - set { base.Exclude = value; } + get => base.Exclude; + set => base.Exclude = value; } /// /// Gets the dynamic parameters for the set-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Item.SetItemDynamicParameters(Path[0], Value, context); } + return InvokeProvider.Item.SetItemDynamicParameters(".", Value, context); } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(_paths); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(_paths); #endregion Command parameters #region Command data @@ -2619,10 +2352,10 @@ protected override void ProcessRecord() pathNotFound)); } } - } // ProcessRecord + } #endregion Command code - } // SetItemCommand + } #endregion SetItemCommand @@ -2631,118 +2364,84 @@ protected override void ProcessRecord() /// /// Removes the specified item using the namespace providers. /// - [Cmdlet(VerbsCommon.Remove, "Item", SupportsShouldProcess = true, DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113373")] + [Cmdlet(VerbsCommon.Remove, "Item", SupportsShouldProcess = true, DefaultParameterSetName = PathParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113373")] public class RemoveItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { - get - { - return _paths; - } - set - { - _paths = value; - } - } // Path + get => _paths; + set => _paths = value; + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get - { - return _paths; - } // get - + get => _paths; set { base.SuppressWildcardExpansion = true; _paths = value; - } // set - } // LiteralPath + } + } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { - get - { - return base.Filter; - } - set - { - base.Filter = value; - } + get => base.Filter; + set => base.Filter = value; } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { - get - { - return base.Include; - } // get - - set - { - base.Include = value; - } // set - } // Include + get => base.Include; + set => base.Include = value; + } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { - get - { - return base.Exclude; - } // get - - set - { - base.Exclude = value; - } // set - } // Exclude + get => base.Exclude; + set => base.Exclude = value; + } /// - /// Gets or sets the recurse property + /// Gets or sets the recurse property. /// [Parameter] public SwitchParameter Recurse { - get - { - return _recurse; - } - set - { - _recurse = value; - } - } // Recurse + get => _recurse; + set => _recurse = value; + } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -2752,59 +2451,44 @@ public SwitchParameter Recurse /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get - { - return base.Force; - } - set - { - base.Force = value; - } - } // Force + get => base.Force; + set => base.Force = value; + } /// /// Gets the dynamic parameters for the remove-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Item.RemoveItemDynamicParameters(Path[0], Recurse, context); } + return InvokeProvider.Item.RemoveItemDynamicParameters(".", Recurse, context); - } // GetDynamicParameters + } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(_paths); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(_paths); #endregion Command parameters #region Command data /// - /// The path used when doing a delete + /// The path used when doing a delete. /// private string[] _paths; @@ -2848,6 +2532,7 @@ protected override void ProcessRecord() new Collection(), null); } + try { resolvedPSPaths = SessionState.Path.GetResolvedPSPathFromPSPath(path, currentContext); @@ -3041,6 +2726,7 @@ protected override void ProcessRecord() { continue; } + shouldRecurse = true; } @@ -3092,10 +2778,10 @@ protected override void ProcessRecord() } } } - } // ProcessRecord + } #endregion Command code - } // RemoveItemCommand + } #endregion RemoveItemCommand @@ -3105,37 +2791,35 @@ protected override void ProcessRecord() /// Moves an item from the specified location to the specified destination using /// the namespace providers. /// - [Cmdlet(VerbsCommon.Move, "Item", DefaultParameterSetName = "Path", SupportsShouldProcess = true, SupportsTransactions = true, + [Cmdlet(VerbsCommon.Move, "Item", DefaultParameterSetName = PathParameterSet, SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113350")] public class MoveItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { - get - { - return _paths; - } - set - { - _paths = value; - } - } // Path + get => _paths; + set => _paths = value; + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get { return _paths; } + get => _paths; set { base.SuppressWildcardExpansion = true; @@ -3144,15 +2828,14 @@ public string[] LiteralPath } /// - /// Gets or sets the destination property + /// Gets or sets the destination property. /// [Parameter(Position = 1, ValueFromPipelineByPropertyName = true)] public string Destination { get; set; } = "."; /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -3162,42 +2845,41 @@ public string[] LiteralPath /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get { return base.Force; } - set { base.Force = value; } + get => base.Force; + set => base.Force = value; } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { - get { return base.Filter; } - set { base.Filter = value; } + get => base.Filter; + set => base.Filter = value; } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { - get { return base.Include; } - set { base.Include = value; } + get => base.Include; + set => base.Include = value; } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { - get { return base.Exclude; } - set { base.Exclude = value; } + get => base.Exclude; + set => base.Exclude = value; } /// @@ -3205,47 +2887,38 @@ public override string[] Exclude /// if the object that is set should be written to the pipeline. /// Defaults to false. /// - /// [Parameter] public SwitchParameter PassThru { - get { return _passThrough; } - set { _passThrough = value; } + get => _passThrough; + set => _passThrough = value; } /// /// Gets the dynamic parameters for the move-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Item.MoveItemDynamicParameters(Path[0], Destination, context); } + return InvokeProvider.Item.MoveItemDynamicParameters(".", Destination, context); } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(_paths); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(_paths); #endregion Command parameters @@ -3306,7 +2979,7 @@ private Collection GetResolvedPaths(string path) } /// - /// Moves the specified item to the specified destination + /// Moves the specified item to the specified destination. /// protected override void ProcessRecord() { @@ -3314,7 +2987,7 @@ protected override void ProcessRecord() { if (base.SuppressWildcardExpansion) { - MoveItem(path); + MoveItem(path, literalPath: true); } else { @@ -3323,210 +2996,204 @@ protected override void ProcessRecord() foreach (PathInfo resolvedPathInfo in resolvedPaths) { string resolvedPath = resolvedPathInfo.Path; - MoveItem(resolvedPath); + MoveItem(resolvedPath, literalPath: true); } } } - } // ProcessRecord + } - private void MoveItem(string path) + private void MoveItem(string path, bool literalPath = false) { CmdletProviderContext currentContext = CmdletProviderContext; + currentContext.SuppressWildcardExpansion = literalPath; - do + try { - try - { - string escapedPath = path; - if (!base.SuppressWildcardExpansion) { escapedPath = WildcardPattern.Escape(path); } - if (!InvokeProvider.Item.Exists(escapedPath, currentContext)) - { - PSInvalidOperationException invalidOperation = - (PSInvalidOperationException) - PSTraceSource.NewInvalidOperationException( - NavigationResources.MoveItemDoesntExist, - path); - - WriteError( - new ErrorRecord( - invalidOperation.ErrorRecord, - invalidOperation)); - continue; - } - } - catch (PSNotSupportedException notSupported) - { - WriteError( - new ErrorRecord( - notSupported.ErrorRecord, - notSupported)); - continue; - } - catch (DriveNotFoundException driveNotFound) - { - WriteError( - new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - continue; - } - catch (ProviderNotFoundException providerNotFound) - { - WriteError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - continue; - } - catch (ItemNotFoundException pathNotFound) + if (!InvokeProvider.Item.Exists(path, currentContext)) { - WriteError( - new ErrorRecord( - pathNotFound.ErrorRecord, - pathNotFound)); - continue; - } - + PSInvalidOperationException invalidOperation = + (PSInvalidOperationException) + PSTraceSource.NewInvalidOperationException( + NavigationResources.MoveItemDoesntExist, + path); - // See if the item to be moved is in use. - bool isCurrentLocationOrAncestor = false; - try - { - isCurrentLocationOrAncestor = SessionState.Path.IsCurrentLocationOrAncestor(path, currentContext); - } - catch (PSNotSupportedException notSupported) - { - WriteError( - new ErrorRecord( - notSupported.ErrorRecord, - notSupported)); - continue; - } - catch (DriveNotFoundException driveNotFound) - { WriteError( new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - continue; - } - catch (ProviderNotFoundException providerNotFound) - { - WriteError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - continue; - } - catch (ItemNotFoundException pathNotFound) - { - WriteError( - new ErrorRecord( - pathNotFound.ErrorRecord, - pathNotFound)); - continue; + invalidOperation.ErrorRecord, + invalidOperation)); + return; } + } + catch (PSNotSupportedException notSupported) + { + WriteError( + new ErrorRecord( + notSupported.ErrorRecord, + notSupported)); + return; + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + return; + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + return; + } + catch (ItemNotFoundException pathNotFound) + { + WriteError( + new ErrorRecord( + pathNotFound.ErrorRecord, + pathNotFound)); + return; + } - if (isCurrentLocationOrAncestor) - { - PSInvalidOperationException invalidOperation = - (PSInvalidOperationException) - PSTraceSource.NewInvalidOperationException( - NavigationResources.MoveItemInUse, - path); + // See if the item to be moved is in use. + bool isCurrentLocationOrAncestor = false; + try + { + isCurrentLocationOrAncestor = SessionState.Path.IsCurrentLocationOrAncestor(path, currentContext); + } + catch (PSNotSupportedException notSupported) + { + WriteError( + new ErrorRecord( + notSupported.ErrorRecord, + notSupported)); + return; + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + return; + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + return; + } + catch (ItemNotFoundException pathNotFound) + { + WriteError( + new ErrorRecord( + pathNotFound.ErrorRecord, + pathNotFound)); + return; + } - WriteError( - new ErrorRecord( - invalidOperation.ErrorRecord, - invalidOperation)); - continue; - } + if (isCurrentLocationOrAncestor) + { + PSInvalidOperationException invalidOperation = + (PSInvalidOperationException) + PSTraceSource.NewInvalidOperationException( + NavigationResources.MoveItemInUse, + path); - // Default to the CmdletProviderContext that will direct output to - // the pipeline. + WriteError( + new ErrorRecord( + invalidOperation.ErrorRecord, + invalidOperation)); + return; + } - CmdletProviderContext currentCommandContext = currentContext; - currentCommandContext.PassThru = PassThru; + // Default to the CmdletProviderContext that will direct output to + // the pipeline. - tracer.WriteLine("Moving {0} to {1}", path, Destination); + currentContext.PassThru = PassThru; - try - { - // Now do the move - string escapedPath = path; - if (!base.SuppressWildcardExpansion) { escapedPath = WildcardPattern.Escape(path); } - InvokeProvider.Item.Move(escapedPath, Destination, currentCommandContext); - } - catch (PSNotSupportedException notSupported) - { - WriteError( - new ErrorRecord( - notSupported.ErrorRecord, - notSupported)); - continue; - } - catch (DriveNotFoundException driveNotFound) - { - WriteError( - new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - continue; - } - catch (ProviderNotFoundException providerNotFound) - { - WriteError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - continue; - } - catch (ItemNotFoundException pathNotFound) - { - WriteError( - new ErrorRecord( - pathNotFound.ErrorRecord, - pathNotFound)); - continue; - } + tracer.WriteLine("Moving {0} to {1}", path, Destination); + + try + { + // Now do the move + InvokeProvider.Item.Move(path, Destination, currentContext); + } + catch (PSNotSupportedException notSupported) + { + WriteError( + new ErrorRecord( + notSupported.ErrorRecord, + notSupported)); + return; + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + return; + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + return; + } + catch (ItemNotFoundException pathNotFound) + { + WriteError( + new ErrorRecord( + pathNotFound.ErrorRecord, + pathNotFound)); + return; } - while (false); } #endregion Command code - } // MoveItemCommand + } #endregion MoveItemCommand #region RenameItemCommand /// - /// Renames a specified item to a new name using the namespace providers + /// Renames a specified item to a new name using the namespace providers. /// - [Cmdlet(VerbsCommon.Rename, "Item", SupportsShouldProcess = true, SupportsTransactions = true, DefaultParameterSetName = "ByPath", + [Cmdlet(VerbsCommon.Rename, "Item", SupportsShouldProcess = true, SupportsTransactions = true, DefaultParameterSetName = ByPathParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113382")] public class RenameItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + private const string ByPathParameterSet = "ByPath"; + private const string ByLiteralPathParameterSet = "ByLiteralPath"; + /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")] + [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ByPathParameterSet)] public string Path { - get { return _path; } - set { _path = value; } + get => _path; + set => _path = value; } /// - /// Gets or sets the literal path property + /// Gets or sets the literal path property. /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")] - [Alias("PSPath")] + [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ByLiteralPathParameterSet)] + [Alias("PSPath", "LP")] public string LiteralPath { - get { return _path; } + get => _path; set { _path = value; @@ -3535,15 +3202,14 @@ public string LiteralPath } /// - /// Gets or sets the newName property + /// Gets or sets the newName property. /// [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string NewName { get; set; } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -3553,57 +3219,45 @@ public string LiteralPath /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get { return base.Force; } - set { base.Force = value; } + get => base.Force; + set => base.Force = value; } - /// /// Gets or sets the pass through property which determines /// if the object that is set should be written to the pipeline. /// Defaults to false. /// - /// [Parameter] public SwitchParameter PassThru { - get { return _passThrough; } - set { _passThrough = value; } + get => _passThrough; + set => _passThrough = value; } /// /// Gets the dynamic parameters for the rename-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { return InvokeProvider.Item.RenameItemDynamicParameters(Path, NewName, context); } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(new string[] { _path }); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(new string[] { _path }); #endregion Command parameters @@ -3624,22 +3278,86 @@ protected override bool ProviderSupportsShouldProcess #region Command code + private Collection GetResolvedPaths(string path) + { + Collection results = null; + try + { + results = SessionState.Path.GetResolvedPSPathFromPSPath(path, CmdletProviderContext); + } + catch (PSNotSupportedException notSupported) + { + WriteError( + new ErrorRecord( + notSupported.ErrorRecord, + notSupported)); + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + } + catch (ItemNotFoundException pathNotFound) + { + WriteError( + new ErrorRecord( + pathNotFound.ErrorRecord, + pathNotFound)); + } + + return results; + } + /// - /// Moves the specified item to the specified destination + /// Moves the specified item to the specified destination. /// protected override void ProcessRecord() + { + if (SuppressWildcardExpansion) + { + RenameItem(Path, literalPath: true); + return; + } + + Collection resolvedPaths = GetResolvedPaths(Path); + if (resolvedPaths == null) + { + return; + } + + if (resolvedPaths.Count == 1) + { + RenameItem(resolvedPaths[0].Path, literalPath: true); + } + else + { + RenameItem(WildcardPattern.Unescape(Path), literalPath: true); + } + } + + private void RenameItem(string path, bool literalPath = false) { CmdletProviderContext currentContext = CmdletProviderContext; + currentContext.SuppressWildcardExpansion = literalPath; try { - if (!InvokeProvider.Item.Exists(Path, currentContext)) + if (!InvokeProvider.Item.Exists(path, currentContext)) { PSInvalidOperationException invalidOperation = (PSInvalidOperationException) PSTraceSource.NewInvalidOperationException( NavigationResources.RenameItemDoesntExist, - Path); + path); WriteError( new ErrorRecord( @@ -3685,7 +3403,7 @@ protected override void ProcessRecord() bool isCurrentLocationOrAncestor = false; try { - isCurrentLocationOrAncestor = SessionState.Path.IsCurrentLocationOrAncestor(_path, currentContext); + isCurrentLocationOrAncestor = SessionState.Path.IsCurrentLocationOrAncestor(path, currentContext); } catch (PSNotSupportedException notSupported) { @@ -3726,7 +3444,7 @@ protected override void ProcessRecord() (PSInvalidOperationException) PSTraceSource.NewInvalidOperationException( NavigationResources.RenamedItemInUse, - Path); + path); WriteError( new ErrorRecord( @@ -3737,15 +3455,14 @@ protected override void ProcessRecord() // Default to the CmdletProviderContext that will direct output to // the pipeline. - currentContext.PassThru = PassThru; - tracer.WriteLine("Rename {0} to {1}", Path, NewName); + tracer.WriteLine("Rename {0} to {1}", path, NewName); try { // Now do the rename - InvokeProvider.Item.Rename(Path, NewName, currentContext); + InvokeProvider.Item.Rename(path, NewName, currentContext); } catch (PSNotSupportedException notSupported) { @@ -3779,49 +3496,47 @@ protected override void ProcessRecord() pathNotFound)); return; } - } // ProcessRecord + } #endregion Command code - } // RenameItemCommand + } #endregion RenameItemCommand #region CopyItemCommand /// - /// Copies a specified item to a new location using the namespace providers + /// Copies a specified item to a new location using the namespace providers. /// - [Cmdlet(VerbsCommon.Copy, "Item", DefaultParameterSetName = "Path", SupportsShouldProcess = true, SupportsTransactions = true, + [Cmdlet(VerbsCommon.Copy, "Item", DefaultParameterSetName = PathParameterSet, SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113292")] public class CopyItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { - get - { - return _paths; - } - set - { - _paths = value; - } - } // Path + get => _paths; + set => _paths = value; + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get { return _paths; } + get => _paths; set { base.SuppressWildcardExpansion = true; @@ -3830,18 +3545,18 @@ public string[] LiteralPath } /// - /// Gets or sets the destination property + /// Gets or sets the destination property. /// [Parameter(Position = 1, ValueFromPipelineByPropertyName = true)] public string Destination { get; set; } /// - /// Gets or sets the container property + /// Gets or sets the container property. /// [Parameter] public SwitchParameter Container { - get { return _container; } + get => _container; set { _containerSpecified = true; @@ -3850,9 +3565,8 @@ public SwitchParameter Container } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -3862,56 +3576,54 @@ public SwitchParameter Container /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get { return base.Force; } - set { base.Force = value; } + get => base.Force; + set => base.Force = value; } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { - get { return base.Filter; } - set { base.Filter = value; } + get => base.Filter; + set => base.Filter = value; } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { - get { return base.Include; } - set { base.Include = value; } + get => base.Include; + set => base.Include = value; } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { - get { return base.Exclude; } - set { base.Exclude = value; } + get => base.Exclude; + set => base.Exclude = value; } /// - /// Gets or sets the recurse property + /// Gets or sets the recurse property. /// [Parameter] public SwitchParameter Recurse { - get { return _recurse; } + get => _recurse; set { _recurse = value; - // If -Container is not specified but -Recurse // is, then -Container takes on the same value // as -Recurse @@ -3927,47 +3639,38 @@ public SwitchParameter Recurse /// if the object that is set should be written to the pipeline. /// Defaults to false. /// - /// [Parameter] public SwitchParameter PassThru { - get { return _passThrough; } - set { _passThrough = value; } + get => _passThrough; + set => _passThrough = value; } /// /// Gets the dynamic parameters for the copy-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Item.CopyItemDynamicParameters(Path[0], Destination, Recurse, context); } + return InvokeProvider.Item.CopyItemDynamicParameters(".", Destination, Recurse, context); - } // GetDynamicParameters + } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(_paths); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(_paths); #endregion Command parameters @@ -4001,7 +3704,7 @@ protected override bool ProviderSupportsShouldProcess #region Command code /// - /// Copies the specified item(s) to the specified destination + /// Copies the specified item(s) to the specified destination. /// protected override void ProcessRecord() { @@ -4052,64 +3755,57 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord + } #endregion Command code - } // CopyItemCommand + } #endregion CopyItemCommand #region ClearItemCommand /// - /// Clears an item at the specified location + /// Clears an item at the specified location. /// - [Cmdlet(VerbsCommon.Clear, "Item", DefaultParameterSetName = "Path", SupportsShouldProcess = true, SupportsTransactions = true, + [Cmdlet(VerbsCommon.Clear, "Item", DefaultParameterSetName = PathParameterSet, SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113283")] public class ClearItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { - get - { - return _paths; - } - set - { - _paths = value; - } - } // Path + get => _paths; + set => _paths = value; + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get - { - return _paths; - } // get - + get => _paths; set { base.SuppressWildcardExpansion = true; _paths = value; - } // set - } // LiteralPath + } + } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -4119,103 +3815,68 @@ public string[] LiteralPath /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { - get - { - return base.Force; - } - set - { - base.Force = value; - } - } // Force + get => base.Force; + set => base.Force = value; + } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { - get - { - return base.Filter; - } - set - { - base.Filter = value; - } - } // Filter + get => base.Filter; + set => base.Filter = value; + } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { - get - { - return base.Include; - } // get - - set - { - base.Include = value; - } // set - } // Include + get => base.Include; + set => base.Include = value; + } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { - get - { - return base.Exclude; - } // get - - set - { - base.Exclude = value; - } // set - } // Exclude + get => base.Exclude; + set => base.Exclude = value; + } /// /// Gets the dynamic parameters for the clear-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Item.ClearItemDynamicParameters(Path[0], context); } + return InvokeProvider.Item.ClearItemDynamicParameters(".", context); - } // GetDynamicParameters + } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(_paths); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(_paths); #endregion Command parameters @@ -4231,7 +3892,7 @@ protected override bool ProviderSupportsShouldProcess #region Command code /// - /// Clears the specified item + /// Clears the specified item. /// protected override void ProcessRecord() { @@ -4283,143 +3944,109 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord - #endregion Command code + } - } // ClearItemCommand + #endregion Command code + } #endregion ClearItemCommand #region InvokeItemCommand /// - /// Invokes an item at the specified location + /// Invokes an item at the specified location. /// - [Cmdlet(VerbsLifecycle.Invoke, "Item", DefaultParameterSetName = "Path", SupportsShouldProcess = true, SupportsTransactions = true, + [Cmdlet(VerbsLifecycle.Invoke, "Item", DefaultParameterSetName = PathParameterSet, SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113345")] public class InvokeItemCommand : CoreCommandWithCredentialsBase { #region Command parameters + + private const string PathParameterSet = "Path"; + private const string LiteralPathParameterSet = "LiteralPath"; + /// - /// Gets or sets the path property + /// Gets or sets the path property. /// - [Parameter(Position = 0, ParameterSetName = "Path", + [Parameter(Position = 0, ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Path { - get - { - return _paths; - } - set - { - _paths = value; - } - } // Path + get => _paths; + set => _paths = value; + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// - [Parameter(ParameterSetName = "LiteralPath", + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get - { - return _paths; - } // get - + get => _paths; set { base.SuppressWildcardExpansion = true; _paths = value; - } // set - } // LiteralPath + } + } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { - get - { - return base.Filter; - } - set - { - base.Filter = value; - } - } // Filter + get => base.Filter; + set => base.Filter = value; + } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { - get - { - return base.Include; - } // get - - set - { - base.Include = value; - } // set - } // Include + get => base.Include; + set => base.Include = value; + } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { - get - { - return base.Exclude; - } // get - - set - { - base.Exclude = value; - } // set - } // Exclude + get => base.Exclude; + set => base.Exclude = value; + } /// /// Gets the dynamic parameters for the invoke-item cmdlet. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Item.InvokeItemDynamicParameters(Path[0], context); } + return InvokeProvider.Item.InvokeItemDynamicParameters(".", context); - } // GetDynamicParameters + } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// - protected override bool ProviderSupportsShouldProcess - { - get - { - return base.DoesProviderSupportShouldProcess(_paths); - } - } + protected override bool ProviderSupportsShouldProcess => DoesProviderSupportShouldProcess(_paths); #endregion Command parameters @@ -4435,7 +4062,7 @@ protected override bool ProviderSupportsShouldProcess #region Command code /// - /// Invokes the specified item + /// Invokes the specified item. /// protected override void ProcessRecord() { @@ -4481,10 +4108,10 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord + } #endregion Command code - } // InvokeItemCommand + } #endregion InvokeItemCommand @@ -4495,7 +4122,7 @@ protected override void ProcessRecord() #region GetProviderCommand /// - /// Gets a core command provider by name + /// Gets a core command provider by name. /// [Cmdlet(VerbsCommon.Get, "PSProvider", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113329")] [OutputType(typeof(ProviderInfo))] @@ -4506,13 +4133,12 @@ public class GetPSProviderCommand : CoreCommandBase /// /// Gets or sets the provider that will be removed. /// - /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty()] public string[] PSProvider { - get { return _provider; } - set { _provider = value ?? Utils.EmptyArray(); } + get => _provider; + set => _provider = value ?? Array.Empty(); } #endregion Command parameters @@ -4521,7 +4147,7 @@ public string[] PSProvider /// /// The string ID of the provider to remove. /// - private string[] _provider = new string[0]; + private string[] _provider = Array.Empty(); #endregion Command data @@ -4590,13 +4216,12 @@ protected override void ProcessRecord() } } } - } // ProcessRecord + } #endregion Command code - } // GetProviderCommand + } #endregion GetProviderCommand #endregion Provider commands -} // namespace Microsoft.PowerShell.Commands - +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/NewPropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/NewPropertyCommand.cs index 9d36ec244edf..863cee7c8b5e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/NewPropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/NewPropertyCommand.cs @@ -1,8 +1,8 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -17,7 +17,7 @@ public class NewItemPropertyCommand : ItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true)] public string[] Path @@ -25,38 +25,37 @@ public string[] Path get { return paths; - } // get + } set { paths = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return paths; - } // get + } set { base.SuppressWildcardExpansion = true; paths = value; - } // set - } // LiteralPath + } + } /// - /// The name of the property to create on the item + /// The name of the property to create on the item. /// - /// [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)] [Alias("PSProperty")] public string Name { get; set; } @@ -64,7 +63,6 @@ public string[] LiteralPath /// /// The type of the property to create on the item. /// - /// [Parameter(ValueFromPipelineByPropertyName = true)] [Alias("Type")] public string PropertyType { get; set; } @@ -72,14 +70,12 @@ public string[] LiteralPath /// /// The value of the property to create on the item. /// - /// [Parameter(ValueFromPipelineByPropertyName = true)] public object Value { get; set; } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -89,7 +85,6 @@ public string[] LiteralPath /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { @@ -97,35 +92,34 @@ public override SwitchParameter Force { return base.Force; } + set { base.Force = value; } - } // Force + } /// /// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Property.NewPropertyDynamicParameters(Path[0], Name, PropertyType, Value, context); } + return InvokeProvider.Property.NewPropertyDynamicParameters(".", Name, PropertyType, Value, context); - } // GetDynamicParameters + } #endregion Parameters @@ -136,7 +130,7 @@ internal override object GetDynamicParameters(CmdletProviderContext context) #region Command code /// - /// Creates the property on the item + /// Creates the property on the item. /// protected override void ProcessRecord() { @@ -179,9 +173,8 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord + } #endregion Command code - - } // NewItemPropertyCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs index 1b096166a7bd..46e9ba14a2dc 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs @@ -1,12 +1,12 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Management.Automation; using System.Management.Automation.Internal; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -29,26 +29,25 @@ public class SplitPathCommand : CoreCommandWithCredentialsBase #region Parameters /// - /// The parameter set name to get the parent path + /// The parameter set name to get the parent path. /// private const string parentSet = "ParentSet"; /// - /// The parameter set name to get the leaf name + /// The parameter set name to get the leaf name. /// private const string leafSet = "LeafSet"; /// - /// The parameter set name to get the leaf base name + /// The parameter set name to get the leaf base name. /// private const string leafBaseSet = "LeafBaseSet"; /// - /// The parameter set name to get the extension + /// The parameter set name to get the extension. /// private const string extensionSet = "ExtensionSet"; - /// /// The parameter set name to get the qualifier set. /// @@ -70,7 +69,7 @@ public class SplitPathCommand : CoreCommandWithCredentialsBase private const string literalPathSet = "LiteralPathSet"; /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = parentSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [Parameter(Position = 0, ParameterSetName = leafSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -82,91 +81,79 @@ public class SplitPathCommand : CoreCommandWithCredentialsBase public string[] Path { get; set; } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPathSet", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return Path; - } // get + } set { base.SuppressWildcardExpansion = true; Path = value; - } // set - } // LiteralPath + } + } /// - /// Determines if the qualifier should be returned + /// Determines if the qualifier should be returned. /// - /// /// /// If true the qualifier of the path will be returned. /// The qualifier is the drive or provider that is qualifying /// the MSH path. /// - /// [Parameter(Position = 1, ValueFromPipelineByPropertyName = true, ParameterSetName = qualifierSet, Mandatory = false)] public SwitchParameter Qualifier { get; set; } /// - /// Determines if the qualifier should be returned + /// Determines if the qualifier should be returned. /// - /// /// /// If true the qualifier of the path will be returned. /// The qualifier is the drive or provider that is qualifying /// the MSH path. /// - /// [Parameter(ParameterSetName = noQualifierSet, Mandatory = false, ValueFromPipelineByPropertyName = true)] public SwitchParameter NoQualifier { get; set; } /// - /// Determines if the parent path should be returned + /// Determines if the parent path should be returned. /// - /// /// /// If true the parent of the path will be returned. /// - /// [Parameter(ParameterSetName = parentSet, Mandatory = false, ValueFromPipelineByPropertyName = true)] public SwitchParameter Parent { get; set; } = true; /// - /// Determines if the leaf name should be returned + /// Determines if the leaf name should be returned. /// - /// /// /// If true the leaf name of the path will be returned. /// - /// [Parameter(ParameterSetName = leafSet, Mandatory = false, ValueFromPipelineByPropertyName = true)] public SwitchParameter Leaf { get; set; } /// - /// Determines if the leaf base name (name without extension) should be returned + /// Determines if the leaf base name (name without extension) should be returned. /// - /// /// /// If true the leaf base name of the path will be returned. /// - /// [Parameter(ParameterSetName = leafBaseSet, Mandatory = false, ValueFromPipelineByPropertyName = true)] public SwitchParameter LeafBase { get; set; } /// - /// Determines if the extension should be returned + /// Determines if the extension should be returned. /// - /// /// /// If true the extension of the path will be returned. /// - /// [Parameter(ParameterSetName = extensionSet, Mandatory = false, ValueFromPipelineByPropertyName = true)] public SwitchParameter Extension { get; set; } @@ -187,7 +174,6 @@ public string[] LiteralPath #region parameter data - #endregion parameter data #region Command code @@ -314,7 +300,7 @@ protected override void ProcessRecord() continue; case qualifierSet: - int separatorIndex = pathsToParse[index].IndexOf(":", StringComparison.CurrentCulture); + int separatorIndex = pathsToParse[index].IndexOf(':'); if (separatorIndex < 0) { @@ -351,6 +337,7 @@ protected override void ProcessRecord() separatorIndex + 1); } } + break; case parentSet: @@ -360,7 +347,7 @@ protected override void ProcessRecord() result = SessionState.Path.ParseParent( pathsToParse[index], - String.Empty, + string.Empty, CmdletProviderContext, true); } @@ -371,7 +358,7 @@ protected override void ProcessRecord() // provider. Since the paths for these types of // providers can't be split, asking for the parent // is asking for an empty string. - result = String.Empty; + result = string.Empty; } break; @@ -433,28 +420,25 @@ protected override void ProcessRecord() false, "Only a known parameter set should be called"); break; - } // switch + } if (result != null) { WriteObject(result); } - } // for each path - } // ProcessRecord + } + } #endregion Command code /// /// Removes either the drive or provider qualifier or both from the path. /// - /// /// /// The path to strip the provider qualifier from. /// - /// /// /// The path without the qualifier. /// - /// private string RemoveQualifier(string path) { Dbg.Diagnostics.Assert( @@ -465,7 +449,7 @@ private string RemoveQualifier(string path) if (SessionState.Path.IsProviderQualified(path)) { - int index = path.IndexOf("::", StringComparison.CurrentCulture); + int index = path.IndexOf("::", StringComparison.Ordinal); if (index != -1) { @@ -475,7 +459,7 @@ private string RemoveQualifier(string path) } else { - string driveName = String.Empty; + string driveName = string.Empty; if (SessionState.Path.IsPSAbsolute(path, out driveName)) { @@ -489,7 +473,7 @@ private string RemoveQualifier(string path) } return result; - } // RemoveQualifier - } // SplitPathCommand -} // namespace Microsoft.PowerShell.Commands + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughContentCommandBase.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughContentCommandBase.cs index cb70655f8bc4..17c7082b1a92 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughContentCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughContentCommandBase.cs @@ -1,22 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// /// The base class for the */content commands that also take - /// a passthrough parameter + /// a passthrough parameter. /// public class PassThroughContentCommandBase : ContentCommandBase { #region Parameters /// - /// Gets or sets the passthrough parameter to the command + /// Gets or sets the passthrough parameter to the command. /// [Parameter] public SwitchParameter PassThru @@ -24,16 +24,16 @@ public SwitchParameter PassThru get { return _passThrough; - } // get + } set { _passThrough = value; - } // set - } // PassThru + } + } /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// protected override bool ProviderSupportsShouldProcess @@ -62,20 +62,18 @@ protected override bool ProviderSupportsShouldProcess /// Initializes a CmdletProviderContext instance to the current context of /// the command. /// - /// /// /// A CmdletProviderContext instance initialized to the context of the current /// command. /// - /// internal CmdletProviderContext GetCurrentContext() { CmdletProviderContext currentCommandContext = CmdletProviderContext; currentCommandContext.PassThru = PassThru; return currentCommandContext; - } // GetCurrentContext + } #endregion protected members - } // PassThroughContentCommandBase -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughPropertyCommandBase.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughPropertyCommandBase.cs index 5028632301b0..27e33a015643 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughPropertyCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/PassThroughPropertyCommandBase.cs @@ -1,22 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// /// The base class for the */property commands that also take - /// a passthrough parameter + /// a passthrough parameter. /// public class PassThroughItemPropertyCommandBase : ItemPropertyCommandBase { #region Parameters /// - /// Gets or sets the passthrough parameter to the command + /// Gets or sets the passthrough parameter to the command. /// [Parameter] public SwitchParameter PassThru @@ -24,18 +24,17 @@ public SwitchParameter PassThru get { return _passThrough; - } // get + } set { _passThrough = value; - } // set - } // PassThru + } + } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -45,7 +44,6 @@ public SwitchParameter PassThru /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { @@ -53,11 +51,12 @@ public override SwitchParameter Force { return base.Force; } + set { base.Force = value; } - } // Force + } #endregion Parameters @@ -74,7 +73,7 @@ public override SwitchParameter Force #region protected members /// - /// Determines if the provider for the specified path supports ShouldProcess + /// Determines if the provider for the specified path supports ShouldProcess. /// /// protected override bool ProviderSupportsShouldProcess @@ -89,20 +88,18 @@ protected override bool ProviderSupportsShouldProcess /// Initializes a CmdletProviderContext instance to the current context of /// the command. /// - /// /// /// A CmdletProviderContext instance initialized to the context of the current /// command. /// - /// internal CmdletProviderContext GetCurrentContext() { CmdletProviderContext currentCommandContext = CmdletProviderContext; currentCommandContext.PassThru = PassThru; return currentCommandContext; - } // GetCurrentContext + } #endregion protected members - } // PassThroughItemPropertyCommandBase -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/PingPathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/PingPathCommand.cs index 66bbe573a17a..acf16bfc539f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/PingPathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/PingPathCommand.cs @@ -1,14 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// The valid values for the -PathType parameter for test-path + /// The valid values for the -PathType parameter for test-path. /// public enum TestPathType { @@ -29,7 +30,7 @@ public enum TestPathType } /// - /// A command to determine if an item exists at a specified path + /// A command to determine if an item exists at a specified path. /// [Cmdlet(VerbsDiagnostic.Test, "Path", DefaultParameterSetName = "Path", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113418")] [OutputType(typeof(bool))] @@ -38,25 +39,33 @@ public class TestPathCommand : CoreCommandWithCredentialsBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + [AllowNull] + [AllowEmptyCollection] + [AllowEmptyString] public string[] Path { get { return _paths; } + set { _paths = value; } } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] + [AllowNull] + [AllowEmptyCollection] + [AllowEmptyString] public string[] LiteralPath { get { return _paths; } + set { base.SuppressWildcardExpansion = true; @@ -65,44 +74,47 @@ public string[] LiteralPath } /// - /// Gets or sets the filter property + /// Gets or sets the filter property. /// [Parameter] public override string Filter { get { return base.Filter; } + set { base.Filter = value; } } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include { get { return base.Include; } + set { base.Include = value; } } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude { get { return base.Exclude; } + set { base.Exclude = value; } } /// - /// Gets or sets the isContainer property + /// Gets or sets the isContainer property. /// [Parameter] [Alias("Type")] public TestPathType PathType { get; set; } = TestPathType.Any; /// - /// Gets or sets the IsValid parameter + /// Gets or sets the IsValid parameter. /// [Parameter] public SwitchParameter IsValid { get; set; } = new SwitchParameter(); @@ -112,23 +124,20 @@ public override string[] Exclude /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { object result = null; if (this.PathType == TestPathType.Any && !IsValid) { - if (Path != null && Path.Length > 0) + if (Path != null && Path.Length > 0 && Path[0] != null) { result = InvokeProvider.Item.ItemExistsDynamicParameters(Path[0], context); } @@ -137,15 +146,16 @@ internal override object GetDynamicParameters(CmdletProviderContext context) result = InvokeProvider.Item.ItemExistsDynamicParameters(".", context); } } + return result; - } // GetDynamicParameters + } #endregion Parameters #region parameter data /// - /// The path to the item to ping + /// The path to the item to ping. /// private string[] _paths; @@ -158,12 +168,39 @@ internal override object GetDynamicParameters(CmdletProviderContext context) /// protected override void ProcessRecord() { + if (_paths == null || _paths.Length == 0) + { + WriteError(new ErrorRecord( + new ArgumentNullException(TestPathResources.PathIsNullOrEmptyCollection), + "NullPathNotPermitted", + ErrorCategory.InvalidArgument, + Path)); + + return; + } + CmdletProviderContext currentContext = CmdletProviderContext; foreach (string path in _paths) { bool result = false; + if (path == null) + { + WriteError(new ErrorRecord( + new ArgumentNullException(TestPathResources.PathIsNullOrEmptyCollection), + "NullPathNotPermitted", + ErrorCategory.InvalidArgument, + Path)); + continue; + } + + if (string.IsNullOrWhiteSpace(path)) + { + WriteObject(result); + continue; + } + try { if (IsValid) @@ -188,6 +225,7 @@ protected override void ProcessRecord() } } } + // Any of the known exceptions means the path does not exist. catch (PSNotSupportedException) { @@ -204,10 +242,9 @@ protected override void ProcessRecord() WriteObject(result); } - } // ProcessRecord + } #endregion Command code - - } // PingPathCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index 30ef0e096ace..4df58d8fee76 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -1,62 +1,57 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; -using System.Diagnostics; // Process class using System.ComponentModel; // Win32Exception -using System.Runtime.ConstrainedExecution; -using System.Runtime.Serialization; -using System.Threading; -using System.Management.Automation; +using System.Diagnostics; // Process class using System.Diagnostics.CodeAnalysis; -using System.Net; using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Net; +using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; +using System.Runtime.Serialization; using System.Security; using System.Security.Permissions; using System.Security.Principal; -using Microsoft.Win32.SafeHandles; -using System.Management.Automation.Internal; -using Microsoft.PowerShell.Commands.Internal; +using System.Text; +using System.Threading; + using Microsoft.Management.Infrastructure; +using Microsoft.PowerShell.Commands.Internal; +using Microsoft.Win32.SafeHandles; using FileNakedHandle = System.IntPtr; using DWORD = System.UInt32; namespace Microsoft.PowerShell.Commands { - // 2004/12/17-JonN ProcessNameGlobAttribute was deeply wrong. - // For example, if you pass in a single Process, it will match - // all processes with the same name. - // I have removed the globbing code. - #region ProcessBaseCommand /// - /// This class implements the base for process commands + /// This class implements the base for process commands. /// public abstract class ProcessBaseCommand : Cmdlet { #region Parameters /// - /// The various process selection modes + /// The various process selection modes. /// internal enum MatchMode { /// - /// Select all processes + /// Select all processes. /// All, /// - /// Select processes matching the supplied names + /// Select processes matching the supplied names. /// ByName, /// - /// Select the processes matching the id + /// Select the processes matching the id. /// ById, /// @@ -97,12 +92,14 @@ public virtual Process[] InputObject { return _input; } + set { myMode = MatchMode.ByInput; _input = value; } } + private Process[] _input = null; #endregion Parameters @@ -139,23 +136,23 @@ internal List MatchingProcesses() // before being stopped. PM confirms that this is fine. _matchingProcesses.Sort(ProcessComparison); return _matchingProcesses; - } // MatchingProcesses + } /// - /// sort function to sort by Name first, then Id + /// Sort function to sort by Name first, then Id. /// - /// first Process object - /// second Process object + /// First Process object. + /// Second Process object. /// - /// as String.Compare: returns less than zero if x less than y, - /// greater than 0 if x greater than y, 0 if x == y + /// As string.Compare: returns less than zero if x less than y, + /// greater than 0 if x greater than y, 0 if x == y. /// private static int ProcessComparison(Process x, Process y) { - int diff = String.Compare( + int diff = string.Compare( SafeGetProcessName(x), SafeGetProcessName(y), - StringComparison.CurrentCultureIgnoreCase); + StringComparison.OrdinalIgnoreCase); if (0 != diff) return diff; return SafeGetProcessId(x) - SafeGetProcessId(y); @@ -171,11 +168,12 @@ private static int ProcessComparison(Process x, Process y) /// private void RetrieveMatchingProcessesByProcessName() { - if (null == processNames) + if (processNames == null) { _matchingProcesses = new List(AllProcesses); return; } + foreach (string pattern in processNames) { WildcardPattern wildcard = @@ -188,20 +186,30 @@ private void RetrieveMatchingProcessesByProcessName() found = true; AddIdempotent(process); } + if (!found && !WildcardPattern.ContainsWildcardCharacters(pattern)) { + string errorText = ProcessResources.NoProcessFoundForGivenName; + string errorName = nameof(ProcessResources.NoProcessFoundForGivenName); + + if (int.TryParse(pattern, out int x) && x >= 0) + { + errorText = ProcessResources.RecommendIdTagForGivenName; + errorName = nameof(ProcessResources.RecommendIdTagForGivenName); + } + WriteNonTerminatingError( - pattern, - 0, - pattern, - null, - ProcessResources.NoProcessFoundForGivenName, - "NoProcessFoundForGivenName", - ErrorCategory.ObjectNotFound); + processName: pattern, + processId: 0, + targetObject: pattern, + innerException: null, + resourceId: errorText, + errorId: errorName, + category: ErrorCategory.ObjectNotFound); } } - } // MatchingProcessesByProcessName + } /// /// Retrieves the list of all processes matching the Id @@ -212,11 +220,12 @@ private void RetrieveMatchingProcessesByProcessName() /// private void RetrieveMatchingProcessesById() { - if (null == processIds) + if (processIds == null) { Diagnostics.Assert(false, "null processIds"); throw PSTraceSource.NewInvalidOperationException(); } + foreach (int processId in processIds) { Process process; @@ -238,7 +247,7 @@ private void RetrieveMatchingProcessesById() continue; } } - } // MatchingProcessesById + } /// /// Retrieves the list of all processes matching the InputObject @@ -247,20 +256,21 @@ private void RetrieveMatchingProcessesById() /// private void RetrieveProcessesByInput() { - if (null == InputObject) + if (InputObject == null) { Diagnostics.Assert(false, "null InputObject"); throw PSTraceSource.NewInvalidOperationException(); } + foreach (Process process in InputObject) { SafeRefresh(process); AddIdempotent(process); } - } // MatchingProcessesByInput + } /// - /// Retrieve the master list of all processes + /// Retrieve the master list of all processes. /// /// /// @@ -272,15 +282,17 @@ internal Process[] AllProcesses { get { - if (null == _allProcesses) + if (_allProcesses == null) { List processes = new List(); processes.AddRange(Process.GetProcesses()); _allProcesses = processes.ToArray(); } + return _allProcesses; } } + private Process[] _allProcesses = null; /// @@ -289,7 +301,7 @@ internal Process[] AllProcesses /// We use a Dictionary to optimize the check whether the object /// is already in the list. /// - /// process to add to list + /// Process to add to list. private void AddIdempotent( Process process) { @@ -348,7 +360,7 @@ internal Process[] AllProcesses string message = StringUtil.Format(resourceId, processName, processId, - (null == innerException) ? "" : innerException.Message); + (innerException == null) ? string.Empty : innerException.Message); ProcessCommandException exception = new ProcessCommandException(message, innerException); exception.ProcessName = processName; @@ -367,11 +379,11 @@ internal static string SafeGetProcessName(Process process) } catch (Win32Exception) { - return ""; + return string.Empty; } catch (InvalidOperationException) { - return ""; + return string.Empty; } } @@ -434,12 +446,12 @@ internal static bool TryHasExited(Process process) } #endregion Internal - }//ProcessBaseCommand + } #endregion ProcessBaseCommand #region GetProcessCommand /// - /// This class implements the get-process command + /// This class implements the get-process command. /// [Cmdlet(VerbsCommon.Get, "Process", DefaultParameterSetName = NameParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113324", RemotingCapability = RemotingCapability.SupportedByCommand)] @@ -460,9 +472,8 @@ public sealed class GetProcessCommand : ProcessBaseCommand #region Parameters /// - /// Has the list of process names on which to this command will work + /// Has the list of process names on which to this command will work. /// - // [ProcessNameGlobAttribute] [Parameter(Position = 0, ParameterSetName = NameParameterSet, ValueFromPipelineByPropertyName = true)] [Parameter(Position = 0, ParameterSetName = NameWithUserNameParameterSet, ValueFromPipelineByPropertyName = true)] [Alias("ProcessName")] @@ -470,6 +481,7 @@ public sealed class GetProcessCommand : ProcessBaseCommand public string[] Name { get { return processNames; } + set { myMode = MatchMode.ByName; @@ -478,7 +490,7 @@ public string[] Name } /// - /// gets/sets an array of process IDs + /// Gets/sets an array of process IDs. /// [Parameter(ParameterSetName = IdParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Parameter(ParameterSetName = IdWithUserNameParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] @@ -489,6 +501,7 @@ public int[] Id { return processIds; } + set { myMode = MatchMode.ById; @@ -497,7 +510,7 @@ public int[] Id } /// - /// Input is a stream of [collections of] Process objects + /// Input is a stream of [collections of] Process objects. /// [Parameter(ParameterSetName = InputObjectParameterSet, Mandatory = true, ValueFromPipeline = true)] [Parameter(ParameterSetName = InputObjectWithUserNameParameterSet, Mandatory = true, ValueFromPipeline = true)] @@ -507,6 +520,7 @@ public override Process[] InputObject { return base.InputObject; } + set { base.InputObject = value; @@ -514,7 +528,7 @@ public override Process[] InputObject } /// - /// Include the UserName + /// Include the UserName. /// [Parameter(ParameterSetName = NameWithUserNameParameterSet, Mandatory = true)] [Parameter(ParameterSetName = IdWithUserNameParameterSet, Mandatory = true)] @@ -522,12 +536,14 @@ public override Process[] InputObject public SwitchParameter IncludeUserName { get { return _includeUserName; } + set { _includeUserName = value; } } + private bool _includeUserName = false; /// - ///To display the modules of a process + /// To display the modules of a process. /// [Parameter(ParameterSetName = NameParameterSet)] @@ -537,7 +553,7 @@ public SwitchParameter IncludeUserName public SwitchParameter Module { get; set; } /// - ///To display the fileversioninfo of the main module of a process + /// To display the fileversioninfo of the main module of a process. /// [Parameter(ParameterSetName = NameParameterSet)] [Parameter(ParameterSetName = IdParameterSet)] @@ -551,7 +567,7 @@ public SwitchParameter IncludeUserName #region Overrides /// - /// Check the elevation mode if IncludeUserName is specified + /// Check the elevation mode if IncludeUserName is specified. /// protected override void BeginProcessing() { @@ -565,13 +581,12 @@ protected override void BeginProcessing() } /// - /// Write the process objects + /// Write the process objects. /// protected override void ProcessRecord() { foreach (Process process in MatchingProcesses()) { - //if module and fileversion are to be displayed if (Module.IsPresent && FileVersionInfo.IsPresent) { ProcessModule tempmodule = null; @@ -580,7 +595,7 @@ protected override void ProcessRecord() ProcessModuleCollection modules = process.Modules; foreach (ProcessModule pmodule in modules) { - //assigning to tempmodule to rethrow for exceptions on 64 bit machines + // Assigning to tempmodule to rethrow for exceptions on 64 bit machines tempmodule = pmodule; WriteObject(pmodule.FileVersionInfo, true); } @@ -618,7 +633,6 @@ protected override void ProcessRecord() } else if (Module.IsPresent) { - //if only modules are to be displayed try { WriteObject(process.Modules, true); @@ -648,10 +662,13 @@ protected override void ProcessRecord() } else if (FileVersionInfo.IsPresent) { - //if fileversion of each process is to be displayed try { - WriteObject(PsUtils.GetMainModule(process).FileVersionInfo, true); + ProcessModule mainModule = PsUtils.GetMainModule(process); + if (mainModule != null) + { + WriteObject(mainModule.FileVersionInfo, true); + } } catch (InvalidOperationException exception) { @@ -688,20 +705,20 @@ protected override void ProcessRecord() { WriteObject(IncludeUserName.IsPresent ? AddUserNameToProcess(process) : (object)process); } - }//for loop - } // ProcessRecord + } + } #endregion Overrides #region Privates /// - /// New PSTypeName added to the process object + /// New PSTypeName added to the process object. /// private const string TypeNameForProcessWithUserName = "System.Diagnostics.Process#IncludeUserName"; /// - /// Add the 'UserName' NoteProperty to the Process object + /// Add the 'UserName' NoteProperty to the Process object. /// /// /// @@ -719,9 +736,8 @@ private static PSObject AddUserNameToProcess(Process process) return processAsPsobj; } - /// - /// Retrieve the UserName through PInvoke + /// Retrieve the UserName through PInvoke. /// /// /// @@ -743,7 +759,7 @@ private static string RetrieveProcessUserName(Process process) int error; if (!Win32Native.OpenProcessToken(process.Handle, TOKEN_QUERY, out processTokenHandler)) { break; } - // Set the default length to be 256, so it will be sufficient for most cases + // Set the default length to be 256, so it will be sufficient for most cases. int tokenInfoLength = 256; tokenUserInfo = Marshal.AllocHGlobal(tokenInfoLength); if (!Win32Native.GetTokenInformation(processTokenHandler, Win32Native.TOKEN_INFORMATION_CLASS.TokenUser, tokenUserInfo, tokenInfoLength, out tokenInfoLength)) @@ -764,46 +780,39 @@ private static string RetrieveProcessUserName(Process process) var tokenUser = Marshal.PtrToStructure(tokenUserInfo); - // Set the default length to be 256, so it will be sufficient for most cases - int userNameLength = 256, domainNameLength = 256; - var userNameStr = new StringBuilder(userNameLength); - var domainNameStr = new StringBuilder(domainNameLength); + // Max username is defined as UNLEN = 256 in lmcons.h + // Max domainname is defined as DNLEN = CNLEN = 15 in lmcons.h + // The buffer length must be +1, last position is for a null string terminator. + int userNameLength = 257; + int domainNameLength = 16; + Span userNameStr = stackalloc char[userNameLength]; + Span domainNameStr = stackalloc char[domainNameLength]; Win32Native.SID_NAME_USE accountType; + // userNameLength and domainNameLength will be set to actual lengths. if (!Win32Native.LookupAccountSid(null, tokenUser.User.Sid, userNameStr, ref userNameLength, domainNameStr, ref domainNameLength, out accountType)) { - error = Marshal.GetLastWin32Error(); - if (error == Win32Native.ERROR_INSUFFICIENT_BUFFER) - { - userNameStr.EnsureCapacity(userNameLength); - domainNameStr.EnsureCapacity(domainNameLength); - - if (!Win32Native.LookupAccountSid(null, tokenUser.User.Sid, userNameStr, ref userNameLength, domainNameStr, ref domainNameLength, out accountType)) { break; } - } - else - { - break; - } + break; } - userName = domainNameStr + "\\" + userNameStr; + userName = string.Concat(domainNameStr.Slice(0, domainNameLength), "\\", userNameStr.Slice(0, userNameLength)); } while (false); } catch (NotSupportedException) { - // The Process not started yet, or it's a process from a remote machine + // The Process not started yet, or it's a process from a remote machine. } catch (InvalidOperationException) { - // The Process has exited, Process.Handle will raise this exception + // The Process has exited, Process.Handle will raise this exception. } catch (Win32Exception) { - // We might get an AccessDenied error + // We might get an AccessDenied error. } catch (Exception) { - // I don't expect to get other exceptions, + // I don't expect to get other exceptions. } finally { @@ -823,12 +832,12 @@ private static string RetrieveProcessUserName(Process process) } #endregion Privates - }//GetProcessCommand + } #endregion GetProcessCommand #region WaitProcessCommand /// - /// This class implements the Wait-process command + /// This class implements the Wait-process command. /// [Cmdlet(VerbsLifecycle.Wait, "Process", DefaultParameterSetName = "Name", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135277")] public sealed class WaitProcessCommand : ProcessBaseCommand @@ -852,6 +861,7 @@ public int[] Id { return processIds; } + set { myMode = MatchMode.ById; @@ -860,7 +870,7 @@ public int[] Id } /// - /// Name of the processes to wait on for termination + /// Name of the processes to wait on for termination. /// [Parameter( ParameterSetName = "Name", @@ -872,6 +882,7 @@ public int[] Id public string[] Name { get { return processNames; } + set { myMode = MatchMode.ByName; @@ -880,7 +891,7 @@ public string[] Name } /// - /// If specified, wait for this number of seconds + /// If specified, wait for this number of seconds. /// [Parameter(Position = 1)] [Alias("TimeoutSec")] @@ -892,23 +903,24 @@ public int Timeout { return _timeout; } + set { _timeout = value; _timeOutSpecified = true; } } + private int _timeout = 0; private bool _timeOutSpecified; - #endregion Parameters private bool _disposed = false; #region IDisposable /// - /// Dispose method of IDisposable interface. + /// Dispose method of IDisposable interface. /// public void Dispose() { @@ -919,6 +931,7 @@ public void Dispose() _waitHandle.Dispose(); _waitHandle = null; } + _disposed = true; } } @@ -944,17 +957,16 @@ private void myProcess_Exited(object sender, System.EventArgs e) private List _processList = new List(); - //Wait handle which is used by thread to sleep. + // Wait handle which is used by thread to sleep. private ManualResetEvent _waitHandle; private int _numberOfProcessesToWaitFor; - /// - /// gets the list of process + /// Gets the list of process. /// protected override void ProcessRecord() { - //adding the processes into the list + // adding the processes into the list foreach (Process process in MatchingProcesses()) { // Idle process has processid zero,so handle that because we cannot wait on it. @@ -970,12 +982,13 @@ protected override void ProcessRecord() WriteNonTerminatingError(process, null, ProcessResources.WaitOnItself, "WaitOnItself", ErrorCategory.ObjectNotFound); continue; } + _processList.Add(process); } - } // ProcessRecord + } /// - /// Wait for the process to terminate + /// Wait for the process to terminate. /// protected override void EndProcessing() { @@ -1011,13 +1024,13 @@ protected override void EndProcessing() _waitHandle.WaitOne(); } } + foreach (Process process in _processList) { try { if (!process.HasExited) { - //write the error string message = StringUtil.Format(ProcessResources.ProcessNotTerminated, new object[] { process.ProcessName, process.Id }); ErrorRecord errorRecord = new ErrorRecord(new TimeoutException(message), "ProcessNotTerminated", ErrorCategory.CloseError, process); WriteError(errorRecord); @@ -1031,7 +1044,7 @@ protected override void EndProcessing() } /// - /// StopProcessing + /// StopProcessing. /// protected override void StopProcessing() { @@ -1042,12 +1055,12 @@ protected override void StopProcessing() } #endregion Overrides - }//WaitProcessCommand + } #endregion WaitProcessCommand #region StopProcessCommand /// - /// This class implements the stop-process command + /// This class implements the stop-process command. /// /// /// Processes will be sorted before being stopped. PM confirms @@ -1061,9 +1074,8 @@ public sealed class StopProcessCommand : ProcessBaseCommand { #region Parameters /// - /// Has the list of process names on which to this command will work + /// Has the list of process names on which to this command will work. /// - // [ProcessNameGlobAttribute] [Parameter( ParameterSetName = "Name", Mandatory = true, @@ -1075,6 +1087,7 @@ public string[] Name { return processNames; } + set { processNames = value; @@ -1083,7 +1096,7 @@ public string[] Name } /// - /// gets/sets an array of process IDs + /// Gets/sets an array of process IDs. /// [Parameter( Position = 0, @@ -1096,6 +1109,7 @@ public int[] Id { return processIds; } + set { myMode = MatchMode.ById; @@ -1104,7 +1118,7 @@ public int[] Id } /// - /// gets/sets an array of objects + /// Gets/sets an array of objects. /// [Parameter( Position = 0, @@ -1118,6 +1132,7 @@ public new Process[] InputObject { return base.InputObject; } + set { base.InputObject = value; @@ -1132,12 +1147,10 @@ public new Process[] InputObject public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } } - - //Addition by v-ramch Mar 18 2008 - //Added force parameter /// /// Specifies whether to force a process to kill /// even if it has dependent services. @@ -1196,7 +1209,6 @@ protected override void ProcessRecord() } catch (Win32Exception ex) { - // This process could not be stopped, so write a non-terminating error. WriteNonTerminatingError( process, ex, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.CloseError); @@ -1205,7 +1217,6 @@ protected override void ProcessRecord() try { - //check if the process is current process and kill it at last if (Process.GetCurrentProcess().Id == SafeGetProcessId(process)) { _shouldKillCurrentProcess = true; @@ -1214,7 +1225,6 @@ protected override void ProcessRecord() if (Platform.IsWindows && !Force) { - // Check if the process is owned by current user if (!IsProcessOwnedByCurrentUser(process)) { string message = StringUtil.Format( @@ -1228,13 +1238,12 @@ protected override void ProcessRecord() } } - //if the process is svchost stop all the dependent services before killing process - if (string.Equals(SafeGetProcessName(process), "SVCHOST", StringComparison.CurrentCultureIgnoreCase)) + // If the process is svchost stop all the dependent services before killing process + if (string.Equals(SafeGetProcessName(process), "SVCHOST", StringComparison.OrdinalIgnoreCase)) { StopDependentService(process); } - // kill the process if (!process.HasExited) { process.Kill(); @@ -1244,8 +1253,6 @@ protected override void ProcessRecord() { if (!TryHasExited(process)) { - // This process could not be stopped, - // so write a non-terminating error. WriteNonTerminatingError( process, exception, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.CloseError); @@ -1256,8 +1263,6 @@ protected override void ProcessRecord() { if (!TryHasExited(process)) { - // This process could not be stopped, - // so write a non-terminating error. WriteNonTerminatingError( process, exception, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.CloseError); @@ -1268,8 +1273,7 @@ protected override void ProcessRecord() if (PassThru) WriteObject(process); } - } // ProcessRecord - + } /// /// Kill the current process here. @@ -1280,31 +1284,31 @@ protected override void EndProcessing() { StopProcess(Process.GetCurrentProcess()); } - }//EndProcessing + } #endregion Overrides #region Private /// - /// should the current powershell process to be killed + /// Should the current powershell process to be killed. /// private bool _shouldKillCurrentProcess; /// - /// Boolean variables to display the warning using shouldcontinue + /// Boolean variables to display the warning using ShouldContinue. /// - private bool _yesToAll,_noToAll; + private bool _yesToAll, _noToAll; /// - /// Current windows user name + /// Current windows user name. /// private string _currentUserName; /// - /// gets the owner of the process + /// Gets the owner of the process. /// /// - /// returns the owner + /// Returns the owner. private bool IsProcessOwnedByCurrentUser(Process process) { const uint TOKEN_QUERY = 0x0008; @@ -1323,19 +1327,19 @@ private bool IsProcessOwnedByCurrentUser(Process process) using (var processUser = new WindowsIdentity(ph)) { - return string.Equals(processUser.Name, _currentUserName, StringComparison.CurrentCultureIgnoreCase); + return string.Equals(processUser.Name, _currentUserName, StringComparison.OrdinalIgnoreCase); } } } catch (IdentityNotMappedException) { - //Catching IdentityMappedException - //Need not throw error. + // Catching IdentityMappedException + // Need not throw error. } catch (ArgumentException) { - //Catching ArgumentException. In Win2k3 Token is zero - //Need not throw error. + // Catching ArgumentException. In Win2k3 Token is zero + // Need not throw error. } finally { @@ -1346,7 +1350,7 @@ private bool IsProcessOwnedByCurrentUser(Process process) } /// - /// Stop the service that depends on the process and its child services + /// Stop the service that depends on the process and its child services. /// /// private void StopDependentService(Process process) @@ -1364,7 +1368,6 @@ private void StopDependentService(Process process) string serviceName = oService.CimInstanceProperties["Name"].Value.ToString(); using (var service = new System.ServiceProcess.ServiceController(serviceName)) { - //try stopping the service, if cant we are not writing exception try { service.Stop(); @@ -1386,9 +1389,9 @@ private void StopDependentService(Process process) } /// - /// stops the given process throws non terminating error if cant - /// process to be stopped - /// true if process stopped successfully else false + /// Stops the given process throws non terminating error if can't. + /// Process to be stopped. + /// True if process stopped successfully else false. /// private void StopProcess(Process process) { @@ -1409,7 +1412,7 @@ private void StopProcess(Process process) exception = e; } - if (null != exception) + if (exception != null) { if (!TryHasExited(process)) { @@ -1423,12 +1426,12 @@ private void StopProcess(Process process) } #endregion Private - }//StopProcessCommand + } #endregion StopProcessCommand #region DebugProcessCommand /// - /// This class implements the Debug-process command + /// This class implements the Debug-process command. /// [Cmdlet(VerbsDiagnostic.Debug, "Process", DefaultParameterSetName = "Name", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135206")] public sealed class DebugProcessCommand : ProcessBaseCommand @@ -1452,6 +1455,7 @@ public int[] Id { return processIds; } + set { myMode = MatchMode.ById; @@ -1460,7 +1464,7 @@ public int[] Id } /// - /// Name of the processes to wait on for termination + /// Name of the processes to wait on for termination. /// [Parameter( ParameterSetName = "Name", @@ -1472,6 +1476,7 @@ public int[] Id public string[] Name { get { return processNames; } + set { myMode = MatchMode.ByName; @@ -1484,11 +1489,10 @@ public string[] Name #region Overrides /// - /// gets the list of process and attach the debugger to the processes + /// Gets the list of process and attach the debugger to the processes. /// protected override void ProcessRecord() { - //for the processes foreach (Process process in MatchingProcesses()) { string targetMessage = StringUtil.Format( @@ -1498,7 +1502,7 @@ protected override void ProcessRecord() if (!ShouldProcess(targetMessage)) { continue; } - // sometimes Idle process has processid zero,so handle that because we cannot attach debugger to it. + // Sometimes Idle process has processid zero,so handle that because we cannot attach debugger to it. if (process.Id == 0) { WriteNonTerminatingError( @@ -1531,12 +1535,12 @@ protected override void ProcessRecord() AttachDebuggerToProcess(process); } - } // ProcessRecord + } #endregion Overrides /// - /// Attach debugger to the process + /// Attach debugger to the process. /// private void AttachDebuggerToProcess(Process process) { @@ -1575,7 +1579,7 @@ private void AttachDebuggerToProcess(Process process) } /// - /// Map the return code from 'AttachDebugger' to error message + /// Map the return code from 'AttachDebugger' to error message. /// private string MapReturnCodeToErrorMessage(int returnCode) { @@ -1589,6 +1593,7 @@ private string MapReturnCodeToErrorMessage(int returnCode) case 21: errorMessage = ProcessResources.AttachDebuggerReturnCode21; break; default: Diagnostics.Assert(false, "Unreachable code."); break; } + return errorMessage; } } @@ -1597,7 +1602,7 @@ private string MapReturnCodeToErrorMessage(int returnCode) #region StartProcessCommand /// - /// This class implements the Start-process command + /// This class implements the Start-process command. /// [Cmdlet(VerbsLifecycle.Start, "Process", DefaultParameterSetName = "Default", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135261")] [OutputType(typeof(Process))] @@ -1609,26 +1614,23 @@ public sealed class StartProcessCommand : PSCmdlet, IDisposable #region Parameters /// - /// Path/FileName of the process to start + /// Path/FileName of the process to start. /// [Parameter(Mandatory = true, Position = 0)] [ValidateNotNullOrEmpty] - [Alias("PSPath")] + [Alias("PSPath", "Path")] public string FilePath { get; set; } - /// - /// Arguments for the process + /// Arguments for the process. /// [Parameter(Position = 1)] [Alias("Args")] - [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] ArgumentList { get; set; } - /// - /// Credentials for the process + /// Credentials for the process. /// [Parameter(ParameterSetName = "Default")] [Alias("RunAs")] @@ -1637,63 +1639,67 @@ public sealed class StartProcessCommand : PSCmdlet, IDisposable public PSCredential Credential { get { return _credential; } + set { _credential = value; _isDefaultSetParameterSpecified = true; } } + private PSCredential _credential; /// - /// working directory of the process + /// Working directory of the process. /// [Parameter] [ValidateNotNullOrEmpty] public string WorkingDirectory { get; set; } - /// - /// load user profile from registry + /// Load user profile from registry. /// [Parameter(ParameterSetName = "Default")] [Alias("Lup")] public SwitchParameter LoadUserProfile { get { return _loaduserprofile; } + set { _loaduserprofile = value; _isDefaultSetParameterSpecified = true; } } + private SwitchParameter _loaduserprofile = SwitchParameter.Present; /// - /// starts process in a new window + /// Starts process in a new window. /// [Parameter(ParameterSetName = "Default")] [Alias("nnw")] public SwitchParameter NoNewWindow { get { return _nonewwindow; } + set { _nonewwindow = value; _isDefaultSetParameterSpecified = true; } } + private SwitchParameter _nonewwindow; /// - /// passthru parameter + /// PassThru parameter. /// [Parameter] public SwitchParameter PassThru { get; set; } - /// - /// Redirect error + /// Redirect error. /// [Parameter(ParameterSetName = "Default")] [Alias("RSE")] @@ -1701,17 +1707,18 @@ public SwitchParameter NoNewWindow public string RedirectStandardError { get { return _redirectstandarderror; } + set { _redirectstandarderror = value; _isDefaultSetParameterSpecified = true; } } - private string _redirectstandarderror; + private string _redirectstandarderror; /// - /// Redirect input + /// Redirect input. /// [Parameter(ParameterSetName = "Default")] [Alias("RSI")] @@ -1719,17 +1726,18 @@ public string RedirectStandardError public string RedirectStandardInput { get { return _redirectstandardinput; } + set { _redirectstandardinput = value; _isDefaultSetParameterSpecified = true; } } - private string _redirectstandardinput; + private string _redirectstandardinput; /// - /// Redirect output + /// Redirect output. /// [Parameter(ParameterSetName = "Default")] [Alias("RSO")] @@ -1737,61 +1745,66 @@ public string RedirectStandardInput public string RedirectStandardOutput { get { return _redirectstandardoutput; } + set { _redirectstandardoutput = value; _isDefaultSetParameterSpecified = true; } } + private string _redirectstandardoutput; /// - /// Verb + /// Verb. /// /// - /// The 'Verb' parameter is not supported in OneCore PowerShell - /// because 'UseShellExecute' is not supported in CoreCLR. + /// The 'Verb' parameter is only supported on Windows Desktop. /// [Parameter(ParameterSetName = "UseShellExecute")] [ValidateNotNullOrEmpty] public string Verb { get; set; } /// - /// Window style of the process window + /// Window style of the process window. /// [Parameter] [ValidateNotNullOrEmpty] public ProcessWindowStyle WindowStyle { get { return _windowstyle; } + set { _windowstyle = value; _windowstyleSpecified = true; } } + private ProcessWindowStyle _windowstyle = ProcessWindowStyle.Normal; private bool _windowstyleSpecified = false; /// - /// wait for th eprocess to terminate + /// Wait for the process to terminate. /// [Parameter] public SwitchParameter Wait { get; set; } /// - /// Default Environment + /// Default Environment. /// [Parameter(ParameterSetName = "Default")] public SwitchParameter UseNewEnvironment { get { return _UseNewEnvironment; } + set { _UseNewEnvironment = value; _isDefaultSetParameterSpecified = true; } } + private SwitchParameter _UseNewEnvironment; #endregion @@ -1799,7 +1812,7 @@ public SwitchParameter UseNewEnvironment #region overrides /// - /// BeginProcessing + /// BeginProcessing. /// protected override void BeginProcessing() { @@ -1835,12 +1848,11 @@ protected override void BeginProcessing() } } - //create an instance of the ProcessStartInfo Class ProcessStartInfo startInfo = new ProcessStartInfo(); - //use ShellExecute by default if we are running on full windows SKUs + // Use ShellExecute by default if we are running on full windows SKUs startInfo.UseShellExecute = Platform.IsWindowsDesktop; - //Path = Mandatory parameter -> Will not be empty. + // Path = Mandatory parameter -> Will not be empty. try { CommandInfo cmdinfo = CommandDiscovery.LookupCommandInfo( @@ -1852,24 +1864,24 @@ protected override void BeginProcessing() catch (CommandNotFoundException) { startInfo.FileName = FilePath; +#if UNIX + // Arguments are passed incorrectly to the executable used for ShellExecute and not to filename https://github.com/dotnet/corefx/issues/30718 + // so don't use ShellExecute if arguments are specified + + // Linux relies on `xdg-open` and macOS relies on `open` which behave differently than Windows ShellExecute when running console commands + // as a new console will be opened. So to avoid that, we only use ShellExecute on non-Windows if the filename is not an actual command (like a URI) + startInfo.UseShellExecute = (ArgumentList == null); +#endif } - //Arguments + if (ArgumentList != null) { - StringBuilder sb = new StringBuilder(); - foreach (string str in ArgumentList) - { - sb.Append(str); - sb.Append(' '); - } - startInfo.Arguments = sb.ToString(); ; + startInfo.Arguments = string.Join(' ', ArgumentList); } - - //WorkingDirectory if (WorkingDirectory != null) { - //WorkingDirectory -> Not Exist -> Throw Error + // WorkingDirectory -> Not Exist -> Throw Error WorkingDirectory = ResolveFilePath(WorkingDirectory); if (!Directory.Exists(WorkingDirectory)) { @@ -1878,11 +1890,12 @@ protected override void BeginProcessing() WriteError(er); return; } + startInfo.WorkingDirectory = WorkingDirectory; } else { - //Working Directory not specified -> Assign Current Path. + // Working Directory not specified -> Assign Current Path. startInfo.WorkingDirectory = ResolveFilePath(this.SessionState.Path.CurrentFileSystemLocation.Path); } @@ -1893,7 +1906,6 @@ protected override void BeginProcessing() startInfo.UseShellExecute = false; } - //UseNewEnvironment if (_UseNewEnvironment) { startInfo.EnvironmentVariables.Clear(); @@ -1901,24 +1913,20 @@ protected override void BeginProcessing() LoadEnvironmentVariable(startInfo, Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)); } - //WindowStyle startInfo.WindowStyle = _windowstyle; - //NewWindow if (_nonewwindow) { startInfo.CreateNoWindow = _nonewwindow; } #if !UNIX - //LoadUserProfile. startInfo.LoadUserProfile = _loaduserprofile; #endif if (_credential != null) { - //Gets NetworkCredentials NetworkCredential nwcredential = _credential.GetNetworkCredential(); startInfo.UserName = nwcredential.UserName; - if (String.IsNullOrEmpty(nwcredential.Domain)) + if (string.IsNullOrEmpty(nwcredential.Domain)) { startInfo.Domain = "."; } @@ -1926,10 +1934,11 @@ protected override void BeginProcessing() { startInfo.Domain = nwcredential.Domain; } + startInfo.Password = _credential.Password; } - //RedirectionInput File Check -> Not Exist -> Throw Error + // RedirectionInput File Check -> Not Exist -> Throw Error if (_redirectstandardinput != null) { _redirectstandardinput = ResolveFilePath(_redirectstandardinput); @@ -1942,12 +1951,12 @@ protected override void BeginProcessing() } } - //RedirectionInput == RedirectionOutput -> Throw Error + // RedirectionInput == RedirectionOutput -> Throw Error if (_redirectstandardinput != null && _redirectstandardoutput != null) { _redirectstandardinput = ResolveFilePath(_redirectstandardinput); _redirectstandardoutput = ResolveFilePath(_redirectstandardoutput); - if (_redirectstandardinput.Equals(_redirectstandardoutput, StringComparison.CurrentCultureIgnoreCase)) + if (_redirectstandardinput.Equals(_redirectstandardoutput, StringComparison.OrdinalIgnoreCase)) { message = StringUtil.Format(ProcessResources.DuplicateEntry, "RedirectStandardInput", "RedirectStandardOutput"); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); @@ -1956,12 +1965,12 @@ protected override void BeginProcessing() } } - //RedirectionInput == RedirectionError -> Throw Error + // RedirectionInput == RedirectionError -> Throw Error if (_redirectstandardinput != null && _redirectstandarderror != null) { _redirectstandardinput = ResolveFilePath(_redirectstandardinput); _redirectstandarderror = ResolveFilePath(_redirectstandarderror); - if (_redirectstandardinput.Equals(_redirectstandarderror, StringComparison.CurrentCultureIgnoreCase)) + if (_redirectstandardinput.Equals(_redirectstandarderror, StringComparison.OrdinalIgnoreCase)) { message = StringUtil.Format(ProcessResources.DuplicateEntry, "RedirectStandardInput", "RedirectStandardError"); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); @@ -1970,12 +1979,12 @@ protected override void BeginProcessing() } } - //RedirectionOutput == RedirectionError -> Throw Error + // RedirectionOutput == RedirectionError -> Throw Error if (_redirectstandardoutput != null && _redirectstandarderror != null) { _redirectstandarderror = ResolveFilePath(_redirectstandarderror); _redirectstandardoutput = ResolveFilePath(_redirectstandardoutput); - if (_redirectstandardoutput.Equals(_redirectstandarderror, StringComparison.CurrentCultureIgnoreCase)) + if (_redirectstandardoutput.Equals(_redirectstandarderror, StringComparison.OrdinalIgnoreCase)) { message = StringUtil.Format(ProcessResources.DuplicateEntry, "RedirectStandardOutput", "RedirectStandardError"); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); @@ -1986,19 +1995,16 @@ protected override void BeginProcessing() } else if (ParameterSetName.Equals("UseShellExecute")) { - //Verb if (Verb != null) { startInfo.Verb = Verb; } - //WindowStyle + startInfo.WindowStyle = _windowstyle; } string targetMessage = StringUtil.Format(ProcessResources.StartProcessTarget, startInfo.FileName, startInfo.Arguments.Trim()); if (!ShouldProcess(targetMessage)) { return; } - //Starts the Process Process process = Start(startInfo); - //Wait and Passthru Implementation. if (PassThru.IsPresent) { if (process != null) @@ -2065,7 +2071,7 @@ protected override void StopProcessing() #region IDisposable Overrides /// - /// Dispose WaitHandle used to honor -Wait parameter + /// Dispose WaitHandle used to honor -Wait parameter. /// public void Dispose() { @@ -2112,6 +2118,7 @@ private void LoadEnvironmentVariable(ProcessStartInfo startinfo, IDictionary Env { processEnvironment.Remove(entry.Key.ToString()); } + if (entry.Key.ToString().Equals("PATH")) { processEnvironment.Add(entry.Key.ToString(), Environment.GetEnvironmentVariable(entry.Key.ToString(), EnvironmentVariableTarget.Machine) + ";" + Environment.GetEnvironmentVariable(entry.Key.ToString(), EnvironmentVariableTarget.User)); @@ -2125,24 +2132,6 @@ private void LoadEnvironmentVariable(ProcessStartInfo startinfo, IDictionary Env private Process Start(ProcessStartInfo startInfo) { -#if UNIX - Process process = new Process() { StartInfo = startInfo }; - SetupInputOutputRedirection(process); - process.Start(); - if (process.StartInfo.RedirectStandardOutput) - { - process.BeginOutputReadLine(); - } - if (process.StartInfo.RedirectStandardError) - { - process.BeginErrorReadLine(); - } - if (process.StartInfo.RedirectStandardInput) - { - WriteToStandardInput(process); - } - return process; -#else Process process = null; if (startInfo.UseShellExecute) { @@ -2150,10 +2139,30 @@ private Process Start(ProcessStartInfo startInfo) } else { +#if UNIX + process = new Process() { StartInfo = startInfo }; + SetupInputOutputRedirection(process); + process.Start(); + if (process.StartInfo.RedirectStandardOutput) + { + process.BeginOutputReadLine(); + } + + if (process.StartInfo.RedirectStandardError) + { + process.BeginErrorReadLine(); + } + + if (process.StartInfo.RedirectStandardInput) + { + WriteToStandardInput(process); + } +#else process = StartWithCreateProcess(startInfo); +#endif } + return process; -#endif } #if UNIX @@ -2162,7 +2171,7 @@ private Process Start(ProcessStartInfo startInfo) private void StdOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { - if (!String.IsNullOrEmpty(outLine.Data)) + if (!string.IsNullOrEmpty(outLine.Data)) { _outputWriter.WriteLine(outLine.Data); _outputWriter.Flush(); @@ -2171,7 +2180,7 @@ private void StdOutputHandler(object sendingProcess, DataReceivedEventArgs outLi private void StdErrorHandler(object sendingProcess, DataReceivedEventArgs outLine) { - if (!String.IsNullOrEmpty(outLine.Data)) + if (!string.IsNullOrEmpty(outLine.Data)) { _errorWriter.WriteLine(outLine.Data); _errorWriter.Flush(); @@ -2195,6 +2204,7 @@ private void StreamClosing() { _outputWriter.Dispose(); } + if (_errorWriter != null) { _errorWriter.Dispose(); @@ -2255,6 +2265,7 @@ private void WriteToStandardInput(Process p) string line = reader.ReadToEnd(); writer.WriteLine(line); } + writer.Dispose(); } #else @@ -2263,7 +2274,6 @@ private SafeFileHandle GetSafeFileHandleForRedirection(string RedirectionPath, u System.IntPtr hFileHandle = System.IntPtr.Zero; ProcessNativeMethods.SECURITY_ATTRIBUTES lpSecurityAttributes = new ProcessNativeMethods.SECURITY_ATTRIBUTES(); - hFileHandle = ProcessNativeMethods.CreateFileW(RedirectionPath, ProcessNativeMethods.GENERIC_READ | ProcessNativeMethods.GENERIC_WRITE, ProcessNativeMethods.FILE_SHARE_WRITE | ProcessNativeMethods.FILE_SHARE_READ, @@ -2279,6 +2289,7 @@ private SafeFileHandle GetSafeFileHandleForRedirection(string RedirectionPath, u ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } + SafeFileHandle sf = new SafeFileHandle(hFileHandle, true); return sf; } @@ -2287,21 +2298,24 @@ private static StringBuilder BuildCommandLine(string executableFileName, string { StringBuilder builder = new StringBuilder(); string str = executableFileName.Trim(); - bool flag = str.StartsWith("\"", StringComparison.Ordinal) && str.EndsWith("\"", StringComparison.Ordinal); + bool flag = str.StartsWith('"') && str.EndsWith('"'); if (!flag) { - builder.Append("\""); + builder.Append('"'); } + builder.Append(str); if (!flag) { - builder.Append("\""); + builder.Append('"'); } + if (!string.IsNullOrEmpty(arguments)) { - builder.Append(" "); + builder.Append(' '); builder.Append(arguments); } + return builder; } @@ -2321,6 +2335,7 @@ private static byte[] ConvertEnvVarsToByteArray(StringDictionary sd) builder.Append(strArray2[i]); builder.Append('\0'); } + builder.Append('\0'); // Use Unicode encoding @@ -2329,6 +2344,7 @@ private static byte[] ConvertEnvVarsToByteArray(StringDictionary sd) { throw new InvalidOperationException("EnvironmentBlockTooLong"); } + return bytes; } @@ -2341,14 +2357,14 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation = new SafeNativeMethods.PROCESS_INFORMATION(); int error = 0; GCHandle pinnedEnvironmentBlock = new GCHandle(); - string message = String.Empty; + string message = string.Empty; - //building the cmdline with the file name given and it's arguments + // building the cmdline with the file name given and it's arguments StringBuilder cmdLine = BuildCommandLine(startinfo.FileName, startinfo.Arguments); try { - //RedirectionStandardInput + // RedirectionStandardInput if (_redirectstandardinput != null) { startinfo.RedirectStandardInput = true; @@ -2359,7 +2375,7 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) { lpStartupInfo.hStdInput = new SafeFileHandle(ProcessNativeMethods.GetStdHandle(-10), false); } - //RedirectionStandardOutput + // RedirectionStandardOutput if (_redirectstandardoutput != null) { startinfo.RedirectStandardOutput = true; @@ -2370,7 +2386,7 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) { lpStartupInfo.hStdOutput = new SafeFileHandle(ProcessNativeMethods.GetStdHandle(-11), false); } - //RedirectionStandardError + // RedirectionStandardError if (_redirectstandarderror != null) { startinfo.RedirectStandardError = true; @@ -2381,40 +2397,40 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) { lpStartupInfo.hStdError = new SafeFileHandle(ProcessNativeMethods.GetStdHandle(-12), false); } - //STARTF_USESTDHANDLES + // STARTF_USESTDHANDLES lpStartupInfo.dwFlags = 0x100; int creationFlags = 0; if (startinfo.CreateNoWindow) { - //No new window: Inherit the parent process's console window + // No new window: Inherit the parent process's console window creationFlags = 0x00000000; } else { - //CREATE_NEW_CONSOLE + // CREATE_NEW_CONSOLE creationFlags |= 0x00000010; - //STARTF_USESHOWWINDOW + // STARTF_USESHOWWINDOW lpStartupInfo.dwFlags |= 0x00000001; // On headless SKUs like NanoServer and IoT, window style can only be the default value 'Normal'. switch (startinfo.WindowStyle) { case ProcessWindowStyle.Normal: - //SW_SHOWNORMAL + // SW_SHOWNORMAL lpStartupInfo.wShowWindow = 1; break; case ProcessWindowStyle.Minimized: - //SW_SHOWMINIMIZED + // SW_SHOWMINIMIZED lpStartupInfo.wShowWindow = 2; break; case ProcessWindowStyle.Maximized: - //SW_SHOWMAXIMIZED + // SW_SHOWMAXIMIZED lpStartupInfo.wShowWindow = 3; break; case ProcessWindowStyle.Hidden: - //SW_HIDE + // SW_HIDE lpStartupInfo.wShowWindow = 0; break; } @@ -2435,6 +2451,7 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) AddressOfEnvironmentBlock = pinnedEnvironmentBlock.AddrOfPinnedObject(); } } + bool flag; if (_credential != null) @@ -2475,6 +2492,7 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) er = er ?? new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } + goto Label_03AE; } finally @@ -2484,7 +2502,7 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) Marshal.ZeroFreeCoTaskMemUnicode(password); } } - }//end of if + } ProcessNativeMethods.SECURITY_ATTRIBUTES lpProcessAttributes = new ProcessNativeMethods.SECURITY_ATTRIBUTES(); ProcessNativeMethods.SECURITY_ATTRIBUTES lpThreadAttributes = new ProcessNativeMethods.SECURITY_ATTRIBUTES(); @@ -2518,6 +2536,7 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) lpProcessInformation.Dispose(); } } +#endif /// /// This method will be used only on Windows full desktop. @@ -2535,9 +2554,9 @@ private Process StartWithShellExecute(ProcessStartInfo startInfo) ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } + return result; } -#endif #endregion } @@ -2655,15 +2674,13 @@ internal static class ProcessNativeMethods internal static UInt32 OF_READWRITE = 0x00000002; internal static UInt32 OPEN_EXISTING = 3; - // Methods - // static NativeMethods(); - - [DllImport(PinvokeDllNames.GetStdHandleDllName, CharSet = CharSet.Ansi, SetLastError = true)] + [DllImport(PinvokeDllNames.GetStdHandleDllName, SetLastError = true)] public static extern IntPtr GetStdHandle(int whichHandle); [DllImport(PinvokeDllNames.CreateProcessWithLogonWDllName, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CreateProcessWithLogonW(string userName, string domain, IntPtr password, @@ -2677,6 +2694,7 @@ internal static class ProcessNativeMethods SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation); [DllImport(PinvokeDllNames.CreateProcessDllName, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CreateProcess([MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpCommandLine, SECURITY_ATTRIBUTES lpProcessAttributes, @@ -2702,7 +2720,6 @@ internal static class ProcessNativeMethods System.IntPtr hTemplateFile ); - [Flags] internal enum LogonFlags { @@ -2731,12 +2748,14 @@ internal SafeLocalMemHandle() : base(true) { } + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] internal SafeLocalMemHandle(IntPtr existingHandle, bool ownsHandle) : base(ownsHandle) { base.SetHandle(existingHandle); } + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport(PinvokeDllNames.LocalFreeDllName)] private static extern IntPtr LocalFree(IntPtr hMem); protected override bool ReleaseHandle() @@ -2745,7 +2764,6 @@ protected override bool ReleaseHandle() } } - [StructLayout(LayoutKind.Sequential)] internal class STARTUPINFO { @@ -2788,11 +2806,13 @@ public void Dispose(bool disposing) this.hStdInput.Dispose(); this.hStdInput = null; } + if ((this.hStdOutput != null) && !this.hStdOutput.IsInvalid) { this.hStdOutput.Dispose(); this.hStdOutput = null; } + if ((this.hStdError != null) && !this.hStdError.IsInvalid) { this.hStdError.Dispose(); @@ -2828,7 +2848,7 @@ public PROCESS_INFORMATION() } /// - /// Dispose + /// Dispose. /// public void Dispose() { @@ -2836,7 +2856,7 @@ public void Dispose() } /// - /// Dispose + /// Dispose. /// /// private void Dispose(bool disposing) @@ -2878,32 +2898,32 @@ protected override bool ReleaseHandle() #region ProcessCommandException /// - /// Non-terminating errors occurring in the process noun commands + /// Non-terminating errors occurring in the process noun commands. /// [Serializable] public class ProcessCommandException : SystemException { #region ctors /// - /// unimplemented standard constructor + /// Unimplemented standard constructor. /// - /// doesn't return + /// Doesn't return. public ProcessCommandException() : base() { throw new NotImplementedException(); } /// - /// standard constructor + /// Standard constructor. /// /// - /// constructed object + /// Constructed object. public ProcessCommandException(string message) : base(message) { } /// - /// standard constructor + /// Standard constructor. /// /// /// @@ -2915,11 +2935,11 @@ public ProcessCommandException(string message, Exception innerException) #region Serialization /// - /// serialization constructor + /// Serialization constructor. /// /// /// - /// constructed object + /// Constructed object. protected ProcessCommandException( SerializationInfo info, StreamingContext context) @@ -2928,10 +2948,10 @@ public ProcessCommandException(string message, Exception innerException) _processName = info.GetString("ProcessName"); } /// - /// Serializer + /// Serializer. /// - /// serialization information - /// streaming context + /// Serialization information. + /// Streaming context. [SecurityPermissionAttribute( SecurityAction.Demand, SerializationFormatter = true)] @@ -2950,18 +2970,20 @@ public ProcessCommandException(string message, Exception innerException) #region Properties /// - /// Name of the process which could not be found or operated upon + /// Name of the process which could not be found or operated upon. /// /// public string ProcessName { get { return _processName; } + set { _processName = value; } } - private string _processName = String.Empty; + + private string _processName = string.Empty; #endregion Properties - } // class ProcessCommandException + } #endregion ProcessCommandException -}//Microsoft.PowerShell.Commands +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/PropertyCommandBase.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/PropertyCommandBase.cs index f64d33e18f7e..ceda21a531f5 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/PropertyCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/PropertyCommandBase.cs @@ -1,21 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// The base class for the */property commands + /// The base class for the */property commands. /// public class ItemPropertyCommandBase : CoreCommandWithCredentialsBase { #region Parameters /// - /// Gets or sets the filter parameter + /// Gets or sets the filter parameter. /// [Parameter] public override string Filter @@ -23,16 +24,16 @@ public override string Filter get { return base.Filter; - } // get + } set { base.Filter = value; - } // set - } // Filter + } + } /// - /// Gets or sets the include property + /// Gets or sets the include property. /// [Parameter] public override string[] Include @@ -40,16 +41,16 @@ public override string[] Include get { return base.Include; - } // get + } set { base.Include = value; - } // set - } // Include + } + } /// - /// Gets or sets the exclude property + /// Gets or sets the exclude property. /// [Parameter] public override string[] Exclude @@ -57,22 +58,22 @@ public override string[] Exclude get { return base.Exclude; - } // get + } set { base.Exclude = value; - } // set - } // Exclude + } + } #endregion Parameters #region parameter data /// - /// The path to the item + /// The path to the item. /// - internal string[] paths = new string[0]; + internal string[] paths = Array.Empty(); #endregion parameter data - } // ItemPropertyCommandBase -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/RegisterWMIEventCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/RegisterWMIEventCommand.cs index 091e1903a45b..f2f95e0ca43e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/RegisterWMIEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/RegisterWMIEventCommand.cs @@ -1,16 +1,15 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; using System.Collections.Generic; -using System.Management.Automation; using System.Collections.ObjectModel; using System.Diagnostics; -using System.Threading; using System.Management; +using System.Management.Automation; using System.Text; +using System.Threading; namespace Microsoft.PowerShell.Commands { @@ -24,42 +23,41 @@ public class RegisterWmiEventCommand : ObjectEventRegistrationBase #region parameters /// - /// The WMI namespace to use + /// The WMI namespace to use. /// [Parameter] [Alias("NS")] public string Namespace { get; set; } = "root\\cimv2"; /// - /// The credential to use + /// The credential to use. /// [Parameter] [Credential()] public PSCredential Credential { get; set; } /// - /// The ComputerName in which to query + /// The ComputerName in which to query. /// [Parameter] [Alias("Cn")] [ValidateNotNullOrEmpty] public string ComputerName { get; set; } = "localhost"; - /// - /// The WMI class to use + /// The WMI class to use. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "class")] public string Class { get; set; } = null; /// - /// The query string to search for objects + /// The query string to search for objects. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "query")] public string Query { get; set; } = null; /// - /// Timeout in milliseconds + /// Timeout in milliseconds. /// [Parameter] [Alias("TimeoutMSec")] @@ -69,6 +67,7 @@ public Int64 Timeout { return _timeOut; } + set { _timeOut = value; @@ -87,6 +86,7 @@ private string BuildEventQuery(string objectName) returnValue.Append(objectName); return returnValue.ToString(); } + private string GetScopeString(string computer, string namespaceParameter) { StringBuilder returnValue = new StringBuilder("\\\\"); @@ -97,26 +97,25 @@ private string GetScopeString(string computer, string namespaceParameter) } #endregion helper functions - /// - /// Returns the object that generates events to be monitored + /// Returns the object that generates events to be monitored. /// - protected override Object GetSourceObject() + protected override object GetSourceObject() { string wmiQuery = this.Query; if (this.Class != null) { - //Validate class format + // Validate class format for (int i = 0; i < this.Class.Length; i++) { - if (Char.IsLetterOrDigit(this.Class[i]) || this.Class[i].Equals('_')) + if (char.IsLetterOrDigit(this.Class[i]) || this.Class[i].Equals('_')) { continue; } ErrorRecord errorRecord = new ErrorRecord( new ArgumentException( - String.Format( + string.Format( Thread.CurrentThread.CurrentCulture, "Class", this.Class)), "INVALID_QUERY_IDENTIFIER", @@ -135,7 +134,7 @@ protected override Object GetSourceObject() if (this.Credential != null) { System.Net.NetworkCredential cred = this.Credential.GetNetworkCredential(); - if (String.IsNullOrEmpty(cred.Domain)) + if (string.IsNullOrEmpty(cred.Domain)) { conOptions.Username = cred.UserName; } @@ -143,6 +142,7 @@ protected override Object GetSourceObject() { conOptions.Username = cred.Domain + "\\" + cred.UserName; } + conOptions.Password = cred.Password; } @@ -159,9 +159,9 @@ protected override Object GetSourceObject() } /// - /// Returns the event name to be monitored on the input object + /// Returns the event name to be monitored on the input object. /// - protected override String GetSourceObjectEventName() + protected override string GetSourceObjectEventName() { return "EventArrived"; } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/RemovePropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/RemovePropertyCommand.cs index b6c1b4b3e7d6..428787653338 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/RemovePropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/RemovePropertyCommand.cs @@ -1,8 +1,9 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -17,7 +18,7 @@ public class RemoveItemPropertyCommand : ItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -26,50 +27,49 @@ public string[] Path get { return paths; - } // get + } set { paths = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return paths; - } // get + } set { base.SuppressWildcardExpansion = true; paths = value; - } // set - } // LiteralPath + } + } /// - /// The name of the property to create on the item + /// The name of the property to create on the item. /// - /// [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)] [Alias("PSProperty")] public string[] Name { get { return _property; } - set { _property = value ?? Utils.EmptyArray(); } + + set { _property = value ?? Array.Empty(); } } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// - /// /// /// Gives the provider guidance on how vigorous it should be about performing /// the operation. If true, the provider should do everything possible to perform @@ -79,11 +79,11 @@ public string[] Name /// the destination is read-only, if force is true, the provider should copy over /// the existing read-only file. If force is false, the provider should write an error. /// - /// [Parameter] public override SwitchParameter Force { get { return base.Force; } + set { base.Force = value; } } @@ -92,16 +92,13 @@ public override SwitchParameter Force /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { string propertyName = null; @@ -114,8 +111,9 @@ internal override object GetDynamicParameters(CmdletProviderContext context) { return InvokeProvider.Property.RemovePropertyDynamicParameters(Path[0], propertyName, context); } + return InvokeProvider.Property.RemovePropertyDynamicParameters(".", propertyName, context); - } // GetDynamicParameters + } #endregion Parameters @@ -124,14 +122,14 @@ internal override object GetDynamicParameters(CmdletProviderContext context) /// /// The property to be created. /// - private string[] _property = new string[0]; + private string[] _property = Array.Empty(); #endregion parameter data #region Command code /// - /// Removes the property from the item + /// Removes the property from the item. /// protected override void ProcessRecord() { @@ -177,9 +175,8 @@ protected override void ProcessRecord() } } } - } // ProcessRecord + } #endregion Command code - - } // RemoveItemPropertyCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/RemoveWMIObjectCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/RemoveWMIObjectCommand.cs index 711cd7ea074f..c9fb150b766c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/RemoveWMIObjectCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/RemoveWMIObjectCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management; @@ -9,7 +8,7 @@ namespace Microsoft.PowerShell.Commands { /// - /// A command to Remove WMI Object + /// A command to Remove WMI Object. /// [Cmdlet(VerbsCommon.Remove, "WmiObject", DefaultParameterSetName = "class", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113381", RemotingCapability = RemotingCapability.OwnedByCommand)] @@ -17,31 +16,33 @@ public class RemoveWmiObject : WmiBaseCmdlet { #region Parameters /// - /// The WMI Object to use + /// The WMI Object to use. /// - /// [Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = "object")] public ManagementObject InputObject { get { return _inputObject; } + set { _inputObject = value; } } /// - /// The WMI Path to use + /// The WMI Path to use. /// [Parameter(Mandatory = true, ParameterSetName = "path")] public string Path { get { return _path; } + set { _path = value; } } /// - /// The WMI class to use + /// The WMI class to use. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "class")] public string Class { get { return _className; } + set { _className = value; } } @@ -64,6 +65,7 @@ protected override void ProcessRecord() RunAsJob("Remove-WMIObject"); return; } + if (_inputObject != null) { try @@ -72,6 +74,7 @@ protected override void ProcessRecord() { return; } + _inputObject.Delete(); } catch (ManagementException e) @@ -84,6 +87,7 @@ protected override void ProcessRecord() ErrorRecord errorRecord = new ErrorRecord(e, "RemoveWMICOMException", ErrorCategory.InvalidOperation, null); WriteError(errorRecord); } + return; } else @@ -94,13 +98,13 @@ protected override void ProcessRecord() if (_path != null) { mPath = new ManagementPath(_path); - if (String.IsNullOrEmpty(mPath.NamespacePath)) + if (string.IsNullOrEmpty(mPath.NamespacePath)) { mPath.NamespacePath = this.Namespace; } else if (namespaceSpecified) { - //ThrowTerminatingError + // ThrowTerminatingError ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "NamespaceSpecifiedWithPath", @@ -110,19 +114,21 @@ protected override void ProcessRecord() if (mPath.Server != "." && serverNameSpecified) { - //ThrowTerminatingError + // ThrowTerminatingError ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "ComputerNameSpecifiedWithPath", ErrorCategory.InvalidOperation, this.ComputerName)); } + if (!(mPath.Server == "." && serverNameSpecified)) { string[] serverName = new string[] { mPath.Server }; ComputerName = serverName; } } + foreach (string name in ComputerName) { try @@ -140,6 +146,7 @@ protected override void ProcessRecord() ManagementObject mInstance = new ManagementObject(mPath); mObject = mInstance; } + ManagementScope mScope = new ManagementScope(mPath, options); mObject.Scope = mScope; } @@ -150,10 +157,12 @@ protected override void ProcessRecord() mObject = mClass; mObject.Scope = scope; } + if (!ShouldProcess(mObject["__PATH"].ToString())) { continue; } + mObject.Delete(); } catch (ManagementException e) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/RenamePropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/RenamePropertyCommand.cs index 5e3000ceb574..f04dd40bb8c3 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/RenamePropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/RenamePropertyCommand.cs @@ -1,14 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// A command to rename a property of an item at a specified path + /// A command to rename a property of an item at a specified path. /// [Cmdlet(VerbsCommon.Rename, "ItemProperty", DefaultParameterSetName = "Path", SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113383")] @@ -17,7 +17,7 @@ public class RenameItemPropertyCommand : PassThroughItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -26,46 +26,44 @@ public string Path get { return _path; - } // get + } set { _path = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { get { return _path; - } // get + } set { base.SuppressWildcardExpansion = true; _path = value; - } // set - } // LiteralPath + } + } /// - /// The properties to be renamed on the item + /// The properties to be renamed on the item. /// - /// [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)] [Alias("PSProperty")] public string Name { get; set; } /// - /// The new name of the property on the item + /// The new name of the property on the item. /// - /// [Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true)] public string NewName { get; set; } @@ -74,24 +72,22 @@ public string LiteralPath /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null) { return InvokeProvider.Property.RenamePropertyDynamicParameters(Path, Name, NewName, context); } + return InvokeProvider.Property.RenamePropertyDynamicParameters(".", Name, NewName, context); - } // GetDynamicParameters + } #endregion Parameters @@ -146,9 +142,8 @@ protected override void ProcessRecord() pathNotFound.ErrorRecord, pathNotFound)); } - } // ProcessRecord + } #endregion Command code - - } // RenameItemPropertyCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs index d1222aa65965..d0b96c57399b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs @@ -1,11 +1,11 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections.ObjectModel; using System.Management.Automation; + using Dbg = System.Management.Automation; -using System.Collections.ObjectModel; namespace Microsoft.PowerShell.Commands { @@ -20,7 +20,7 @@ public class ResolvePathCommand : CoreCommandWithCredentialsBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -29,33 +29,33 @@ public string[] Path get { return _paths; - } // get + } set { _paths = value; - } // set - } // Path + } + } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return _paths; - } // get + } set { base.SuppressWildcardExpansion = true; _paths = value; - } // set - } // LiteralPath + } + } /// /// Gets or sets the value that determines if the resolved path should @@ -67,22 +67,22 @@ public SwitchParameter Relative get { return _relative; - } // get + } set { _relative = value; - } // set - } // Relative - private SwitchParameter _relative; + } + } + private SwitchParameter _relative; #endregion Parameters #region parameter data /// - /// The path to resolve + /// The path to resolve. /// private string[] _paths; @@ -107,13 +107,28 @@ protected override void ProcessRecord() { foreach (PathInfo currentPath in result) { + // When result path and base path is on different PSDrive + // (../)*path should not go beyond the root of base path + if (currentPath.Drive != SessionState.Path.CurrentLocation.Drive && + SessionState.Path.CurrentLocation.Drive != null && + !currentPath.ProviderPath.StartsWith( + SessionState.Path.CurrentLocation.Drive.Root, StringComparison.OrdinalIgnoreCase)) + { + WriteObject(currentPath.Path, enumerateCollection: false); + continue; + } + string adjustedPath = SessionState.Path.NormalizeRelativePath(currentPath.Path, SessionState.Path.CurrentLocation.ProviderPath); - if (!adjustedPath.StartsWith(".", StringComparison.OrdinalIgnoreCase)) + // Do not insert './' if result path is not relative + if (!adjustedPath.StartsWith( + currentPath.Drive?.Root ?? currentPath.Path, StringComparison.OrdinalIgnoreCase) && + !adjustedPath.StartsWith('.')) { adjustedPath = SessionState.Path.Combine(".", adjustedPath); } - WriteObject(adjustedPath, false); + + WriteObject(adjustedPath, enumerateCollection: false); } } } @@ -152,13 +167,12 @@ protected override void ProcessRecord() if (!_relative) { - WriteObject(result, true); + WriteObject(result, enumerateCollection: true); } } - } // ProcessRecord + } #endregion Command code - - } // ResolvePathCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs index 4f48e18b8e0c..63c71991debd 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs @@ -1,8 +1,8 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -26,6 +26,6 @@ protected override void EndProcessing() this.Context.TransactionManager.Rollback(); } } - } // RollbackTransactionCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs index 0e4229762a76..9f27b746a2f3 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs @@ -1,6 +1,6 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #if !UNIX // Not built on Unix using System; @@ -14,6 +14,7 @@ using System.Runtime.Serialization; using System.Runtime.InteropServices; // Marshal, DllImport using System.Security.Permissions; +using System.Security.AccessControl; using NakedWin32Handle = System.IntPtr; using DWORD = System.UInt32; @@ -22,17 +23,17 @@ namespace Microsoft.PowerShell.Commands #region ServiceBaseCommand /// - /// This class implements the base for service commands + /// This class implements the base for service commands. /// public abstract class ServiceBaseCommand : Cmdlet { #region Internal /// - /// Confirm that the operation should proceed + /// Confirm that the operation should proceed. /// - /// service object to be acted on - /// true if operation should continue, false otherwise + /// Service object to be acted on. + /// True if operation should continue, false otherwise. protected bool ShouldProcessServiceOperation(ServiceController service) { return ShouldProcessServiceOperation( @@ -41,11 +42,11 @@ protected bool ShouldProcessServiceOperation(ServiceController service) } /// - /// Confirm that the operation should proceed + /// Confirm that the operation should proceed. /// - /// display name of service to be acted on - /// service name of service to be acted on - /// true if operation should continue, false otherwise + /// Display name of service to be acted on. + /// Service name of service to be acted on. + /// True if operation should continue, false otherwise. protected bool ShouldProcessServiceOperation( string displayName, string serviceName) { @@ -103,7 +104,7 @@ protected bool ShouldProcessServiceOperation(ServiceController service) string message = StringUtil.Format(errorMessage, serviceName, displayName, - (null == innerException) ? String.Empty : innerException.Message); + (innerException == null) ? string.Empty : innerException.Message); var exception = new ServiceCommandException(message, innerException); exception.ServiceName = serviceName; @@ -112,38 +113,38 @@ protected bool ShouldProcessServiceOperation(ServiceController service) } #endregion Internal - } // class ServiceBaseCommand + } #endregion ServiceBaseCommand #region MultipleServiceCommandBase /// /// This class implements the base for service commands which can - /// operate on multiple services + /// operate on multiple services. /// public abstract class MultipleServiceCommandBase : ServiceBaseCommand { #region Parameters /// - /// The various process selection modes + /// The various process selection modes. /// internal enum SelectionMode { /// - /// Select all services + /// Select all services. /// Default = 0, /// - /// Select services matching the supplied names + /// Select services matching the supplied names. /// DisplayName = 1, /// - /// Select services based on pipeline input + /// Select services based on pipeline input. /// InputObject = 2, /// - /// Select services by Service name + /// Select services by Service name. /// ServiceName = 3 }; @@ -159,7 +160,7 @@ internal enum SelectionMode internal string[] serviceNames = null; /// - /// gets/sets an array of display names for services + /// Gets/sets an array of display names for services. /// [Parameter(ParameterSetName = "DisplayName", Mandatory = true)] public string[] DisplayName @@ -168,12 +169,14 @@ public string[] DisplayName { return displayNames; } + set { displayNames = value; selectionMode = SelectionMode.DisplayName; } } + internal string[] displayNames = null; /// @@ -190,11 +193,13 @@ public string[] Include { return include; } + set { include = value; } } + internal string[] include = null; /// @@ -211,11 +216,13 @@ public string[] Exclude { return exclude; } + set { exclude = value; } } + internal string[] exclude = null; // 1054295-2004/12/01-JonN This also works around 1054295. @@ -237,19 +244,21 @@ public ServiceController[] InputObject { return _inputObject; } + set { _inputObject = value; selectionMode = SelectionMode.InputObject; } } + private ServiceController[] _inputObject = null; #endregion Parameters #region Internal /// - /// Retrieve the master list of all services + /// Retrieve the master list of all services. /// /// /// @@ -261,13 +270,15 @@ internal ServiceController[] AllServices { get { - if (null == _allServices) + if (_allServices == null) { _allServices = ServiceController.GetServices(); } + return _allServices; } } + private ServiceController[] _allServices = null; internal ServiceController GetOneService(string nameOfService) @@ -313,12 +324,12 @@ internal List MatchingServices() // before being stopped. JimTru confirms that this is OK. matchingServices.Sort(ServiceComparison); return matchingServices; - } // MatchingServices + } // sort by servicename private static int ServiceComparison(ServiceController x, ServiceController y) { - return String.Compare(x.ServiceName, y.ServiceName, StringComparison.CurrentCultureIgnoreCase); + return string.Compare(x.ServiceName, y.ServiceName, StringComparison.OrdinalIgnoreCase); } /// @@ -339,12 +350,13 @@ private List MatchingServicesByServiceName() { List matchingServices = new List(); - if (null == serviceNames) + if (serviceNames == null) { foreach (ServiceController service in AllServices) { IncludeExcludeAdd(matchingServices, service, false); } + return matchingServices; } @@ -377,7 +389,7 @@ private List MatchingServicesByServiceName() { WriteNonTerminatingError( pattern, - String.Empty, + string.Empty, pattern, null, "NoServiceFoundForGivenName", @@ -385,8 +397,9 @@ private List MatchingServicesByServiceName() ErrorCategory.ObjectNotFound); } } + return matchingServices; - } // MatchingServicesByServiceName + } /// /// Retrieves the list of all services matching the DisplayName, @@ -399,11 +412,12 @@ private List MatchingServicesByServiceName() private List MatchingServicesByDisplayName() { List matchingServices = new List(); - if (null == DisplayName) + if (DisplayName == null) { Diagnostics.Assert(false, "null DisplayName"); throw PSTraceSource.NewInvalidOperationException(); } + foreach (string pattern in DisplayName) { WildcardPattern wildcard = @@ -416,10 +430,11 @@ private List MatchingServicesByDisplayName() found = true; IncludeExcludeAdd(matchingServices, service, true); } + if (!found && !WildcardPattern.ContainsWildcardCharacters(pattern)) { WriteNonTerminatingError( - String.Empty, + string.Empty, pattern, pattern, null, @@ -428,8 +443,9 @@ private List MatchingServicesByDisplayName() ErrorCategory.ObjectNotFound); } } + return matchingServices; - } // MatchingServicesByDisplayName + } /// /// Retrieves the list of all services matching the InputObject, @@ -439,18 +455,20 @@ private List MatchingServicesByDisplayName() private List MatchingServicesByInput() { List matchingServices = new List(); - if (null == InputObject) + if (InputObject == null) { Diagnostics.Assert(false, "null InputObject"); throw PSTraceSource.NewInvalidOperationException(); } + foreach (ServiceController service in InputObject) { service.Refresh(); IncludeExcludeAdd(matchingServices, service, false); } + return matchingServices; - } // MatchingServicesByInput + } /// /// Add to , @@ -458,17 +476,17 @@ private List MatchingServicesByInput() /// and (if ) if it is not /// already on . /// - /// list of services - /// service to add to list - /// check list for duplicates + /// List of services. + /// Service to add to list. + /// Check list for duplicates. private void IncludeExcludeAdd( List list, ServiceController service, bool checkDuplicates) { - if (null != include && !Matches(service, include)) + if (include != null && !Matches(service, include)) return; - if (null != exclude && Matches(service, exclude)) + if (exclude != null && Matches(service, exclude)) return; if (checkDuplicates) { @@ -481,6 +499,7 @@ private List MatchingServicesByInput() } } } + list.Add(service); } @@ -493,7 +512,7 @@ private List MatchingServicesByInput() /// private bool Matches(ServiceController service, string[] matchList) { - if (null == matchList) + if (matchList == null) throw PSTraceSource.NewArgumentNullException("matchList"); string serviceID = (selectionMode == SelectionMode.DisplayName) ? service.DisplayName @@ -504,16 +523,17 @@ private bool Matches(ServiceController service, string[] matchList) if (wildcard.IsMatch(serviceID)) return true; } + return false; } #endregion Internal - } // class MultipleServiceCommandBase + } #endregion MultipleServiceCommandBase #region GetServiceCommand /// - /// This class implements the get-service command + /// This class implements the get-service command. /// [Cmdlet(VerbsCommon.Get, "Service", DefaultParameterSetName = "Default", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113332", RemotingCapability = RemotingCapability.SupportedByCommand)] @@ -522,7 +542,7 @@ public sealed class GetServiceCommand : MultipleServiceCommandBase { #region Parameters /// - /// gets/sets an array of service names + /// Gets/sets an array of service names. /// /// /// The ServiceName parameter is declared in subclasses, @@ -537,6 +557,7 @@ public string[] Name { return serviceNames; } + set { serviceNames = value; @@ -551,7 +572,6 @@ public string[] Name [Alias("DS")] public SwitchParameter DependentServices { get; set; } - /// /// This returns the ServicesDependedOn of the specified service. /// @@ -563,7 +583,7 @@ public string[] Name #region Overrides /// - /// Write the service objects + /// Write the service objects. /// protected override void ProcessRecord() { @@ -582,6 +602,7 @@ protected override void ProcessRecord() WriteObject(dependantserv); } } + if (RequiredServices.IsPresent) { foreach (ServiceController servicedependedon in service.ServicesDependedOn) @@ -599,8 +620,9 @@ protected override void ProcessRecord() /// Adds UserName, Description, BinaryPathName, DelayedAutoStart and StartupType to a ServiceController object. /// /// - /// ServiceController as PSObject with UserName, Description and StartupType added - private PSObject AddProperties(ServiceController service) { + /// ServiceController as PSObject with UserName, Description and StartupType added. + private PSObject AddProperties(ServiceController service) + { NakedWin32Handle hScManager = IntPtr.Zero; NakedWin32Handle hService = IntPtr.Zero; int lastError = 0; @@ -612,7 +634,8 @@ protected override void ProcessRecord() lpDatabaseName: null, dwDesiredAccess: NativeMethods.SC_MANAGER_CONNECT ); - if (IntPtr.Zero == hScManager) { + if (IntPtr.Zero == hScManager) + { lastError = Marshal.GetLastWin32Error(); Win32Exception exception = new Win32Exception(lastError); WriteNonTerminatingError( @@ -622,12 +645,14 @@ protected override void ProcessRecord() ServiceResources.FailToOpenServiceControlManager, ErrorCategory.PermissionDenied); } + hService = NativeMethods.OpenServiceW( hScManager, service.ServiceName, NativeMethods.SERVICE_QUERY_CONFIG ); - if (IntPtr.Zero == hService) { + if (IntPtr.Zero == hService) + { lastError = Marshal.GetLastWin32Error(); Win32Exception exception = new Win32Exception(lastError); WriteNonTerminatingError( @@ -647,7 +672,8 @@ protected override void ProcessRecord() NativeMethods.QUERY_SERVICE_CONFIG serviceInfo = new NativeMethods.QUERY_SERVICE_CONFIG(); querySuccessful = querySuccessful && NativeMethods.QueryServiceConfig(hService, out serviceInfo); - if(!querySuccessful) { + if (!querySuccessful) + { WriteNonTerminatingError( service: service, innerException: null, @@ -679,20 +705,25 @@ protected override void ProcessRecord() } finally { - if (IntPtr.Zero != hService) { + if (IntPtr.Zero != hService) + { bool succeeded = NativeMethods.CloseServiceHandle(hService); - if (!succeeded) { + if (!succeeded) + { Diagnostics.Assert(lastError != 0, "ErrorCode not success"); } } - if (IntPtr.Zero != hScManager) { + if (IntPtr.Zero != hScManager) + { bool succeeded = NativeMethods.CloseServiceHandle(hScManager); - if (!succeeded) { + if (!succeeded) + { Diagnostics.Assert(lastError != 0, "ErrorCode not success"); } } - } // finally + } + return serviceAsPSObj; } } @@ -707,7 +738,7 @@ public abstract class ServiceOperationBaseCommand : MultipleServiceCommandBase { #region Parameters /// - /// gets/sets an array of service names + /// Gets/sets an array of service names. /// /// /// The ServiceName parameter is declared in subclasses, @@ -721,6 +752,7 @@ public string[] Name { return serviceNames; } + set { serviceNames = value; @@ -729,7 +761,7 @@ public string[] Name } /// - /// Service controller objects + /// Service controller objects. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "InputObject", ValueFromPipeline = true)] [ValidateNotNullOrEmpty] @@ -740,6 +772,7 @@ public new ServiceController[] InputObject { return base.InputObject; } + set { base.InputObject = value; @@ -760,8 +793,8 @@ public new ServiceController[] InputObject /// Waits forever for the service to reach the desired status, but /// writes a string to WriteWarning every 2 seconds. /// - /// service on which to operate - /// desired status + /// Service on which to operate. + /// Desired status. /// /// This is the expected status while the operation is incomplete. /// If the service is in some other state, this means that the @@ -777,7 +810,7 @@ public new ServiceController[] InputObject /// /// errorMessage for a nonterminating error if operation fails /// - /// true if action succeeded + /// True if action succeeded. /// /// WriteWarning will throw this if the pipeline has been stopped. /// This means that the delay between hitting CTRL-C and stopping @@ -817,6 +850,7 @@ public new ServiceController[] InputObject ErrorCategory.OpenError); return false; } + string message = StringUtil.Format(resourceIdPending, serviceController.ServiceName, serviceController.DisplayName @@ -830,8 +864,8 @@ public new ServiceController[] InputObject /// /// This will start the service. /// - /// service to start - /// true iff the service was started + /// Service to start. + /// True iff the service was started. internal bool DoStartService(ServiceController serviceController) { Exception exception = null; @@ -847,13 +881,14 @@ internal bool DoStartService(ServiceController serviceController) catch (InvalidOperationException e) { Win32Exception eInner = e.InnerException as Win32Exception; - if (null == eInner + if (eInner == null || NativeMethods.ERROR_SERVICE_ALREADY_RUNNING != eInner.NativeErrorCode) { exception = e; } } - if (null != exception) + + if (exception != null) { // This service refused to accept the start command, // so write a non-terminating error. @@ -877,16 +912,17 @@ internal bool DoStartService(ServiceController serviceController) { return false; } + return true; } /// /// This will stop the service. /// - /// service to stop - /// stop dependent services + /// Service to stop. + /// Stop dependent services. /// - /// true iff the service was stopped + /// True iff the service was stopped. internal List DoStopService(ServiceController serviceController, bool force, bool waitForServiceToStop) { // Ignore ServiceController.CanStop. CanStop will be set false @@ -963,13 +999,14 @@ internal List DoStopService(ServiceController serviceControll { Win32Exception eInner = e.InnerException as Win32Exception; - if (null == eInner + if (eInner == null || NativeMethods.ERROR_SERVICE_NOT_ACTIVE != eInner.NativeErrorCode) { exception = e; } } - if (null != exception) + + if (exception != null) { // This service refused to accept the stop command, // so write a non-terminating error. @@ -1009,7 +1046,7 @@ internal List DoStopService(ServiceController serviceControll } /// - /// Check if all dependent services are stopped + /// Check if all dependent services are stopped. /// /// /// @@ -1025,13 +1062,14 @@ private bool HaveAllDependentServicesStopped(ICollection depe return false; } } + return true; } /// - /// This removes all services that are not stopped from a list of services + /// This removes all services that are not stopped from a list of services. /// - /// a list of services + /// A list of services. internal void RemoveNotStoppedServices(List services) { foreach (ServiceController service in services) @@ -1047,8 +1085,8 @@ internal void RemoveNotStoppedServices(List services) /// /// This will pause the service. /// - /// service to pause - /// true iff the service was paused + /// Service to pause. + /// True iff the service was paused. internal bool DoPauseService(ServiceController serviceController) { Exception exception = null; @@ -1063,19 +1101,22 @@ internal bool DoPauseService(ServiceController serviceController) { serviceNotRunning = true; } + exception = e; } catch (InvalidOperationException e) { Win32Exception eInner = e.InnerException as Win32Exception; - if (null != eInner + if (eInner != null && NativeMethods.ERROR_SERVICE_NOT_ACTIVE == eInner.NativeErrorCode) { serviceNotRunning = true; } + exception = e; } - if (null != exception) + + if (exception != null) { // This service refused to accept the pause command, // so write a non-terminating error. @@ -1125,8 +1166,8 @@ internal bool DoPauseService(ServiceController serviceController) /// /// This will resume the service. /// - /// service to resume - /// true iff the service was resumed + /// Service to resume. + /// True iff the service was resumed. internal bool DoResumeService(ServiceController serviceController) { Exception exception = null; @@ -1141,19 +1182,22 @@ internal bool DoResumeService(ServiceController serviceController) { serviceNotRunning = true; } + exception = e; } catch (InvalidOperationException e) { Win32Exception eInner = e.InnerException as Win32Exception; - if (null != eInner + if (eInner != null && NativeMethods.ERROR_SERVICE_NOT_ACTIVE == eInner.NativeErrorCode) { serviceNotRunning = true; } + exception = e; } - if (null != exception) + + if (exception != null) { // This service refused to accept the continue command, // so write a non-terminating error. @@ -1205,7 +1249,7 @@ internal bool DoResumeService(ServiceController serviceController) #region StopServiceCommand /// - /// This class implements the stop-service command + /// This class implements the stop-service command. /// /// /// Note that the services will be sorted before being stopped. @@ -1223,7 +1267,7 @@ public sealed class StopServiceCommand : ServiceOperationBaseCommand public SwitchParameter Force { get; set; } /// - /// Specifies whether to wait for a service to reach the stopped state before returning + /// Specifies whether to wait for a service to reach the stopped state before returning. /// [Parameter] public SwitchParameter NoWait { get; set; } @@ -1256,20 +1300,20 @@ protected override void ProcessRecord() } } } - } // ProcessRecord - } // StopServiceCommand + } + } #endregion StopServiceCommand #region StartServiceCommand /// - /// This class implements the start-service command + /// This class implements the start-service command. /// [Cmdlet(VerbsLifecycle.Start, "Service", DefaultParameterSetName = "InputObject", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113406")] [OutputType(typeof(ServiceController))] public sealed class StartServiceCommand : ServiceOperationBaseCommand { /// - /// Start the services + /// Start the services. /// protected override void ProcessRecord() { @@ -1288,20 +1332,20 @@ protected override void ProcessRecord() WriteObject(serviceController); } } - } // ProcessRecord - } // class StartServiceCommand + } + } #endregion StartServiceCommand #region SuspendServiceCommand /// - /// This class implements the suspend-service command + /// This class implements the suspend-service command. /// [Cmdlet(VerbsLifecycle.Suspend, "Service", DefaultParameterSetName = "InputObject", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113416")] [OutputType(typeof(ServiceController))] public sealed class SuspendServiceCommand : ServiceOperationBaseCommand { /// - /// Start the services + /// Start the services. /// protected override void ProcessRecord() { @@ -1320,13 +1364,13 @@ protected override void ProcessRecord() WriteObject(serviceController); } } - } // ProcessRecord - } // class SuspendServiceCommand + } + } #endregion SuspendServiceCommand #region ResumeServiceCommand /// - /// This class implements the resume-service command + /// This class implements the resume-service command. /// [Cmdlet(VerbsLifecycle.Resume, "Service", DefaultParameterSetName = "InputObject", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113386")] @@ -1334,7 +1378,7 @@ protected override void ProcessRecord() public sealed class ResumeServiceCommand : ServiceOperationBaseCommand { /// - /// Start the services + /// Start the services. /// protected override void ProcessRecord() { @@ -1346,20 +1390,21 @@ protected override void ProcessRecord() { continue; } + if (DoResumeService(serviceController)) { if (PassThru) WriteObject(serviceController); } } - } // ProcessRecord - } // class ResumeServiceCommand + } + } #endregion ResumeServiceCommand #region RestartServiceCommand /// - /// This class implements the restart-service command + /// This class implements the restart-service command. /// [Cmdlet(VerbsLifecycle.Restart, "Service", DefaultParameterSetName = "InputObject", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113385")] @@ -1391,7 +1436,7 @@ protected override void ProcessRecord() continue; } - //Set the NoWait parameter to false since we are not adding this switch to this cmdlet. + // Set the NoWait parameter to false since we are not adding this switch to this cmdlet. List stoppedServices = DoStopService(serviceController, Force, true); if (stoppedServices.Count > 0) @@ -1406,14 +1451,14 @@ protected override void ProcessRecord() } } } - } // ProcessRecord - } // RestartServiceCommand + } + } #endregion RestartServiceCommand #region SetServiceCommand /// - /// This class implements the set-service command + /// This class implements the set-service command. /// [Cmdlet(VerbsCommon.Set, "Service", SupportsShouldProcess = true, DefaultParameterSetName = "Name", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113399", RemotingCapability = RemotingCapability.SupportedByCommand)] @@ -1423,20 +1468,22 @@ public class SetServiceCommand : ServiceOperationBaseCommand #region Parameters /// - /// service name + /// Service name. /// /// [Parameter(Mandatory = true, ParameterSetName = "Name", Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [Alias("ServiceName", "SN")] - public new String Name + public new string Name { get { return serviceName; } + set { serviceName = value; } } - internal String serviceName = null; + + internal string serviceName = null; /// /// The following is the definition of the input parameter "InputObject". @@ -1457,65 +1504,80 @@ public new String Name public new string DisplayName { get { return displayName; } + set { displayName = value; } } + internal string displayName = null; /// - /// Account under which the service should run + /// Account under which the service should run. /// /// [Parameter] [Credential()] public PSCredential Credential { get; set; } - - /// /// The following is the definition of the input parameter "Description". /// Specifies a new description for the service. /// The service description appears in Services in Computer Management. /// Description is not a property of the ServiceController object that - /// Get-Service retrieve + /// Get-Service retrieve. /// [Parameter] [ValidateNotNullOrEmpty] public string Description { get { return description; } + set { description = value; } } - internal string description = null; + internal string description = null; /// /// The following is the definition of the input parameter "StartupType". + /// "Set-Service -StartType" sets ServiceController.InputObject.StartType. /// Changes the starting mode of the service. Valid values for StartupType are: /// -- Automatic: Start when the system starts. /// -- Manual : Starts only when started by a user or program. - /// -- Disabled : Can + /// -- Disabled : Can. /// [Parameter] - [Alias("StartMode", "SM", "ST")] + [Alias("StartMode", "SM", "ST", "StartType")] [ValidateNotNullOrEmpty] public ServiceStartupType StartupType { get { return startupType; } + set { startupType = value; } } + // We set the initial value to an invalid value so that we can // distinguish when this is and is not set. internal ServiceStartupType startupType = ServiceStartupType.InvalidValue; + /// + /// Sets the SecurityDescriptorSddl of the service using a SDDL string. + /// + [Parameter] + [Alias("sd")] + [ValidateNotNullOrEmpty] + public string SecurityDescriptorSddl + { + get; + set; + } /// /// The following is the definition of the input parameter "Status". @@ -1523,24 +1585,35 @@ public ServiceStartupType StartupType /// Paused). If it is already in that state, do nothing. If it is not, do the /// appropriate action to bring about the desired result (start/stop/suspend the /// service) and issue an error if this cannot be achieved. - /// Status can be Paused , Running and Stopped + /// Status can be Paused , Running and Stopped. /// [Parameter] [ValidateSetAttribute(new string[] { "Running", "Stopped", "Paused" })] public string Status { get { return serviceStatus; } + set { serviceStatus = value; } } + internal string serviceStatus = null; + /// + /// The following is the definition of the input parameter "Force". + /// This parameter is useful only when parameter "Stop" is enabled. + /// If "Force" is enabled, it will also stop the dependent services. + /// If not, it will send an error when this service has dependent ones. + /// + [Parameter] + public SwitchParameter Force { get; set; } + /// /// This is not a parameter for this cmdlet. /// - //This has been shadowed from base class and removed parameter tag to fix gcm "Set-Service" -syntax + // This has been shadowed from base class and removed parameter tag to fix gcm "Set-Service" -syntax [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public new string[] Include { @@ -1548,17 +1621,19 @@ public new string[] Include { return include; } + set { include = null; } } + internal new string[] include = null; /// /// This is not a parameter for this cmdlet. /// - //This has been shadowed from base class and removed parameter tag to fix gcm "Set-Service" -syntax + // This has been shadowed from base class and removed parameter tag to fix gcm "Set-Service" -syntax [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public new string[] Exclude { @@ -1566,17 +1641,18 @@ public new string[] Exclude { return exclude; } + set { exclude = null; } } + internal new string[] exclude = null; #endregion Parameters #region Overrides /// - /// /// [ArchitectureSensitive] protected override void ProcessRecord() @@ -1598,7 +1674,8 @@ protected override void ProcessRecord() service = new ServiceController(serviceName); objServiceShouldBeDisposed = true; } - Diagnostics.Assert(!String.IsNullOrEmpty(Name), "null ServiceName"); + + Diagnostics.Assert(!string.IsNullOrEmpty(Name), "null ServiceName"); // "new ServiceController" will succeed even if // there is no such service. This checks whether @@ -1607,14 +1684,14 @@ protected override void ProcessRecord() } catch (ArgumentException ex) { - //cannot use WriteNonterminatingError as service is null + // cannot use WriteNonterminatingError as service is null ErrorRecord er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.ObjectNotFound, Name); WriteError(er); return; } catch (InvalidOperationException ex) { - //cannot use WriteNonterminatingError as service is null + // cannot use WriteNonterminatingError as service is null ErrorRecord er = new ErrorRecord(ex, "InvalidOperationException", ErrorCategory.ObjectNotFound, Name); WriteError(er); return; @@ -1635,7 +1712,7 @@ protected override void ProcessRecord() try { hScManager = NativeMethods.OpenSCManagerW( - String.Empty, + string.Empty, null, NativeMethods.SC_MANAGER_CONNECT ); @@ -1652,11 +1729,13 @@ protected override void ProcessRecord() ErrorCategory.PermissionDenied); return; } + hService = NativeMethods.OpenServiceW( hScManager, Name, - NativeMethods.SERVICE_CHANGE_CONFIG + NativeMethods.SERVICE_CHANGE_CONFIG | NativeMethods.WRITE_DAC | NativeMethods.WRITE_OWNER ); + if (IntPtr.Zero == hService) { int lastError = Marshal.GetLastWin32Error(); @@ -1670,8 +1749,8 @@ protected override void ProcessRecord() return; } // Modify startup type or display name or credential - if (!String.IsNullOrEmpty(DisplayName) - || ServiceStartupType.InvalidValue != StartupType || null != Credential) + if (!string.IsNullOrEmpty(DisplayName) + || ServiceStartupType.InvalidValue != StartupType || Credential != null) { DWORD dwStartType = NativeMethods.SERVICE_NO_CHANGE; if (!NativeMethods.TryGetNativeStartupType(StartupType, out dwStartType)) @@ -1684,11 +1763,12 @@ protected override void ProcessRecord() } string username = null; - if (null != Credential) + if (Credential != null) { username = Credential.UserName; password = Marshal.SecureStringToCoTaskMemUnicode(Credential.Password); } + bool succeeded = NativeMethods.ChangeServiceConfigW( hService, NativeMethods.SERVICE_NO_CHANGE, @@ -1714,7 +1794,7 @@ protected override void ProcessRecord() ErrorCategory.PermissionDenied); return; } - } // modify startup type or display name + } NativeMethods.SERVICE_DESCRIPTIONW sd = new NativeMethods.SERVICE_DESCRIPTIONW(); sd.lpDescription = Description; @@ -1773,38 +1853,31 @@ protected override void ProcessRecord() if (!service.Status.Equals(ServiceControllerStatus.Running)) { if (service.Status.Equals(ServiceControllerStatus.Paused)) - //resume service + // resume service DoResumeService(service); else - //start service + // start service DoStartService(service); } } - else if (Status.Equals("Stopped", StringComparison.CurrentCultureIgnoreCase)) + else if (Status.Equals("Stopped", StringComparison.OrdinalIgnoreCase)) { if (!service.Status.Equals(ServiceControllerStatus.Stopped)) { - //check for the dependent services as set-service dont have force parameter + // Check for the dependent services as set-service dont have force parameter ServiceController[] dependentServices = service.DependentServices; - if ((dependentServices != null) && (dependentServices.Length > 0)) + if ((!Force) && (dependentServices != null) && (dependentServices.Length > 0)) { WriteNonTerminatingError(service, null, "ServiceHasDependentServicesNoForce", ServiceResources.ServiceHasDependentServicesNoForce, ErrorCategory.InvalidOperation); return; } - ServiceController[] servicedependedon = service.ServicesDependedOn; - - if ((servicedependedon != null) && (servicedependedon.Length > 0)) - { - WriteNonTerminatingError(service, null, "ServiceIsDependentOnNoForce", ServiceResources.ServiceIsDependentOnNoForce, ErrorCategory.InvalidOperation); - return; - } // Stop service, pass 'true' to the force parameter as we have already checked for the dependent services. - DoStopService(service, force: true, waitForServiceToStop: true); + DoStopService(service, Force, waitForServiceToStop: true); } } - else if (Status.Equals("Paused", StringComparison.CurrentCultureIgnoreCase)) + else if (Status.Equals("Paused", StringComparison.OrdinalIgnoreCase)) { if (!service.Status.Equals(ServiceControllerStatus.Paused)) { @@ -1812,6 +1885,38 @@ protected override void ProcessRecord() } } } + + if(!string.IsNullOrEmpty(SecurityDescriptorSddl)) + { + var rawSecurityDescriptor = new RawSecurityDescriptor(SecurityDescriptorSddl); + RawAcl rawDiscretionaryAcl = rawSecurityDescriptor.DiscretionaryAcl ; + var discretionaryAcl = new DiscretionaryAcl (false, false, rawDiscretionaryAcl ); + + byte[] rawDacl = new byte[discretionaryAcl.BinaryLength]; + discretionaryAcl.GetBinaryForm(rawDacl, 0); + rawSecurityDescriptor.DiscretionaryAcl = new RawAcl(rawDacl, 0); + byte[] securityDescriptorByte = new byte[rawSecurityDescriptor.BinaryLength]; + rawSecurityDescriptor.GetBinaryForm(securityDescriptorByte, 0); + + status = NativeMethods.SetServiceObjectSecurity( + hService, + SecurityInfos.DiscretionaryAcl, + securityDescriptorByte); + + if (!status) + { + int lastError = Marshal.GetLastWin32Error(); + Win32Exception exception = new Win32Exception(lastError); + bool accessDenied = exception.NativeErrorCode == NativeMethods.ERROR_ACCESS_DENIED; + WriteNonTerminatingError( + service, + exception, + nameof(ServiceResources.CouldNotSetServiceSecurityDescriptorSddl), + StringUtil.Format(ServiceResources.CouldNotSetServiceSecurityDescriptorSddl, Name, exception.Message), + accessDenied ? ErrorCategory.PermissionDenied : ErrorCategory.InvalidOperation); + } + } + if (PassThru.IsPresent) { // To display the service, refreshing the service would not show the display name after updating @@ -1825,6 +1930,7 @@ protected override void ProcessRecord() { Marshal.FreeCoTaskMem(delayedAutoStartInfoBuffer); } + if (IntPtr.Zero != hService) { bool succeeded = NativeMethods.CloseServiceHandle(hService); @@ -1856,14 +1962,15 @@ protected override void ProcessRecord() ErrorCategory.PermissionDenied); } } - } // finally - } //End try + } + } finally { if (IntPtr.Zero != password) { Marshal.ZeroFreeCoTaskMemUnicode(password); } + if (objServiceShouldBeDisposed) { service.Dispose(); @@ -1872,12 +1979,12 @@ protected override void ProcessRecord() } #endregion Overrides - } // class SetServiceCommand + } #endregion SetServiceCommand #region NewServiceCommand /// - /// This class implements the set-service command + /// This class implements the set-service command. /// [Cmdlet(VerbsCommon.New, "Service", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113359")] [OutputType(typeof(ServiceController))] @@ -1885,7 +1992,7 @@ public class NewServiceCommand : ServiceBaseCommand { #region Parameters /// - /// Name of the service to create + /// Name of the service to create. /// /// [Parameter(Position = 0, Mandatory = true)] @@ -1893,24 +2000,29 @@ public class NewServiceCommand : ServiceBaseCommand public string Name { get { return serviceName; } + set { serviceName = value; } } + internal string serviceName = null; /// - /// The executable which implements this service + /// The executable which implements this service. /// /// [Parameter(Position = 1, Mandatory = true)] + [Alias("Path")] public string BinaryPathName { get { return binaryPathName; } + set { binaryPathName = value; } } + internal string binaryPathName = null; /// - /// DisplayName of the service to create + /// DisplayName of the service to create. /// /// [Parameter] @@ -1918,12 +2030,14 @@ public string BinaryPathName public string DisplayName { get { return displayName; } + set { displayName = value; } } + internal string displayName = null; /// - /// Description of the service to create + /// Description of the service to create. /// /// [Parameter] @@ -1931,8 +2045,10 @@ public string DisplayName public string Description { get { return description; } + set { description = value; } } + internal string description = null; /// @@ -1943,12 +2059,14 @@ public string Description public ServiceStartupType StartupType { get { return startupType; } + set { startupType = value; } } + internal ServiceStartupType startupType = ServiceStartupType.Automatic; /// - /// Account under which the service should run + /// Account under which the service should run. /// /// [Parameter] @@ -1956,38 +2074,42 @@ public ServiceStartupType StartupType public PSCredential Credential { get { return credential; } + set { credential = value; } } + internal PSCredential credential = null; /// - /// Other services on which the new service depends + /// Other services on which the new service depends. /// /// [Parameter] public string[] DependsOn { get { return dependsOn; } + set { dependsOn = value; } } + internal string[] dependsOn = null; #endregion Parameters #region Overrides /// - /// Create the service + /// Create the service. /// [ArchitectureSensitive] protected override void BeginProcessing() { - Diagnostics.Assert(!String.IsNullOrEmpty(Name), + Diagnostics.Assert(!string.IsNullOrEmpty(Name), "null ServiceName"); - Diagnostics.Assert(!String.IsNullOrEmpty(BinaryPathName), + Diagnostics.Assert(!string.IsNullOrEmpty(BinaryPathName), "null BinaryPathName"); // confirm the operation first // this is always false if WhatIf is set - if (!ShouldProcessServiceOperation(DisplayName ?? String.Empty, Name)) + if (!ShouldProcessServiceOperation(DisplayName ?? string.Empty, Name)) { return; } @@ -2018,6 +2140,7 @@ protected override void BeginProcessing() ErrorCategory.PermissionDenied); return; } + if (!NativeMethods.TryGetNativeStartupType(StartupType, out DWORD dwStartType)) { WriteNonTerminatingError(StartupType.ToString(), "New-Service", Name, @@ -2028,13 +2151,14 @@ protected override void BeginProcessing() } // set up the double-null-terminated lpDependencies parameter IntPtr lpDependencies = IntPtr.Zero; - if (null != DependsOn) + if (DependsOn != null) { int numchars = 1; // final null foreach (string dependedOn in DependsOn) { numchars += dependedOn.Length + 1; } + char[] doubleNullArray = new char[numchars]; int pos = 0; foreach (string dependedOn in DependsOn) @@ -2047,6 +2171,7 @@ protected override void BeginProcessing() pos += dependedOn.Length; doubleNullArray[pos++] = (char)0; // null terminator } + doubleNullArray[pos++] = (char)0; // double-null terminator Diagnostics.Assert(pos == numchars, "lpDependencies build error"); lpDependencies = Marshal.AllocHGlobal( @@ -2056,7 +2181,7 @@ protected override void BeginProcessing() // set up the Credential parameter string username = null; - if (null != Credential) + if (Credential != null) { username = Credential.UserName; password = Marshal.SecureStringToCoTaskMemUnicode(Credential.Password); @@ -2120,7 +2245,8 @@ protected override void BeginProcessing() } // Set the delayed auto start - if(StartupType == ServiceStartupType.AutomaticDelayedStart) { + if (StartupType == ServiceStartupType.AutomaticDelayedStart) + { NativeMethods.SERVICE_DELAYED_AUTO_START_INFO ds = new NativeMethods.SERVICE_DELAYED_AUTO_START_INFO(); ds.fDelayedAutostart = true; size = Marshal.SizeOf(ds); @@ -2204,12 +2330,12 @@ protected override void BeginProcessing() } } #endregion Overrides - } // class NewServiceCommand + } #endregion NewServiceCommand #region RemoveServiceCommand /// - /// This class implements the Remove-Service command + /// This class implements the Remove-Service command. /// [Cmdlet(VerbsCommon.Remove, "Service", SupportsShouldProcess = true, DefaultParameterSetName = "Name")] public class RemoveServiceCommand : ServiceBaseCommand @@ -2217,7 +2343,7 @@ public class RemoveServiceCommand : ServiceBaseCommand #region Parameters /// - /// Name of the service to remove + /// Name of the service to remove. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "Name")] [Alias("ServiceName", "SN")] @@ -2236,7 +2362,7 @@ public class RemoveServiceCommand : ServiceBaseCommand #region Overrides /// - /// Remove the service + /// Remove the service. /// [ArchitectureSensitive] protected override void ProcessRecord() @@ -2256,7 +2382,8 @@ protected override void ProcessRecord() service = new ServiceController(Name); objServiceShouldBeDisposed = true; } - Diagnostics.Assert(!String.IsNullOrEmpty(Name), "null ServiceName"); + + Diagnostics.Assert(!string.IsNullOrEmpty(Name), "null ServiceName"); // "new ServiceController" will succeed even if there is no such service. // This checks whether the service actually exists. @@ -2291,7 +2418,7 @@ protected override void ProcessRecord() try { hScManager = NativeMethods.OpenSCManagerW( - lpMachineName: String.Empty, + lpMachineName: string.Empty, lpDatabaseName: null, dwDesiredAccess: NativeMethods.SC_MANAGER_ALL_ACCESS ); @@ -2308,6 +2435,7 @@ protected override void ProcessRecord() ErrorCategory.PermissionDenied); return; } + hService = NativeMethods.OpenServiceW( hScManager, Name, @@ -2361,8 +2489,8 @@ protected override void ProcessRecord() Diagnostics.Assert(lastError != 0, "ErrorCode not success"); } } - } // Finally - } // End try + } + } finally { if (objServiceShouldBeDisposed) @@ -2372,21 +2500,21 @@ protected override void ProcessRecord() } } #endregion Overrides - } // class RemoveServiceCommand + } #endregion RemoveServiceCommand #region ServiceCommandException /// - /// Non-terminating errors occurring in the service noun commands + /// Non-terminating errors occurring in the service noun commands. /// [Serializable] public class ServiceCommandException : SystemException { #region ctors /// - /// unimplemented standard constructor + /// Unimplemented standard constructor. /// - /// doesn't return + /// Doesn't return. public ServiceCommandException() : base() { @@ -2394,17 +2522,17 @@ public ServiceCommandException() } /// - /// standard constructor + /// Standard constructor. /// /// - /// constructed object + /// Constructed object. public ServiceCommandException(string message) : base(message) { } /// - /// standard constructor + /// Standard constructor. /// /// /// @@ -2416,11 +2544,11 @@ public ServiceCommandException(string message, Exception innerException) #region Serialization /// - /// serialization constructor + /// Serialization constructor. /// /// /// - /// constructed object + /// Constructed object. protected ServiceCommandException(SerializationInfo info, StreamingContext context) : base(info, context) { @@ -2432,10 +2560,10 @@ protected ServiceCommandException(SerializationInfo info, StreamingContext conte _serviceName = info.GetString("ServiceName"); } /// - /// Serializer + /// Serializer. /// - /// serialization information - /// streaming context + /// Serialization information. + /// Streaming context. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -2451,17 +2579,19 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont #region Properties /// - /// Name of the service which could not be found or operated upon + /// Name of the service which could not be found or operated upon. /// /// public string ServiceName { get { return _serviceName; } + set { _serviceName = value; } } - private string _serviceName = String.Empty; + + private string _serviceName = string.Empty; #endregion Properties - } // class ServiceCommandException + } #endregion ServiceCommandException #region NativeMethods @@ -2471,6 +2601,7 @@ internal static class NativeMethods internal const int ERROR_SERVICE_ALREADY_RUNNING = 1056; internal const int ERROR_SERVICE_NOT_ACTIVE = 1062; internal const int ERROR_INSUFFICIENT_BUFFER = 122; + internal const DWORD ERROR_ACCESS_DENIED = 0x5; internal const DWORD SC_MANAGER_CONNECT = 1; internal const DWORD SC_MANAGER_CREATE_SERVICE = 2; internal const DWORD SC_MANAGER_ALL_ACCESS = 0xf003f; @@ -2484,7 +2615,8 @@ internal static class NativeMethods internal const DWORD SERVICE_CONFIG_DESCRIPTION = 1; internal const DWORD SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3; internal const DWORD SERVICE_CONFIG_SERVICE_SID_INFO = 5; - + internal const DWORD WRITE_DAC = 262144; + internal const DWORD WRITE_OWNER =524288; internal const DWORD SERVICE_WIN32_OWN_PROCESS = 0x10; internal const DWORD SERVICE_ERROR_NORMAL = 1; @@ -2605,6 +2737,16 @@ internal static extern [In] IntPtr lpPassword ); + + [DllImport(PinvokeDllNames.SetServiceObjectSecurityDllName, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern + bool SetServiceObjectSecurity( + NakedWin32Handle hSCManager, + System.Security.AccessControl.SecurityInfos dwSecurityInformation, + byte[] lpSecurityDescriptor + ); + /// /// CreateJobObject API creates or opens a job object. /// @@ -2679,7 +2821,8 @@ internal static bool QueryServiceConfig(NakedWin32Handle hService, out NativeMet cbBufSize: 0, pcbBytesNeeded: out bufferSizeNeeded); - if (status != true && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) { + if (status != true && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) + { return status; } @@ -2699,6 +2842,7 @@ internal static bool QueryServiceConfig(NakedWin32Handle hService, out NativeMet { Marshal.FreeCoTaskMem(lpBuffer); } + return status; } @@ -2715,7 +2859,8 @@ internal static bool QueryServiceConfig2(NakedWin32Handle hService, DWORD inf cbBufSize: 0, pcbBytesNeeded: out bufferSizeNeeded); - if (status != true && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) { + if (status != true && Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) + { return status; } @@ -2736,11 +2881,12 @@ internal static bool QueryServiceConfig2(NakedWin32Handle hService, DWORD inf { Marshal.FreeCoTaskMem(lpBuffer); } + return status; } /// - /// Get appropriate win32 StartupType + /// Get appropriate win32 StartupType. /// /// /// StartupType provided by the user. @@ -2774,13 +2920,14 @@ internal static bool TryGetNativeStartupType(ServiceStartupType StartupType, out success = false; break; } + return success; } internal static ServiceStartupType GetServiceStartupType(ServiceStartMode startMode, bool delayedAutoStart) { ServiceStartupType result = ServiceStartupType.Disabled; - switch(startMode) + switch (startMode) { case ServiceStartMode.Automatic: result = delayedAutoStart ? ServiceStartupType.AutomaticDelayedStart : ServiceStartupType.Automatic; @@ -2792,6 +2939,7 @@ internal static ServiceStartupType GetServiceStartupType(ServiceStartMode startM result = ServiceStartupType.Disabled; break; } + return result; } } @@ -2801,7 +2949,8 @@ internal static ServiceStartupType GetServiceStartupType(ServiceStartMode startM /// ///Enum for usage with StartupType. Automatic, Manual and Disabled index matched from System.ServiceProcess.ServiceStartMode /// - public enum ServiceStartupType { + public enum ServiceStartupType + { ///Invalid service InvalidValue = -1, ///Automatic service diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetClipboardCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetClipboardCommand.cs index a59d4a69670f..bce2f7ec14e5 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetClipboardCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetClipboardCommand.cs @@ -1,16 +1,19 @@ -using System; -using System.Management.Automation; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; -using System.Windows.Forms; -using System.Collections.Specialized; -using System.Linq; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Text; using System.Text.RegularExpressions; +using System.Windows.Forms; namespace Microsoft.PowerShell.Commands { @@ -67,17 +70,19 @@ public class SetClipboardCommand : PSCmdlet public SwitchParameter AsHtml { get { return _asHtml; } + set { _isHtmlSet = true; _asHtml = value; } } + private bool _asHtml; private bool _isHtmlSet = false; /// - /// This method implements the BeginProcessing method for Set-Clipboard command + /// This method implements the BeginProcessing method for Set-Clipboard command. /// protected override void BeginProcessing() { @@ -85,7 +90,7 @@ protected override void BeginProcessing() } /// - /// This method implements the ProcessRecord method for Set-Clipboard command + /// This method implements the ProcessRecord method for Set-Clipboard command. /// protected override void ProcessRecord() { @@ -93,7 +98,7 @@ protected override void ProcessRecord() if (Value == null && _isHtmlSet) { ThrowTerminatingError(new ErrorRecord(new InvalidOperationException( - String.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidHtmlCombine)), + string.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidHtmlCombine)), "FailedToSetClipboard", ErrorCategory.InvalidOperation, "Clipboard")); } @@ -112,7 +117,7 @@ protected override void ProcessRecord() } /// - /// This method implements the EndProcessing method for Set-Clipboard command + /// This method implements the EndProcessing method for Set-Clipboard command. /// protected override void EndProcessing() { @@ -142,11 +147,12 @@ private void SetClipboardContent(List contentList, bool append, bool asH if ((contentList == null || contentList.Count == 0) && !append) { - setClipboardShouldProcessTarget = String.Format(CultureInfo.InvariantCulture, ClipboardResources.ClipboardCleared); + setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.ClipboardCleared); if (ShouldProcess(setClipboardShouldProcessTarget, "Set-Clipboard")) { Clipboard.Clear(); } + return; } @@ -155,7 +161,7 @@ private void SetClipboardContent(List contentList, bool append, bool asH { if (!Clipboard.ContainsText()) { - WriteVerbose(String.Format(CultureInfo.InvariantCulture, ClipboardResources.NoAppendableClipboardContent)); + WriteVerbose(string.Format(CultureInfo.InvariantCulture, ClipboardResources.NoAppendableClipboardContent)); append = false; } else @@ -183,11 +189,11 @@ private void SetClipboardContent(List contentList, bool append, bool asH if (append) { - setClipboardShouldProcessTarget = String.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendClipboardContent, verboseString); + setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendClipboardContent, verboseString); } else { - setClipboardShouldProcessTarget = String.Format(CultureInfo.InvariantCulture, ClipboardResources.SetClipboardContent, verboseString); + setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.SetClipboardContent, verboseString); } if (ShouldProcess(setClipboardShouldProcessTarget, "Set-Clipboard")) @@ -217,7 +223,7 @@ private void CopyFilesToClipboard(List fileList, bool append, bool isLit { if (!Clipboard.ContainsFileDropList()) { - WriteVerbose(String.Format(CultureInfo.InvariantCulture, ClipboardResources.NoAppendableClipboardContent)); + WriteVerbose(string.Format(CultureInfo.InvariantCulture, ClipboardResources.NoAppendableClipboardContent)); append = false; } else @@ -225,7 +231,7 @@ private void CopyFilesToClipboard(List fileList, bool append, bool isLit StringCollection clipBoardContent = Clipboard.GetFileDropList(); dropFiles = new HashSet(clipBoardContent.Cast().ToList(), StringComparer.OrdinalIgnoreCase); - //we need the count of original files so we can get the accurate files number that has been appended. + // we need the count of original files so we can get the accurate files number that has been appended. clipBoardContentLength = clipBoardContent.Count; } } @@ -270,22 +276,22 @@ private void CopyFilesToClipboard(List fileList, bool append, bool isLit { if (append) { - setClipboardShouldProcessTarget = String.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendSingleFileToClipboard, dropFiles.ElementAt(dropFiles.Count - 1)); + setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendSingleFileToClipboard, dropFiles.ElementAt(dropFiles.Count - 1)); } else { - setClipboardShouldProcessTarget = String.Format(CultureInfo.InvariantCulture, ClipboardResources.SetSingleFileToClipboard, dropFiles.ElementAt(0)); + setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.SetSingleFileToClipboard, dropFiles.ElementAt(0)); } } else { if (append) { - setClipboardShouldProcessTarget = String.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendMultipleFilesToClipboard, (dropFiles.Count - clipBoardContentLength)); + setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendMultipleFilesToClipboard, (dropFiles.Count - clipBoardContentLength)); } else { - setClipboardShouldProcessTarget = String.Format(CultureInfo.InvariantCulture, ClipboardResources.SetMultipleFilesToClipboard, dropFiles.Count); + setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.SetMultipleFilesToClipboard, dropFiles.Count); } } @@ -302,8 +308,8 @@ private void CopyFilesToClipboard(List fileList, bool append, bool isLit /// /// Generate HTML fragment data string with header that is required for the clipboard. /// - /// the html to generate for - /// the resulted string + /// The html to generate for. + /// The resulted string. private static string GetHtmlDataString(string html) { // The string contains index references to other spots in the string, so we need placeholders so we can compute the offsets. @@ -329,15 +335,15 @@ private static string GetHtmlDataString(string html) int fragmentEndIdx = html.LastIndexOf(EndFragment, StringComparison.OrdinalIgnoreCase); // if html tag is missing add it surrounding the given html - //find the index of " 0 ? html.IndexOf('>', htmlOpenIdx) + 1 : -1; - //find the index of " 0 ? html.IndexOf('>', bodyOpenIdx) + 1 : -1; @@ -355,7 +361,7 @@ private static string GetHtmlDataString(string html) else { // insert start/end fragments in the proper place (related to html/body tags if exists) so the paste will work correctly - //find the index of " /// Calculates the number of bytes produced by encoding the string in the string builder in UTF-8 and not .NET default string encoding. /// - /// the string builder to count its string - /// optional: the start index to calculate from (default - start of string) - /// optional: the end index to calculate to (default - end of string) - /// the number of bytes required to encode the string in UTF-8 + /// The string builder to count its string. + /// Optional: the start index to calculate from (default - start of string). + /// Optional: the end index to calculate to (default - end of string). + /// The number of bytes required to encode the string in UTF-8. private static int GetByteCount(StringBuilder sb, int start = 0, int end = -1) { char[] _byteCount = new char[1]; @@ -414,6 +420,7 @@ private static int GetByteCount(StringBuilder sb, int start = 0, int end = -1) _byteCount[0] = sb[i]; count += Encoding.UTF8.GetByteCount(_byteCount); } + return count; } } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetContentCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetContentCommand.cs index bd2584a3f7aa..2187264866b4 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetContentCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetContentCommand.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; using System.Management.Automation.Internal; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// A command to set the content of an item at a specified path + /// A command to set the content of an item at a specified path. /// [Cmdlet(VerbsCommon.Set, "Content", DefaultParameterSetName = "Path", SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113392")] @@ -21,11 +21,9 @@ public class SetContentCommand : WriteContentCommandBase /// Called by the base class before the streams are open for the path. /// This override clears the content from the item. /// - /// /// /// The path to the items that will be opened for writing content. /// - /// internal override void BeforeOpenStreams(string[] paths) { if (paths == null || paths.Length == 0) @@ -66,24 +64,21 @@ internal override void BeforeOpenStreams(string[] paths) } catch (ItemNotFoundException) { - //If the item is not found then there is nothing to clear so ignore this exception. + // If the item is not found then there is nothing to clear so ignore this exception. continue; } } - } // BeforeOpenStreams + } /// /// Makes the call to ShouldProcess with appropriate action and target strings. /// - /// /// /// The path to the item on which the content will be set. /// - /// /// /// True if the action should continue or false otherwise. /// - /// internal override bool CallShouldProcess(string path) { string action = NavigationResources.SetContentAction; @@ -93,6 +88,6 @@ internal override bool CallShouldProcess(string path) return ShouldProcess(target, action); } #endregion protected members - } // SetContentCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetPropertyCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetPropertyCommand.cs index f64bfaf32172..1bbb6068ae9d 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetPropertyCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetPropertyCommand.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// A command to set the property of an item at a specified path + /// A command to set the property of an item at a specified path. /// [Cmdlet(VerbsCommon.Set, "ItemProperty", DefaultParameterSetName = "propertyValuePathSet", SupportsShouldProcess = true, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113396")] @@ -23,7 +23,7 @@ public class SetItemPropertyCommand : PassThroughItemPropertyCommandBase #region Parameters /// - /// Gets or sets the path parameter to the command + /// Gets or sets the path parameter to the command. /// [Parameter(Position = 0, ParameterSetName = propertyPSObjectPathSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] @@ -32,20 +32,22 @@ public class SetItemPropertyCommand : PassThroughItemPropertyCommandBase public string[] Path { get { return paths; } + set { paths = value; } } /// - /// Gets or sets the literal path parameter to the command + /// Gets or sets the literal path parameter to the command. /// [Parameter(ParameterSetName = propertyValueLiteralPathSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] [Parameter(ParameterSetName = propertyPSObjectLiteralPathSet, Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get { return paths; } + set { base.SuppressWildcardExpansion = true; @@ -58,26 +60,22 @@ public string[] LiteralPath /// /// The name of the property to set. /// - /// /// /// This value type is determined by the InvokeProvider. /// - /// [Parameter(Position = 1, ParameterSetName = propertyValuePathSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Parameter(Position = 1, ParameterSetName = propertyValueLiteralPathSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Alias("PSProperty")] - public string Name { get; set; } = String.Empty; + public string Name { get; set; } = string.Empty; /// /// The value of the property to set. /// - /// /// /// This value type is determined by the InvokeProvider. /// - /// [Parameter(Position = 2, ParameterSetName = propertyValuePathSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Parameter(Position = 2, ParameterSetName = propertyValueLiteralPathSet, @@ -87,7 +85,7 @@ public string[] LiteralPath #endregion Property Value set - #region Shell Object set + #region Shell object set /// /// A PSObject that contains the properties and values to be set. @@ -101,23 +99,20 @@ public string[] LiteralPath ValueFromPipeline = true)] public PSObject InputObject { get; set; } - #endregion Shell Object set + #endregion Shell object set /// /// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { PSObject mshObject = null; @@ -126,24 +121,26 @@ internal override object GetDynamicParameters(CmdletProviderContext context) { case propertyValuePathSet: case propertyValueLiteralPathSet: - if (!String.IsNullOrEmpty(Name)) + if (!string.IsNullOrEmpty(Name)) { mshObject = new PSObject(); mshObject.Properties.Add(new PSNoteProperty(Name, Value)); } + break; default: mshObject = InputObject; break; - } // switch + } if (Path != null && Path.Length > 0) { return InvokeProvider.Property.SetPropertyDynamicParameters(Path[0], mshObject, context); } + return InvokeProvider.Property.SetPropertyDynamicParameters(".", mshObject, context); - } // GetDynamicParameters + } #endregion Parameters @@ -154,7 +151,7 @@ internal override object GetDynamicParameters(CmdletProviderContext context) #region Command code /// - /// Sets the content of the item at the specified path + /// Sets the content of the item at the specified path. /// protected override void ProcessRecord() { @@ -183,7 +180,7 @@ protected override void ProcessRecord() false, "One of the parameter sets should have been resolved or an error should have been thrown by the command processor"); break; - } // switch + } foreach (string path in Path) { @@ -224,9 +221,8 @@ protected override void ProcessRecord() continue; } } - } // ProcessRecord + } #endregion Command code - - } // SetItemPropertyCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetWMIInstanceCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetWMIInstanceCommand.cs index acdbea27d006..68c8fdfd5076 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/SetWMIInstanceCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/SetWMIInstanceCommand.cs @@ -1,23 +1,22 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; -using System.Management; -using System.Text; -using System.Management.Automation.Provider; -using System.ComponentModel; using System.Collections; using System.Collections.ObjectModel; -using System.Security.AccessControl; -using System.Runtime.InteropServices; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.Management; +using System.Management.Automation; +using System.Management.Automation.Provider; +using System.Runtime.InteropServices; +using System.Security.AccessControl; +using System.Text; namespace Microsoft.PowerShell.Commands { /// - /// A command to Set WMI Instance + /// A command to Set WMI Instance. /// [Cmdlet(VerbsCommon.Set, "WmiInstance", DefaultParameterSetName = "class", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113402", RemotingCapability = RemotingCapability.OwnedByCommand)] @@ -25,26 +24,25 @@ public sealed class SetWmiInstance : WmiBaseCmdlet { #region Parameters /// - /// The WMI Object to use + /// The WMI Object to use. /// - /// [Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = "object")] public ManagementObject InputObject { get; set; } = null; /// - /// The WMI Path to use + /// The WMI Path to use. /// [Parameter(ParameterSetName = "path", Mandatory = true)] public string Path { get; set; } = null; /// - /// The WMI class to use + /// The WMI class to use. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "class")] public string Class { get; set; } = null; /// - /// The property name /value pair + /// The property name /value pair. /// [Parameter(ParameterSetName = "path")] [Parameter(Position = 2, ParameterSetName = "class")] @@ -54,12 +52,13 @@ public sealed class SetWmiInstance : WmiBaseCmdlet public Hashtable Arguments { get; set; } = null; /// - /// The Flag to use + /// The Flag to use. /// [Parameter] public PutType PutType { get { return _putType; } + set { _putType = value; flagSpecified = true; } } @@ -81,6 +80,7 @@ protected override void ProcessRecord() RunAsJob("Set-WMIInstance"); return; } + if (InputObject != null) { object result = null; @@ -96,6 +96,7 @@ protected override void ProcessRecord() { return; } + mObj.Put(pOptions); } else @@ -103,6 +104,7 @@ protected override void ProcessRecord() InvalidOperationException exp = new InvalidOperationException(); throw exp; } + result = mObj; } catch (ManagementException e) @@ -115,14 +117,15 @@ protected override void ProcessRecord() ErrorRecord errorRecord = new ErrorRecord(e, "SetWMICOMException", ErrorCategory.InvalidOperation, null); WriteError(errorRecord); } + WriteObject(result); } else { ManagementPath mPath = null; - //If Class is specified only CreateOnly flag is supported + // If Class is specified only CreateOnly flag is supported mPath = this.SetWmiInstanceBuildManagementPath(); - //If server name is specified loop through it. + // If server name is specified loop through it. if (mPath != null) { if (!(mPath.Server == "." && serverNameSpecified)) @@ -131,6 +134,7 @@ protected override void ProcessRecord() ComputerName = serverName; } } + ConnectionOptions options = GetConnectionOption(); object result = null; ManagementObject mObject = null; @@ -148,6 +152,7 @@ protected override void ProcessRecord() { continue; } + mObject.Put(pOptions); } else @@ -155,6 +160,7 @@ protected override void ProcessRecord() InvalidOperationException exp = new InvalidOperationException(); throw exp; } + result = mObject; } catch (ManagementException e) @@ -167,6 +173,7 @@ protected override void ProcessRecord() ErrorRecord errorRecord = new ErrorRecord(e, "SetWMICOMException", ErrorCategory.InvalidOperation, null); WriteError(errorRecord); } + if (result != null) { WriteObject(result); diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs index 4d91c4d5461a..509c87915dfb 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs @@ -1,9 +1,9 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -26,6 +26,7 @@ public int Timeout { return (int)_timeout.TotalMinutes; } + set { // The transactions constructor treats a timeout of @@ -38,6 +39,7 @@ public int Timeout _timeoutSpecified = true; } } + private bool _timeoutSpecified = false; private TimeSpan _timeout = TimeSpan.MinValue; @@ -49,8 +51,10 @@ public int Timeout public SwitchParameter Independent { get { return _independent; } + set { _independent = value; } } + private SwitchParameter _independent; /// @@ -60,8 +64,10 @@ public SwitchParameter Independent public RollbackSeverity RollbackPreference { get { return _rollbackPreference; } + set { _rollbackPreference = value; } } + private RollbackSeverity _rollbackPreference = RollbackSeverity.Error; /// @@ -99,6 +105,6 @@ protected override void EndProcessing() } } } - } // StartTransactionCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs new file mode 100644 index 000000000000..19974c8891b7 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs @@ -0,0 +1,932 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// The implementation of the "Test-Connection" cmdlet. + /// + [Cmdlet(VerbsDiagnostic.Test, "Connection", DefaultParameterSetName = ParameterSetPingCount, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135266")] + [OutputType(typeof(PingReport), ParameterSetName = new string[] { ParameterSetPingCount })] + [OutputType(typeof(PingReply), ParameterSetName = new string[] { ParameterSetPingContinues, ParameterSetDetectionOfMTUSize })] + [OutputType(typeof(bool), ParameterSetName = new string[] { ParameterSetPingCount, ParameterSetPingContinues, ParameterSetConnectionByTCPPort })] + [OutputType(typeof(Int32), ParameterSetName = new string[] { ParameterSetDetectionOfMTUSize })] + [OutputType(typeof(TraceRouteReply), ParameterSetName = new string[] { ParameterSetTraceRoute })] + public class TestConnectionCommand : PSCmdlet + { + private const string ParameterSetPingCount = "PingCount"; + private const string ParameterSetPingContinues = "PingContinues"; + private const string ParameterSetTraceRoute = "TraceRoute"; + private const string ParameterSetConnectionByTCPPort = "ConnectionByTCPPort"; + private const string ParameterSetDetectionOfMTUSize = "DetectionOfMTUSize"; + + #region Parameters + + /// + /// Do ping test. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + public SwitchParameter Ping { get; set; } = true; + + /// + /// Force using IPv4 protocol. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + [Parameter(ParameterSetName = ParameterSetTraceRoute)] + [Parameter(ParameterSetName = ParameterSetDetectionOfMTUSize)] + [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)] + public SwitchParameter IPv4 { get; set; } + + /// + /// Force using IPv6 protocol. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + [Parameter(ParameterSetName = ParameterSetTraceRoute)] + [Parameter(ParameterSetName = ParameterSetDetectionOfMTUSize)] + [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)] + public SwitchParameter IPv6 { get; set; } + + /// + /// Do reverse DNS lookup to get names for IP addresses. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + [Parameter(ParameterSetName = ParameterSetTraceRoute)] + [Parameter(ParameterSetName = ParameterSetDetectionOfMTUSize)] + [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)] + public SwitchParameter ResolveDestination { get; set; } + + /// + /// Source from which to do a test (ping, trace route, ...). + /// The default is Local Host. + /// Remoting is not yet implemented internally in the cmdlet. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + [Parameter(ParameterSetName = ParameterSetTraceRoute)] + [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)] + public string Source { get; } = Dns.GetHostName(); + + /// + /// The number of times the Ping data packets can be forwarded by routers. + /// As gateways and routers transmit packets through a network, + /// they decrement the Time-to-Live (TTL) value found in the packet header. + /// The default (from Windows) is 128 hops. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + [Parameter(ParameterSetName = ParameterSetTraceRoute)] + [ValidateRange(0, sMaxHops)] + [Alias("Ttl", "TimeToLive", "Hops")] + public int MaxHops { get; set; } = sMaxHops; + + private const int sMaxHops = 128; + + /// + /// Count of attempts. + /// The default (from Windows) is 4 times. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [ValidateRange(ValidateRangeKind.Positive)] + public int Count { get; set; } = 4; + + /// + /// Delay between attempts. + /// The default (from Windows) is 1 second. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + [ValidateRange(ValidateRangeKind.Positive)] + public int Delay { get; set; } = 1; + + /// + /// Buffer size to send. + /// The default (from Windows) is 32 bites. + /// Max value is 65500 (limit from Windows API). + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + [Alias("Size", "Bytes", "BS")] + [ValidateRange(0, 65500)] + public int BufferSize { get; set; } = DefaultSendBufferSize; + + /// + /// Don't fragment ICMP packages. + /// Currently CoreFX not supports this on Unix. + /// + [Parameter(ParameterSetName = ParameterSetPingCount)] + [Parameter(ParameterSetName = ParameterSetPingContinues)] + public SwitchParameter DontFragment { get; set; } + + /// + /// Continue ping until user press Ctrl-C + /// or Int.MaxValue threshold reached. + /// + [Parameter(ParameterSetName = ParameterSetPingContinues)] + public SwitchParameter Continues { get; set; } + + /// + /// Set short output kind ('bool' for Ping, 'int' for MTU size ...). + /// Default is to return typed result object(s). + /// + [Parameter()] + public SwitchParameter Quiet; + + /// + /// Time-out value in seconds. + /// If a response is not received in this time, no response is assumed. + /// It is not the cmdlet timeout! It is a timeout for waiting one ping response. + /// The default (from Windows) is 5 second. + /// + [Parameter()] + [ValidateRange(ValidateRangeKind.Positive)] + public int TimeoutSeconds { get; set; } = 5; + + /// + /// Destination - computer name or IP address. + /// + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipeline = true, + ValueFromPipelineByPropertyName = true)] + [ValidateNotNullOrEmpty] + [Alias("ComputerName")] + public string[] TargetName { get; set; } + + /// + /// Detect MTU size. + /// + [Parameter(Mandatory = true, ParameterSetName = ParameterSetDetectionOfMTUSize)] + public SwitchParameter MTUSizeDetect { get; set; } + + /// + /// Do traceroute test. + /// + [Parameter(Mandatory = true, ParameterSetName = ParameterSetTraceRoute)] + public SwitchParameter Traceroute { get; set; } + + /// + /// Do tcp connection test. + /// + [ValidateRange(0, 65535)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSetConnectionByTCPPort)] + public int TCPPort { get; set; } + + #endregion Parameters + + /// + /// Init the cmdlet. + /// + protected override void BeginProcessing() + { + base.BeginProcessing(); + + switch (ParameterSetName) + { + case ParameterSetPingContinues: + Count = int.MaxValue; + break; + } + } + + /// + /// Process a connection test. + /// + protected override void ProcessRecord() + { + foreach (var targetName in TargetName) + { + switch (ParameterSetName) + { + case ParameterSetPingCount: + case ParameterSetPingContinues: + ProcessPing(targetName); + break; + case ParameterSetDetectionOfMTUSize: + ProcessMTUSize(targetName); + break; + case ParameterSetTraceRoute: + ProcessTraceroute(targetName); + break; + case ParameterSetConnectionByTCPPort: + ProcessConnectionByTCPPort(targetName); + break; + } + } + } + + #region ConnectionTest + + private void ProcessConnectionByTCPPort(String targetNameOrAddress) + { + string resolvedTargetName = null; + IPAddress targetAddress = null; + + if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress)) + { + return; + } + + WriteConnectionTestHeader(resolvedTargetName, targetAddress.ToString()); + + TcpClient client = new TcpClient(); + + try + { + Task connectionTask = client.ConnectAsync(targetAddress, TCPPort); + string targetString = targetAddress.ToString(); + + for (var i = 1; i <= TimeoutSeconds; i++) + { + WriteConnectionTestProgress(targetNameOrAddress, targetString, i); + + Task timeoutTask = Task.Delay(millisecondsDelay: 1000); + Task.WhenAny(connectionTask, timeoutTask).Result.Wait(); + + if (timeoutTask.Status == TaskStatus.Faulted || timeoutTask.Status == TaskStatus.Canceled) + { + // Waiting is interrupted by Ctrl-C. + WriteObject(false); + return; + } + + if (connectionTask.Status == TaskStatus.RanToCompletion) + { + WriteObject(true); + return; + } + } + } + catch + { + // Silently ignore connection errors. + } + finally + { + client.Close(); + WriteConnectionTestFooter(); + } + + WriteObject(false); + } + + private void WriteConnectionTestHeader(string resolvedTargetName, string targetAddress) + { + _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.ConnectionTestStart, resolvedTargetName, targetAddress); + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace); + WriteProgress(record); + } + + private void WriteConnectionTestProgress(string targetNameOrAddress, string targetAddress, int timeout) + { + var msg = StringUtil.Format(TestConnectionResources.ConnectionTestDescription, + targetNameOrAddress, + targetAddress, + timeout); + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg); + WriteProgress(record); + } + + private void WriteConnectionTestFooter() + { + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace); + record.RecordType = ProgressRecordType.Completed; + WriteProgress(record); + } + + #endregion ConnectionTest + + #region TracerouteTest + private void ProcessTraceroute(String targetNameOrAddress) + { + string resolvedTargetName = null; + IPAddress targetAddress = null; + byte[] buffer = GetSendBuffer(BufferSize); + + if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress)) + { + return; + } + + WriteConsoleTraceRouteHeader(resolvedTargetName, targetAddress.ToString()); + + TraceRouteResult traceRouteResult = new TraceRouteResult(Source, targetAddress, resolvedTargetName); + + Int32 currentHop = 1; + Ping sender = new Ping(); + PingOptions pingOptions = new PingOptions(currentHop, DontFragment.IsPresent); + PingReply reply = null; + Int32 timeout = TimeoutSeconds * 1000; + + do + { + TraceRouteReply traceRouteReply = new TraceRouteReply(); + + pingOptions.Ttl = traceRouteReply.Hop = currentHop; + currentHop++; + + // In the specific case we don't use 'Count' property. + // If we change 'DefaultTraceRoutePingCount' we should change 'ConsoleTraceRouteReply' resource string. + for (int i = 1; i <= DefaultTraceRoutePingCount; i++) + { + try + { + reply = sender.Send(targetAddress, timeout, buffer, pingOptions); + + traceRouteReply.PingReplies.Add(reply); + } + catch (PingException ex) + { + string message = StringUtil.Format(TestConnectionResources.NoPingResult, + resolvedTargetName, + ex.Message); + Exception pingException = new System.Net.NetworkInformation.PingException(message, ex.InnerException); + ErrorRecord errorRecord = new ErrorRecord(pingException, + TestConnectionExceptionId, + ErrorCategory.ResourceUnavailable, + resolvedTargetName); + WriteError(errorRecord); + + continue; + } + catch + { + // Ignore host resolve exceptions. + } + + // We use short delay because it is impossible DoS with trace route. + Thread.Sleep(200); + } + + if (ResolveDestination && reply.Status == IPStatus.Success) + { + traceRouteReply.ReplyRouterName = Dns.GetHostEntry(reply.Address).HostName; + } + + traceRouteReply.ReplyRouterAddress = reply.Address; + + WriteTraceRouteProgress(traceRouteReply); + + traceRouteResult.Replies.Add(traceRouteReply); + } while (reply != null && currentHop <= sMaxHops && (reply.Status == IPStatus.TtlExpired || reply.Status == IPStatus.TimedOut)); + + WriteTraceRouteFooter(); + + if (Quiet.IsPresent) + { + WriteObject(currentHop <= sMaxHops); + } + else + { + WriteObject(traceRouteResult); + } + } + + private void WriteConsoleTraceRouteHeader(string resolvedTargetName, string targetAddress) + { + _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.TraceRouteStart, resolvedTargetName, targetAddress, MaxHops); + + WriteInformation(_testConnectionProgressBarActivity, s_PSHostTag); + + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace); + WriteProgress(record); + } + + private string _testConnectionProgressBarActivity; + private static string[] s_PSHostTag = new string[] { "PSHOST" }; + + private void WriteTraceRouteProgress(TraceRouteReply traceRouteReply) + { + string msg = string.Empty; + + if (traceRouteReply.PingReplies[2].Status == IPStatus.TtlExpired || traceRouteReply.PingReplies[2].Status == IPStatus.Success) + { + var routerAddress = traceRouteReply.ReplyRouterAddress.ToString(); + var routerName = traceRouteReply.ReplyRouterName ?? routerAddress; + var roundtripTime0 = traceRouteReply.PingReplies[0].Status == IPStatus.TimedOut ? "*" : traceRouteReply.PingReplies[0].RoundtripTime.ToString(); + var roundtripTime1 = traceRouteReply.PingReplies[1].Status == IPStatus.TimedOut ? "*" : traceRouteReply.PingReplies[1].RoundtripTime.ToString(); + msg = StringUtil.Format(TestConnectionResources.TraceRouteReply, + traceRouteReply.Hop, roundtripTime0, roundtripTime1, traceRouteReply.PingReplies[2].RoundtripTime.ToString(), + routerName, routerAddress); + } + else + { + msg = StringUtil.Format(TestConnectionResources.TraceRouteTimeOut, traceRouteReply.Hop); + } + + WriteInformation(msg, s_PSHostTag); + + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg); + WriteProgress(record); + } + + private void WriteTraceRouteFooter() + { + WriteInformation(TestConnectionResources.TraceRouteComplete, s_PSHostTag); + + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace); + record.RecordType = ProgressRecordType.Completed; + WriteProgress(record); + } + + /// + /// The class contains an information about a trace route attempt. + /// + public class TraceRouteReply + { + internal TraceRouteReply() + { + PingReplies = new List(DefaultTraceRoutePingCount); + } + + /// + /// Number of current hop (router). + /// + public int Hop; + + /// + /// List of ping replies for current hop (router). + /// + public List PingReplies; + + /// + /// Router IP address. + /// + public IPAddress ReplyRouterAddress; + + /// + /// Resolved router name. + /// + public string ReplyRouterName; + } + + /// + /// The class contains an information about the source, the destination and trace route results. + /// + public class TraceRouteResult + { + internal TraceRouteResult(string source, IPAddress destinationAddress, string destinationHost) + { + Source = source; + DestinationAddress = destinationAddress; + DestinationHost = destinationHost; + Replies = new List(); + } + + /// + /// Source from which to trace route. + /// + public string Source { get; } + + /// + /// Destination to which to trace route. + /// + public IPAddress DestinationAddress { get; } + + /// + /// Destination to which to trace route. + /// + public string DestinationHost { get; } + + /// + /// + public List Replies { get; } + } + + #endregion TracerouteTest + + #region MTUSizeTest + private void ProcessMTUSize(String targetNameOrAddress) + { + PingReply reply, replyResult = null; + + string resolvedTargetName = null; + IPAddress targetAddress = null; + + if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress)) + { + return; + } + + WriteMTUSizeHeader(resolvedTargetName, targetAddress.ToString()); + + // Cautious! Algorithm is sensitive to changing boundary values. + int HighMTUSize = 10000; + int CurrentMTUSize = 1473; + int LowMTUSize = targetAddress.AddressFamily == AddressFamily.InterNetworkV6 ? 1280 : 68; + Int32 timeout = TimeoutSeconds * 1000; + + try + { + Ping sender = new Ping(); + PingOptions pingOptions = new PingOptions(MaxHops, true); + int retry = 1; + + while (LowMTUSize < (HighMTUSize - 1)) + { + byte[] buffer = GetSendBuffer(CurrentMTUSize); + + WriteMTUSizeProgress(CurrentMTUSize, retry); + + WriteDebug(StringUtil.Format("LowMTUSize: {0}, CurrentMTUSize: {1}, HighMTUSize: {2}", LowMTUSize, CurrentMTUSize, HighMTUSize)); + + reply = sender.Send(targetAddress, timeout, buffer, pingOptions); + + // Cautious! Algorithm is sensitive to changing boundary values. + if (reply.Status == IPStatus.PacketTooBig) + { + HighMTUSize = CurrentMTUSize; + retry = 1; + } + else if (reply.Status == IPStatus.Success) + { + LowMTUSize = CurrentMTUSize; + replyResult = reply; + retry = 1; + } + else + { + // Target host don't reply - try again up to 'Count'. + if (retry >= Count) + { + string message = StringUtil.Format(TestConnectionResources.NoPingResult, + targetAddress, + reply.Status.ToString()); + Exception pingException = new System.Net.NetworkInformation.PingException(message); + ErrorRecord errorRecord = new ErrorRecord(pingException, + TestConnectionExceptionId, + ErrorCategory.ResourceUnavailable, + targetAddress); + WriteError(errorRecord); + return; + } + else + { + retry++; + continue; + } + } + + CurrentMTUSize = (LowMTUSize + HighMTUSize) / 2; + + // Prevent DoS attack. + Thread.Sleep(100); + } + } + catch (PingException ex) + { + string message = StringUtil.Format(TestConnectionResources.NoPingResult, targetAddress, ex.Message); + Exception pingException = new System.Net.NetworkInformation.PingException(message, ex.InnerException); + ErrorRecord errorRecord = new ErrorRecord(pingException, + TestConnectionExceptionId, + ErrorCategory.ResourceUnavailable, + targetAddress); + WriteError(errorRecord); + return; + } + + WriteMTUSizeFooter(); + + if (Quiet.IsPresent) + { + WriteObject(CurrentMTUSize); + } + else + { + var res = PSObject.AsPSObject(replyResult); + + PSMemberInfo sourceProperty = new PSNoteProperty("Source", Source); + res.Members.Add(sourceProperty); + PSMemberInfo destinationProperty = new PSNoteProperty("Destination", targetNameOrAddress); + res.Members.Add(destinationProperty); + PSMemberInfo mtuSizeProperty = new PSNoteProperty("MTUSize", CurrentMTUSize); + res.Members.Add(mtuSizeProperty); + res.TypeNames.Insert(0, "PingReply#MTUSize"); + + WriteObject(res); + } + } + + private void WriteMTUSizeHeader(string resolvedTargetName, string targetAddress) + { + _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.MTUSizeDetectStart, + resolvedTargetName, + targetAddress, + BufferSize); + + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace); + WriteProgress(record); + } + + private void WriteMTUSizeProgress(int currentMTUSize, int retry) + { + var msg = StringUtil.Format(TestConnectionResources.MTUSizeDetectDescription, currentMTUSize, retry); + + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg); + WriteProgress(record); + } + + private void WriteMTUSizeFooter() + { + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace); + record.RecordType = ProgressRecordType.Completed; + WriteProgress(record); + } + + #endregion MTUSizeTest + + #region PingTest + + private void ProcessPing(String targetNameOrAddress) + { + string resolvedTargetName = null; + IPAddress targetAddress = null; + + if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress)) + { + return; + } + + if (!Continues.IsPresent) + { + WritePingHeader(resolvedTargetName, targetAddress.ToString()); + } + + bool quietResult = true; + byte[] buffer = GetSendBuffer(BufferSize); + + Ping sender = new Ping(); + PingOptions pingOptions = new PingOptions(MaxHops, DontFragment.IsPresent); + PingReply reply = null; + PingReport pingReport = new PingReport(Source, resolvedTargetName); + Int32 timeout = TimeoutSeconds * 1000; + Int32 delay = Delay * 1000; + + for (int i = 1; i <= Count; i++) + { + try + { + reply = sender.Send(targetAddress, timeout, buffer, pingOptions); + } + catch (PingException ex) + { + string message = StringUtil.Format(TestConnectionResources.NoPingResult, resolvedTargetName, ex.Message); + Exception pingException = new System.Net.NetworkInformation.PingException(message, ex.InnerException); + ErrorRecord errorRecord = new ErrorRecord(pingException, + TestConnectionExceptionId, + ErrorCategory.ResourceUnavailable, + resolvedTargetName); + WriteError(errorRecord); + + quietResult = false; + continue; + } + + if (Continues.IsPresent) + { + WriteObject(reply); + } + else + { + if (Quiet.IsPresent) + { + // Return 'true' only if all pings have completed successfully. + quietResult &= reply.Status == IPStatus.Success; + } + else + { + pingReport.Replies.Add(reply); + } + + WritePingProgress(reply); + } + + // Delay between ping but not after last ping. + if (i < Count && Delay > 0) + { + Thread.Sleep(delay); + } + } + + if (!Continues.IsPresent) + { + WritePingFooter(); + } + + if (Quiet.IsPresent) + { + WriteObject(quietResult); + } + else + { + WriteObject(pingReport); + } + } + + private void WritePingHeader(string resolvedTargetName, string targetAddress) + { + _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.MTUSizeDetectStart, + resolvedTargetName, + targetAddress, + BufferSize); + + WriteInformation(_testConnectionProgressBarActivity, s_PSHostTag); + + ProgressRecord record = new ProgressRecord(s_ProgressId, + _testConnectionProgressBarActivity, + ProgressRecordSpace); + WriteProgress(record); + } + + private void WritePingProgress(PingReply reply) + { + string msg = string.Empty; + if (reply.Status != IPStatus.Success) + { + msg = TestConnectionResources.PingTimeOut; + } + else + { + msg = StringUtil.Format(TestConnectionResources.PingReply, + reply.Address.ToString(), + reply.Buffer.Length, + reply.RoundtripTime, + reply.Options?.Ttl); + } + + WriteInformation(msg, s_PSHostTag); + + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg); + WriteProgress(record); + } + + private void WritePingFooter() + { + WriteInformation(TestConnectionResources.PingComplete, s_PSHostTag); + + ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace); + record.RecordType = ProgressRecordType.Completed; + WriteProgress(record); + } + + /// + /// The class contains an information about the source, the destination and ping results. + /// + public class PingReport + { + internal PingReport(string source, string destination) + { + Source = source; + Destination = destination; + Replies = new List(); + } + + /// + /// Source from which to ping. + /// + public string Source { get; } + + /// + /// Destination to which to ping. + /// + public string Destination { get; } + + /// + /// Ping results for every ping attempt. + /// + public List Replies { get; } + } + + #endregion PingTest + + private bool InitProcessPing(String targetNameOrAddress, out string resolvedTargetName, out IPAddress targetAddress) + { + IPHostEntry hostEntry = null; + + resolvedTargetName = targetNameOrAddress; + + if (IPAddress.TryParse(targetNameOrAddress, out targetAddress)) + { + if (ResolveDestination) + { + hostEntry = Dns.GetHostEntry(targetNameOrAddress); + resolvedTargetName = hostEntry.HostName; + } + } + else + { + try + { + hostEntry = Dns.GetHostEntry(targetNameOrAddress); + + if (ResolveDestination) + { + resolvedTargetName = hostEntry.HostName; + hostEntry = Dns.GetHostEntry(hostEntry.HostName); + } + } + catch (Exception ex) + { + string message = StringUtil.Format(TestConnectionResources.NoPingResult, + resolvedTargetName, + TestConnectionResources.CannotResolveTargetName); + Exception pingException = new System.Net.NetworkInformation.PingException(message, ex); + ErrorRecord errorRecord = new ErrorRecord(pingException, + TestConnectionExceptionId, + ErrorCategory.ResourceUnavailable, + resolvedTargetName); + WriteError(errorRecord); + return false; + } + + if (IPv6 || IPv4) + { + AddressFamily addressFamily = IPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork; + + foreach (var address in hostEntry.AddressList) + { + if (address.AddressFamily == addressFamily) + { + targetAddress = address; + break; + } + } + + if (targetAddress == null) + { + string message = StringUtil.Format(TestConnectionResources.NoPingResult, + resolvedTargetName, + TestConnectionResources.TargetAddressAbsent); + Exception pingException = new System.Net.NetworkInformation.PingException(message, null); + ErrorRecord errorRecord = new ErrorRecord(pingException, + TestConnectionExceptionId, + ErrorCategory.ResourceUnavailable, + resolvedTargetName); + WriteError(errorRecord); + return false; + } + } + else + { + targetAddress = hostEntry.AddressList[0]; + } + } + + return true; + } + + // Users most often use the default buffer size so we cache the buffer. + // Creates and filles a send buffer. This follows the ping.exe and CoreFX model. + private byte[] GetSendBuffer(int bufferSize) + { + if (bufferSize == DefaultSendBufferSize && s_DefaultSendBuffer != null) + { + return s_DefaultSendBuffer; + } + + byte[] sendBuffer = new byte[bufferSize]; + + for (int i = 0; i < bufferSize; i++) + { + sendBuffer[i] = (byte)((int)'a' + i % 23); + } + + if (bufferSize == DefaultSendBufferSize && s_DefaultSendBuffer == null) + { + s_DefaultSendBuffer = sendBuffer; + } + + return sendBuffer; + } + + // Count of pings sent per each trace route hop. + // Default = 3 (from Windows). + // If we change 'DefaultTraceRoutePingCount' we should change 'ConsoleTraceRouteReply' resource string. + private const int DefaultTraceRoutePingCount = 3; + + /// Create the default send buffer once and cache it. + private const int DefaultSendBufferSize = 32; + private static byte[] s_DefaultSendBuffer = null; + + // Random value for WriteProgress Activity Id. + private static readonly int s_ProgressId = 174593053; + + // Empty message string for Progress Bar. + private const string ProgressRecordSpace = " "; + + private const string TestConnectionExceptionId = "TestConnectionException"; + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs index 75b41682981d..4f5651f36794 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs @@ -1,11 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Management.Automation; using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Globalization; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Management.Automation; +using System.Runtime.InteropServices; namespace Microsoft.PowerShell.Commands { @@ -17,7 +20,7 @@ namespace Microsoft.PowerShell.Commands [Alias("gtz")] public class GetTimeZoneCommand : PSCmdlet { -#region Parameters + #region Parameters /// /// A list of the local time zone ids that the cmdlet should look up. @@ -40,10 +43,10 @@ public class GetTimeZoneCommand : PSCmdlet [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] Name { get; set; } -#endregion Parameters + #endregion Parameters /// - /// Implementation of the ProcessRecord method for Get-TimeZone + /// Implementation of the ProcessRecord method for Get-TimeZone. /// protected override void ProcessRecord() { @@ -73,7 +76,7 @@ protected override void ProcessRecord() } else // ParameterSetName == "Name" { - if (null != Name) + if (Name != null) { // lookup each time zone name (or wildcard pattern) foreach (string tzname in Name) @@ -121,13 +124,13 @@ protected override void ProcessRecord() [Alias("stz")] public class SetTimeZoneCommand : PSCmdlet { -#region string constants + #region string constants private const string TimeZoneTarget = "Local System"; -#endregion string constants + #endregion string constants -#region Parameters + #region Parameters /// /// The name of the local time zone that the system should use. @@ -148,15 +151,15 @@ public class SetTimeZoneCommand : PSCmdlet public string Name { get; set; } /// - /// Request return of the new local time zone as a TimeZoneInfo object + /// Request return of the new local time zone as a TimeZoneInfo object. /// [Parameter] public SwitchParameter PassThru { get; set; } -#endregion Parameters + #endregion Parameters /// - /// Implementation of the ProcessRecord method for Get-TimeZone + /// Implementation of the ProcessRecord method for Get-TimeZone. /// [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "Since Name is not a parameter of this method, it confuses FXCop. It is the appropriate value for the exception.")] protected override void ProcessRecord() @@ -317,7 +320,7 @@ protected override void ProcessRecord() } } -#region Helper functions + #region Helper functions /// /// True if the current process has access to change the time zone setting. @@ -370,7 +373,7 @@ protected bool HasAccess } /// - /// Set the SeTimeZonePrivilege, which controls access to the SetDynamicTimeZoneInformation API + /// Set the SeTimeZonePrivilege, which controls access to the SetDynamicTimeZoneInformation API. /// /// Set to true to enable (or false to disable) the privilege. protected void SetAccessToken(bool enable) @@ -421,20 +424,20 @@ protected void ThrowWin32Error() throw new Win32Exception(error); } -#endregion Helper functions + #endregion Helper functions -#region Win32 interop helper + #region Win32 interop helper internal class NativeMethods { /// - /// Private constructor to prevent instantiation + /// Private constructor to prevent instantiation. /// private NativeMethods() { } -#region Native DLL locations + #region Native DLL locations private const string SetDynamicTimeZoneApiDllName = "api-ms-win-core-timezone-l1-1-0.dll"; private const string GetTimeZoneInformationForYearApiDllName = "api-ms-win-core-timezone-l1-1-0.dll"; @@ -446,12 +449,12 @@ private NativeMethods() private const string CloseHandleApiDllName = "api-ms-win-downlevel-kernel32-l1-1-0.dll"; private const string SendMessageTimeoutApiDllName = "ext-ms-win-rtcore-ntuser-window-ext-l1-1-0.dll"; -#endregion Native DLL locations + #endregion Native DLL locations -#region Win32 SetDynamicTimeZoneInformation imports + #region Win32 SetDynamicTimeZoneInformation imports /// - /// Used to marshal win32 SystemTime structure to managed code layer + /// Used to marshal win32 SystemTime structure to managed code layer. /// [StructLayout(LayoutKind.Sequential)] public struct SystemTime @@ -499,7 +502,7 @@ public struct SystemTime } /// - /// Used to marshal win32 DYNAMIC_TIME_ZONE_INFORMATION structure to managed code layer + /// Used to marshal win32 DYNAMIC_TIME_ZONE_INFORMATION structure to managed code layer. /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct DYNAMIC_TIME_ZONE_INFORMATION @@ -550,7 +553,7 @@ public struct DYNAMIC_TIME_ZONE_INFORMATION } /// - /// Used to marshal win32 TIME_ZONE_INFORMATION structure to managed code layer + /// Used to marshal win32 TIME_ZONE_INFORMATION structure to managed code layer. /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct TIME_ZONE_INFORMATION @@ -591,49 +594,51 @@ public struct TIME_ZONE_INFORMATION } /// - /// PInvoke SetDynamicTimeZoneInformation API + /// PInvoke SetDynamicTimeZoneInformation API. /// /// A DYNAMIC_TIME_ZONE_INFORMATION structure representing the desired local time zone. /// [DllImport(SetDynamicTimeZoneApiDllName, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetDynamicTimeZoneInformation([In] ref DYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation); [DllImport(GetTimeZoneInformationForYearApiDllName, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetTimeZoneInformationForYear([In] ushort wYear, [In] ref DYNAMIC_TIME_ZONE_INFORMATION pdtzi, ref TIME_ZONE_INFORMATION ptzi); -#endregion Win32 SetDynamicTimeZoneInformation imports + #endregion Win32 SetDynamicTimeZoneInformation imports -#region Win32 AdjustTokenPrivilege imports + #region Win32 AdjustTokenPrivilege imports /// - /// Definition of TOKEN_QUERY constant from Win32 API + /// Definition of TOKEN_QUERY constant from Win32 API. /// public const int TOKEN_QUERY = 0x00000008; /// - /// Definition of TOKEN_ADJUST_PRIVILEGES constant from Win32 API + /// Definition of TOKEN_ADJUST_PRIVILEGES constant from Win32 API. /// public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; /// - /// Definition of SE_PRIVILEGE_ENABLED constant from Win32 API + /// Definition of SE_PRIVILEGE_ENABLED constant from Win32 API. /// public const int SE_PRIVILEGE_ENABLED = 0x00000002; /// - /// Definition of SE_TIME_ZONE_NAME constant from Win32 API + /// Definition of SE_TIME_ZONE_NAME constant from Win32 API. /// - public const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege"; //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx + public const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege"; // https://msdn.microsoft.com/library/bb530716(VS.85).aspx /// - /// PInvoke GetCurrentProcess API + /// PInvoke GetCurrentProcess API. /// /// [DllImport(GetCurrentProcessApiDllName, ExactSpelling = true)] public static extern IntPtr GetCurrentProcess(); /// - /// PInvoke OpenProcessToken API + /// PInvoke OpenProcessToken API. /// /// /// @@ -644,7 +649,7 @@ public struct TIME_ZONE_INFORMATION public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle); /// - /// PInvoke LookupPrivilegeValue API + /// PInvoke LookupPrivilegeValue API. /// /// /// @@ -655,7 +660,7 @@ public struct TIME_ZONE_INFORMATION public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref long lpLuid); /// - /// PInvoke PrivilegeCheck API + /// PInvoke PrivilegeCheck API. /// /// /// @@ -665,9 +670,8 @@ public struct TIME_ZONE_INFORMATION [return: MarshalAs(UnmanagedType.Bool)] public static extern bool PrivilegeCheck(IntPtr ClientToken, ref PRIVILEGE_SET RequiredPrivileges, ref bool pfResult); - /// - /// PInvoke AdjustTokenPrivilege API + /// PInvoke AdjustTokenPrivilege API. /// /// /// @@ -682,7 +686,7 @@ public struct TIME_ZONE_INFORMATION ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength); /// - /// PInvoke CloseHandle API + /// PInvoke CloseHandle API. /// /// /// @@ -691,7 +695,7 @@ public struct TIME_ZONE_INFORMATION public static extern bool CloseHandle(IntPtr hObject); /// - /// Used to marshal win32 PRIVILEGE_SET structure to managed code layer + /// Used to marshal win32 PRIVILEGE_SET structure to managed code layer. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct PRIVILEGE_SET @@ -703,7 +707,7 @@ public struct PRIVILEGE_SET } /// - /// Used to marshal win32 TOKEN_PRIVILEGES structure to managed code layer + /// Used to marshal win32 TOKEN_PRIVILEGES structure to managed code layer. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct TOKEN_PRIVILEGES @@ -713,27 +717,27 @@ public struct TOKEN_PRIVILEGES public int Attributes; } -#endregion Win32 AdjustTokenPrivilege imports + #endregion Win32 AdjustTokenPrivilege imports -#region Win32 SendMessage imports + #region Win32 SendMessage imports /// - /// Definition of WM_SETTINGCHANGE constant from Win32 API + /// Definition of WM_SETTINGCHANGE constant from Win32 API. /// public const int WM_SETTINGCHANGE = 0x001A; /// - /// Definition of HWND_BROADCAST constant from Win32 API + /// Definition of HWND_BROADCAST constant from Win32 API. /// public const int HWND_BROADCAST = (-1); /// - /// Definition of SMTO_ABORTIFHUNG constant from Win32 API + /// Definition of SMTO_ABORTIFHUNG constant from Win32 API. /// public const int SMTO_ABORTIFHUNG = 0x0002; /// - /// PInvoke SendMessageTimeout API + /// PInvoke SendMessageTimeout API. /// /// /// @@ -746,26 +750,26 @@ public struct TOKEN_PRIVILEGES [DllImport(SendMessageTimeoutApiDllName, SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr SendMessageTimeout(IntPtr hWnd, int Msg, IntPtr wParam, string lParam, int fuFlags, int uTimeout, ref int lpdwResult); -#endregion Win32 SendMessage imports + #endregion Win32 SendMessage imports } -#endregion Win32 interop helper + #endregion Win32 interop helper } #endif /// - /// static Helper class for working with system time zones. + /// Static Helper class for working with system time zones. /// internal static class TimeZoneHelper { -#region Error Ids + #region Error Ids internal const string TimeZoneNotFoundError = "TimeZoneNotFound"; internal const string MultipleMatchingTimeZonesError = "MultipleMatchingTimeZones"; internal const string InsufficientPermissionsError = "InsufficientPermissions"; internal const string SetTimeZoneFailedError = "SetTimeZoneFailed"; -#endregion Error Ids + #endregion Error Ids /// /// Find the system time zone by checking first against StandardName and then, diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs index a36f997a1441..6b734d0ec4f5 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs @@ -1,10 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; using System.Management.Automation.Internal; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -17,7 +17,7 @@ public class UseTransactionCommand : PSCmdlet { /// /// This parameter specifies the script block to run in the current - /// PowerShell transaction + /// PowerShell transaction. /// [Parameter(Position = 0, Mandatory = true)] public ScriptBlock TransactedScript @@ -26,15 +26,17 @@ public ScriptBlock TransactedScript { return _transactedScript; } + set { _transactedScript = value; } } + private ScriptBlock _transactedScript; /// - /// Commits the current transaction + /// Commits the current transaction. /// protected override void EndProcessing() { @@ -42,7 +44,7 @@ protected override void EndProcessing() { try { - var emptyArray = Utils.EmptyArray(); + var emptyArray = Array.Empty(); _transactedScript.InvokeUsingCmdlet( contextCmdlet: this, useLocalScope: false, @@ -87,6 +89,6 @@ protected override void EndProcessing() } } } - } // CommitTransactionCommand -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/WMIHelper.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/WMIHelper.cs index 8cf7df9d61db..a90a8971e060 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/WMIHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/WMIHelper.cs @@ -1,23 +1,24 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Management.Automation; using System.Management; +using System.Management.Automation; using System.Management.Automation.Internal; -using System.Text; using System.Management.Automation.Provider; -using System.ComponentModel; -using System.Collections; -using System.Collections.ObjectModel; -using System.Security.AccessControl; +using System.Management.Automation.Remoting; using System.Runtime.InteropServices; +using System.Security.AccessControl; +using System.Text; using System.Threading; -using System.Management.Automation.Remoting; -using System.Diagnostics.CodeAnalysis; + using Microsoft.PowerShell.Commands.Internal; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -26,13 +27,13 @@ namespace Microsoft.PowerShell.Commands /// /// Base class for all WMI helper classes. This is an abstract class - /// and the helpers need to derive from this + /// and the helpers need to derive from this. /// internal abstract class AsyncCmdletHelper : IThrottleOperation { /// /// Exception raised internally when any method of this class - /// is executed + /// is executed. /// internal Exception InternalException { @@ -41,6 +42,7 @@ internal Exception InternalException return internalException; } } + protected Exception internalException = null; } @@ -52,12 +54,12 @@ internal Exception InternalException internal class WmiAsyncCmdletHelper : AsyncCmdletHelper { /// - /// Internal Constructor + /// Internal Constructor. /// - /// Job associated with this operation - /// object associated with this operation - /// computer on which the operation is invoked - /// sink to get wmi objects + /// Job associated with this operation. + /// Object associated with this operation. + /// Computer on which the operation is invoked. + /// Sink to get wmi objects. internal WmiAsyncCmdletHelper(PSWmiChildJob childJob, Cmdlet wmiObject, string computerName, ManagementOperationObserver results) { _wmiObject = wmiObject; @@ -71,11 +73,11 @@ internal WmiAsyncCmdletHelper(PSWmiChildJob childJob, Cmdlet wmiObject, string c /// Internal Constructor. This variant takes a count parameter that determines how many times /// the WMI command is executed. /// - /// Job associated with this operation - /// Object associated with this operation - /// Computer on which the operation is invoked - /// Sink to return wmi objects - /// Number of times the WMI command is executed + /// Job associated with this operation. + /// Object associated with this operation. + /// Computer on which the operation is invoked. + /// Sink to return wmi objects. + /// Number of times the WMI command is executed. internal WmiAsyncCmdletHelper(PSWmiChildJob childJob, Cmdlet wmiObject, string computerName, ManagementOperationObserver results, int count) : this(childJob, wmiObject, computerName, results) { @@ -89,18 +91,19 @@ internal WmiAsyncCmdletHelper(PSWmiChildJob childJob, Cmdlet wmiObject, string c private int _cmdCount = 1; private PSWmiChildJob _job; /// - /// current operation state + /// Current operation state. /// internal WmiState State { get { return _state; } + set { _state = value; } } private WmiState _state; /// - /// Cancel WMI connection + /// Cancel WMI connection. /// internal override void StopOperation() { @@ -109,20 +112,21 @@ internal override void StopOperation() RaiseOperationCompleteEvent(null, OperationState.StopComplete); } /// - /// Uses this.filter, this.wmiClass and this.property to retrieve the filter + /// Uses this.filter, this.wmiClass and this.property to retrieve the filter. /// private string GetWmiQueryString() { GetWmiObjectCommand getObject = (GetWmiObjectCommand)_wmiObject; StringBuilder returnValue = new StringBuilder("select "); - returnValue.Append(String.Join(", ", getObject.Property)); + returnValue.Append(string.Join(", ", getObject.Property)); returnValue.Append(" from "); returnValue.Append(getObject.Class); - if (!String.IsNullOrEmpty(getObject.Filter)) + if (!string.IsNullOrEmpty(getObject.Filter)) { returnValue.Append(" where "); returnValue.Append(getObject.Filter); } + return returnValue.ToString(); } @@ -156,27 +160,27 @@ internal override void StartOperation() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + thread.IsBackground = true; - //thread.SetApartmentState( ApartmentState.STA); + thread.SetApartmentState(ApartmentState.STA); thread.Start(); } /// - /// /// internal override event EventHandler OperationComplete; private Cmdlet _wmiObject; /// - /// Raise operation completion event + /// Raise operation completion event. /// internal void RaiseOperationCompleteEvent(EventArgs baseEventArgs, OperationState state) { OperationStateEventArgs operationStateEventArgs = new OperationStateEventArgs(); operationStateEventArgs.OperationState = state; OperationComplete.SafeInvoke(this, operationStateEventArgs); - } // RaiseOperationCompleteEvent + } /// /// Raise WMI state changed event @@ -202,10 +206,10 @@ private void ConnectSetWmi() try { PutOptions pOptions = new PutOptions(); - //Extra check + // Extra check if (setObject.InputObject.GetType() == typeof(ManagementClass)) { - //Check if Flag specified is CreateOnly or not + // Check if Flag specified is CreateOnly or not if (setObject.flagSpecified && setObject.PutType != PutType.CreateOnly) { InvalidOperationException e = new InvalidOperationException("CreateOnlyFlagNotSpecifiedWithClassPath"); @@ -214,12 +218,13 @@ private void ConnectSetWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + mObj = ((ManagementClass)setObject.InputObject).CreateInstance(); setObject.PutType = PutType.CreateOnly; } else { - //Check if Flag specified is Updateonly or UpdateOrCreateOnly or not + // Check if Flag specified is Updateonly or UpdateOrCreateOnly or not if (setObject.flagSpecified) { if (!(setObject.PutType == PutType.UpdateOnly || setObject.PutType == PutType.UpdateOrCreate)) @@ -238,6 +243,7 @@ private void ConnectSetWmi() mObj = (ManagementObject)setObject.InputObject.Clone(); } + if (setObject.Arguments != null) { IDictionaryEnumerator en = setObject.Arguments.GetEnumerator(); @@ -246,6 +252,7 @@ private void ConnectSetWmi() mObj[en.Key as string] = en.Value; } } + pOptions.Type = setObject.PutType; if (mObj != null) { @@ -281,7 +288,7 @@ private void ConnectSetWmi() else { ManagementPath mPath = null; - //If Class is specified only CreateOnly flag is supported + // If Class is specified only CreateOnly flag is supported if (setObject.Class != null) { if (setObject.flagSpecified && setObject.PutType != PutType.CreateOnly) @@ -292,12 +299,13 @@ private void ConnectSetWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + setObject.PutType = PutType.CreateOnly; } else { mPath = new ManagementPath(setObject.Path); - if (String.IsNullOrEmpty(mPath.NamespacePath)) + if (string.IsNullOrEmpty(mPath.NamespacePath)) { mPath.NamespacePath = setObject.Namespace; } @@ -318,6 +326,7 @@ private void ConnectSetWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + if (mPath.IsClass) { if (setObject.flagSpecified && setObject.PutType != PutType.CreateOnly) @@ -328,6 +337,7 @@ private void ConnectSetWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + setObject.PutType = PutType.CreateOnly; } else @@ -349,7 +359,7 @@ private void ConnectSetWmi() } } } - //If server name is specified loop through it. + // If server name is specified loop through it. if (mPath != null) { if (!(mPath.Server == "." && setObject.serverNameSpecified)) @@ -357,6 +367,7 @@ private void ConnectSetWmi() _computerName = mPath.Server; } } + ConnectionOptions options = setObject.GetConnectionOption(); ManagementObject mObject = null; try @@ -373,7 +384,7 @@ private void ConnectSetWmi() } else { - //This can throw if path does not exist caller should catch it. + // This can throw if path does not exist caller should catch it. ManagementObject mInstance = new ManagementObject(mPath); mInstance.Scope = mScope; try @@ -389,6 +400,7 @@ private void ConnectSetWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + int namespaceIndex = setObject.Path.IndexOf(':'); if (namespaceIndex == -1) { @@ -397,6 +409,7 @@ private void ConnectSetWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + int classIndex = (setObject.Path.Substring(namespaceIndex)).IndexOf('.'); if (classIndex == -1) { @@ -405,13 +418,14 @@ private void ConnectSetWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } - //Get class object and create instance. + // Get class object and create instance. string newPath = setObject.Path.Substring(0, classIndex + namespaceIndex); ManagementPath classPath = new ManagementPath(newPath); ManagementClass mClass = new ManagementClass(classPath); mClass.Scope = mScope; mInstance = mClass.CreateInstance(); } + mObject = mInstance; } } @@ -422,6 +436,7 @@ private void ConnectSetWmi() mClass.Scope = scope; mObject = mClass.CreateInstance(); } + if (setObject.Arguments != null) { IDictionaryEnumerator en = setObject.Arguments.GetEnumerator(); @@ -430,6 +445,7 @@ private void ConnectSetWmi() mObject[en.Key as string] = en.Value; } } + PutOptions pOptions = new PutOptions(); pOptions.Type = setObject.PutType; if (mObject != null) @@ -491,6 +507,7 @@ private void ConnectInvokeWmi() inParamCount--; } } + invokeObject.InputObject.InvokeMethod(_results, invokeObject.Name, inputParameters, null); } catch (ManagementException e) @@ -511,6 +528,7 @@ private void ConnectInvokeWmi() _state = WmiState.Failed; RaiseOperationCompleteEvent(null, OperationState.StopComplete); } + return; } else @@ -521,7 +539,7 @@ private void ConnectInvokeWmi() if (invokeObject.Path != null) { mPath = new ManagementPath(invokeObject.Path); - if (String.IsNullOrEmpty(mPath.NamespacePath)) + if (string.IsNullOrEmpty(mPath.NamespacePath)) { mPath.NamespacePath = invokeObject.Namespace; } @@ -542,7 +560,7 @@ private void ConnectInvokeWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } - //If server name is specified loop through it. + // If server name is specified loop through it. if (!(mPath.Server == "." && invokeObject.serverNameSpecified)) { _computerName = mPath.Server; @@ -583,6 +601,7 @@ private void ConnectInvokeWmi() ManagementObject mInstance = new ManagementObject(mPath); mObject = mInstance; } + ManagementScope mScope = new ManagementScope(mPath, options); mObject.Scope = mScope; } @@ -660,7 +679,7 @@ private void ConnectInvokeWmi() } /// - /// Check if we need to enable the shutdown privilege + /// Check if we need to enable the shutdown privilege. /// /// /// @@ -673,11 +692,11 @@ private bool NeedToEnablePrivilege(string computer, string methodName, ref bool { result = true; - // CLR 4.0 Port note - use https://msdn.microsoft.com/en-us/library/system.net.networkinformation.ipglobalproperties.hostname(v=vs.110).aspx + // CLR 4.0 Port note - use https://msdn.microsoft.com/library/system.net.networkinformation.ipglobalproperties.hostname(v=vs.110).aspx string localName = System.Net.Dns.GetHostName(); // And for this, use PsUtils.GetHostname() - string localFullName = System.Net.Dns.GetHostEntry("").HostName; + string localFullName = System.Net.Dns.GetHostEntry(string.Empty).HostName; if (computer.Equals(".") || computer.Equals("localhost", StringComparison.OrdinalIgnoreCase) || computer.Equals(localName, StringComparison.OrdinalIgnoreCase) || computer.Equals(localFullName, StringComparison.OrdinalIgnoreCase)) @@ -721,6 +740,7 @@ private void ConnectRemoveWmi() _state = WmiState.Failed; RaiseOperationCompleteEvent(null, OperationState.StopComplete); } + return; } else @@ -731,7 +751,7 @@ private void ConnectRemoveWmi() if (removeObject.Path != null) { mPath = new ManagementPath(removeObject.Path); - if (String.IsNullOrEmpty(mPath.NamespacePath)) + if (string.IsNullOrEmpty(mPath.NamespacePath)) { mPath.NamespacePath = removeObject.Namespace; } @@ -752,11 +772,13 @@ private void ConnectRemoveWmi() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + if (!(mPath.Server == "." && removeObject.serverNameSpecified)) { _computerName = mPath.Server; } } + try { if (removeObject.Path != null) @@ -772,6 +794,7 @@ private void ConnectRemoveWmi() ManagementObject mInstance = new ManagementObject(mPath); mObject = mInstance; } + ManagementScope mScope = new ManagementScope(mPath, options); mObject.Scope = mScope; } @@ -782,6 +805,7 @@ private void ConnectRemoveWmi() mObject = mClass; mObject.Scope = scope; } + mObject.Delete(_results); } catch (ManagementException e) @@ -819,7 +843,7 @@ private void ConnectGetWMI() if (!getObject.ValidateClassFormat()) { ArgumentException e = new ArgumentException( - String.Format( + string.Format( Thread.CurrentThread.CurrentCulture, "Class", getObject.Class)); @@ -828,6 +852,7 @@ private void ConnectGetWMI() RaiseOperationCompleteEvent(null, OperationState.StopComplete); return; } + try { if (getObject.Recurse.IsPresent) @@ -851,6 +876,7 @@ private void ConnectGetWMI() namespaceArray.Add(connectNamespace + "\\" + obj["Name"]); } } + if (topNamespace) { topNamespace = false; @@ -860,6 +886,7 @@ private void ConnectGetWMI() { sinkArray.Add(_job.GetNewSink()); } + connectArray.Add(scope); currentNamespaceCount++; } @@ -882,6 +909,7 @@ private void ConnectGetWMI() currentNamespaceCount++; continue; } + if (topNamespace) { topNamespace = false; @@ -891,6 +919,7 @@ private void ConnectGetWMI() { searcher.Get((ManagementOperationObserver)sinkArray[currentNamespaceCount]); } + currentNamespaceCount++; } } @@ -922,8 +951,10 @@ private void ConnectGetWMI() _state = WmiState.Failed; RaiseOperationCompleteEvent(null, OperationState.StopComplete); } + return; } + string queryString = string.IsNullOrEmpty(getObject.Query) ? GetWmiQueryString() : getObject.Query; ObjectQuery query = new ObjectQuery(queryString.ToString()); try @@ -975,16 +1006,16 @@ internal sealed class WmiJobStateEventArgs : EventArgs } /// - /// Enumerated type defining the state of the WMI operation + /// Enumerated type defining the state of the WMI operation. /// public enum WmiState { /// - /// The operation has not been started + /// The operation has not been started. /// NotStarted = 0, /// - /// The operation is executing + /// The operation is executing. /// Running = 1, /// @@ -1018,22 +1049,21 @@ internal static string GetScopeString(string computer, string namespaceParameter } #endregion Helper Classes - /// - /// A class to set WMI connection options + /// A class to set WMI connection options. /// public class WmiBaseCmdlet : Cmdlet { #region Parameters /// - /// Perform Async operation + /// Perform Async operation. /// [Parameter] public SwitchParameter AsJob { get; set; } = false; /// - /// The Impersonation level to use + /// The Impersonation level to use. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1043,7 +1073,7 @@ public class WmiBaseCmdlet : Cmdlet public ImpersonationLevel Impersonation { get; set; } = ImpersonationLevel.Impersonate; /// - /// The Authentication level to use + /// The Authentication level to use. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1053,7 +1083,7 @@ public class WmiBaseCmdlet : Cmdlet public AuthenticationLevel Authentication { get; set; } = AuthenticationLevel.PacketPrivacy; /// - /// The Locale to use + /// The Locale to use. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1063,7 +1093,7 @@ public class WmiBaseCmdlet : Cmdlet public string Locale { get; set; } = null; /// - /// If all Privileges are enabled + /// If all Privileges are enabled. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1073,7 +1103,7 @@ public class WmiBaseCmdlet : Cmdlet public SwitchParameter EnableAllPrivileges { get; set; } /// - /// The Authority to use + /// The Authority to use. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1083,7 +1113,7 @@ public class WmiBaseCmdlet : Cmdlet public string Authority { get; set; } = null; /// - /// The credential to use + /// The credential to use. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1094,13 +1124,13 @@ public class WmiBaseCmdlet : Cmdlet public PSCredential Credential { get; set; } /// - /// The credential to use + /// The credential to use. /// [Parameter] public Int32 ThrottleLimit { get; set; } = s_DEFAULT_THROTTLE_LIMIT; /// - /// The ComputerName in which to query + /// The ComputerName in which to query. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1113,10 +1143,11 @@ public class WmiBaseCmdlet : Cmdlet public string[] ComputerName { get { return _computerName; } + set { _computerName = value; serverNameSpecified = true; } } /// - /// The WMI namespace to use + /// The WMI namespace to use. /// [Parameter(ParameterSetName = "path")] [Parameter(ParameterSetName = "class")] @@ -1127,6 +1158,7 @@ public string[] ComputerName public string Namespace { get { return _nameSpace; } + set { _nameSpace = value; namespaceSpecified = true; } } #endregion Parameters @@ -1137,7 +1169,7 @@ public string Namespace /// private string[] _computerName = new string[] { "localhost" }; /// - /// WMI namespace + /// WMI namespace. /// private string _nameSpace = "root\\cimv2"; /// @@ -1155,7 +1187,7 @@ public string Namespace #region Command code /// - /// Get connection options + /// Get connection options. /// internal ConnectionOptions GetConnectionOption() { @@ -1174,10 +1206,11 @@ internal ConnectionOptions GetConnectionOption() options.SecurePassword = this.Credential.Password; } } + return options; } /// - /// Set wmi instance helper + /// Set wmi instance helper. /// internal ManagementObject SetWmiInstanceGetObject(ManagementPath mPath, string serverName) { @@ -1198,7 +1231,7 @@ internal ManagementObject SetWmiInstanceGetObject(ManagementPath mPath, string s } else { - //This can throw if path does not exist caller should catch it. + // This can throw if path does not exist caller should catch it. ManagementObject mInstance = new ManagementObject(mPath); mInstance.Scope = mScope; try @@ -1211,23 +1244,26 @@ internal ManagementObject SetWmiInstanceGetObject(ManagementPath mPath, string s { throw; } + int namespaceIndex = setObject.Path.IndexOf(':'); if (namespaceIndex == -1) { throw; } + int classIndex = (setObject.Path.Substring(namespaceIndex)).IndexOf('.'); if (classIndex == -1) { throw; } - //Get class object and create instance. + // Get class object and create instance. string newPath = setObject.Path.Substring(0, classIndex + namespaceIndex); ManagementPath classPath = new ManagementPath(newPath); ManagementClass mClass = new ManagementClass(classPath); mClass.Scope = mScope; mInstance = mClass.CreateInstance(); } + mObject = mInstance; } } @@ -1238,6 +1274,7 @@ internal ManagementObject SetWmiInstanceGetObject(ManagementPath mPath, string s mClass.Scope = scope; mObject = mClass.CreateInstance(); } + if (setObject.Arguments != null) { IDictionaryEnumerator en = setObject.Arguments.GetEnumerator(); @@ -1247,10 +1284,11 @@ internal ManagementObject SetWmiInstanceGetObject(ManagementPath mPath, string s } } } + return mObject; } /// - /// Set wmi instance helper for building management path + /// Set wmi instance helper for building management path. /// internal ManagementPath SetWmiInstanceBuildManagementPath() { @@ -1258,30 +1296,31 @@ internal ManagementPath SetWmiInstanceBuildManagementPath() var wmiInstance = this as SetWmiInstance; if (wmiInstance != null) { - //If Class is specified only CreateOnly flag is supported + // If Class is specified only CreateOnly flag is supported if (wmiInstance.Class != null) { if (wmiInstance.flagSpecified && wmiInstance.PutType != PutType.CreateOnly) { - //Throw Terminating error + // Throw Terminating error ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "CreateOnlyFlagNotSpecifiedWithClassPath", ErrorCategory.InvalidOperation, wmiInstance.PutType)); } + wmiInstance.PutType = PutType.CreateOnly; } else { mPath = new ManagementPath(wmiInstance.Path); - if (String.IsNullOrEmpty(mPath.NamespacePath)) + if (string.IsNullOrEmpty(mPath.NamespacePath)) { mPath.NamespacePath = wmiInstance.Namespace; } else if (wmiInstance.namespaceSpecified) { - //ThrowTerminatingError + // ThrowTerminatingError ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "NamespaceSpecifiedWithPath", @@ -1291,24 +1330,26 @@ internal ManagementPath SetWmiInstanceBuildManagementPath() if (mPath.Server != "." && wmiInstance.serverNameSpecified) { - //ThrowTerminatingError + // ThrowTerminatingError ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "ComputerNameSpecifiedWithPath", ErrorCategory.InvalidOperation, wmiInstance.ComputerName)); } + if (mPath.IsClass) { if (wmiInstance.flagSpecified && wmiInstance.PutType != PutType.CreateOnly) { - //Throw Terminating error + // Throw Terminating error ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "CreateOnlyFlagNotSpecifiedWithClassPath", ErrorCategory.InvalidOperation, wmiInstance.PutType)); } + wmiInstance.PutType = PutType.CreateOnly; } else @@ -1317,7 +1358,7 @@ internal ManagementPath SetWmiInstanceBuildManagementPath() { if (!(wmiInstance.PutType == PutType.UpdateOnly || wmiInstance.PutType == PutType.UpdateOrCreate)) { - //Throw terminating error + // Throw terminating error ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "NonUpdateFlagSpecifiedWithInstancePath", @@ -1332,45 +1373,47 @@ internal ManagementPath SetWmiInstanceBuildManagementPath() } } } + return mPath; } /// - /// Set wmi instance helper for pipeline input + /// Set wmi instance helper for pipeline input. /// internal ManagementObject SetWmiInstanceGetPipelineObject() { - //Should only be called from Set-WMIInstance cmdlet + // Should only be called from Set-WMIInstance cmdlet ManagementObject mObj = null; var wmiInstance = this as SetWmiInstance; if (wmiInstance != null) { - //Extra check + // Extra check if (wmiInstance.InputObject != null) { if (wmiInstance.InputObject.GetType() == typeof(ManagementClass)) { - //Check if Flag specified is CreateOnly or not + // Check if Flag specified is CreateOnly or not if (wmiInstance.flagSpecified && wmiInstance.PutType != PutType.CreateOnly) { - //Throw terminating error + // Throw terminating error ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "CreateOnlyFlagNotSpecifiedWithClassPath", ErrorCategory.InvalidOperation, wmiInstance.PutType)); } + mObj = ((ManagementClass)wmiInstance.InputObject).CreateInstance(); wmiInstance.PutType = PutType.CreateOnly; } else { - //Check if Flag specified is Updateonly or UpdateOrCreateOnly or not + // Check if Flag specified is Updateonly or UpdateOrCreateOnly or not if (wmiInstance.flagSpecified) { if (!(wmiInstance.PutType == PutType.UpdateOnly || wmiInstance.PutType == PutType.UpdateOrCreate)) { - //Throw terminating error + // Throw terminating error ThrowTerminatingError(new ErrorRecord( new InvalidOperationException(), "NonUpdateFlagSpecifiedWithInstancePath", @@ -1385,6 +1428,7 @@ internal ManagementObject SetWmiInstanceGetPipelineObject() mObj = (ManagementObject)wmiInstance.InputObject.Clone(); } + if (wmiInstance.Arguments != null) { IDictionaryEnumerator en = wmiInstance.Arguments.GetEnumerator(); @@ -1395,6 +1439,7 @@ internal ManagementObject SetWmiInstanceGetPipelineObject() } } } + return mObj; } @@ -1408,6 +1453,7 @@ internal void RunAsJob(string cmdletName) { ((System.Management.Automation.Runspaces.LocalRunspace)_context.CurrentRunspace).JobRepository.Add(wmiJob); } + WriteObject(wmiJob); } // Get the PowerShell execution context if it's available at cmdlet creation time... @@ -1416,7 +1462,7 @@ internal void RunAsJob(string cmdletName) #endregion Command code } /// - /// A class to perform async operations for WMI cmdlets + /// A class to perform async operations for WMI cmdlets. /// internal class PSWmiJob : Job @@ -1424,7 +1470,7 @@ internal class PSWmiJob : Job #region internal constructor /// - ///Internal constructor for initializing WMI jobs + ///Internal constructor for initializing WMI jobs. /// internal PSWmiJob(Cmdlet cmds, string[] computerName, int throttleLimt, string command) : base(command, null) @@ -1438,6 +1484,7 @@ internal PSWmiJob(Cmdlet cmds, string[] computerName, int throttleLimt, string c job.JobUnblocked += new EventHandler(HandleJobUnblocked); ChildJobs.Add(job); } + CommonInit(throttleLimt); } @@ -1476,7 +1523,7 @@ internal PSWmiJob(Cmdlet cmds, string[] computerName, int throttleLimit, string private const string WMIJobType = "WmiJob"; /// - /// Handles the StateChanged event from each of the child job objects + /// Handles the StateChanged event from each of the child job objects. /// /// /// @@ -1494,14 +1541,15 @@ private void HandleChildJobStateChanged(object sender, JobStateEventArgs e) return; } - //Ignore state changes which are not resulting in state change to finished. + // Ignore state changes which are not resulting in state change to finished. if ((!IsFinishedState(e.JobStateInfo.State)) || (e.JobStateInfo.State == JobState.NotStarted)) { return; } + if (e.JobStateInfo.State == JobState.Failed) { - //If any of the child job failed, we set status to failed + // If any of the child job failed, we set status to failed _atleastOneChildJobFailed = true; } @@ -1510,17 +1558,18 @@ private void HandleChildJobStateChanged(object sender, JobStateEventArgs e) { _finishedChildJobsCount++; - //We are done + // We are done if (_finishedChildJobsCount == ChildJobs.Count) { allChildJobsFinished = true; } } + if (allChildJobsFinished) { - //if any child job failed, set status to failed - //If stop was called set, status to stopped - //else completed + // if any child job failed, set status to failed + // If stop was called set, status to stopped + // else completed if (_atleastOneChildJobFailed) { SetJobState(JobState.Failed); @@ -1539,7 +1588,7 @@ private void HandleChildJobStateChanged(object sender, JobStateEventArgs e) private bool _stopIsCalled = false; private string _statusMessage; /// - /// Message indicating status of the job + /// Message indicating status of the job. /// public override string StatusMessage { @@ -1548,19 +1597,19 @@ public override string StatusMessage return _statusMessage; } } - //ISSUE: Implement StatusMessage + // ISSUE: Implement StatusMessage /// - /// Checks the status of remote command execution + /// Checks the status of remote command execution. /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] private void SetStatusMessage() { _statusMessage = "test"; - } // SetStatusMessage + } private bool _moreData = false; /// - /// indicates if more data is available + /// Indicates if more data is available. /// /// /// This has more data if any of the child jobs have more data. @@ -1570,10 +1619,10 @@ public override bool HasMoreData get { // moreData is set to false and will be set to true - //if at least one child is has more data. + // if at least one child is has more data. - //if ( (!moreData)) - //{ + // if ( (!moreData)) + // { bool atleastOneChildHasMoreData = false; for (int i = 0; i < ChildJobs.Count; i++) @@ -1586,14 +1635,14 @@ public override bool HasMoreData } _moreData = atleastOneChildHasMoreData; - //} + // } return _moreData; } } /// - /// Computers on which this job is running + /// Computers on which this job is running. /// public override string Location { @@ -1602,7 +1651,8 @@ public override string Location return ConstructLocation(); } } - private String ConstructLocation() + + private string ConstructLocation() { StringBuilder location = new StringBuilder(); @@ -1611,16 +1661,17 @@ private String ConstructLocation() location.Append(job.Location); location.Append(","); } + location.Remove(location.Length - 1, 1); return location.ToString(); } /// - /// Stop Job + /// Stop Job. /// public override void StopJob() { - //AssertNotDisposed(); + // AssertNotDisposed(); if (!IsFinishedState(JobStateInfo.State)) { @@ -1650,6 +1701,7 @@ protected override void Dispose(bool disposing) { StopJob(); } + _throttleManager.Dispose(); foreach (Job job in ChildJobs) { @@ -1666,12 +1718,12 @@ protected override void Dispose(bool disposing) private bool _isDisposed = false; /// - /// Initialization common to both constructors + /// Initialization common to both constructors. /// private void CommonInit(int throttleLimit) { - //Since no results are produced by any streams. We should - //close all the streams + // Since no results are produced by any streams. We should + // close all the streams base.CloseAllStreams(); // set status to "in progress" @@ -1683,9 +1735,9 @@ private void CommonInit(int throttleLimit) /// /// Handles JobUnblocked event from a child job and decrements /// count of blocked child jobs. When count reaches 0, sets the - /// state of the parent job to running + /// state of the parent job to running. /// - /// sender of this event, unused + /// Sender of this event, unused. /// event arguments, should be empty in this /// case private void HandleJobUnblocked(object sender, EventArgs eventArgs) @@ -1708,22 +1760,20 @@ private void HandleJobUnblocked(object sender, EventArgs eventArgs) } } - - private ThrottleManager _throttleManager = new ThrottleManager(); private object _syncObject = new object(); // sync object } /// - /// Class for WmiChildJob object. This job object Execute wmi cmdlet + /// Class for WmiChildJob object. This job object Execute wmi cmdlet. /// internal class PSWmiChildJob : Job { #region internal constructor /// - /// Internal constructor for initializing WMI jobs + /// Internal constructor for initializing WMI jobs. /// internal PSWmiChildJob(Cmdlet cmds, string computerName, ThrottleManager throttleManager) : base(null, null) @@ -1776,25 +1826,24 @@ internal PSWmiChildJob(Cmdlet cmds, string computerName, ThrottleManager throttl #endregion internal constructor private WmiAsyncCmdletHelper _helper; - //bool _bFinished; + // bool _bFinished; private ThrottleManager _throttleManager; private object _syncObject = new object(); // sync object private int _sinkCompleted; private bool _bJobFailed; private bool _bAtLeastOneObject; - private ArrayList _wmiSinkArray; /// /// Event raised by this job to indicate to its parent that - /// its now unblocked by the user + /// its now unblocked by the user. /// internal event EventHandler JobUnblocked; /// /// Set the state of the current job from blocked to /// running and raise an event indicating to this - /// parent job that this job is unblocked + /// parent job that this job is unblocked. /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal void UnblockJob() @@ -1802,6 +1851,7 @@ internal void UnblockJob() SetJobState(JobState.Running, null); JobUnblocked.SafeInvoke(this, EventArgs.Empty); } + internal ManagementOperationObserver GetNewSink() { ManagementOperationObserver wmiSink = new ManagementOperationObserver(); @@ -1810,13 +1860,14 @@ internal ManagementOperationObserver GetNewSink() { _sinkCompleted++; } + wmiSink.ObjectReady += new ObjectReadyEventHandler(this.NewObject); wmiSink.Completed += new CompletedEventHandler(this.JobDone); return wmiSink; } /// - /// it receives Management objects + /// It receives Management objects. /// private void NewObject(object sender, ObjectReadyEventArgs obj) { @@ -1824,6 +1875,7 @@ private void NewObject(object sender, ObjectReadyEventArgs obj) { _bAtLeastOneObject = true; } + this.WriteObject(obj.NewObject); } @@ -1836,14 +1888,16 @@ private void JobDone(object sender, CompletedEventArgs obj) { _sinkCompleted--; } + if (obj.Status != ManagementStatus.NoError) { _bJobFailed = true; } + if (_sinkCompleted == 0) { - //Notify throttle manager and change the state to complete - //Two cases where _bFinished should be set to false. + // Notify throttle manager and change the state to complete + // Two cases where _bFinished should be set to false. // 1) Invalid class or some other condition so that after making a connection WMI is throwing an error // 2) We could not get any instance for the class. /*if(bAtLeastOneObject ) @@ -1863,7 +1917,7 @@ private void JobDone(object sender, CompletedEventArgs obj) } /// - /// It is called when the call to Win32shutdown is successfully completed + /// It is called when the call to Win32shutdown is successfully completed. /// private void JobDoneForWin32Shutdown(object sender, EventArgs arg) { @@ -1871,6 +1925,7 @@ private void JobDoneForWin32Shutdown(object sender, EventArgs arg) { _sinkCompleted--; } + if (_sinkCompleted == 0) { _helper.RaiseOperationCompleteEvent(null, OperationState.StopComplete); @@ -1880,14 +1935,13 @@ private void JobDoneForWin32Shutdown(object sender, EventArgs arg) } /// - /// Message indicating status of the job + /// Message indicating status of the job. /// public override string StatusMessage { get; } = "test"; - /// /// Indicates if there is more data available in - /// this Job + /// this Job. /// public override bool HasMoreData { @@ -1899,12 +1953,12 @@ public override bool HasMoreData /// /// Returns the computer on which this command is - /// running + /// running. /// public override string Location { get; } /// - /// Stops the job + /// Stops the job. /// public override void StopJob() { @@ -1936,10 +1990,11 @@ protected override void Dispose(bool disposing) } } } + private bool _isDisposed; /// - /// Handles operation complete event + /// Handles operation complete event. /// private void HandleOperationComplete(object sender, OperationStateEventArgs stateEventArgs) { @@ -1947,7 +2002,7 @@ private void HandleOperationComplete(object sender, OperationStateEventArgs stat if (helper.State == WmiState.NotStarted) { - //This is a case WMI operation was not started. + // This is a case WMI operation was not started. SetJobState(JobState.Stopped, helper.InternalException); } else if (helper.State == WmiState.Running) @@ -1968,7 +2023,7 @@ private void HandleOperationComplete(object sender, OperationStateEventArgs stat } } /// - /// Handles WMI state changed + /// Handles WMI state changed. /// private void HandleWMIState(object sender, WmiJobStateEventArgs stateEventArgs) { @@ -1995,15 +2050,15 @@ private void HandleWMIState(object sender, WmiJobStateEventArgs stateEventArgs) } /// - /// Handle a throttle complete event + /// Handle a throttle complete event. /// - /// sender of this event - /// not used in this method + /// Sender of this event. + /// Not used in this method. private void HandleThrottleComplete(object sender, EventArgs eventArgs) { if (_helper.State == WmiState.NotStarted) { - //This is a case WMI operation was not started. + // This is a case WMI operation was not started. SetJobState(JobState.Stopped, _helper.InternalException); } else if (_helper.State == WmiState.Running) @@ -2022,7 +2077,7 @@ private void HandleThrottleComplete(object sender, EventArgs eventArgs) { SetJobState(JobState.Stopped, _helper.InternalException); } - //Do Nothing - } // HandleThrottleComplete + // Do Nothing + } } } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs index 7ddb52ec825d..929dcf6f6e1f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs @@ -1,39 +1,39 @@ -/********************************************************************-- -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.IO; -using System.Net; -using System.Xml; -using System.Text; using System.CodeDom; using System.CodeDom.Compiler; -using System.Web.Services; -using System.Web.Services.Description; -using System.Web.Services.Discovery; -using System.Management; -using System.Management.Automation; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using Microsoft.CSharp; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Globalization; -using Dbg = System.Management.Automation; -using System.Runtime.InteropServices; +using System.IO; +using System.Management; +using System.Management.Automation; +using System.Net; +using System.Reflection; using System.Resources; -using Microsoft.Win32; +using System.Runtime.InteropServices; +using System.Text; using System.Text.RegularExpressions; +using System.Web.Services; +using System.Web.Services.Description; +using System.Web.Services.Discovery; +using System.Xml; +using Microsoft.CSharp; +using Microsoft.Win32; + +using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { #region New-WebServiceProxy /// - /// Cmdlet for new-WebService Proxy + /// Cmdlet for new-WebService Proxy. /// [Cmdlet(VerbsCommon.New, "WebServiceProxy", DefaultParameterSetName = "NoCredentials", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135238")] public sealed class NewWebServiceProxy : PSCmdlet @@ -41,7 +41,7 @@ public sealed class NewWebServiceProxy : PSCmdlet #region Parameters /// - /// URI of the web service + /// URI of the web service. /// [Parameter(Mandatory = true, Position = 0)] [ValidateNotNullOrEmpty] @@ -49,15 +49,17 @@ public sealed class NewWebServiceProxy : PSCmdlet public System.Uri Uri { get { return _uri; } + set { _uri = value; } } + private System.Uri _uri; /// - /// Parameter Class name + /// Parameter Class name. /// [Parameter(Position = 1)] [ValidateNotNullOrEmpty] @@ -65,15 +67,17 @@ public System.Uri Uri public string Class { get { return _class; } + set { _class = value; } } + private string _class; /// - /// namespace + /// Namespace. /// [Parameter(Position = 2)] [ValidateNotNullOrEmpty] @@ -81,15 +85,17 @@ public string Class public string Namespace { get { return _namespace; } + set { _namespace = value; } } + private string _namespace; /// - /// Credential + /// Credential. /// [Parameter(ParameterSetName = "Credential")] [ValidateNotNullOrEmpty] @@ -98,16 +104,17 @@ public string Namespace public PSCredential Credential { get { return _credential; } + set { _credential = value; } } - private PSCredential _credential; + private PSCredential _credential; /// - /// use default credential.. + /// Use default credential.. /// [Parameter(ParameterSetName = "UseDefaultCredential")] [ValidateNotNull] @@ -115,11 +122,13 @@ public PSCredential Credential public SwitchParameter UseDefaultCredential { get { return _usedefaultcredential; } + set { _usedefaultcredential = value; } } + private SwitchParameter _usedefaultcredential; #endregion @@ -136,17 +145,17 @@ public SwitchParameter UseDefaultCredential private static Dictionary s_srccodeCache = new Dictionary(); /// - /// holds the hash code of the source generated. + /// Holds the hash code of the source generated. /// private int _sourceHash; /// - /// Random class + /// Random class. /// private object _cachelock = new object(); private static Random s_rnd = new Random(); /// - /// BeginProcessing code + /// BeginProcessing code. /// protected override void BeginProcessing() { @@ -156,7 +165,7 @@ protected override void BeginProcessing() ErrorRecord er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } - //check if system.web is available.This assembly is not available in win server core. + // check if system.web is available.This assembly is not available in win server core. string AssemblyString = "System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; try { @@ -175,7 +184,7 @@ protected override void BeginProcessing() { if (s_uriCache.ContainsKey(_uri)) { - //if uri is present in the cache + // if uri is present in the cache string ns; s_uriCache.TryGetValue(_uri, out ns); string[] data = ns.Split('|'); @@ -187,14 +196,16 @@ protected override void BeginProcessing() _class = data[1]; } } + sourceCache = Int32.Parse(data[2].ToString(), CultureInfo.InvariantCulture); } } + if (string.IsNullOrEmpty(_namespace)) { _namespace = "Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy" + GenerateRandomName(); } - //if class is null,generate a name for it + // if class is null,generate a name for it if (string.IsNullOrEmpty(_class)) { _class = "MyClass" + GenerateRandomName(); @@ -203,9 +214,9 @@ protected override void BeginProcessing() Assembly webserviceproxy = GenerateWebServiceProxyAssembly(_namespace, _class); if (webserviceproxy == null) return; - Object instance = InstantiateWebServiceProxy(webserviceproxy); + object instance = InstantiateWebServiceProxy(webserviceproxy); - //to set the credentials into the generated webproxy Object + // to set the credentials into the generated webproxy Object PropertyInfo[] pinfo = instance.GetType().GetProperties(); foreach (PropertyInfo pr in pinfo) { @@ -217,6 +228,7 @@ protected override void BeginProcessing() pr.SetValue(instance, flag as object, null); } } + if (pr.Name.Equals("Credentials", StringComparison.OrdinalIgnoreCase)) { if (Credential != null) @@ -227,12 +239,13 @@ protected override void BeginProcessing() } } - //disposing the entries in a cache - //Adding to Cache + // disposing the entries in a cache + // Adding to Cache lock (s_uriCache) { s_uriCache.Remove(_uri); } + if (sourceCache > 0) { lock (_cachelock) @@ -240,18 +253,20 @@ protected override void BeginProcessing() s_srccodeCache.Remove(sourceCache); } } + string key = string.Join("|", new string[] { _namespace, _class, _sourceHash.ToString(System.Globalization.CultureInfo.InvariantCulture) }); lock (s_uriCache) { s_uriCache.Add(_uri, key); } + lock (_cachelock) { s_srccodeCache.Add(_sourceHash, instance); } WriteObject(instance, true); - }//End BeginProcessing() + } #endregion @@ -261,9 +276,9 @@ protected override void BeginProcessing() private static object s_sequenceNumberLock = new object(); /// - /// Generates a random name + /// Generates a random name. /// - /// string + /// String. private string GenerateRandomName() { string rndname = null; @@ -291,11 +306,12 @@ private string GenerateRandomName() { return (sequenceString + rndname.Substring(rndname.Length - 30)); } + return (sequenceString + rndname); } /// - /// Generates the Assembly + /// Generates the Assembly. /// /// /// @@ -305,11 +321,11 @@ private Assembly GenerateWebServiceProxyAssembly(string NameSpace, string ClassN { DiscoveryClientProtocol dcp = new DiscoveryClientProtocol(); - //if paramset is defaultcredential, set the flag in wcclient + // if paramset is defaultcredential, set the flag in wcclient if (_usedefaultcredential.IsPresent) dcp.UseDefaultCredentials = true; - //if paramset is credential, assign the credentials + // if paramset is credential, assign the credentials if (ParameterSetName.Equals("Credential", StringComparison.OrdinalIgnoreCase)) dcp.Credentials = _credential.GetNetworkCredential(); @@ -339,7 +355,7 @@ private Assembly GenerateWebServiceProxyAssembly(string NameSpace, string ClassN if (!string.IsNullOrEmpty(NameSpace)) codeNS.Name = NameSpace; - //create the class and add it to the namespace + // create the class and add it to the namespace if (!string.IsNullOrEmpty(ClassName)) { CodeTypeDeclaration codeClass = new CodeTypeDeclaration(ClassName); @@ -348,12 +364,12 @@ private Assembly GenerateWebServiceProxyAssembly(string NameSpace, string ClassN codeNS.Types.Add(codeClass); } - //create a web reference to the uri docs + // create a web reference to the uri docs WebReference wref = new WebReference(dcp.Documents, codeNS); WebReferenceCollection wrefs = new WebReferenceCollection(); wrefs.Add(wref); - //create a codecompileunit and add the namespace to it + // create a codecompileunit and add the namespace to it CodeCompileUnit codecompileunit = new CodeCompileUnit(); codecompileunit.Namespaces.Add(codeNS); @@ -361,7 +377,7 @@ private Assembly GenerateWebServiceProxyAssembly(string NameSpace, string ClassN wrefOptions.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateNewAsync | System.Xml.Serialization.CodeGenerationOptions.GenerateOldAsync | System.Xml.Serialization.CodeGenerationOptions.GenerateProperties; wrefOptions.Verbose = true; - //create a csharpprovider and compile it + // create a csharpprovider and compile it CSharpCodeProvider csharpprovider = new CSharpCodeProvider(); StringCollection Warnings = ServiceDescriptionImporter.GenerateWebReferences(wrefs, csharpprovider, codecompileunit, wrefOptions); @@ -376,10 +392,10 @@ private Assembly GenerateWebServiceProxyAssembly(string NameSpace, string ClassN ErrorRecord er = new ErrorRecord(ex, "NotImplementedException", ErrorCategory.ObjectNotFound, _uri); WriteError(er); } - //generate the hashcode of the CodeCompileUnit + // generate the hashcode of the CodeCompileUnit _sourceHash = codegenerator.ToString().GetHashCode(); - //if the sourcehash matches the hashcode in the cache,the proxy hasnt changed and so + // if the sourcehash matches the hashcode in the cache,the proxy hasnt changed and so // return the instance of th eproxy in the cache if (s_srccodeCache.ContainsKey(_sourceHash)) { @@ -388,6 +404,7 @@ private Assembly GenerateWebServiceProxyAssembly(string NameSpace, string ClassN WriteObject(obj, true); return null; } + CompilerParameters options = new CompilerParameters(); CompilerResults results = null; @@ -421,7 +438,7 @@ private Assembly GenerateWebServiceProxyAssembly(string NameSpace, string ClassN } /// - /// Function to add all the assemblies required to generate the web proxy + /// Function to add all the assemblies required to generate the web proxy. /// /// /// @@ -440,23 +457,24 @@ private void GetReferencedAssemblies(Assembly assembly, CompilerParameters param } /// /// Instantiates the object - /// if a type of WebServiceBindingAttribute is not found, throw an exception + /// if a type of WebServiceBindingAttribute is not found, throw an exception. /// /// /// private object InstantiateWebServiceProxy(Assembly assembly) { Type proxyType = null; - //loop through the types of the assembly and identify the type having + // loop through the types of the assembly and identify the type having // a web service binding attribute foreach (Type type in assembly.GetTypes()) { - Object[] obj = type.GetCustomAttributes(typeof(WebServiceBindingAttribute), false); + object[] obj = type.GetCustomAttributes(typeof(WebServiceBindingAttribute), false); if (obj.Length > 0) { proxyType = type; break; } + if (proxyType != null) break; } @@ -468,6 +486,6 @@ private object InstantiateWebServiceProxy(Assembly assembly) } #endregion - }//end class + } #endregion -}//Microsoft.Powershell.commands +} diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/WriteContentCommandBase.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/WriteContentCommandBase.cs index ec5d50ab3bf0..dc1221f81eed 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/WriteContentCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/WriteContentCommandBase.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -8,6 +7,7 @@ using System.Collections.ObjectModel; using System.Management.Automation; using System.Management.Automation.Provider; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -22,11 +22,9 @@ public class WriteContentCommandBase : PassThroughContentCommandBase /// /// The value of the content to set. /// - /// /// /// This value type is determined by the InvokeProvider. /// - /// [Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [AllowNull] [AllowEmptyCollection] @@ -35,13 +33,13 @@ public object[] Value get { return _content; - } // get + } set { _content = value; } - } // Value + } #endregion Parameters @@ -60,7 +58,6 @@ public object[] Value /// This bool is used to determine if the path /// parameter was specified on the command line or via the pipeline. /// - /// private bool _pipingPaths; /// @@ -77,7 +74,7 @@ public object[] Value /// /// Determines if the paths are specified on the command line - /// or being piped in + /// or being piped in. /// protected override void BeginProcessing() { @@ -102,7 +99,7 @@ protected override void ProcessRecord() if (_content == null) { - _content = new object[0]; + _content = Array.Empty(); } if (_pipingPaths) @@ -188,16 +185,15 @@ protected override void ProcessRecord() contentStreams = new List(); } } - } // ProcessRecord + } /// - /// Closes all the content writers + /// Closes all the content writers. /// - /// protected override void EndProcessing() { Dispose(true); - } // EndProcessing + } #endregion Command code @@ -208,24 +204,20 @@ protected override void EndProcessing() /// from the provider. If the current position needs to be changed before writing /// the content, this method should be overridden to do that. /// - /// /// /// The content holders that contain the writers to be moved. /// - /// internal virtual void SeekContentPosition(List contentHolders) { // default does nothing. - } // SeekContentPosition + } /// /// Called by the base class before the streams are open for the path. /// - /// /// /// The path to the items that will be opened for writing content. /// - /// internal virtual void BeforeOpenStreams(string[] paths) { } @@ -235,33 +227,29 @@ internal virtual void BeforeOpenStreams(string[] paths) /// that require dynamic parameters should override this method and return the /// dynamic parameter object. /// - /// /// /// The context under which the command is running. /// - /// /// /// An object representing the dynamic parameters for the cmdlet or null if there /// are none. /// - /// internal override object GetDynamicParameters(CmdletProviderContext context) { if (Path != null && Path.Length > 0) { return InvokeProvider.Content.GetContentWriterDynamicParameters(Path[0], context); } + return InvokeProvider.Content.GetContentWriterDynamicParameters(".", context); } /// /// Gets the IContentWriters for the current path(s) /// - /// /// /// An array of IContentWriters for the current path(s) /// - /// internal List GetContentWriters( string[] writerPaths, CmdletProviderContext currentCommandContext) @@ -330,17 +318,17 @@ internal override object GetDynamicParameters(CmdletProviderContext context) results.Add(holder); } } - } // foreach pathInfo in pathInfos + } return results; - } // GetContentWriters + } /// - /// Gets the list of paths accepted by the user + /// Gets the list of paths accepted by the user. /// - /// The list of unfiltered paths - /// The current context - /// The list of paths accepted by the user + /// The list of unfiltered paths. + /// The current context. + /// The list of paths accepted by the user. private string[] GetAcceptedPaths(string[] unfilteredPaths, CmdletProviderContext currentContext) { Collection pathInfos = ResolvePaths(unfilteredPaths, true, false, currentContext); @@ -355,9 +343,9 @@ private string[] GetAcceptedPaths(string[] unfilteredPaths, CmdletProviderContex } } - return (string[])paths.ToArray(typeof(String)); + return (string[])paths.ToArray(typeof(string)); } #endregion protected members - } // WriteContentCommandBase -} // namespace Microsoft.PowerShell.Commands + } +} diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/CmdletizationResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/CmdletizationResources.resx index 1a25e938a385..15bfadffe7b3 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/CmdletizationResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/CmdletizationResources.resx @@ -124,10 +124,6 @@ {1} is a placeholder for a server name. Example: "localhost". - - ..\..\..\..\src\cimSupport\cmdletization\xml\cmdlets-over-objects.xsd;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - {Locked} - CIM method {1} on the {0} CIM object {0} is a placeholder for a CIM path. Example: \\SERVER1\ROOT\cimv2:Win32_Process.Handle="11828" diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx index 87bc01c6da2f..63a671c02488 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/ComputerResources.resx @@ -153,9 +153,6 @@ The command cannot locate the "{0}" restore point. Verify the "{0}" sequence number, and then try the command again. - - Testing connection to computer '{0}' failed: {1} - {0} ({1}) diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx index e460ad2f016e..0c1151be6b74 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx @@ -120,6 +120,9 @@ Cannot find a process with the name "{0}". Verify the process name and call the cmdlet again. + + Cannot find a process with the name "{0}". Try running with -Id to search by Id of processes. + This command cannot be run because the debugger cannot be attached to the process "{0} ({1})". Specify another process and Run your command. diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx index 6218714a18c2..3792ce8db992 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx @@ -132,9 +132,6 @@ Cannot stop service '{1} ({0})' because it has dependent services. - - Cannot stop service '{1} ({0})' because it is dependent on other services. - Service '{1} ({0})' cannot be stopped due to the following error: {2} @@ -171,6 +168,9 @@ Service '{1} ({0})' automatic (delayed start) cannot be configured due to the following error: {2} + + Service '{0}' security descriptor cannot be configured due to the following error: {1} + Service '{1} ({0})' cannot be created due to the following error: {2} @@ -182,7 +182,7 @@ Service '{1} ({0})' cannot be removed due to the following error: {2} - + 'Cannot access dependent services of '{1} ({0})' diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/TestConnectionResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/TestConnectionResources.resx new file mode 100644 index 000000000000..794680166ccf --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Management/resources/TestConnectionResources.resx @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Tracing route to {0} [{1}] over a maximum of {2} hops: + + + {0,3} {1} ms {2} ms {3} ms {4} [{5}] + + + {0,3} * ms * ms * ms Request timed out. + + + Trace complete. + + + Trying to connect to {0} [{1}]: + + + Target: {0} [{1}]. Seconds: {2} + + + Pinging {0} [{1}] with {2} bytes of data: + + + MTU size: {0}. Attempt: {1} + + + Testing connection to computer '{0}' failed: {1} + + + Cannot resolve the target name. + + + Target IPv4/IPv6 address absent. + + + Pinging {0} [{1}] with {2} bytes of data: + + + Request timed out. + + + Reply from {0}: bytes={1} time={2}ms TTL={3} + + + Ping complete. + + diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/TestPathResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/TestPathResources.resx new file mode 100644 index 000000000000..c60c4318a641 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Management/resources/TestPathResources.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The provided Path argument was null or an empty collection. + + diff --git a/src/Microsoft.PowerShell.Commands.Management/singleshell/installer/MshManagementMshSnapin.cs b/src/Microsoft.PowerShell.Commands.Management/singleshell/installer/MshManagementMshSnapin.cs index 742ccf2f2a05..abd768a782b5 100644 --- a/src/Microsoft.PowerShell.Commands.Management/singleshell/installer/MshManagementMshSnapin.cs +++ b/src/Microsoft.PowerShell.Commands.Management/singleshell/installer/MshManagementMshSnapin.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.ComponentModel; using System.Management.Automation; @@ -8,14 +7,11 @@ namespace Microsoft.PowerShell { /// - /// /// MshManagementMshSnapin (or MshManagementMshSnapinInstaller) is a class for facilitating registry /// of necessary information for monad management mshsnapin. /// - /// This class will be built with monad management dll - /// + /// This class will be built with monad management dll. /// - /// [RunInstaller(true)] public sealed class PSManagementPSSnapIn : PSSnapIn { diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 33741706393a..6ceadabe013f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -1,13 +1,14 @@  - PowerShell Core's Microsoft.PowerShell.Commands.Utility project + PowerShell's Microsoft.PowerShell.Commands.Utility project $(NoWarn);CS1570 Microsoft.PowerShell.Commands.Utility + @@ -24,7 +25,7 @@ - + @@ -32,19 +33,8 @@ - + - - - - - - - - - - - @@ -64,20 +54,10 @@ - - portable - - - - $(DefineConstants);UNIX - - - - full - - - + + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddMember.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddMember.cs index 9c19d68183b6..dbde9521828e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddMember.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddMember.cs @@ -1,17 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; +using System.Collections.ObjectModel; +using System.Globalization; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Reflection; -using System.Globalization; namespace Microsoft.PowerShell.Commands { @@ -22,7 +20,7 @@ namespace Microsoft.PowerShell.Commands HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113280", RemotingCapability = RemotingCapability.None)] public class AddMemberCommand : PSCmdlet { - private static object s_notSpecified = new object(); + private static readonly object s_notSpecified = new object(); private static bool HasBeenSpecified(object obj) { return !System.Object.ReferenceEquals(obj, s_notSpecified); @@ -30,7 +28,7 @@ private static bool HasBeenSpecified(object obj) private PSObject _inputObject; /// - /// The object to add a member to + /// The object to add a member to. /// [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = "MemberSet")] [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = "TypeNameSet")] @@ -39,59 +37,62 @@ private static bool HasBeenSpecified(object obj) public PSObject InputObject { set { _inputObject = value; } + get { return _inputObject; } } private PSMemberTypes _memberType; /// - /// The member type of to be added + /// The member type of to be added. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "MemberSet")] [Alias("Type")] public PSMemberTypes MemberType { set { _memberType = value; } + get { return _memberType; } } private string _memberName; /// - /// The name of the new member + /// The name of the new member. /// [Parameter(Mandatory = true, Position = 1, ParameterSetName = "MemberSet")] public string Name { set { _memberName = value; } + get { return _memberName; } } private object _value1 = s_notSpecified; /// - /// First value of the new member. The meaning of this value - /// changes according to the member type. + /// First value of the new member. The meaning of this value changes according to the member type. /// [Parameter(Position = 2, ParameterSetName = "MemberSet")] public object Value { set { _value1 = value; } + get { return _value1; } } private object _value2 = s_notSpecified; /// - /// Second value of the new member. The meaning of this value - /// changes according to the member type. + /// Second value of the new member. The meaning of this value changes according to the member type. /// [Parameter(Position = 3, ParameterSetName = "MemberSet")] public object SecondValue { set { _value2 = value; } + get { return _value2; } } private string _typeName; /// - /// Add new type name to the specified object for TypeNameSet + /// Add new type name to the specified object for TypeNameSet. /// [Parameter(Mandatory = true, ParameterSetName = "TypeNameSet")] [Parameter(ParameterSetName = "MemberSet")] @@ -101,12 +102,13 @@ public object SecondValue public string TypeName { set { _typeName = value; } + get { return _typeName; } } private bool _force; /// - /// True if we should overwrite a possibly existing member + /// True if we should overwrite a possibly existing member. /// [Parameter(ParameterSetName = "MemberSet")] [Parameter(ParameterSetName = NotePropertySingleMemberSet)] @@ -114,13 +116,14 @@ public string TypeName public SwitchParameter Force { set { _force = value; } + get { return _force; } } private bool _passThru /* = false */; + /// - /// Gets or sets the parameter -passThru which states output from - /// the command should be placed in the pipeline. + /// Gets or sets the parameter -passThru which states output from the command should be placed in the pipeline. /// [Parameter(ParameterSetName = "MemberSet")] [Parameter(ParameterSetName = "TypeNameSet")] @@ -129,10 +132,10 @@ public SwitchParameter Force public SwitchParameter PassThru { set { _passThru = value; } + get { return _passThru; } } - #region Simplifying NoteProperty Declaration private const string NotePropertySingleMemberSet = "NotePropertySingleMemberSet"; @@ -140,7 +143,7 @@ public SwitchParameter PassThru private string _notePropertyName; /// - /// The name of the new NoteProperty member + /// The name of the new NoteProperty member. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = NotePropertySingleMemberSet)] [ValidateNotePropertyNameAttribute()] @@ -149,38 +152,40 @@ public SwitchParameter PassThru public string NotePropertyName { set { _notePropertyName = value; } + get { return _notePropertyName; } } private object _notePropertyValue; /// - /// The value of the new NoteProperty member + /// The value of the new NoteProperty member. /// [Parameter(Mandatory = true, Position = 1, ParameterSetName = NotePropertySingleMemberSet)] [AllowNull] public object NotePropertyValue { set { _notePropertyValue = value; } + get { return _notePropertyValue; } } // Use IDictionary to support both Hashtable and OrderedHashtable private IDictionary _property; + /// - /// The NoteProperty members to be set + /// The NoteProperty members to be set. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = NotePropertyMultiMemberSet)] [ValidateNotNullOrEmpty] - [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public IDictionary NotePropertyMembers { get { return _property; } + set { _property = value; } } #endregion Simplifying NoteProperty Declaration - private static object GetParameterType(object sourceValue, Type destinationType) { return LanguagePrimitives.ConvertTo(sourceValue, destinationType, CultureInfo.InvariantCulture); @@ -246,6 +251,7 @@ private PSMemberInfo GetAliasProperty() Type value2Type = (Type)GetParameterType(_value2, typeof(Type)); return new PSAliasProperty(_memberName, value1Str, value2Type); } + return new PSAliasProperty(_memberName, value1Str); } @@ -268,11 +274,13 @@ private PSMemberInfo GetCodeProperty() { value1MethodInfo = (MethodInfo)GetParameterType(_value1, typeof(MethodInfo)); } + MethodInfo value2MethodInfo = null; if (HasBeenSpecified(_value2)) { value2MethodInfo = (MethodInfo)GetParameterType(_value2, typeof(MethodInfo)); } + return new PSCodeProperty(_memberName, value1MethodInfo, value2MethodInfo); } @@ -283,6 +291,7 @@ private PSMemberInfo GetMemberSet() { return new PSMemberSet(_memberName); } + Collection value1Collection = (Collection)GetParameterType(_value1, typeof(Collection)); return new PSMemberSet(_memberName, value1Collection); @@ -324,16 +333,18 @@ private PSMemberInfo GetScriptProperty() { value1ScriptBlock = (ScriptBlock)GetParameterType(_value1, typeof(ScriptBlock)); } + ScriptBlock value2ScriptBlock = null; if (HasBeenSpecified(_value2)) { value2ScriptBlock = (ScriptBlock)GetParameterType(_value2, typeof(ScriptBlock)); } + return new PSScriptProperty(_memberName, value1ScriptBlock, value2ScriptBlock); } /// - /// This method implements the ProcessRecord method for add-member command + /// This method implements the ProcessRecord method for add-member command. /// protected override void ProcessRecord() { @@ -350,6 +361,7 @@ protected override void ProcessRecord() { WriteObject(_inputObject); } + return; } @@ -374,8 +386,10 @@ protected override void ProcessRecord() { memberCount++; } + memberCountHelper = memberCountHelper >> 1; } + if (memberCount != 1) { ThrowTerminatingError(NewError("WrongMemberCount", "WrongMemberCount", null, _memberType.ToString())); @@ -434,7 +448,7 @@ protected override void ProcessRecord() } /// - /// Add the member to the target object + /// Add the member to the target object. /// /// /// @@ -465,12 +479,13 @@ private bool AddMemberToTarget(PSMemberInfo member) } } } + _inputObject.Members.Add(member); return true; } /// - /// Process the 'NotePropertyMultiMemberSet' parameter set + /// Process the 'NotePropertyMultiMemberSet' parameter set. /// private void ProcessNotePropertyMultiMemberSet() { @@ -496,6 +511,7 @@ private void ProcessNotePropertyMultiMemberSet() { UpdateTypeNames(); } + if (result && _passThru) { WriteObject(_inputObject); @@ -508,6 +524,7 @@ private void UpdateTypeNames() Type type; string typeNameInUse = _typeName; if (LanguagePrimitives.TryConvertTo(_typeName, out type)) { typeNameInUse = type.FullName; } + _inputObject.TypeNames.Insert(0, typeNameInUse); } @@ -529,12 +546,11 @@ private ErrorRecord NewError(string errorId, string resourceId, object targetObj /// So when given a string or a number that can be converted, we make sure it gets /// bound to -MemberType, instead of -NotePropertyName. /// - /// /// /// This exception will be hidden in the positional binding phase. So we make sure /// if the argument can be converted to PSMemberTypes, it gets bound to the -MemberType /// parameter. We are sure that when this exception is thrown, the current positional - /// argument can be successfully bound to + /// argument can be successfully bound to. /// private sealed class ValidateNotePropertyNameAttribute : ValidateArgumentsAttribute { @@ -564,7 +580,7 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin } /// - /// Transform the integer arguments to strings for the parameter NotePropertyName + /// Transform the integer arguments to strings for the parameter NotePropertyName. /// internal sealed class NotePropertyTransformationAttribute : ArgumentTransformationAttribute { @@ -576,9 +592,9 @@ public override object Transform(EngineIntrinsics engineIntrinsics, object input var result = LanguagePrimitives.ConvertTo(target); return result; } + return inputData; } } } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index 50d406dc9348..4e6fc6764320 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -1,243 +1,153 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; - +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Management.Automation; using System.Management.Automation.Internal; using System.Reflection; +using System.Runtime.Loader; using System.Security; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; - +using Microsoft.CodeAnalysis.Text; using PathType = System.IO.Path; - namespace Microsoft.PowerShell.Commands { /// - /// Languages supported for code generation + /// Languages supported for code generation. /// - [SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces")] public enum Language { /// - /// The C# programming language: latest version. - /// - CSharp, - - /// - /// The C# programming language v7 - /// - CSharpVersion7, - - /// - /// The C# programming language v6 - /// - CSharpVersion6, - - /// - /// The C# programming language v5 - /// - CSharpVersion5, - - /// - /// The C# programming language v4 - /// - CSharpVersion4, - - /// - /// The C# programming language v3 (for Linq, etc) - /// - CSharpVersion3, - - /// - /// The C# programming language v2 - /// - CSharpVersion2, - - /// - /// The C# programming language v1 + /// The C# programming language. /// - CSharpVersion1, - - /// - /// The Visual Basic programming language - /// - VisualBasic, - - /// - /// The Managed JScript programming language - /// - JScript, + CSharp } /// - /// Types supported for the OutputAssembly parameter + /// Types supported for the OutputAssembly parameter. /// public enum OutputAssemblyType { /// - /// A Dynamically linked library (DLL) + /// A Dynamically linked library (DLL). /// Library, /// - /// An executable application that targets the console subsystem + /// An executable application that targets the console subsystem. /// ConsoleApplication, /// - /// An executable application that targets the graphical subsystem + /// An executable application that targets the graphical subsystem. /// WindowsApplication } - /// - /// Compile error or warning. - /// - public class AddTypeCompilerError - { - /// - /// FileName, if compiled from paths. - /// - public string FileName { get; internal set; } - - /// - /// Line number. - /// - public int Line { get; internal set; } - - /// - /// Column number. - /// - public int Column { get; internal set; } - - /// - /// Error number code, i.e. CS0116 - /// - public string ErrorNumber { get; internal set; } - - /// - /// Error message text. - /// - public string ErrorText { get; internal set; } - - /// - /// true if warning. false if error. - /// - public bool IsWarning { get; internal set; } - } - /// /// Adds a new type to the Application Domain. /// This version is based on CodeAnalysis (Roslyn). /// - [Cmdlet(VerbsCommon.Add, "Type", DefaultParameterSetName = "FromSource", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135195")] + [Cmdlet(VerbsCommon.Add, "Type", DefaultParameterSetName = FromSourceParameterSetName, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135195")] [OutputType(typeof(Type))] public sealed class AddTypeCommand : PSCmdlet { + #region Parameters + /// - /// The source code of this type. + /// The source code of this generated type. /// - [Parameter(Mandatory = true, Position = 0, ParameterSetName = "FromSource")] - public String TypeDefinition + [Parameter(Mandatory = true, Position = 0, ParameterSetName = FromSourceParameterSetName)] + [ValidateTrustedData] + public string TypeDefinition { get { - return sourceCode; + return _sourceCode; } + set { - sourceCode = value; + _sourceCode = value; } } /// - /// The name of the type used for auto-generated types. + /// The name of the type (class) used for auto-generated types. /// - [Parameter(Mandatory = true, Position = 0, ParameterSetName = "FromMember")] - public String Name { get; set; } + [Parameter(Mandatory = true, Position = 0, ParameterSetName = FromMemberParameterSetName)] + [ValidateTrustedData] + public string Name { get; set; } /// - /// The source code of this method / member. + /// The source code of this generated method / member. /// - [Parameter(Mandatory = true, Position = 1, ParameterSetName = "FromMember")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] MemberDefinition + [Parameter(Mandatory = true, Position = 1, ParameterSetName = FromMemberParameterSetName)] + public string[] MemberDefinition { get { - return new string[] { sourceCode }; + return new string[] { _sourceCode }; } + set { - sourceCode = ""; + _sourceCode = string.Empty; if (value != null) { - sourceCode = String.Join("\n", value); + _sourceCode = string.Join("\n", value); } } } - internal String sourceCode; + private string _sourceCode; /// - /// The namespaced used for the auto-generated type. + /// The namespace used for the auto-generated type. /// - [Parameter(ParameterSetName = "FromMember")] - [Alias("NS")] + [Parameter(ParameterSetName = FromMemberParameterSetName)] [AllowNull] - public String Namespace - { - get - { - return typeNamespace; - } - set - { - typeNamespace = value?.Trim(); - } - } - - internal string typeNamespace = "Microsoft.PowerShell.Commands.AddType.AutoGeneratedTypes"; + [Alias("NS")] + public string Namespace { get; set; } = "Microsoft.PowerShell.Commands.AddType.AutoGeneratedTypes"; /// /// Any using statements required by the auto-generated type. /// - [Parameter(ParameterSetName = "FromMember")] + [Parameter(ParameterSetName = FromMemberParameterSetName)] + [ValidateNotNull()] [Alias("Using")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] UsingNamespace { get; set; } = Utils.EmptyArray(); + public string[] UsingNamespace { get; set; } = Array.Empty(); /// /// The path to the source code or DLL to load. /// - [Parameter(Mandatory = true, Position = 0, ParameterSetName = "FromPath")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] + [Parameter(Mandatory = true, Position = 0, ParameterSetName = FromPathParameterSetName)] + [ValidateTrustedData] public string[] Path { get { - return paths; + return _paths; } + set { if (value == null) { - paths = null; + _paths = null; return; } @@ -249,8 +159,7 @@ public string[] Path foreach (string path in pathValue) { // Try to resolve the path - ProviderInfo provider = null; - Collection newPaths = SessionState.Path.GetResolvedProviderPathFromPSPath(path, out provider); + Collection newPaths = SessionState.Path.GetResolvedProviderPathFromPSPath(path, out ProviderInfo _); // If it didn't resolve, add the original back // for a better error message. @@ -271,20 +180,21 @@ public string[] Path /// /// The literal path to the source code or DLL to load. /// - [Parameter(Mandatory = true, ParameterSetName = "FromLiteralPath")] - [Alias("PSPath")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] + [Parameter(Mandatory = true, ParameterSetName = FromLiteralPathParameterSetName)] + [Alias("PSPath", "LP")] + [ValidateTrustedData] public string[] LiteralPath { get { - return paths; + return _paths; } + set { if (value == null) { - paths = null; + _paths = null; return; } @@ -301,12 +211,8 @@ public string[] LiteralPath private void ProcessPaths(List resolvedPaths) { - // Now, get the file type. At the same time, make sure - // we aren't attempting to mix languages, as that is - // not supported by the CodeDomProvider. While it - // would be possible to partition the files into - // languages, that would be much too complex to - // describe. + // Validate file extensions. + // Make sure we don't mix source files from different languages (if we support any other languages in future). string activeExtension = null; foreach (string path in resolvedPaths) { @@ -318,16 +224,8 @@ private void ProcessPaths(List resolvedPaths) Language = Language.CSharp; break; - case ".VB": - Language = Language.VisualBasic; - break; - - case ".JS": - Language = Language.JScript; - break; - case ".DLL": - loadAssembly = true; + _loadAssembly = true; break; // Throw an error if it is an unrecognized extension @@ -340,7 +238,6 @@ private void ProcessPaths(List resolvedPaths) currentExtension); ThrowTerminatingError(errorRecord); - break; } @@ -348,9 +245,9 @@ private void ProcessPaths(List resolvedPaths) { activeExtension = currentExtension; } - else if (!String.Equals(activeExtension, currentExtension, StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(activeExtension, currentExtension, StringComparison.OrdinalIgnoreCase)) { - // Throw an error if they are switching extensions + // All files must have the same extension otherwise throw. ErrorRecord errorRecord = new ErrorRecord( new Exception( StringUtil.Format(AddTypeStrings.MultipleExtensionsNotSupported)), @@ -360,82 +257,73 @@ private void ProcessPaths(List resolvedPaths) ThrowTerminatingError(errorRecord); } - - paths = resolvedPaths.ToArray(); } + + _paths = resolvedPaths.ToArray(); } - internal string[] paths; + private string[] _paths; /// /// The name of the assembly to load. /// - [Parameter(Mandatory = true, ParameterSetName = "FromAssemblyName")] + [Parameter(Mandatory = true, ParameterSetName = FromAssemblyNameParameterSetName)] [Alias("AN")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] AssemblyName - { - get - { - return assemblyNames; - } - set - { - assemblyNames = value; - loadAssembly = true; - } - } + [ValidateTrustedData] + public string[] AssemblyName { get; set; } - internal String[] assemblyNames; - internal bool loadAssembly = false; + private bool _loadAssembly = false; /// - /// The language used to generate source code. + /// The language used to compile the source code. + /// Default is C#. /// - [Parameter(ParameterSetName = "FromSource")] - [Parameter(ParameterSetName = "FromMember")] + [Parameter(ParameterSetName = FromSourceParameterSetName)] + [Parameter(ParameterSetName = FromMemberParameterSetName)] public Language Language { get; set; } = Language.CSharp; /// /// Any reference DLLs to use in the compilation. /// - [Parameter(ParameterSetName = "FromSource")] - [Parameter(ParameterSetName = "FromMember")] - [Parameter(ParameterSetName = "FromPath")] - [Parameter(ParameterSetName = "FromLiteralPath")] + [Parameter(ParameterSetName = FromSourceParameterSetName)] + [Parameter(ParameterSetName = FromMemberParameterSetName)] + [Parameter(ParameterSetName = FromPathParameterSetName)] + [Parameter(ParameterSetName = FromLiteralPathParameterSetName)] [Alias("RA")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] ReferencedAssemblies + public string[] ReferencedAssemblies { - get { return referencedAssemblies; } + get { return _referencedAssemblies; } + set { - if (value != null) { referencedAssemblies = value; } + if (value != null) { _referencedAssemblies = value; } } } - internal string[] referencedAssemblies = Utils.EmptyArray(); + + private string[] _referencedAssemblies = Array.Empty(); /// /// The path to the output assembly. /// - [Parameter(ParameterSetName = "FromSource")] - [Parameter(ParameterSetName = "FromMember")] - [Parameter(ParameterSetName = "FromPath")] - [Parameter(ParameterSetName = "FromLiteralPath")] + [Parameter(ParameterSetName = FromSourceParameterSetName)] + [Parameter(ParameterSetName = FromMemberParameterSetName)] + [Parameter(ParameterSetName = FromPathParameterSetName)] + [Parameter(ParameterSetName = FromLiteralPathParameterSetName)] [Alias("OA")] public string OutputAssembly { get { - return outputAssembly; + return _outputAssembly; } + set { - outputAssembly = value; + _outputAssembly = value; - if (outputAssembly != null) + if (_outputAssembly != null) { - outputAssembly = outputAssembly.Trim(); + _outputAssembly = _outputAssembly.Trim(); // Try to resolve the path ProviderInfo provider = null; @@ -443,21 +331,21 @@ public string OutputAssembly try { - newPaths = SessionState.Path.GetResolvedProviderPathFromPSPath(outputAssembly, out provider); + newPaths = SessionState.Path.GetResolvedProviderPathFromPSPath(_outputAssembly, out provider); } // Ignore the ItemNotFound -- we handle it. catch (ItemNotFoundException) { } ErrorRecord errorRecord = new ErrorRecord( new Exception( - StringUtil.Format(AddTypeStrings.OutputAssemblyDidNotResolve, outputAssembly)), + StringUtil.Format(AddTypeStrings.OutputAssemblyDidNotResolve, _outputAssembly)), "INVALID_OUTPUT_ASSEMBLY", ErrorCategory.InvalidArgument, - outputAssembly); + _outputAssembly); // If it resolved to a non-standard provider, // generate an error. - if (!String.Equals("FileSystem", provider.Name, StringComparison.OrdinalIgnoreCase)) + if (!string.Equals("FileSystem", provider.Name, StringComparison.OrdinalIgnoreCase)) { ThrowTerminatingError(errorRecord); return; @@ -475,49 +363,36 @@ public string OutputAssembly else if (newPaths.Count == 0) { // We can't create one with wildcard characters - if (WildcardPattern.ContainsWildcardCharacters(outputAssembly)) + if (WildcardPattern.ContainsWildcardCharacters(_outputAssembly)) { ThrowTerminatingError(errorRecord); } // Create the file else { - outputAssembly = SessionState.Path.GetUnresolvedProviderPathFromPSPath(outputAssembly); + _outputAssembly = SessionState.Path.GetUnresolvedProviderPathFromPSPath(_outputAssembly); } } // It resolved to a single file else { - outputAssembly = newPaths[0]; + _outputAssembly = newPaths[0]; } } } } - internal string outputAssembly = null; + + private string _outputAssembly = null; /// /// The output type of the assembly. /// - [Parameter(ParameterSetName = "FromSource")] - [Parameter(ParameterSetName = "FromMember")] - [Parameter(ParameterSetName = "FromPath")] - [Parameter(ParameterSetName = "FromLiteralPath")] + [Parameter(ParameterSetName = FromSourceParameterSetName)] + [Parameter(ParameterSetName = FromMemberParameterSetName)] + [Parameter(ParameterSetName = FromPathParameterSetName)] + [Parameter(ParameterSetName = FromLiteralPathParameterSetName)] [Alias("OT")] - public OutputAssemblyType OutputType - { - get - { - return outputType; - } - set - { - outputTypeSpecified = true; - outputType = value; - } - } - internal OutputAssemblyType outputType = OutputAssemblyType.Library; - internal bool outputTypeSpecified = false; - + public OutputAssemblyType OutputType { get; set; } = OutputAssemblyType.Library; /// /// Flag to pass the resulting types along. @@ -528,23 +403,64 @@ public OutputAssemblyType OutputType /// /// Flag to ignore warnings during compilation. /// - [Parameter()] + [Parameter(ParameterSetName = FromSourceParameterSetName)] + [Parameter(ParameterSetName = FromMemberParameterSetName)] + [Parameter(ParameterSetName = FromPathParameterSetName)] + [Parameter(ParameterSetName = FromLiteralPathParameterSetName)] public SwitchParameter IgnoreWarnings { get; set; } - internal string GenerateTypeSource(string typeNamespace, string name, string sourceCode, Language language) + /// + /// Roslyn command line parameters. + /// https://github.com/dotnet/roslyn/blob/master/docs/compilers/CSharp/CommandLine.md + /// + /// Parser options: + /// langversion:string - language version from: + /// [enum]::GetNames([Microsoft.CodeAnalysis.CSharp.LanguageVersion]) + /// define:symbol list - preprocessor symbols: + /// /define:UNIX,DEBUG - CSharp + /// + /// Compilation options: + /// optimize{+|-} - optimization level + /// parallel{+|-} - concurrent build + /// warnaserror{+|-} - report warnings to errors + /// warnaserror{+|-}:strings - report specific warnings to errors + /// warn:number - warning level (0-4) for CSharp + /// nowarn - disable all warnings + /// nowarn:strings - disable a list of individual warnings + /// usings:strings - ';'-delimited usings for CSharp + /// + /// Emit options: + /// platform:string - limit which platforms this code can run on; must be x86, x64, Itanium, arm, AnyCPU32BitPreferred or anycpu (default) + /// delaysign{+|-} - delay-sign the assembly using only the public portion of the strong name key + /// keyfile:file - specifies a strong name key file + /// keycontainer:string - specifies a strong name key container + /// highentropyva{+|-} - enable high-entropy ASLR. + /// + [Parameter(ParameterSetName = FromSourceParameterSetName)] + [Parameter(ParameterSetName = FromMemberParameterSetName)] + [Parameter(ParameterSetName = FromPathParameterSetName)] + [Parameter(ParameterSetName = FromLiteralPathParameterSetName)] + [ValidateNotNullOrEmpty] + public string[] CompilerOptions { get; set; } + + #endregion Parameters + + #region GererateSource + + private string GenerateTypeSource(string typeNamespace, string typeName, string sourceCodeText, Language language) { - string usingSource = String.Format( - CultureInfo.CurrentCulture, + string usingSource = string.Format( + CultureInfo.InvariantCulture, GetUsingTemplate(language), GetUsingSet(language)); - string typeSource = String.Format( - CultureInfo.CurrentCulture, - GetMethodTemplate(language), Name, sourceCode); + string typeSource = string.Format( + CultureInfo.InvariantCulture, + GetMethodTemplate(language), typeName, sourceCodeText); - if (!String.IsNullOrEmpty(typeNamespace)) + if (!string.IsNullOrEmpty(typeNamespace)) { - return usingSource + String.Format( - CultureInfo.CurrentCulture, + return usingSource + string.Format( + CultureInfo.InvariantCulture, GetNamespaceTemplate(language), typeNamespace, typeSource); } else @@ -553,241 +469,82 @@ internal string GenerateTypeSource(string typeNamespace, string name, string sou } } - internal bool IsCSharp(Language language) - { - switch (language) - { - case Language.CSharp: - case Language.CSharpVersion2: - case Language.CSharpVersion3: - case Language.CSharpVersion1: - case Language.CSharpVersion4: - case Language.CSharpVersion5: - case Language.CSharpVersion6: - case Language.CSharpVersion7: - return true; - default: - return false; - } - } - // Get the -FromMember template for a given language - internal string GetMethodTemplate(Language language) + private string GetMethodTemplate(Language language) { - if (IsCSharp(language)) - { - return - " public class {0}\n" + - " {{\n" + - " {1}\n" + - " }}\n"; - } - switch (language) { - case Language.VisualBasic: - return - " public Class {0}\n" + - " \n" + - " {1}\n" + - " \n" + - " End Class\n"; - case Language.JScript: + case Language.CSharp: return " public class {0}\n" + " {{\n" + " {1}\n" + " }}\n"; } - return null; + + throw PSTraceSource.NewNotSupportedException(); } // Get the -FromMember namespace template for a given language - internal string GetNamespaceTemplate(Language language) + private string GetNamespaceTemplate(Language language) { - if (IsCSharp(language)) - { - return - "namespace {0}\n" + - "{{\n" + - "{1}\n" + - "}}\n"; - } - switch (language) { - case Language.VisualBasic: - return - "Namespace {0}\n" + - "\n" + - "{1}\n" + - "End Namespace\n"; - case Language.JScript: + case Language.CSharp: return - "package {0}\n" + + "namespace {0}\n" + "{{\n" + "{1}\n" + "}}\n"; } - return null; + + throw PSTraceSource.NewNotSupportedException(); } // Get the -FromMember namespace template for a given language - internal string GetUsingTemplate(Language language) + private string GetUsingTemplate(Language language) { - if (IsCSharp(language)) - { - return - "using System;\n" + - "using System.Runtime.InteropServices;\n" + - "{0}" + - "\n"; - } - switch (language) { - case Language.VisualBasic: - return - "Imports System\n" + - "Imports System.Runtime.InteropServices\n" + - "{0}" + - "\n"; - case Language.JScript: + case Language.CSharp: return - "import System;\n" + - "import System.Runtime.InteropServices;\n" + + "using System;\n" + + "using System.Runtime.InteropServices;\n" + "{0}" + "\n"; } - return null; + + throw PSTraceSource.NewNotSupportedException(); } // Generate the code for the using statements - internal string GetUsingSet(Language language) + private string GetUsingSet(Language language) { StringBuilder usingNamespaceSet = new StringBuilder(); - if (IsCSharp(language)) - { - foreach (string namespaceValue in UsingNamespace) - { - usingNamespaceSet.Append("using " + namespaceValue + ";\n"); - } - } - else - { - switch (language) - { - case Language.VisualBasic: - foreach (string namespaceValue in UsingNamespace) - { - usingNamespaceSet.Append("Imports " + namespaceValue + "\n"); - } - break; - - case Language.JScript: - foreach (string namespaceValue in UsingNamespace) - { - usingNamespaceSet.Append("import " + namespaceValue + ";\n"); - } - break; - } - } - - return usingNamespaceSet.ToString(); - } - - internal void HandleCompilerErrors(AddTypeCompilerError[] compilerErrors) - { - // Get the source code that corresponds to their type in the case of errors - string[] actualSource = Utils.EmptyArray(); - - // Get the source code that corresponds to the - // error if we generated it - if ((compilerErrors.Length > 0) && - (!String.Equals(ParameterSetName, "FromPath", StringComparison.OrdinalIgnoreCase)) && - (!String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase)) - ) - { - actualSource = sourceCode.Split(Utils.Separators.Newline); - } - - // Write any errors to the pipeline - foreach (var error in compilerErrors) - { - OutputError(error, actualSource); - } - - if (compilerErrors.Any(e => !e.IsWarning)) - { - ErrorRecord errorRecord = new ErrorRecord( - new InvalidOperationException(AddTypeStrings.CompilerErrors), - "COMPILER_ERRORS", - ErrorCategory.InvalidData, - null); - ThrowTerminatingError(errorRecord); - } - } - - private void OutputError(AddTypeCompilerError error, string[] actualSource) - { - // Get the actual line of the file if they - // used the -FromPath parameter set - if (String.Equals(ParameterSetName, "FromPath", StringComparison.OrdinalIgnoreCase) || - String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase) - ) - { - if (!String.IsNullOrEmpty(error.FileName)) - { - actualSource = System.IO.File.ReadAllLines(error.FileName); - } - } - string errorText = StringUtil.Format(AddTypeStrings.CompilationErrorFormat, - error.FileName, error.Line, error.ErrorText) + Environment.NewLine; - - for (int lineNumber = error.Line - 1; lineNumber < error.Line + 2; lineNumber++) + switch (language) { - if (lineNumber > 0) - { - if (lineNumber > actualSource.Length) - break; - - string lineText = ""; - - if (lineNumber == error.Line) + case Language.CSharp: + foreach (string namespaceValue in UsingNamespace) { - lineText += ">>> "; + usingNamespaceSet.Append("using " + namespaceValue + ";\n"); } - lineText += actualSource[lineNumber - 1]; - - errorText += Environment.NewLine + StringUtil.Format(AddTypeStrings.CompilationErrorFormat, - error.FileName, lineNumber, lineText) + Environment.NewLine; - } - } + break; - if (error.IsWarning) - { - WriteWarning(errorText); + default: + throw PSTraceSource.NewNotSupportedException(); } - else - { - ErrorRecord errorRecord = new ErrorRecord( - new Exception(errorText), - "SOURCE_CODE_ERROR", - ErrorCategory.InvalidData, - error); - WriteError(errorRecord); - } + return usingNamespaceSet.ToString(); } - private static Dictionary s_sourceCache = new Dictionary(); + #endregion GererateSource /// - /// Generate the type(s). + /// Prevent code compilation in ConstrainedLanguage mode. /// - protected override void EndProcessing() + protected override void BeginProcessing() { // Prevent code compilation in ConstrainedLanguage mode if (SessionState.LanguageMode == PSLanguageMode.ConstrainedLanguage) @@ -796,75 +553,82 @@ protected override void EndProcessing() new ErrorRecord( new PSNotSupportedException(AddTypeStrings.CannotDefineNewType), "CannotDefineNewType", ErrorCategory.PermissionDenied, null)); } + } + /// + /// Generate and load the type(s). + /// + protected override void EndProcessing() + { // Generate an error if they've specified an output // assembly type without an output assembly - if (String.IsNullOrEmpty(outputAssembly) && outputTypeSpecified) + if (string.IsNullOrEmpty(_outputAssembly) && this.MyInvocation.BoundParameters.ContainsKey(nameof(OutputType))) { ErrorRecord errorRecord = new ErrorRecord( new Exception( - String.Format( + string.Format( CultureInfo.CurrentCulture, AddTypeStrings.OutputTypeRequiresOutputAssembly)), "OUTPUTTYPE_REQUIRES_ASSEMBLY", ErrorCategory.InvalidArgument, - outputType); + OutputType); ThrowTerminatingError(errorRecord); return; } - if (loadAssembly) - { - if (String.Equals(ParameterSetName, "FromPath", StringComparison.OrdinalIgnoreCase) || - String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase)) - { - LoadAssemblies(this.paths); - } - if (String.Equals(ParameterSetName, "FromAssemblyName", StringComparison.OrdinalIgnoreCase)) - { - LoadAssemblies(this.assemblyNames); - } + if (_loadAssembly) + { + // File extension is ".DLL" (ParameterSetName = FromPathParameterSetName or FromLiteralPathParameterSetName). + LoadAssemblies(_paths); + } + else if (ParameterSetName == FromAssemblyNameParameterSetName) + { + LoadAssemblies(AssemblyName); } else { - // Load the source if they want to load from a file - if (String.Equals(ParameterSetName, "FromPath", StringComparison.OrdinalIgnoreCase) || - String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase) - ) - { - if (paths.Length == 1) - { - sourceCode = File.ReadAllText(paths[0]); - } - else - { + // Process a source code from files or strings. + SourceCodeProcessing(); + } + } - // We replace 'ReadAllText' with 'StringBuilder' and 'ReadAllLines' - // to avoide temporary LOH allocations. + #region LoadAssembly - StringBuilder sb = new StringBuilder(8192); + // We now ship .Net Core's reference assemblies with PowerShell, so that Add-Type can work + // in a predictable way and won't be broken when we move to newer version of .NET Core. + // The reference assemblies are located at '$PSHOME\ref'. + private static readonly string s_netcoreAppRefFolder = PathType.Combine(PathType.GetDirectoryName(typeof(PSObject).Assembly.Location), "ref"); + private static readonly string s_frameworkFolder = PathType.GetDirectoryName(typeof(object).Assembly.Location); - foreach (string file in paths) - { - foreach (string line in File.ReadAllLines(file)) - { - sb.AppendLine(line); - } - } + // These assemblies are always automatically added to ReferencedAssemblies. + private static readonly Lazy s_autoReferencedAssemblies = new Lazy(InitAutoIncludedRefAssemblies); - sourceCode = sb.ToString(); - } - } - else if (String.Equals(ParameterSetName, "FromMember", StringComparison.OrdinalIgnoreCase)) - { - sourceCode = GenerateTypeSource(typeNamespace, Name, sourceCode, Language); - } + // A HashSet of assembly names to be ignored if they are specified in '-ReferencedAssemblies' + private static readonly Lazy> s_refAssemblyNamesToIgnore = new Lazy>(InitRefAssemblyNamesToIgnore); - CompileSourceToAssembly(this.sourceCode); - } - } + // These assemblies are used, when ReferencedAssemblies parameter is not specified. + private static readonly Lazy> s_defaultAssemblies = new Lazy>(InitDefaultRefAssemblies); + + private bool InMemory { get { return string.IsNullOrEmpty(_outputAssembly); } } + + // These dictionaries prevent reloading already loaded and unchanged code. + // We don't worry about unbounded growing of the cache because in .Net Core 2.0 we can not unload assemblies. + // TODO: review if we will be able to unload assemblies after migrating to .Net Core 2.1. + private static readonly HashSet s_sourceTypesCache = new HashSet(); + private static readonly Dictionary s_sourceAssemblyCache = new Dictionary(); + + private static readonly string s_defaultSdkDirectory = Utils.DefaultPowerShellAppBase; + private const ReportDiagnostic defaultDiagnosticOption = ReportDiagnostic.Error; + private static readonly string[] s_writeInformationTags = new string[] { "PSHOST" }; + private int _syntaxTreesHash; + + private const string FromMemberParameterSetName = "FromMember"; + private const string FromSourceParameterSetName = "FromSource"; + private const string FromPathParameterSetName = "FromPath"; + private const string FromLiteralPathParameterSetName = "FromLiteralPath"; + private const string FromAssemblyNameParameterSetName = "FromAssemblyName"; private void LoadAssemblies(IEnumerable assemblies) { @@ -885,86 +649,29 @@ private void LoadAssemblies(IEnumerable assemblies) } } - private OutputKind OutputAssemblyTypeToOutputKind(OutputAssemblyType outputType) + /// + /// Initialize the list of reference assemblies that will be used when '-ReferencedAssemblies' is not specified. + /// + private static IEnumerable InitDefaultRefAssemblies() { - switch (outputType) + // netcoreapp3.0 currently comes with 148 reference assemblies (maybe more in future), so we use a capacity of '150'. + var defaultRefAssemblies = new List(150); + + foreach (string file in Directory.EnumerateFiles(s_netcoreAppRefFolder, "*.dll", SearchOption.TopDirectoryOnly)) { - case OutputAssemblyType.Library: - return OutputKind.DynamicallyLinkedLibrary; - case OutputAssemblyType.ConsoleApplication: - return OutputKind.ConsoleApplication; - case OutputAssemblyType.WindowsApplication: - return OutputKind.WindowsApplication; - default: - throw new ArgumentOutOfRangeException("outputType"); + defaultRefAssemblies.Add(MetadataReference.CreateFromFile(file)); } - } - - private void CheckTypesForDuplicates(Assembly assembly) - { - foreach (var type in assembly.GetTypes()) - { - if (s_sourceCache.ContainsKey(type.FullName)) - { - if (s_sourceCache[type.FullName] != sourceCode.GetHashCode()) - { - ErrorRecord errorRecord = new ErrorRecord( - new Exception( - String.Format(AddTypeStrings.TypeAlreadyExists, type.FullName)), - "TYPE_ALREADY_EXISTS", - ErrorCategory.InvalidOperation, - type.FullName); - - ThrowTerminatingError(errorRecord); - return; - } - } - else - { - s_sourceCache[type.FullName] = sourceCode.GetHashCode(); - } - } - } - - // We now ship the NetCoreApp2.0 reference assemblies with PowerShell Core, so that Add-Type can work - // in a predictable way and won't be broken when we move to newer version of .NET Core. - // The NetCoreApp2.0 reference assemblies are located at '$PSHOME\ref'. - private static string s_netcoreAppRefFolder = PathType.Combine(PathType.GetDirectoryName(typeof(PSObject).Assembly.Location), "ref"); - private static string s_frameworkFolder = PathType.GetDirectoryName(typeof(object).Assembly.Location); - - // These assemblies are always automatically added to ReferencedAssemblies. - private static Lazy s_autoReferencedAssemblies = new Lazy(InitAutoIncludedRefAssemblies); - - // A HashSet of assembly names to be ignored if they are specified in '-ReferencedAssemblies' - private static Lazy> s_refAssemblyNamesToIgnore = new Lazy>(InitRefAssemblyNamesToIgnore); - - // These assemblies are used, when ReferencedAssemblies parameter is not specified. - private static Lazy s_defaultAssemblies = new Lazy(InitDefaultRefAssemblies); - - private bool InMemory { get { return String.IsNullOrEmpty(outputAssembly); } } - - /// - /// Initialize the list of reference assemblies that will be used when '-ReferencedAssemblies' is not specified. - /// - private static PortableExecutableReference[] InitDefaultRefAssemblies() - { - // netcoreapp2.0 currently comes with 137 reference assemblies (maybe more in future), so we use a capacity of '150'. - var defaultRefAssemblies = new List(150); - foreach (string file in Directory.EnumerateFiles(s_netcoreAppRefFolder, "*.dll", SearchOption.TopDirectoryOnly)) - { - defaultRefAssemblies.Add(MetadataReference.CreateFromFile(file)); - } - defaultRefAssemblies.Add(MetadataReference.CreateFromFile(typeof(PSObject).Assembly.Location)); - return defaultRefAssemblies.ToArray(); + defaultRefAssemblies.Add(MetadataReference.CreateFromFile(typeof(PSObject).Assembly.Location)); + return defaultRefAssemblies; } /// /// Initialize the set of assembly names that should be ignored when they are specified in '-ReferencedAssemblies'. - /// - System.Private.CoreLib.ni.dll - the runtim dll that contains most core/primitive types + /// - System.Private.CoreLib.ni.dll - the runtime dll that contains most core/primitive types /// - System.Private.Uri.dll - the runtime dll that contains 'System.Uri' and related types /// Referencing these runtime dlls may cause ambiguous type identity or other issues. /// - System.Runtime.dll - the corresponding reference dll will be automatically included - /// - System.Runtime.InteropServices.dll - the corresponding reference dll will be automatically included + /// - System.Runtime.InteropServices.dll - the corresponding reference dll will be automatically included. /// private static HashSet InitRefAssemblyNamesToIgnore() { @@ -998,6 +705,8 @@ private static string GetReferenceAssemblyPathBasedOnType(Type type) private string ResolveAssemblyName(string assembly, bool isForReferenceAssembly) { + ErrorRecord errorRecord; + // if it's a path, resolve it if (assembly.Contains(PathType.DirectorySeparatorChar) || assembly.Contains(PathType.AltDirectorySeparatorChar)) { @@ -1008,7 +717,22 @@ private string ResolveAssemblyName(string assembly, bool isForReferenceAssembly) else { var paths = SessionState.Path.GetResolvedPSPathFromPSPath(assembly); - return paths[0].Path; + if (paths.Count > 0) + { + return paths[0].Path; + } + else + { + errorRecord = new ErrorRecord( + new Exception( + string.Format(ParserStrings.ErrorLoadingAssembly, assembly)), + "ErrorLoadingAssembly", + ErrorCategory.InvalidOperation, + assembly); + + ThrowTerminatingError(errorRecord); + return null; + } } } @@ -1016,14 +740,14 @@ private string ResolveAssemblyName(string assembly, bool isForReferenceAssembly) if (!assembly.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) { // It could be a short assembly name or a full assembly name, but we - // alwasy want the short name to find the corresponding assembly file. + // always want the short name to find the corresponding assembly file. var assemblyName = new AssemblyName(assembly); refAssemblyDll = assemblyName.Name + ".dll"; } // We look up in reference/framework only when it's for resolving reference assemblies. // In case of 'Add-Type -AssemblyName' scenario, we don't attempt to resolve against framework assemblies because - // 1. Explicitly loading a framework assembly usually is not necessary in PowerShell Core. + // 1. Explicitly loading a framework assembly usually is not necessary in PowerShell 6+. // 2. A user should use assembly name instead of path if they want to explicitly load a framework assembly. if (isForReferenceAssembly) { @@ -1054,18 +778,23 @@ private string ResolveAssemblyName(string assembly, bool isForReferenceAssembly) } // Look up the assembly in the current folder - string currentFolderPath = SessionState.Path.GetResolvedPSPathFromPSPath(refAssemblyDll)[0].Path; - if (File.Exists(currentFolderPath)) + var resolvedPaths = SessionState.Path.GetResolvedPSPathFromPSPath(refAssemblyDll); + + if (resolvedPaths.Count > 0) { - return currentFolderPath; + string currentFolderPath = resolvedPaths[0].Path; + if (File.Exists(currentFolderPath)) + { + return currentFolderPath; + } } - ErrorRecord errorRecord = new ErrorRecord( - new Exception( - String.Format(ParserStrings.ErrorLoadingAssembly, assembly)), - "ErrorLoadingAssembly", - ErrorCategory.InvalidOperation, - assembly); + errorRecord = new ErrorRecord( + new Exception( + string.Format(ParserStrings.ErrorLoadingAssembly, assembly)), + "ErrorLoadingAssembly", + ErrorCategory.InvalidOperation, + assembly); ThrowTerminatingError(errorRecord); return null; @@ -1075,7 +804,6 @@ private string ResolveAssemblyName(string assembly, bool isForReferenceAssembly) // However, this does give us a massive usability improvement, as users can just say // Add-Type -AssemblyName Forms (instead of System.Windows.Forms) // This is just long, not unmaintainable. - [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] private Assembly LoadAssemblyHelper(string assemblyName) { Assembly loadedAssembly = null; @@ -1092,10 +820,37 @@ private Assembly LoadAssemblyHelper(string assemblyName) // or file corrupted. catch (System.IO.FileLoadException) { } - if (loadedAssembly != null) - return loadedAssembly; + return loadedAssembly; + } - return null; + private IEnumerable GetPortableExecutableReferences() + { + if (ReferencedAssemblies.Length > 0) + { + var tempReferences = new List(s_autoReferencedAssemblies.Value); + foreach (string assembly in ReferencedAssemblies) + { + if (string.IsNullOrWhiteSpace(assembly)) { continue; } + + string resolvedAssemblyPath = ResolveAssemblyName(assembly, true); + + // Ignore some specified reference assemblies + string fileName = PathType.GetFileName(resolvedAssemblyPath); + if (s_refAssemblyNamesToIgnore.Value.Contains(fileName)) + { + WriteVerbose(StringUtil.Format(AddTypeStrings.ReferenceAssemblyIgnored, resolvedAssemblyPath)); + continue; + } + + tempReferences.Add(MetadataReference.CreateFromFile(resolvedAssemblyPath)); + } + + return tempReferences; + } + else + { + return s_defaultAssemblies.Value; + } } private void WriteTypes(Assembly assembly) @@ -1103,95 +858,288 @@ private void WriteTypes(Assembly assembly) WriteObject(assembly.GetTypes(), true); } - private void CompileSourceToAssembly(string source) + #endregion LoadAssembly + + #region SourceCodeProcessing + + private OutputKind OutputAssemblyTypeToOutputKind(OutputAssemblyType outputType) { - CSharpParseOptions parseOptions; - if (IsCSharp(Language)) + switch (outputType) { - switch (Language) + case OutputAssemblyType.Library: + return OutputKind.DynamicallyLinkedLibrary; + case OutputAssemblyType.ConsoleApplication: + return OutputKind.ConsoleApplication; + case OutputAssemblyType.WindowsApplication: + return OutputKind.WindowsApplication; + default: + throw new ArgumentOutOfRangeException("outputType"); + } + } + + private CommandLineArguments ParseCompilerOption(IEnumerable args) + { + string sdkDirectory = s_defaultSdkDirectory; + string baseDirectory = this.SessionState.Path.CurrentLocation.Path; + string additionalReferenceDirectories = null; + + switch (Language) + { + case Language.CSharp: + return CSharpCommandLineParser.Default.Parse(args, baseDirectory, sdkDirectory, additionalReferenceDirectories); + + default: + throw PSTraceSource.NewNotSupportedException(); + } + } + + private SyntaxTree ParseSourceText(SourceText sourceText, ParseOptions parseOptions, string path = "") + { + switch (Language) + { + case Language.CSharp: + return CSharpSyntaxTree.ParseText(sourceText, (CSharpParseOptions)parseOptions, path); + + default: + throw PSTraceSource.NewNotSupportedException(); + } + } + + private CompilationOptions GetDefaultCompilationOptions() + { + switch (Language) + { + case Language.CSharp: + return new CSharpCompilationOptions(OutputAssemblyTypeToOutputKind(OutputType)); + + default: + throw PSTraceSource.NewNotSupportedException(); + } + } + + private bool isSourceCodeUpdated(List syntaxTrees, out Assembly assembly) + { + Diagnostics.Assert(syntaxTrees.Count != 0, "syntaxTrees should contains a source code."); + + _syntaxTreesHash = SyntaxTreeArrayGetHashCode(syntaxTrees); + + if (s_sourceAssemblyCache.TryGetValue(_syntaxTreesHash, out Assembly hashedAssembly)) + { + assembly = hashedAssembly; + return false; + } + else + { + assembly = null; + return true; + } + } + + private void SourceCodeProcessing() + { + ParseOptions parseOptions = null; + CompilationOptions compilationOptions = null; + EmitOptions emitOptions = null; + + if (CompilerOptions != null) + { + var arguments = ParseCompilerOption(CompilerOptions); + + HandleCompilerErrors(arguments.Errors); + + parseOptions = arguments.ParseOptions; + compilationOptions = arguments.CompilationOptions.WithOutputKind(OutputAssemblyTypeToOutputKind(OutputType)); + emitOptions = arguments.EmitOptions; + } + else + { + parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest); + compilationOptions = GetDefaultCompilationOptions(); + } + + if (!IgnoreWarnings.IsPresent) + { + compilationOptions = compilationOptions.WithGeneralDiagnosticOption(defaultDiagnosticOption); + } + + SourceText sourceText; + List syntaxTrees = new List(); + + switch (ParameterSetName) + { + case FromPathParameterSetName: + case FromLiteralPathParameterSetName: + foreach (string filePath in _paths) + { + using (var sourceFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + sourceText = SourceText.From(sourceFile); + syntaxTrees.Add(ParseSourceText(sourceText, parseOptions, path: filePath)); + } + } + + break; + case FromMemberParameterSetName: + _sourceCode = GenerateTypeSource(Namespace, Name, _sourceCode, Language); + + sourceText = SourceText.From(_sourceCode); + syntaxTrees.Add(ParseSourceText(sourceText, parseOptions)); + break; + case FromSourceParameterSetName: + sourceText = SourceText.From(_sourceCode); + syntaxTrees.Add(ParseSourceText(sourceText, parseOptions)); + break; + default: + Diagnostics.Assert(false, "Invalid parameter set: {0}", this.ParameterSetName); + break; + } + + if (!string.IsNullOrEmpty(_outputAssembly) && !PassThru.IsPresent) + { + CompileToAssembly(syntaxTrees, compilationOptions, emitOptions); + } + else + { + // if the source code was already compiled and loaded and not changed + // we get the assembly from the cache. + if (isSourceCodeUpdated(syntaxTrees, out Assembly assembly)) { - case Language.CSharpVersion1: - parseOptions = new CSharpParseOptions(LanguageVersion.CSharp1); - break; - case Language.CSharpVersion2: - parseOptions = new CSharpParseOptions(LanguageVersion.CSharp2); - break; - case Language.CSharpVersion3: - parseOptions = new CSharpParseOptions(LanguageVersion.CSharp3); - break; - case Language.CSharpVersion4: - parseOptions = new CSharpParseOptions(LanguageVersion.CSharp4); - break; - case Language.CSharpVersion5: - parseOptions = new CSharpParseOptions(LanguageVersion.CSharp5); - break; - case Language.CSharpVersion6: - parseOptions = new CSharpParseOptions(LanguageVersion.CSharp6); - break; - case Language.CSharpVersion7: - parseOptions = new CSharpParseOptions(LanguageVersion.CSharp7); - break; - case Language.CSharp: - parseOptions = new CSharpParseOptions(); - break; - default: - parseOptions = null; - break; + CompileToAssembly(syntaxTrees, compilationOptions, emitOptions); + } + else + { + WriteVerbose(AddTypeStrings.AlreadyCompiledandLoaded); + + if (PassThru) + { + WriteTypes(assembly); + } } } - else + } + + private void CompileToAssembly(List syntaxTrees, CompilationOptions compilationOptions, EmitOptions emitOptions) + { + IEnumerable references = GetPortableExecutableReferences(); + Compilation compilation = null; + + switch (Language) + { + case Language.CSharp: + compilation = CSharpCompilation.Create( + PathType.GetRandomFileName(), + syntaxTrees: syntaxTrees, + references: references, + options: (CSharpCompilationOptions)compilationOptions); + break; + + default: + throw PSTraceSource.NewNotSupportedException(); + } + + DoEmitAndLoadAssembly(compilation, emitOptions); + } + + private void CheckDuplicateTypes(Compilation compilation, out ConcurrentBag newTypes) + { + AllNamedTypeSymbolsVisitor visitor = new AllNamedTypeSymbolsVisitor(); + visitor.Visit(compilation.Assembly.GlobalNamespace); + + foreach (var symbolName in visitor.DuplicateSymbols) { ErrorRecord errorRecord = new ErrorRecord( - new Exception(String.Format(CultureInfo.CurrentCulture, AddTypeStrings.SpecialNetVersionRequired, Language.ToString(), string.Empty)), - "LANGUAGE_NOT_SUPPORTED", - ErrorCategory.InvalidArgument, - Language); + new Exception( + string.Format(AddTypeStrings.TypeAlreadyExists, symbolName)), + "TYPE_ALREADY_EXISTS", + ErrorCategory.InvalidOperation, + symbolName); + WriteError(errorRecord); + } + if (visitor.DuplicateSymbols.Count > 0) + { + ErrorRecord errorRecord = new ErrorRecord( + new InvalidOperationException(AddTypeStrings.CompilerErrors), + "COMPILER_ERRORS", + ErrorCategory.InvalidData, + null); ThrowTerminatingError(errorRecord); - parseOptions = null; } - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, parseOptions); - var references = s_defaultAssemblies.Value; - if (ReferencedAssemblies.Length > 0) + newTypes = visitor.UniqueSymbols; + + return; + } + + // Visit symbols in all namespaces and collect duplicates. + private class AllNamedTypeSymbolsVisitor : SymbolVisitor + { + public readonly ConcurrentBag DuplicateSymbols = new ConcurrentBag(); + public readonly ConcurrentBag UniqueSymbols = new ConcurrentBag(); + + public override void VisitNamespace(INamespaceSymbol symbol) { - var tempReferences = new List(s_autoReferencedAssemblies.Value); - foreach (string assembly in ReferencedAssemblies) + // Main cycle. + // For large files we could use symbol.GetMembers().AsParallel().ForAll(s => s.Accept(this)); + foreach (var member in symbol.GetMembers()) { - if (string.IsNullOrWhiteSpace(assembly)) { continue; } - string resolvedAssemblyPath = ResolveAssemblyName(assembly, true); + member.Accept(this); + } + } - // Ignore some specified reference assemblies - string fileName = PathType.GetFileName(resolvedAssemblyPath); - if (s_refAssemblyNamesToIgnore.Value.Contains(fileName)) - { - WriteVerbose(StringUtil.Format(AddTypeStrings.ReferenceAssemblyIgnored, resolvedAssemblyPath)); - continue; - } - tempReferences.Add(MetadataReference.CreateFromFile(resolvedAssemblyPath)); + public override void VisitNamedType(INamedTypeSymbol symbol) + { + // It is namespace-fully-qualified name + var symbolFullName = symbol.ToString(); + + if (s_sourceTypesCache.TryGetValue(symbolFullName, out _)) + { + DuplicateSymbols.Add(symbolFullName); } - references = tempReferences.ToArray(); + else + { + UniqueSymbols.Add(symbolFullName); + } + } + } + + private void CacheNewTypes(ConcurrentBag newTypes) + { + foreach (var typeName in newTypes) + { + s_sourceTypesCache.Add(typeName); } + } - CSharpCompilation compilation = CSharpCompilation.Create( - PathType.GetRandomFileName(), - syntaxTrees: new[] { syntaxTree }, - references: references, - options: new CSharpCompilationOptions(OutputAssemblyTypeToOutputKind(OutputType))); + private void CacheAssembly(Assembly assembly) + { + s_sourceAssemblyCache.Add(_syntaxTreesHash, assembly); + } + private void DoEmitAndLoadAssembly(Compilation compilation, EmitOptions emitOptions) + { EmitResult emitResult; + CheckDuplicateTypes(compilation, out ConcurrentBag newTypes); + if (InMemory) { using (var ms = new MemoryStream()) { - emitResult = compilation.Emit(ms); + emitResult = compilation.Emit(peStream: ms, options: emitOptions); + + HandleCompilerErrors(emitResult.Diagnostics); + if (emitResult.Success) { - ms.Flush(); + // TODO: We could use Assembly.LoadFromStream() in future. + // See https://github.com/dotnet/corefx/issues/26994 ms.Seek(0, SeekOrigin.Begin); - Assembly assembly = Assembly.Load(ms.ToArray()); - CheckTypesForDuplicates(assembly); + Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms); + + CacheNewTypes(newTypes); + CacheAssembly(assembly); + if (PassThru) { WriteTypes(assembly); @@ -1201,36 +1149,169 @@ private void CompileSourceToAssembly(string source) } else { - emitResult = compilation.Emit(outputAssembly); - if (emitResult.Success) + using (var fs = new FileStream(_outputAssembly, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None)) { - if (PassThru) + emitResult = compilation.Emit(peStream: fs, options: emitOptions); + } + + HandleCompilerErrors(emitResult.Diagnostics); + + if (emitResult.Success && PassThru) + { + Assembly assembly = Assembly.LoadFrom(_outputAssembly); + + CacheNewTypes(newTypes); + CacheAssembly(assembly); + + WriteTypes(assembly); + } + } + } + + private void HandleCompilerErrors(ImmutableArray compilerDiagnostics) + { + if (compilerDiagnostics.Length > 0) + { + bool IsError = false; + + foreach (var diagnisticRecord in compilerDiagnostics) + { + // We shouldn't specify input and output files in CompilerOptions parameter + // so suppress errors from Roslyn default command line parser: + // CS1562: Outputs without source must have the /out option specified + // CS2008: No inputs specified + // BC2008: No inputs specified + // + // On emit phase some warnings (like CS8019/BS50001) don't suppressed + // and present in diagnostic report with DefaultSeverity equal to Hidden + // so we skip them explicitly here too. + if (diagnisticRecord.IsSuppressed || diagnisticRecord.DefaultSeverity == DiagnosticSeverity.Hidden || + string.Equals(diagnisticRecord.Id, "CS2008", StringComparison.InvariantCulture) || + string.Equals(diagnisticRecord.Id, "CS1562", StringComparison.InvariantCulture) || + string.Equals(diagnisticRecord.Id, "BC2008", StringComparison.InvariantCulture)) { - Assembly assembly = Assembly.LoadFrom(outputAssembly); - CheckTypesForDuplicates(assembly); - WriteTypes(assembly); + continue; + } + + if (!IsError) + { + IsError = diagnisticRecord.Severity == DiagnosticSeverity.Error || + (diagnisticRecord.IsWarningAsError && diagnisticRecord.Severity == DiagnosticSeverity.Warning); + } + + string errorText = BuildErrorMessage(diagnisticRecord); + + if (diagnisticRecord.Severity == DiagnosticSeverity.Warning) + { + WriteWarning(errorText); + } + else if (diagnisticRecord.Severity == DiagnosticSeverity.Info) + { + WriteInformation(errorText, s_writeInformationTags); + } + else + { + ErrorRecord errorRecord = new ErrorRecord( + new Exception(errorText), + "SOURCE_CODE_ERROR", + ErrorCategory.InvalidData, + diagnisticRecord); + + WriteError(errorRecord); } } + + if (IsError) + { + ErrorRecord errorRecord = new ErrorRecord( + new InvalidOperationException(AddTypeStrings.CompilerErrors), + "COMPILER_ERRORS", + ErrorCategory.InvalidData, + null); + ThrowTerminatingError(errorRecord); + } } + } + + private string BuildErrorMessage(Diagnostic diagnisticRecord) + { + var location = diagnisticRecord.Location; - if (emitResult.Diagnostics.Length > 0) + if (location.SourceTree == null) { - HandleCompilerErrors(GetErrors(emitResult.Diagnostics)); + // For some error types (linker?) we don't have related source code. + return diagnisticRecord.ToString(); + } + else + { + var text = location.SourceTree.GetText(); + var textLines = text.Lines; + + var lineSpan = location.GetLineSpan(); // FileLinePositionSpan type. + var errorLineNumber = lineSpan.StartLinePosition.Line; + + // This is typical Roslyn diagnostic message which contains + // a message number, a source context and an error position. + var diagnisticMessage = diagnisticRecord.ToString(); + var errorLineString = textLines[errorLineNumber].ToString(); + var errorPosition = lineSpan.StartLinePosition.Character; + + StringBuilder sb = new StringBuilder(diagnisticMessage.Length + errorLineString.Length * 2 + 4); + + sb.AppendLine(diagnisticMessage); + sb.AppendLine(errorLineString); + + for (var i = 0; i < errorLineString.Length; i++) + { + if (!char.IsWhiteSpace(errorLineString[i])) + { + // We copy white chars from the source string. + sb.Append(errorLineString, 0, i); + // then pad up to the error position. + sb.Append(' ', Math.Max(0, errorPosition - i)); + // then put "^" into the error position. + sb.AppendLine("^"); + break; + } + } + + return sb.ToString(); } } - private AddTypeCompilerError[] GetErrors(ImmutableArray diagnostics) + private static int SyntaxTreeArrayGetHashCode(IEnumerable sts) { - return diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error || d.Severity == DiagnosticSeverity.Warning) - .Select(d => new AddTypeCompilerError - { - ErrorText = d.GetMessage(), - FileName = null, - Line = d.Location.GetMappedLineSpan().StartLinePosition.Line + 1, // Convert 0-based to 1-based - IsWarning = !d.IsWarningAsError && d.Severity == DiagnosticSeverity.Warning, - Column = d.Location.GetMappedLineSpan().StartLinePosition.Character + 1, // Convert 0-based to 1-based - ErrorNumber = d.Id - }).ToArray(); + // We use our extension method EnumerableExtensions.SequenceGetHashCode(). + List stHashes = new List(); + foreach (var st in sts) + { + stHashes.Add(SyntaxTreeGetHashCode(st)); + } + + return stHashes.SequenceGetHashCode(); + } + + private static int SyntaxTreeGetHashCode(SyntaxTree st) + { + int hash; + + if (string.IsNullOrEmpty(st.FilePath)) + { + // If the file name does not exist, the source text is set by the user using parameters. + // In this case, we assume that the source text is of a small size and we can re-allocate by ToString(). + hash = st.ToString().GetHashCode(); + } + else + { + // If the file was modified, the write time stamp was also modified + // so we do not need to calculate the entire file hash. + var updateTime = File.GetLastWriteTimeUtc(st.FilePath); + hash = Utils.CombineHashCodes(st.FilePath.GetHashCode(), updateTime.GetHashCode()); + } + + return hash; } + + #endregion SourceCodeProcessing } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/compare-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Compare-Object.cs similarity index 91% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/compare-object.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/Compare-Object.cs index 0dd2e5b2c961..b3ccc3b6795f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/compare-object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Compare-Object.cs @@ -1,17 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Collections.Generic; using System.Collections; +using System.Collections.Generic; using System.Management.Automation; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// /// [Cmdlet(VerbsData.Compare, "Object", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113286", RemotingCapability = RemotingCapability.None)] @@ -19,28 +18,24 @@ public sealed class CompareObjectCommand : ObjectCmdletBase { #region Parameters /// - /// /// [Parameter(Position = 0, Mandatory = true)] [AllowEmptyCollection] public PSObject[] ReferenceObject { get; set; } /// - /// /// [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true)] [AllowEmptyCollection] public PSObject[] DifferenceObject { get; set; } /// - /// /// [Parameter] [ValidateRange(0, Int32.MaxValue)] public int SyncWindow { get; set; } = Int32.MaxValue; /// - /// /// /// [Parameter] @@ -48,61 +43,65 @@ public sealed class CompareObjectCommand : ObjectCmdletBase /* not implemented /// - /// /// [Parameter] public SwitchParameter IgnoreWhiteSpace { get { return _ignoreWhiteSpace; } + set { _ignoreWhiteSpace = value; } } + private bool _ignoreWhiteSpace = false; */ /// - /// /// [Parameter] public SwitchParameter ExcludeDifferent { get { return _excludeDifferent; } + set { _excludeDifferent = value; } } + private bool _excludeDifferent /*=false*/; /// - /// /// [Parameter] public SwitchParameter IncludeEqual { get { return _includeEqual; } + set { _isIncludeEqualSpecified = true; _includeEqual = value; } } + private bool _includeEqual /* = false */; private bool _isIncludeEqualSpecified /* = false */; /// - /// /// [Parameter] public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } } + private bool _passThru /* = false */; #endregion Parameters #region Internal private List _referenceEntries; - private List _referenceEntryBacklog + private readonly List _referenceEntryBacklog = new List(); - private List _differenceEntryBacklog + private readonly List _differenceEntryBacklog = new List(); private OrderByProperty _orderByProperty = null; private OrderByPropertyComparer _comparer = null; @@ -146,12 +145,12 @@ private List _differenceEntryBacklog /// While there is no space in referenceEntryBacklog /// Emit oldest entry in referenceEntryBacklog as unmatched /// Remove oldest entry from referenceEntryBacklog - /// Add referenceEntry to referenceEntryBacklog + /// Add referenceEntry to referenceEntryBacklog. /// /// private void Process(OrderByPropertyEntry differenceEntry) { - Diagnostics.Assert(null != _referenceEntries, "null referenceEntries"); + Diagnostics.Assert(_referenceEntries != null, "null referenceEntries"); // Retrieve the next reference object (referenceEntry) if any OrderByPropertyEntry referenceEntry = null; @@ -165,7 +164,7 @@ private void Process(OrderByPropertyEntry differenceEntry) // Return // 2005/07/19 Switched order of referenceEntry and differenceEntry // so that we cast differenceEntry to the type of referenceEntry. - if (null != referenceEntry && null != differenceEntry && + if (referenceEntry != null && differenceEntry != null && 0 == _comparer.Compare(referenceEntry, differenceEntry)) { EmitMatch(referenceEntry); @@ -178,7 +177,7 @@ private void Process(OrderByPropertyEntry differenceEntry) // Clear differenceEntry OrderByPropertyEntry matchingEntry = MatchAndRemove(differenceEntry, _referenceEntryBacklog); - if (null != matchingEntry) + if (matchingEntry != null) { EmitMatch(matchingEntry); differenceEntry = null; @@ -190,7 +189,7 @@ private void Process(OrderByPropertyEntry differenceEntry) // Clear referenceEntry matchingEntry = MatchAndRemove(referenceEntry, _differenceEntryBacklog); - if (null != matchingEntry) + if (matchingEntry != null) { EmitMatch(referenceEntry); referenceEntry = null; @@ -204,7 +203,7 @@ private void Process(OrderByPropertyEntry differenceEntry) // Emit oldest entry in differenceEntryBacklog as unmatched // Remove oldest entry from differenceEntryBacklog // Add differenceEntry to differenceEntryBacklog - if (null != differenceEntry) + if (differenceEntry != null) { if (0 < SyncWindow) { @@ -213,6 +212,7 @@ private void Process(OrderByPropertyEntry differenceEntry) EmitDifferenceOnly(_differenceEntryBacklog[0]); _differenceEntryBacklog.RemoveAt(0); } + _differenceEntryBacklog.Add(differenceEntry); } else @@ -229,7 +229,7 @@ private void Process(OrderByPropertyEntry differenceEntry) // Emit oldest entry in referenceEntryBacklog as unmatched // Remove oldest entry from referenceEntryBacklog // Add referenceEntry to referenceEntryBacklog - if (null != referenceEntry) + if (referenceEntry != null) { if (0 < SyncWindow) { @@ -238,6 +238,7 @@ private void Process(OrderByPropertyEntry differenceEntry) EmitReferenceOnly(_referenceEntryBacklog[0]); _referenceEntryBacklog.RemoveAt(0); } + _referenceEntryBacklog.Add(referenceEntry); } else @@ -249,7 +250,7 @@ private void Process(OrderByPropertyEntry differenceEntry) private void InitComparer() { - if (null != _comparer) + if (_comparer != null) return; List referenceObjectList = new List(ReferenceObject); @@ -273,19 +274,20 @@ private void InitComparer() OrderByPropertyEntry match, List list) { - if (null == match || null == list) + if (match == null || list == null) return null; - Diagnostics.Assert(null != _comparer, "null comparer"); + Diagnostics.Assert(_comparer != null, "null comparer"); for (int i = 0; i < list.Count; i++) { OrderByPropertyEntry listEntry = list[i]; - Diagnostics.Assert(null != listEntry, "null listEntry " + i); + Diagnostics.Assert(listEntry != null, "null listEntry " + i); if (0 == _comparer.Compare(match, listEntry)) { list.RemoveAt(i); return listEntry; } } + return null; } @@ -310,7 +312,7 @@ private void EmitReferenceOnly(OrderByPropertyEntry entry) private void Emit(OrderByPropertyEntry entry, string sideIndicator) { - Diagnostics.Assert(null != entry, "null entry"); + Diagnostics.Assert(entry != null, "null entry"); PSObject mshobj; if (PassThru) @@ -320,7 +322,7 @@ private void Emit(OrderByPropertyEntry entry, string sideIndicator) else { mshobj = new PSObject(); - if (null == Property || 0 == Property.Length) + if (Property == null || 0 == Property.Length) { PSNoteProperty inputNote = new PSNoteProperty( InputObjectPropertyName, entry.inputObject); @@ -329,7 +331,7 @@ private void Emit(OrderByPropertyEntry entry, string sideIndicator) else { List mshParameterList = _orderByProperty.MshParameterList; - Diagnostics.Assert(null != mshParameterList, "null mshParameterList"); + Diagnostics.Assert(mshParameterList != null, "null mshParameterList"); Diagnostics.Assert(mshParameterList.Count == Property.Length, "mshParameterList.Count " + mshParameterList.Count); for (int i = 0; i < Property.Length; i++) @@ -337,11 +339,11 @@ private void Emit(OrderByPropertyEntry entry, string sideIndicator) // 2005/07/05 This is the closest we can come to // the string typed by the user MshParameter mshParameter = mshParameterList[i]; - Diagnostics.Assert(null != mshParameter, "null mshParameter"); + Diagnostics.Assert(mshParameter != null, "null mshParameter"); Hashtable hash = mshParameter.hash; - Diagnostics.Assert(null != hash, "null hash"); + Diagnostics.Assert(hash != null, "null hash"); object prop = hash[FormatParameterDefinitionKeys.ExpressionEntryKey]; - Diagnostics.Assert(null != prop, "null prop"); + Diagnostics.Assert(prop != null, "null prop"); string propName = prop.ToString(); PSNoteProperty propertyNote = new PSNoteProperty( propName, @@ -357,6 +359,7 @@ private void Emit(OrderByPropertyEntry entry, string sideIndicator) } } } + mshobj.Properties.Remove(SideIndicatorPropertyName); PSNoteProperty sideNote = new PSNoteProperty( SideIndicatorPropertyName, sideIndicator); @@ -380,6 +383,7 @@ protected override void BeginProcessing() { return; } + if (_isIncludeEqualSpecified && !_includeEqual) { return; @@ -390,7 +394,6 @@ protected override void BeginProcessing() } /// - /// /// protected override void ProcessRecord() { @@ -405,7 +408,7 @@ protected override void ProcessRecord() return; } - if (null == _comparer && 0 < DifferenceObject.Length) + if (_comparer == null && 0 < DifferenceObject.Length) { InitComparer(); } @@ -422,7 +425,6 @@ protected override void ProcessRecord() } /// - /// /// protected override void EndProcessing() { @@ -441,11 +443,13 @@ protected override void EndProcessing() { EmitDifferenceOnly(differenceEntry); } + _differenceEntryBacklog.Clear(); foreach (OrderByPropertyEntry referenceEntry in _referenceEntryBacklog) { EmitReferenceOnly(referenceEntry); } + _referenceEntryBacklog.Clear(); } #endregion Overrides @@ -482,4 +486,3 @@ private void HandleReferenceObjectOnly() } } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConsoleColorCmdlet.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConsoleColorCmdlet.cs index ffbc04e3cb94..f0b24be51ed9 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConsoleColorCmdlet.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConsoleColorCmdlet.cs @@ -1,8 +1,5 @@ -/********************************************************************++ - -Copyright (c) Microsoft Corporation. All rights reserved. - ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -11,16 +8,14 @@ namespace Microsoft.PowerShell.Commands { /// - /// - /// Base class for a variety of commandlets that take color parameters - /// + /// Base class for a variety of commandlets that take color parameters. /// public class ConsoleColorCmdlet : PSCmdlet { /// - /// Default ctor + /// Default ctor. /// public ConsoleColorCmdlet() { @@ -28,9 +23,7 @@ public ConsoleColorCmdlet() } /// - /// - /// The -ForegroundColor parameter - /// + /// The -ForegroundColor parameter. /// /// @@ -49,6 +42,7 @@ public ConsoleColorCmdlet() return _fgColor; } + set { if (value >= (ConsoleColor)0 && value <= (ConsoleColor)15) @@ -63,10 +57,7 @@ public ConsoleColorCmdlet() } } - - /// - /// /// /// @@ -85,6 +76,7 @@ public ConsoleColorCmdlet() return _bgColor; } + set { if (value >= (ConsoleColor)0 && value <= (ConsoleColor)15) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-SddlString.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-SddlString.cs new file mode 100644 index 000000000000..341b16289c92 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-SddlString.cs @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !UNIX + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Management.Automation; +using System.Security.AccessControl; +using System.Security.Principal; +using System.Text; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// Converts a SDDL string into an object-based representation of a security descriptor. + /// + [Cmdlet(VerbsData.ConvertFrom, "SddlString", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=623636", RemotingCapability = RemotingCapability.None)] + [OutputType(typeof(SecurityDescriptorInfo))] + public sealed class ConvertFromSddlStringCommand : PSCmdlet + { + /// + /// Gets and sets the string representing the security descriptor in SDDL syntax. + /// + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] + public string Sddl { get; set; } + + /// + /// Gets and sets type of rights that this SDDL string represents. + /// + [Parameter] + public AccessRightTypeNames Type + { + get { return _type; } + + set + { + _isTypeSet = true; + _type = value; + } + } + + private AccessRightTypeNames _type; + private bool _isTypeSet = false; + + private string ConvertToNTAccount(SecurityIdentifier securityIdentifier) + { + try + { + return securityIdentifier?.Translate(typeof(NTAccount)).Value; + } + catch + { + return null; + } + } + + private List GetApplicableAccessRights(int accessMask, AccessRightTypeNames? typeName) + { + List typesToExamine = new List(); + List foundAccessRightNames = new List(); + HashSet foundAccessRightValues = new HashSet(); + + if (typeName != null) + { + typesToExamine.Add(GetRealAccessRightType(typeName.Value)); + } + else + { + foreach (AccessRightTypeNames member in Enum.GetValues(typeof(AccessRightTypeNames))) + { + typesToExamine.Add(GetRealAccessRightType(member)); + } + } + + foreach (Type accessRightType in typesToExamine) + { + foreach (string memberName in Enum.GetNames(accessRightType)) + { + int memberValue = (int)Enum.Parse(accessRightType, memberName); + if (!foundAccessRightValues.Contains(memberValue)) + { + foundAccessRightValues.Add(memberValue); + if ((accessMask & memberValue) == memberValue) + { + foundAccessRightNames.Add(memberName); + } + } + } + } + + foundAccessRightNames.Sort(StringComparer.OrdinalIgnoreCase); + return foundAccessRightNames; + } + + private Type GetRealAccessRightType(AccessRightTypeNames typeName) + { + switch (typeName) + { + case AccessRightTypeNames.FileSystemRights: + return typeof(FileSystemRights); + case AccessRightTypeNames.RegistryRights: + return typeof(RegistryRights); + case AccessRightTypeNames.ActiveDirectoryRights: + return typeof(System.DirectoryServices.ActiveDirectoryRights); + case AccessRightTypeNames.MutexRights: + return typeof(MutexRights); + case AccessRightTypeNames.SemaphoreRights: + return typeof(SemaphoreRights); + case AccessRightTypeNames.EventWaitHandleRights: + return typeof(EventWaitHandleRights); + default: + throw new InvalidOperationException(); + } + } + + private string[] ConvertAccessControlListToStrings(CommonAcl acl, AccessRightTypeNames? typeName) + { + if (acl == null || acl.Count == 0) + { + return Array.Empty(); + } + + List aceStringList = new List(acl.Count); + foreach (CommonAce ace in acl) + { + StringBuilder aceString = new StringBuilder(); + string ntAccount = ConvertToNTAccount(ace.SecurityIdentifier); + aceString.Append($"{ntAccount}: {ace.AceQualifier}"); + + if (ace.AceFlags != AceFlags.None) + { + aceString.Append($" {ace.AceFlags}"); + } + + List accessRightList = GetApplicableAccessRights(ace.AccessMask, typeName); + if (accessRightList.Count > 0) + { + string accessRights = string.Join(", ", accessRightList); + aceString.Append($" ({accessRights})"); + } + + aceStringList.Add(aceString.ToString()); + } + + return aceStringList.ToArray(); + } + + /// + /// ProcessRecord method. + /// + protected override void ProcessRecord() + { + CommonSecurityDescriptor rawSecurityDescriptor = null; + try + { + rawSecurityDescriptor = new CommonSecurityDescriptor(isContainer: false, isDS: false, Sddl); + } + catch (Exception e) + { + var ioe = PSTraceSource.NewInvalidOperationException(e, UtilityCommonStrings.InvalidSDDL, e.Message); + ThrowTerminatingError(new ErrorRecord(ioe, "InvalidSDDL", ErrorCategory.InvalidArgument, Sddl)); + } + + string owner = ConvertToNTAccount(rawSecurityDescriptor.Owner); + string group = ConvertToNTAccount(rawSecurityDescriptor.Group); + + AccessRightTypeNames? typeToUse = _isTypeSet ? _type : (AccessRightTypeNames?)null; + string[] discretionaryAcl = ConvertAccessControlListToStrings(rawSecurityDescriptor.DiscretionaryAcl, typeToUse); + string[] systemAcl = ConvertAccessControlListToStrings(rawSecurityDescriptor.SystemAcl, typeToUse); + + var outObj = new SecurityDescriptorInfo(owner, group, discretionaryAcl, systemAcl, rawSecurityDescriptor); + WriteObject(outObj); + } + + /// + /// AccessRight type names. + /// + public enum AccessRightTypeNames + { + /// + /// FileSystemRights. + /// + FileSystemRights, + + /// + /// RegistryRights. + /// + RegistryRights, + + /// + /// ActiveDirectoryRights. + /// + ActiveDirectoryRights, + + /// + /// MutexRights. + /// + MutexRights, + + /// + /// SemaphoreRights. + /// + SemaphoreRights, + + // We have 'CryptoKeyRights' in the list for Windows PowerShell, but that type is not available in .NET Core. + // CryptoKeyRights, + + /// + /// EventWaitHandleRights. + /// + EventWaitHandleRights + } + } + + /// + /// Representation of a security descriptor. + /// + public sealed class SecurityDescriptorInfo + { + internal SecurityDescriptorInfo( + string owner, + string group, + string[] discretionaryAcl, + string[] systemAcl, + CommonSecurityDescriptor rawDescriptor) + { + Owner = owner; + Group = group; + DiscretionaryAcl = discretionaryAcl; + SystemAcl = systemAcl; + RawDescriptor = rawDescriptor; + } + + /// + /// EventWaitHandle rights. + /// + public readonly string Owner; + + /// + /// EventWaitHandle rights. + /// + public readonly string Group; + + /// + /// EventWaitHandle rights. + /// + public readonly string[] DiscretionaryAcl; + + /// + /// EventWaitHandle rights. + /// + public readonly string[] SystemAcl; + + /// + /// EventWaitHandle rights. + /// + public readonly CommonSecurityDescriptor RawDescriptor; + } +} + +#endif diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-StringData.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-StringData.cs index 3d9a63b63292..d4d68dabb738 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-StringData.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-StringData.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; using System.Collections; +using System.Management.Automation; using System.Text.RegularExpressions; namespace Microsoft.PowerShell.Commands { /// - /// Class comment + /// Class comment. /// [Cmdlet(VerbsData.ConvertFrom, "StringData", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113288", RemotingCapability = RemotingCapability.None)] [OutputType(typeof(Hashtable))] @@ -19,8 +18,8 @@ public sealed class ConvertFromStringDataCommand : PSCmdlet private string _stringData; /// - /// The list of properties to display - /// These take the form of an MshExpression + /// The list of properties to display. + /// These take the form of an PSPropertyExpression. /// /// [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] @@ -31,6 +30,7 @@ public string StringData { return _stringData; } + set { _stringData = value; @@ -38,13 +38,12 @@ public string StringData } /// - /// /// protected override void ProcessRecord() { Hashtable result = new Hashtable(StringComparer.OrdinalIgnoreCase); - if (String.IsNullOrEmpty(_stringData)) + if (string.IsNullOrEmpty(_stringData)) { WriteObject(result); return; @@ -56,7 +55,7 @@ protected override void ProcessRecord() { string s = line.Trim(); - if (String.IsNullOrEmpty(s) || s[0] == '#') + if (string.IsNullOrEmpty(s) || s[0] == '#') continue; int index = s.IndexOf('='); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFromMarkdownCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFromMarkdownCommand.cs new file mode 100644 index 000000000000..5df1b5943914 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFromMarkdownCommand.cs @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Security; +using System.Threading.Tasks; + +using Microsoft.PowerShell.MarkdownRender; + +using Dbg = System.Management.Automation; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// Converts a Markdown string to a MarkdownInfo object. + /// The conversion can be done into a HTML text or VT100 encoding string. + /// + [Cmdlet( + VerbsData.ConvertFrom, "Markdown", + DefaultParameterSetName = PathParameterSet, + HelpUri = "https://go.microsoft.com/fwlink/?linkid=2006503")] + [OutputType(typeof(Microsoft.PowerShell.MarkdownRender.MarkdownInfo))] + public class ConvertFromMarkdownCommand : PSCmdlet + { + /// + /// Gets or sets path to the file to convert from Markdown to MarkdownInfo. + /// + [ValidateNotNullOrEmpty] + [Parameter(ParameterSetName = PathParameterSet, Mandatory = true, Position = 0)] + public string[] Path { get; set; } + + /// + /// Gets or sets the path to the file to convert from Markdown to MarkdownInfo. + /// + [ValidateNotNullOrEmpty] + [Alias("PSPath", "LP")] + [Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true)] + public string[] LiteralPath { get; set; } + + /// + /// Gets or sets the InputObject of type System.IO.FileInfo or string with content to convert from Markdown to MarkdownInfo. + /// + [ValidateNotNullOrEmpty] + [Parameter(ParameterSetName = InputObjParamSet, Mandatory = true, ValueFromPipeline = true)] + public PSObject InputObject { get; set; } + + /// + /// Gets or sets if the Markdown document should be converted to a VT100 encoded string. + /// + [Parameter] + public SwitchParameter AsVT100EncodedString { get; set; } + + private const string PathParameterSet = "PathParamSet"; + private const string LiteralPathParameterSet = "LiteralParamSet"; + private const string InputObjParamSet = "InputObjParamSet"; + private MarkdownConversionType _conversionType = MarkdownConversionType.HTML; + private PSMarkdownOptionInfo _mdOption = null; + + /// + /// Read the PSMarkdownOptionInfo set in SessionState. + /// + protected override void BeginProcessing() + { + _mdOption = PSMarkdownOptionInfoCache.Get(this.CommandInfo); + + bool? supportsVT100 = this.Host?.UI.SupportsVirtualTerminal; + + // supportsVT100 == null if the host is null. + // supportsVT100 == false if host does not support VT100. + if (supportsVT100 != true) + { + _mdOption.EnableVT100Encoding = false; + } + + if (AsVT100EncodedString) + { + _conversionType = MarkdownConversionType.VT100; + } + } + + /// + /// Override ProcessRecord. + /// + protected override void ProcessRecord() + { + switch (ParameterSetName) + { + case InputObjParamSet: + object baseObj = InputObject.BaseObject; + + if (baseObj is FileInfo fileInfo) + { + WriteObject( + MarkdownConverter.Convert( + ReadContentFromFile(fileInfo.FullName)?.Result, + _conversionType, + _mdOption)); + } + else if (baseObj is string inpObj) + { + WriteObject(MarkdownConverter.Convert(inpObj, _conversionType, _mdOption)); + } + else + { + string errorMessage = StringUtil.Format(ConvertMarkdownStrings.InvalidInputObjectType, baseObj.GetType()); + ErrorRecord errorRecord = new ErrorRecord( + new InvalidDataException(errorMessage), + "InvalidInputObject", + ErrorCategory.InvalidData, + InputObject); + + WriteError(errorRecord); + } + + break; + + case PathParameterSet: + ConvertEachFile(Path, _conversionType, isLiteral: false, optionInfo: _mdOption); + break; + + case LiteralPathParameterSet: + ConvertEachFile(LiteralPath, _conversionType, isLiteral: true, optionInfo: _mdOption); + break; + } + } + + private void ConvertEachFile(IEnumerable paths, MarkdownConversionType conversionType, bool isLiteral, PSMarkdownOptionInfo optionInfo) + { + foreach (var path in paths) + { + var resolvedPaths = ResolvePath(path, isLiteral); + + foreach (var resolvedPath in resolvedPaths) + { + WriteObject( + MarkdownConverter.Convert( + ReadContentFromFile(resolvedPath)?.Result, + conversionType, + optionInfo)); + } + } + } + + private async Task ReadContentFromFile(string filePath) + { + ErrorRecord errorRecord = null; + + try + { + using (StreamReader reader = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))) + { + string mdContent = await reader.ReadToEndAsync(); + return mdContent; + } + } + catch (FileNotFoundException fnfe) + { + errorRecord = new ErrorRecord( + fnfe, + "FileNotFound", + ErrorCategory.ResourceUnavailable, + filePath); + } + catch (SecurityException se) + { + errorRecord = new ErrorRecord( + se, + "FileSecurityError", + ErrorCategory.SecurityError, + filePath); + } + catch (UnauthorizedAccessException uae) + { + errorRecord = new ErrorRecord( + uae, + "FileUnauthorizedAccess", + ErrorCategory.SecurityError, + filePath); + } + + WriteError(errorRecord); + return null; + } + + private List ResolvePath(string path, bool isLiteral) + { + ProviderInfo provider = null; + PSDriveInfo drive = null; + List resolvedPaths = new List(); + + try + { + if (isLiteral) + { + resolvedPaths.Add(Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out drive)); + } + else + { + resolvedPaths.AddRange(Context.SessionState.Path.GetResolvedProviderPathFromPSPath(path, out provider)); + } + } + catch (ItemNotFoundException infe) + { + var errorRecord = new ErrorRecord( + infe, + "FileNotFound", + ErrorCategory.ResourceUnavailable, + path); + + WriteError(errorRecord); + } + + if (!provider.Name.Equals("FileSystem", StringComparison.OrdinalIgnoreCase)) + { + string errorMessage = StringUtil.Format(ConvertMarkdownStrings.FileSystemPathsOnly, path); + ErrorRecord errorRecord = new ErrorRecord( + new ArgumentException(), + "OnlyFileSystemPathsSupported", + ErrorCategory.InvalidArgument, + path); + + WriteError(errorRecord); + + return null; + } + + return resolvedPaths; + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/convert-HTML.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertTo-Html.cs similarity index 82% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/convert-HTML.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertTo-Html.cs index 89e61edbf982..1374ce6aa458 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/convert-HTML.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertTo-Html.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -11,14 +10,13 @@ using System.Management.Automation.Internal; using System.Net; using System.Text; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// - /// Class comment - /// + /// Class comment. /// [Cmdlet(VerbsData.ConvertTo, "Html", DefaultParameterSetName = "Page", @@ -35,16 +33,18 @@ public PSObject InputObject { return _inputObject; } + set { _inputObject = value; } } + private PSObject _inputObject; /// - /// The list of properties to display - /// These take the form of an MshExpression + /// The list of properties to display. + /// These take the form of a PSPropertyExpression. /// /// [Parameter(Position = 0)] @@ -54,16 +54,17 @@ public object[] Property { return _property; } + set { _property = value; } } + private object[] _property; /// - /// Text to go after the opening body tag - /// and before the table + /// Text to go after the opening body tag and before the table. /// /// [Parameter(ParameterSetName = "Page", Position = 3)] @@ -73,16 +74,17 @@ public string[] Body { return _body; } + set { _body = value; } } + private string[] _body; /// - /// Text to go into the head section - /// of the html doc + /// Text to go into the head section of the html doc. /// /// [Parameter(ParameterSetName = "Page", Position = 1)] @@ -92,11 +94,13 @@ public string[] Head { return _head; } + set { _head = value; } } + private string[] _head; /// @@ -115,17 +119,19 @@ public string Title { return _title; } + set { _title = value; } } + private string _title = "HTML TABLE"; /// /// This specifies whether the objects should /// be rendered as an HTML TABLE or - /// HTML LIST + /// HTML LIST. /// /// [Parameter] @@ -137,17 +143,19 @@ public string As { return _as; } + set { _as = value; } } + private string _as = "Table"; /// /// This specifies a full or partial URI /// for the CSS information. - /// The html should reference the css file specified + /// The HTML should reference the CSS file specified. /// [Parameter(ParameterSetName = "Page")] [Alias("cu", "uri")] @@ -158,12 +166,14 @@ public Uri CssUri { return _cssuri; } + set { _cssuri = value; _cssuriSpecified = true; } } + private Uri _cssuri; private bool _cssuriSpecified; @@ -180,16 +190,17 @@ public SwitchParameter Fragment { return _fragment; } + set { _fragment = value; } } + private SwitchParameter _fragment; /// - /// Specifies the text to include prior the - /// closing body tag of the HTML output + /// Specifies the text to include prior the closing body tag of the HTML output. /// [Parameter] [ValidateNotNullOrEmpty] @@ -200,16 +211,17 @@ public string[] PostContent { return _postContent; } + set { _postContent = value; } } + private string[] _postContent; /// - /// Specifies the text to include after the - /// body tag of the HTML output + /// Specifies the text to include after the body tag of the HTML output. /// [Parameter] [ValidateNotNullOrEmpty] @@ -220,15 +232,17 @@ public string[] PreContent { return _preContent; } + set { _preContent = value; } } + private string[] _preContent; /// - /// Sets and Gets the meta property of the HTML head + /// Sets and Gets the meta property of the HTML head. /// /// [Parameter(ParameterSetName = "Page")] @@ -239,17 +253,19 @@ public Hashtable Meta { return _meta; } + set { _meta = value; _metaSpecified = true; } } + private Hashtable _meta; private bool _metaSpecified = false; /// - /// Specifies the charset encoding for the HTML document + /// Specifies the charset encoding for the HTML document. /// [Parameter(ParameterSetName = "Page")] [ValidateNotNullOrEmpty] @@ -260,18 +276,20 @@ public string Charset { return _charset; } + set { _charset = value; _charsetSpecified = true; } } + private string _charset; private bool _charsetSpecified = false; /// /// When this switch statement is specified, - /// it will change the DOCTYPE to XHTML Transitional DTD + /// it will change the DOCTYPE to XHTML Transitional DTD. /// /// [Parameter(ParameterSetName = "Page")] @@ -282,15 +300,17 @@ public SwitchParameter Transitional { return _transitional; } + set { _transitional = true; } } + private bool _transitional = false; /// - /// definitions for hash table keys + /// Definitions for hash table keys. /// internal static class ConvertHTMLParameterDefinitionKeys { @@ -300,23 +320,25 @@ internal static class ConvertHTMLParameterDefinitionKeys } /// - /// This allows for @{e='foo';label='bar';alignment='center';width='20'} + /// This allows for @{e='foo';label='bar';alignment='center';width='20'}. /// internal class ConvertHTMLExpressionParameterDefinition : CommandParameterDefinition { protected override void SetEntries() { this.hashEntries.Add(new ExpressionEntryDefinition()); - this.hashEntries.Add(new HashtableEntryDefinition(ConvertHTMLParameterDefinitionKeys.LabelEntryKey, new Type[] { typeof(string) })); - this.hashEntries.Add(new HashtableEntryDefinition(ConvertHTMLParameterDefinitionKeys.AlignmentEntryKey, new Type[] { typeof(string) })); - this.hashEntries.Add(new HashtableEntryDefinition(ConvertHTMLParameterDefinitionKeys.WidthEntryKey, new Type[] { typeof(string) })); + this.hashEntries.Add(new LabelEntryDefinition()); + this.hashEntries.Add(new HashtableEntryDefinition(ConvertHTMLParameterDefinitionKeys.AlignmentEntryKey, new[] { typeof(string) })); + + // Note: We accept "width" as either string or int. + this.hashEntries.Add(new HashtableEntryDefinition(ConvertHTMLParameterDefinitionKeys.WidthEntryKey, new[] { typeof(string), typeof(int) })); } } /// - /// Create a list of MshParameter from properties + /// Create a list of MshParameter from properties. /// - /// can be a string, ScriptBlock, or Hashtable + /// Can be a string, ScriptBlock, or Hashtable. /// private List ProcessParameter(object[] properties) { @@ -327,11 +349,12 @@ private List ProcessParameter(object[] properties) { properties = new object[] { "*" }; } + return processor.ProcessParameters(properties, invocationContext); } /// - /// Resolve all wildcards in user input Property into resolvedNameMshParameters + /// Resolve all wildcards in user input Property into resolvedNameMshParameters. /// private void InitializeResolvedNameMshParameters() { @@ -342,16 +365,29 @@ private void InitializeResolvedNameMshParameters() { string label = p.GetEntry(ConvertHTMLParameterDefinitionKeys.LabelEntryKey) as string; string alignment = p.GetEntry(ConvertHTMLParameterDefinitionKeys.AlignmentEntryKey) as string; - string width = p.GetEntry(ConvertHTMLParameterDefinitionKeys.WidthEntryKey) as string; - MshExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as MshExpression; - List resolvedNames = ex.ResolveNames(_inputObject); - foreach (MshExpression resolvedName in resolvedNames) + + // Accept the width both as a string and as an int. + string width; + int? widthNum = p.GetEntry(ConvertHTMLParameterDefinitionKeys.WidthEntryKey) as int?; + width = widthNum != null ? widthNum.Value.ToString() : p.GetEntry(ConvertHTMLParameterDefinitionKeys.WidthEntryKey) as string; + PSPropertyExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as PSPropertyExpression; + List resolvedNames = ex.ResolveNames(_inputObject); + foreach (PSPropertyExpression resolvedName in resolvedNames) { Hashtable ht = CreateAuxPropertyHT(label, alignment, width); - ht.Add(FormatParameterDefinitionKeys.ExpressionEntryKey, resolvedName.ToString()); + if (resolvedName.Script != null) + { + // The argument is a calculated property whose value is calculated by a script block. + ht.Add(FormatParameterDefinitionKeys.ExpressionEntryKey, resolvedName.Script); + } + else + { + ht.Add(FormatParameterDefinitionKeys.ExpressionEntryKey, resolvedName.ToString()); + } resolvedNameProperty.Add(ht); } } + _resolvedNameMshParameters = ProcessParameter(resolvedNameProperty.ToArray()); } @@ -365,19 +401,22 @@ private void InitializeResolvedNameMshParameters() { ht.Add(ConvertHTMLParameterDefinitionKeys.LabelEntryKey, label); } + if (alignment != null) { ht.Add(ConvertHTMLParameterDefinitionKeys.AlignmentEntryKey, alignment); } + if (width != null) { ht.Add(ConvertHTMLParameterDefinitionKeys.WidthEntryKey, width); } + return ht; } /// - /// calls ToString. If an exception occurs, eats it and return string.Empty + /// Calls ToString. If an exception occurs, eats it and return string.Empty. /// /// /// @@ -385,8 +424,9 @@ private static string SafeToString(object obj) { if (obj == null) { - return ""; + return string.Empty; } + try { return obj.ToString(); @@ -395,16 +435,15 @@ private static string SafeToString(object obj) { // eats exception if safe } - return ""; - } + return string.Empty; + } /// - /// /// protected override void BeginProcessing() { - //ValidateNotNullOrEmpty attribute is not working for System.Uri datatype, so handling it here + // ValidateNotNullOrEmpty attribute is not working for System.Uri datatype, so handling it here if ((_cssuriSpecified) && (string.IsNullOrEmpty(_cssuri.OriginalString.Trim()))) { ArgumentException ex = new ArgumentException(StringUtil.Format(UtilityCommonStrings.EmptyCSSUri, "CSSUri")); @@ -414,19 +453,18 @@ protected override void BeginProcessing() _propertyMshParameterList = ProcessParameter(_property); - if (!String.IsNullOrEmpty(_title)) + if (!string.IsNullOrEmpty(_title)) { WebUtility.HtmlEncode(_title); } - // This first line ensures w3c validation will succeed. However we are not specifying // an encoding in the HTML because we don't know where the text will be written and // if a particular encoding will be used. if (!_fragment) { - if(!_transitional) + if (!_transitional) { WriteObject(""); } @@ -434,19 +472,23 @@ protected override void BeginProcessing() { WriteObject(""); } + WriteObject(""); WriteObject(""); - if(_charsetSpecified) + if (_charsetSpecified) { WriteObject(""); } - if(_metaSpecified) + + if (_metaSpecified) { List useditems = new List(); - foreach(string s in _meta.Keys) + foreach (string s in _meta.Keys) { - if(!useditems.Contains(s)){ - switch(s.ToLower()){ + if (!useditems.Contains(s)) + { + switch (s.ToLower()) + { case "content-type": case "default-style": case "x-ua-compatible": @@ -470,36 +512,41 @@ protected override void BeginProcessing() { record.SetInvocationInfo(invocationInfo); } + mshCommandRuntime.WriteWarning(record); WriteObject(""); break; } + useditems.Add(s); } } } + WriteObject(_head ?? new string[] { "" + _title + "" }, true); if (_cssuriSpecified) { WriteObject(""); } + WriteObject(""); if (_body != null) { WriteObject(_body, true); } } + if (_preContent != null) { WriteObject(_preContent, true); } + WriteObject(""); _isTHWritten = false; - _propertyCollector = new StringCollection(); } /// - /// Reads Width and Alignment from Property and write Col tags + /// Reads Width and Alignment from Property and write Col tags. /// /// private void WriteColumns(List mshParams) @@ -517,6 +564,7 @@ private void WriteColumns(List mshParams) COLTag.Append(width); COLTag.Append("\""); } + string alignment = p.GetEntry(ConvertHTMLParameterDefinitionKeys.AlignmentEntryKey) as string; if (alignment != null) { @@ -524,6 +572,7 @@ private void WriteColumns(List mshParams) COLTag.Append(alignment); COLTag.Append("\""); } + COLTag.Append("/>"); } @@ -534,7 +583,7 @@ private void WriteColumns(List mshParams) } /// - /// Writes the list entries when the As parameter has value List + /// Writes the list entries when the As parameter has value List. /// private void WriteListEntry() { @@ -543,12 +592,12 @@ private void WriteListEntry() StringBuilder Listtag = new StringBuilder(); Listtag.Append(""); - //for writing the property value + // for writing the property value Listtag.Append(""); @@ -558,11 +607,11 @@ private void WriteListEntry() } /// - /// To write the Property name + /// To write the Property name. /// private void WritePropertyName(StringBuilder Listtag, MshParameter p) { - //for writing the property name + // for writing the property name string label = p.GetEntry(ConvertHTMLParameterDefinitionKeys.LabelEntryKey) as string; if (label != null) { @@ -570,21 +619,21 @@ private void WritePropertyName(StringBuilder Listtag, MshParameter p) } else { - MshExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as MshExpression; + PSPropertyExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as PSPropertyExpression; Listtag.Append(ex.ToString()); } } /// - /// To write the Property value + /// To write the Property value. /// private void WritePropertyValue(StringBuilder Listtag, MshParameter p) { - MshExpression exValue = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as MshExpression; + PSPropertyExpression exValue = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as PSPropertyExpression; // get the value of the property - List resultList = exValue.GetValues(_inputObject); - foreach (MshExpressionResult result in resultList) + List resultList = exValue.GetValues(_inputObject); + foreach (PSPropertyExpressionResult result in resultList) { // create comma sep list for multiple results if (result.Result != null) @@ -592,8 +641,10 @@ private void WritePropertyValue(StringBuilder Listtag, MshParameter p) string htmlEncodedResult = WebUtility.HtmlEncode(SafeToString(result.Result)); Listtag.Append(htmlEncodedResult); } + Listtag.Append(", "); } + if (Listtag.ToString().EndsWith(", ", StringComparison.Ordinal)) { Listtag.Remove(Listtag.Length - 2, 2); @@ -601,11 +652,11 @@ private void WritePropertyValue(StringBuilder Listtag, MshParameter p) } /// - /// To write the Table header for the object property names + /// To write the Table header for the object property names. /// private void WriteTableHeader(StringBuilder THtag, List resolvedNameMshParameters) { - //write the property names + // write the property names foreach (MshParameter p in resolvedNameMshParameters) { THtag.Append(""); WriteListEntry(); } - else //if the As parameter is Table, first we have to write the property names + else // if the As parameter is Table, first we have to write the property names { WriteColumns(_resolvedNameMshParameters); StringBuilder THtag = new StringBuilder(""); - //write the table header + // write the table header WriteTableHeader(THtag, _resolvedNameMshParameters); THtag.Append(""); @@ -675,12 +725,12 @@ protected override void ProcessRecord() _isTHWritten = true; } } - //if the As parameter is Table, write the property values + // if the As parameter is Table, write the property values if (_as.Equals("Table", StringComparison.OrdinalIgnoreCase)) { StringBuilder TRtag = new StringBuilder(""); - //write the table row + // write the table row WriteTableRow(TRtag, _resolvedNameMshParameters); TRtag.Append(""); @@ -689,16 +739,15 @@ protected override void ProcessRecord() } /// - /// /// protected override void EndProcessing() { - //if fragment,end with table + // if fragment,end with table WriteObject("
"); - //for writing the property name + // for writing the property name WritePropertyName(Listtag, p); Listtag.Append(":"); Listtag.Append(""); WritePropertyValue(Listtag, p); Listtag.Append("
"); @@ -615,11 +666,11 @@ private void WriteTableHeader(StringBuilder THtag, List resolvedNa } /// - /// To write the Table row for the object property values + /// To write the Table row for the object property values. /// private void WriteTableRow(StringBuilder TRtag, List resolvedNameMshParameters) { - //write the property values + // write the property values foreach (MshParameter p in resolvedNameMshParameters) { TRtag.Append(""); @@ -628,12 +679,10 @@ private void WriteTableRow(StringBuilder TRtag, List resolvedNameM } } - //count of the objects + // count of the objects private int _numberObjects = 0; /// - /// - /// /// protected override void ProcessRecord() { @@ -644,6 +693,7 @@ protected override void ProcessRecord() { return; } + _numberObjects++; if (!_isTHWritten) { @@ -653,21 +703,21 @@ protected override void ProcessRecord() return; } - //if the As parameter is given as List + // if the As parameter is given as List if (_as.Equals("List", StringComparison.OrdinalIgnoreCase)) { - //if more than one object,write the horizontal rule to put visual separator + // if more than one object,write the horizontal rule to put visual separator if (_numberObjects > 1) WriteObject("

"); if (_postContent != null) WriteObject(_postContent, true); - //if not fragment end with body and html also + // if not fragment end with body and html also if (!_fragment) { WriteObject(""); @@ -708,15 +757,13 @@ protected override void EndProcessing() #region private /// - /// list of incoming objects to compare + /// List of incoming objects to compare. /// private bool _isTHWritten; - private StringCollection _propertyCollector; private List _propertyMshParameterList; private List _resolvedNameMshParameters; - //private string ResourcesBaseName = "ConvertHTMLStrings"; + // private string ResourcesBaseName = "ConvertHTMLStrings"; #endregion private } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs index 48d42ea9b070..aba6043d2bbc 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Collections.ObjectModel; @@ -17,28 +16,26 @@ internal CSVHelper(char delimiter) } /// - /// Gets or sets the delimiter that separates the values + /// Gets or sets the delimiter that separates the values. /// - /// internal char Delimiter { get; } = ','; /// - /// Parse a CSV String. + /// Parse a CSV string. /// - /// /// - /// String to be parsed + /// String to be parsed. /// - /// internal Collection ParseCsv(string csv) { Collection result = new Collection(); - string tempString = ""; + string tempString = string.Empty; csv = csv.Trim(); if (csv.Length == 0 || csv[0] == '#') { return result; } + bool inQuote = false; for (int i = 0; i < csv.Length; i++) { @@ -48,7 +45,7 @@ internal Collection ParseCsv(string csv) if (!inQuote) { result.Add(tempString); - tempString = ""; + tempString = string.Empty; } else { @@ -62,12 +59,12 @@ internal Collection ParseCsv(string csv) case '"': if (inQuote) { - //If we are at the end of the string or the end of the segment, create a new value - //Otherwise we have an error + // If we are at the end of the string or the end of the segment, create a new value + // Otherwise we have an error if (i == csv.Length - 1) { result.Add(tempString); - tempString = ""; + tempString = string.Empty; inQuote = false; break; } @@ -75,7 +72,7 @@ internal Collection ParseCsv(string csv) if (csv[i + 1] == Delimiter) { result.Add(tempString); - tempString = ""; + tempString = string.Empty; inQuote = false; i++; } @@ -99,15 +96,16 @@ internal Collection ParseCsv(string csv) default: tempString += c; break; - }//switch - }//else - }//for int + } + } + } + if (tempString.Length > 0) { result.Add(tempString); } + return result; } } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CSVCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs similarity index 63% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/CSVCommands.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index 5ee144d0309a..5d4598267f89 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CSVCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -11,6 +10,7 @@ using System.Linq; using System.Management.Automation; using System.Text; + using Dbg = System.Management.Automation.Diagnostics; #pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings @@ -20,33 +20,18 @@ namespace Microsoft.PowerShell.Commands #region BaseCsvWritingCommand /// - /// This class implements the base for exportcsv and converttocsv commands + /// This class implements the base for exportcsv and converttocsv commands. /// public abstract class BaseCsvWritingCommand : PSCmdlet { #region Command Line Parameters /// - /// Property that sets delimiter + /// Property that sets delimiter. /// [Parameter(Position = 1, ParameterSetName = "Delimiter")] [ValidateNotNull] - public char Delimiter - { - get - { - return _delimiter; - } - set - { - _delimiter = value; - } - } - - /// - /// Delimiter to be used. - /// - private char _delimiter; + public char Delimiter { get; set; } /// ///Culture switch for csv conversion @@ -54,17 +39,12 @@ public char Delimiter [Parameter(ParameterSetName = "UseCulture")] public SwitchParameter UseCulture { get; set; } - /// - /// Abstract Property - Input Object which is written in Csv format + /// Abstract Property - Input Object which is written in Csv format. /// Derived as Different Attributes.In ConvertTo-CSV, This is a positional parameter. Export-CSV not a Positional behaviour. /// - public abstract PSObject InputObject - { - get; - set; - } + public abstract PSObject InputObject { get; set; } /// /// IncludeTypeInformation : The #TYPE line should be generated. Default is false. Cannot specify with NoTypeInformation. @@ -80,33 +60,75 @@ public char Delimiter [Alias("NTI")] public SwitchParameter NoTypeInformation { get; set; } = true; - #endregion Command Line Parameters + /// + /// Gets or sets list of fields to quote in output. + /// + [Parameter] + [Alias("QF")] + public string[] QuoteFields { get; set; } + /// + /// Gets or sets option to use or suppress quotes in output. + /// + [Parameter] + [Alias("UQ")] + public QuoteKind UseQuotes { get; set; } = QuoteKind.Always; + #endregion Command Line Parameters /// - /// Write the string to a file or pipeline + /// Kind of output quoting. + /// + public enum QuoteKind + { + /// + /// Never quote output. + /// + Never, + + /// + /// Always quote output. + /// + Always, + + /// + /// Quote output as needed (a field contains used delimiter). + /// + AsNeeded + } + + /// + /// Write the string to a file or pipeline. /// public virtual void WriteCsvLine(string line) { } /// - /// BeginProcessing override + /// BeginProcessing override. /// protected override void BeginProcessing() { + if (this.MyInvocation.BoundParameters.ContainsKey(nameof(QuoteFields)) && this.MyInvocation.BoundParameters.ContainsKey(nameof(UseQuotes))) + { + InvalidOperationException exception = new InvalidOperationException(CsvCommandStrings.CannotSpecifyQuoteFieldsAndUseQuotes); + ErrorRecord errorRecord = new ErrorRecord(exception, "CannotSpecifyQuoteFieldsAndUseQuotes", ErrorCategory.InvalidData, null); + this.ThrowTerminatingError(errorRecord); + } + if (this.MyInvocation.BoundParameters.ContainsKey(nameof(IncludeTypeInformation)) && this.MyInvocation.BoundParameters.ContainsKey(nameof(NoTypeInformation))) { InvalidOperationException exception = new InvalidOperationException(CsvCommandStrings.CannotSpecifyIncludeTypeInformationAndNoTypeInformation); ErrorRecord errorRecord = new ErrorRecord(exception, "CannotSpecifyIncludeTypeInformationAndNoTypeInformation", ErrorCategory.InvalidData, null); this.ThrowTerminatingError(errorRecord); } - if (this.MyInvocation.BoundParameters.ContainsKey("IncludeTypeInformation")) + + if (this.MyInvocation.BoundParameters.ContainsKey(nameof(IncludeTypeInformation))) { NoTypeInformation = !IncludeTypeInformation; } - _delimiter = ImportExportCSVHelper.SetDelimiter(this, ParameterSetName, _delimiter, UseCulture); + + Delimiter = ImportExportCSVHelper.SetDelimiter(this, ParameterSetName, Delimiter, UseCulture); } } #endregion @@ -114,7 +136,7 @@ protected override void BeginProcessing() #region Export-CSV Command /// - /// implementation for the export-csv command + /// Implementation for the Export-Csv command. /// [Cmdlet(VerbsData.Export, "Csv", SupportsShouldProcess = true, DefaultParameterSetName = "Delimiter", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113299")] public sealed class ExportCsvCommand : BaseCsvWritingCommand, IDisposable @@ -131,7 +153,7 @@ public sealed class ExportCsvCommand : BaseCsvWritingCommand, IDisposable public override PSObject InputObject { get; set; } /// - /// mandatory file name to write to + /// Mandatory file name to write to. /// [Parameter(Position = 0)] [ValidateNotNullOrEmpty] @@ -141,21 +163,23 @@ public string Path { return _path; } + set { _path = value; _specifiedPath = true; } } + private string _path; private bool _specifiedPath = false; /// - /// The literal path of the mandatory file name to write to + /// The literal path of the mandatory file name to write to. /// - [Parameter()] + [Parameter] [ValidateNotNullOrEmpty] - [Alias("PSPath")] + [Alias("PSPath", "LP")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string LiteralPath { @@ -163,76 +187,46 @@ public string LiteralPath { return _path; } + set { _path = value; _isLiteralPath = true; } } - private bool _isLiteralPath = false; - + private bool _isLiteralPath = false; /// - /// Property that sets force parameter. + /// Gets or sets property that sets force parameter. /// - [Parameter()] - public SwitchParameter Force - { - get - { - return _force; - } - set - { - _force = value; - } - } - private bool _force; + [Parameter] + public SwitchParameter Force { get; set; } /// - /// Property that prevents file overwrite. + /// Gets or sets property that prevents file overwrite. /// - [Parameter()] + [Parameter] [Alias("NoOverwrite")] - public SwitchParameter NoClobber - { - get - { - return _noclobber; - } - set - { - _noclobber = value; - } - } - private bool _noclobber; - - /// - /// Encoding optional flag - /// - [Parameter()] - [ArgumentToEncodingTransformationAttribute()] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] + public SwitchParameter NoClobber { get; set; } + + /// + /// Gets or sets encoding optional flag. + /// + [Parameter] + [ArgumentToEncodingTransformationAttribute] + [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); /// - /// Property that sets append parameter. + /// Gets or sets property that sets append parameter. /// [Parameter] public SwitchParameter Append { get; set; } - private bool _isActuallyAppending; // true if Append=true AND the file written was not empty (or nonexistent) when the cmdlet was invoked + + // true if Append=true AND the file written was not empty (or nonexistent) when the cmdlet was invoked + private bool _isActuallyAppending; #endregion @@ -244,7 +238,7 @@ public SwitchParameter NoClobber private ExportCsvHelper _helper; /// - /// BeginProcessing override + /// BeginProcessing override. /// protected override void BeginProcessing() { @@ -259,32 +253,36 @@ protected override void BeginProcessing() } _shouldProcess = ShouldProcess(Path); - if (!_shouldProcess) return; + if (!_shouldProcess) + { + return; + } CreateFileStream(); - _helper = new ExportCsvHelper(this, base.Delimiter); + _helper = new ExportCsvHelper(base.Delimiter, base.UseQuotes, base.QuoteFields); } - /// - /// Convert the current input object to Csv and write to file/WriteObject + /// Convert the current input object to Csv and write to file/WriteObject. /// - protected override - void - ProcessRecord() + protected override void ProcessRecord() { if (InputObject == null || _sw == null) { return; } - if (!_shouldProcess) return; - //Process first object + if (!_shouldProcess) + { + return; + } + + // Process first object if (_propertyNames == null) { // figure out the column names (and lock-in their order) - _propertyNames = _helper.BuildPropertyNames(InputObject, _propertyNames); + _propertyNames = ExportCsvHelper.BuildPropertyNames(InputObject, _propertyNames); if (_isActuallyAppending && _preexistingPropertyNames != null) { this.ReconcilePreexistingPropertyNames(); @@ -295,7 +293,7 @@ protected override { if (NoTypeInformation == false) { - WriteCsvLine(_helper.GetTypeString(InputObject)); + WriteCsvLine(ExportCsvHelper.GetTypeString(InputObject)); } WriteCsvLine(_helper.ConvertPropertyNamesCSV(_propertyNames)); @@ -308,7 +306,7 @@ protected override } /// - /// EndProcessing + /// EndProcessing. /// protected override void EndProcessing() { @@ -320,23 +318,26 @@ protected override void EndProcessing() #region file /// - /// handle to file stream + /// Handle to file stream. /// private FileStream _fs; /// - /// stream writer used to write to file + /// Stream writer used to write to file. /// private StreamWriter _sw = null; /// - /// handle to file whose read-only attribute should be reset when we are done + /// Handle to file whose read-only attribute should be reset when we are done. /// private FileInfo _readOnlyFileInfo = null; private void CreateFileStream() { - Dbg.Assert(_path != null, "FileName is mandatory parameter"); + if (_path == null) + { + throw new InvalidOperationException(CsvCommandStrings.FileNameIsAMandatoryParameter); + } string resolvedFilePath = PathUtils.ResolveFilePath(this.Path, this, _isLiteralPath); @@ -371,7 +372,7 @@ private void CreateFileStream() this, this.Path, encodingObject, - false, // defaultEncoding + defaultEncoding: false, Append, Force, NoClobber, @@ -386,7 +387,7 @@ private void CreateFileStream() this, this.Path, Encoding, - false, // defaultEncoding + defaultEncoding: false, Append, Force, NoClobber, @@ -397,9 +398,7 @@ private void CreateFileStream() } } - private - void - CleanUp() + private void CleanUp() { if (_fs != null) { @@ -409,12 +408,15 @@ private void CreateFileStream() _sw.Dispose(); _sw = null; } + _fs.Dispose(); _fs = null; + // reset the read-only attribute - if (null != _readOnlyFileInfo) + if (_readOnlyFileInfo != null) _readOnlyFileInfo.Attributes |= FileAttributes.ReadOnly; } + if (_helper != null) { _helper.Dispose(); @@ -423,8 +425,15 @@ private void CreateFileStream() private void ReconcilePreexistingPropertyNames() { - Dbg.Assert(_isActuallyAppending, "This method should only get called when appending"); - Dbg.Assert(_preexistingPropertyNames != null, "This method should only get called when we have successfully read preexisting property names"); + if (!_isActuallyAppending) + { + throw new InvalidOperationException(CsvCommandStrings.ReconcilePreexistingPropertyNamesMethodShouldOnlyGetCalledWhenAppending); + } + + if (_preexistingPropertyNames == null) + { + throw new InvalidOperationException(CsvCommandStrings.ReconcilePreexistingPropertyNamesMethodShouldOnlyGetCalledWhenPreexistingPropertyNamesHaveBeenReadSuccessfully); + } HashSet appendedPropertyNames = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (string appendedPropertyName in _propertyNames) @@ -455,11 +464,10 @@ private void ReconcilePreexistingPropertyNames() } /// - /// Write the csv line to file + /// Write the csv line to file. /// - /// - public override void - WriteCsvLine(string line) + /// Line to write. + public override void WriteCsvLine(string line) { // NTRAID#Windows Out Of Band Releases-915851-2005/09/13 if (_disposed) @@ -474,21 +482,20 @@ public override void #region IDisposable Members /// - /// Set to true when object is disposed + /// Set to true when object is disposed. /// private bool _disposed; /// - /// public dispose method + /// Public dispose method. /// - public - void - Dispose() + public void Dispose() { if (_disposed == false) { CleanUp(); } + _disposed = true; } @@ -500,49 +507,51 @@ public override void #region Import-CSV Command /// - /// Implements Import-Csv command + /// Implements Import-Csv command. /// - [Cmdlet(VerbsData.Import, "Csv", DefaultParameterSetName = "Delimiter", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113341")] - public sealed - class - ImportCsvCommand : PSCmdlet + [Cmdlet(VerbsData.Import, "Csv", DefaultParameterSetName = "DelimiterPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113341")] + public sealed class ImportCsvCommand : PSCmdlet { #region Command Line Parameters /// - /// Property that sets delimiter + /// Gets or sets property that sets delimiter. /// - [Parameter(Position = 1, ParameterSetName = "Delimiter")] + [Parameter(Position = 1, ParameterSetName = "DelimiterPath")] + [Parameter(Position = 1, ParameterSetName = "DelimiterLiteralPath")] [ValidateNotNull] public char Delimiter { get; set; } - /// - /// mandatory file name to read from + /// Gets or sets mandatory file name to read from. /// - [Parameter(Position = 0, ValueFromPipeline = true)] + [Parameter(Position = 0, ParameterSetName = "DelimiterPath", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] + [Parameter(Position = 0, ParameterSetName = "CulturePath", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] - public String[] Path + public string[] Path { get { return _paths; } + set { _paths = value; _specifiedPath = true; } } + private string[] _paths; private bool _specifiedPath = false; /// - /// The literal path of the mandatory file name to read from + /// Gets or sets the literal path of the mandatory file name to read from. /// - [Parameter(ValueFromPipelineByPropertyName = true)] + [Parameter(ParameterSetName = "DelimiterLiteralPath", Mandatory = true, ValueFromPipelineByPropertyName = true)] + [Parameter(ParameterSetName = "CultureLiteralPath", Mandatory = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] - [Alias("PSPath")] + [Alias("PSPath", "LP")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] LiteralPath { @@ -550,35 +559,26 @@ public string[] LiteralPath { return _paths; } + set { _paths = value; _isLiteralPath = true; } } + private bool _isLiteralPath = false; /// - /// Property that sets UseCulture parameter + /// Gets or sets property that sets UseCulture parameter. /// - [Parameter(ParameterSetName = "UseCulture", Mandatory = true)] + [Parameter(ParameterSetName = "CulturePath", Mandatory = true)] + [Parameter(ParameterSetName = "CultureLiteralPath", Mandatory = true)] [ValidateNotNull] - public SwitchParameter UseCulture - { - get - { - return _useculture; - } - set - { - _useculture = value; - } - } - private bool _useculture; - + public SwitchParameter UseCulture { get; set; } /// - /// Header property to customize the names + /// Gets or sets header property to customize the names. /// [Parameter(Mandatory = false)] [ValidateNotNullOrEmpty] @@ -586,27 +586,16 @@ public SwitchParameter UseCulture public string[] Header { get; set; } /// - /// Encoding optional flag - /// - [Parameter()] - [ArgumentToEncodingTransformationAttribute()] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] + /// Gets or sets encoding optional flag. + /// + [Parameter] + [ArgumentToEncodingTransformationAttribute] + [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); /// - /// Avoid writing out duplicate warning messages when there are - /// one or more unspecified names + /// Avoid writing out duplicate warning messages when there are one or more unspecified names. /// private bool _alreadyWarnedUnspecifiedNames = false; @@ -615,14 +604,15 @@ public SwitchParameter UseCulture #region Override Methods /// - /// + /// BeginProcessing override. /// protected override void BeginProcessing() { - Delimiter = ImportExportCSVHelper.SetDelimiter(this, ParameterSetName, Delimiter, _useculture); + Delimiter = ImportExportCSVHelper.SetDelimiter(this, ParameterSetName, Delimiter, UseCulture); } + /// - /// ProcessRecord overload + /// ProcessRecord overload. /// protected override void ProcessRecord() { @@ -653,8 +643,8 @@ protected override void ProcessRecord() } } } - }//if - }////ProcessRecord + } + } } #endregion Override Methods @@ -663,17 +653,17 @@ protected override void ProcessRecord() #region ConvertTo-CSV Command /// - /// Implements ConvertTo-Csv command + /// Implements ConvertTo-Csv command. /// [Cmdlet(VerbsData.ConvertTo, "Csv", DefaultParameterSetName = "Delimiter", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135203", RemotingCapability = RemotingCapability.None)] - [OutputType(typeof(String))] + [OutputType(typeof(string))] public sealed class ConvertToCsvCommand : BaseCsvWritingCommand { #region Parameter /// - /// Overrides Base InputObject + /// Overrides Base InputObject. /// [Parameter(ValueFromPipeline = true, Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)] public override PSObject InputObject { get; set; } @@ -683,56 +673,52 @@ public sealed class ConvertToCsvCommand : BaseCsvWritingCommand #region Overrides /// - /// Stores Property Names + /// Stores Property Names. /// private IList _propertyNames; /// - /// /// private ExportCsvHelper _helper; /// - /// BeginProcessing override + /// BeginProcessing override. /// - protected override - void - BeginProcessing() + protected override void BeginProcessing() { base.BeginProcessing(); - _helper = new ExportCsvHelper(this, base.Delimiter); + _helper = new ExportCsvHelper(base.Delimiter, base.UseQuotes, base.QuoteFields); } - - /// - /// Convert the current input object to Csv and write to stream/WriteObject + /// Convert the current input object to Csv and write to stream/WriteObject. /// - protected override - void - ProcessRecord() + protected override void ProcessRecord() { if (InputObject == null) { return; } - //Process first object + + // Process first object if (_propertyNames == null) { - _propertyNames = _helper.BuildPropertyNames(InputObject, _propertyNames); + _propertyNames = ExportCsvHelper.BuildPropertyNames(InputObject, _propertyNames); if (NoTypeInformation == false) { - WriteCsvLine(_helper.GetTypeString(InputObject)); + WriteCsvLine(ExportCsvHelper.GetTypeString(InputObject)); } - //Write property information + + // Write property information string properties = _helper.ConvertPropertyNamesCSV(_propertyNames); - if (!properties.Equals("")) + if (!properties.Equals(string.Empty)) WriteCsvLine(properties); } string csv = _helper.ConvertPSObjectToCSV(InputObject, _propertyNames); - //write to the console - if (csv != "") + + // write to the console + if (csv != string.Empty) WriteCsvLine(csv); } @@ -740,11 +726,10 @@ protected override #region CSV conversion /// - /// + /// Write the line to output. /// - /// - public override void - WriteCsvLine(string line) + /// Line to write. + public override void WriteCsvLine(string line) { WriteObject(line); } @@ -757,18 +742,16 @@ public override void #region ConvertFrom-CSV Command /// - /// Implements ConvertFrom-Csv command + /// Implements ConvertFrom-Csv command. /// [Cmdlet(VerbsData.ConvertFrom, "Csv", DefaultParameterSetName = "Delimiter", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135201", RemotingCapability = RemotingCapability.None)] - public sealed - class - ConvertFromCsvCommand : PSCmdlet + public sealed class ConvertFromCsvCommand : PSCmdlet { #region Command Line Parameters /// - /// Property that sets delimiter + /// Property that sets delimiter. /// [Parameter(Position = 1, ParameterSetName = "Delimiter")] [ValidateNotNull] @@ -784,7 +767,7 @@ public sealed public SwitchParameter UseCulture { get; set; } /// - /// Input Object which is written in Csv format + /// Gets or sets input object which is written in Csv format. /// [Parameter(ValueFromPipeline = true, Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)] [ValidateNotNull] @@ -793,7 +776,7 @@ public sealed public PSObject[] InputObject { get; set; } /// - /// Header property to customize the names + /// Gets or sets header property to customize the names. /// [Parameter(Mandatory = false)] [ValidateNotNull] @@ -802,8 +785,7 @@ public sealed public string[] Header { get; set; } /// - /// Avoid writing out duplicate warning messages when there are - /// one or more unspecified names + /// Avoid writing out duplicate warning messages when there are one or more unspecified names. /// private bool _alreadyWarnedUnspecifiedNames = false; @@ -812,25 +794,21 @@ public sealed #region Overrides /// - /// BeginProcessing override + /// BeginProcessing override. /// - protected override - void - BeginProcessing() + protected override void BeginProcessing() { Delimiter = ImportExportCSVHelper.SetDelimiter(this, ParameterSetName, Delimiter, UseCulture); } /// - /// Convert the current input object to Csv and write to stream/WriteObject + /// Convert the current input object to Csv and write to stream/WriteObject. /// - protected override - void - ProcessRecord() + protected override void ProcessRecord() { - foreach (PSObject pObject in InputObject) + foreach (PSObject inputObject in InputObject) { - using (MemoryStream memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(pObject.ToString()))) + using (MemoryStream memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(inputObject.ToString()))) using (StreamReader streamReader = new StreamReader(memoryStream, System.Text.Encoding.Unicode)) { ImportCsvHelper helper = new ImportCsvHelper(this, Delimiter, Header, _typeName, streamReader); @@ -849,6 +827,7 @@ protected override { Header = helper.Header.ToArray(); } + if ((_typeName == null) && (helper.TypeName != null)) { _typeName = helper.TypeName; @@ -869,70 +848,70 @@ protected override #region ExportHelperConversion /// - /// + /// Helper class for Export-Csv and ConvertTo-Csv. /// internal class ExportCsvHelper : IDisposable { - /// - /// - /// - private PSCmdlet _cmdlet; - private char _delimiter; + readonly private BaseCsvWritingCommand.QuoteKind _quoteKind; + readonly private HashSet _quoteFields; + readonly private StringBuilder _outputString; /// - /// + /// Create ExportCsvHelper instance. /// - /// - /// - internal - ExportCsvHelper(PSCmdlet cmdlet, char delimiter) + /// Delimiter char. + /// Kind of quoting. + /// List of fields to quote. + internal ExportCsvHelper(char delimiter, BaseCsvWritingCommand.QuoteKind quoteKind, string[] quoteFields) { - if (cmdlet == null) - { - } - _cmdlet = cmdlet; _delimiter = delimiter; + _quoteKind = quoteKind; + _quoteFields = quoteFields == null ? null : new HashSet(quoteFields, StringComparer.OrdinalIgnoreCase); + _outputString = new StringBuilder(128); } - //Name of properties to be written in CSV format - + // Name of properties to be written in CSV format /// - /// Get the name of properties from source PSObject and - /// add them to _propertyNames. + /// Get the name of properties from source PSObject and add them to _propertyNames. /// - internal - IList - BuildPropertyNames(PSObject source, IList propertyNames) + internal static IList BuildPropertyNames(PSObject source, IList propertyNames) { - Dbg.Assert(propertyNames == null, "This method should be called only once per cmdlet instance"); + if (propertyNames != null) + { + throw new InvalidOperationException(CsvCommandStrings.BuildPropertyNamesMethodShouldBeCalledOnlyOncePerCmdletInstance); + } // serialize only Extended and Adapted properties.. PSMemberInfoCollection srcPropertiesToSearch = - new PSMemberInfoIntegratingCollection(source, - PSObject.GetPropertyCollection(PSMemberViewTypes.Extended | PSMemberViewTypes.Adapted)); + new PSMemberInfoIntegratingCollection( + source, + PSObject.GetPropertyCollection(PSMemberViewTypes.Extended | PSMemberViewTypes.Adapted)); propertyNames = new Collection(); foreach (PSPropertyInfo prop in srcPropertiesToSearch) { propertyNames.Add(prop.Name); } + return propertyNames; } /// - /// Converts PropertyNames in to a CSV string + /// Converts PropertyNames in to a CSV string. /// - /// - internal - string - ConvertPropertyNamesCSV(IList propertyNames) + /// Converted string. + internal string ConvertPropertyNamesCSV(IList propertyNames) { - Dbg.Assert(propertyNames != null, "BuildPropertyNames should be called before this method"); + if (propertyNames == null) + { + throw new ArgumentNullException(nameof(propertyNames)); + } - StringBuilder dest = new StringBuilder(); + _outputString.Clear(); bool first = true; + foreach (string propertyName in propertyNames) { if (first) @@ -941,27 +920,62 @@ internal class ExportCsvHelper : IDisposable } else { - //changed to delimiter - dest.Append(_delimiter); + _outputString.Append(_delimiter); + } + + if (_quoteFields != null) + { + if (_quoteFields.TryGetValue(propertyName, out _)) + { + AppendStringWithEscapeAlways(_outputString, propertyName); + } + else + { + _outputString.Append(propertyName); + } + } + else + { + switch (_quoteKind) + { + case BaseCsvWritingCommand.QuoteKind.Always: + AppendStringWithEscapeAlways(_outputString, propertyName); + break; + case BaseCsvWritingCommand.QuoteKind.AsNeeded: + if (propertyName.Contains(_delimiter)) + { + AppendStringWithEscapeAlways(_outputString, propertyName); + } + else + { + _outputString.Append(propertyName); + } + + break; + case BaseCsvWritingCommand.QuoteKind.Never: + _outputString.Append(propertyName); + break; + } } - EscapeAndAppendString(dest, propertyName); } - return dest.ToString(); + + return _outputString.ToString(); } /// - /// + /// Convert PSObject to CSV string. /// - /// - /// + /// PSObject to convert. + /// Property names. /// - internal - string - ConvertPSObjectToCSV(PSObject mshObject, IList propertyNames) + internal string ConvertPSObjectToCSV(PSObject mshObject, IList propertyNames) { - Dbg.Assert(propertyNames != null, "PropertyName collection can be empty here, but it should not be null"); + if (propertyNames == null) + { + throw new ArgumentNullException(nameof(propertyNames)); + } - StringBuilder dest = new StringBuilder(); + _outputString.Clear(); bool first = true; foreach (string propertyName in propertyNames) @@ -972,30 +986,69 @@ internal class ExportCsvHelper : IDisposable } else { - dest.Append(_delimiter); + _outputString.Append(_delimiter); } - PSPropertyInfo property = mshObject.Properties[propertyName] as PSPropertyInfo; - string value = null; - //If property is not present, assume value is null - if (property != null) + + // If property is not present, assume value is null and skip it. + if (mshObject.Properties[propertyName] is PSPropertyInfo property) { - value = GetToStringValueForProperty(property); + var value = GetToStringValueForProperty(property); + + if (_quoteFields != null) + { + if (_quoteFields.TryGetValue(propertyName, out _)) + { + AppendStringWithEscapeAlways(_outputString, value); + } + else + { + _outputString.Append(value); + } + } + else + { + switch (_quoteKind) + { + case BaseCsvWritingCommand.QuoteKind.Always: + AppendStringWithEscapeAlways(_outputString, value); + break; + case BaseCsvWritingCommand.QuoteKind.AsNeeded: + if (value.Contains(_delimiter)) + { + AppendStringWithEscapeAlways(_outputString, value); + } + else + { + _outputString.Append(value); + } + + break; + case BaseCsvWritingCommand.QuoteKind.Never: + _outputString.Append(value); + break; + default: + Diagnostics.Assert(false, "BaseCsvWritingCommand.QuoteKind has new item."); + break; + } + } } - EscapeAndAppendString(dest, value); } - return dest.ToString(); + + return _outputString.ToString(); } /// - /// Get value from property object + /// Get value from property object. /// - /// - /// - internal - string - GetToStringValueForProperty(PSPropertyInfo property) + /// Property to convert. + /// ToString() value. + internal static string GetToStringValueForProperty(PSPropertyInfo property) { - Dbg.Assert(property != null, "Caller should validate the parameter"); + if (property == null) + { + throw new ArgumentNullException(nameof(property)); + } + string value = null; try { @@ -1005,25 +1058,24 @@ internal class ExportCsvHelper : IDisposable value = temp.ToString(); } } - //If we cannot read some value, treat it as null. catch (Exception) { + // If we cannot read some value, treat it as null. } + return value; } /// - /// Prepares string for writing type information + /// Prepares string for writing type information. /// - /// - /// - internal - string - GetTypeString(PSObject source) + /// PSObject whose type to determine. + /// String with type information. + internal static string GetTypeString(PSObject source) { string type = null; - //get type of source + // get type of source Collection tnh = source.TypeNames; if (tnh == null || tnh.Count == 0) { @@ -1031,14 +1083,20 @@ internal class ExportCsvHelper : IDisposable } else { - Dbg.Assert(tnh[0] != null, "type hierarchy should not have null values"); + if (tnh[0] == null) + { + throw new InvalidOperationException(CsvCommandStrings.TypeHierarchyShouldNotHaveNullValues); + } + string temp = tnh[0]; - //If type starts with CSV: remove it. This would happen when you export - //an imported object. import-csv adds CSV. prefix to the type. + + // If type starts with CSV: remove it. This would happen when you export + // an imported object. import-csv adds CSV. prefix to the type. if (temp.StartsWith(ImportExportCSVHelper.CSVTypePrefix, StringComparison.OrdinalIgnoreCase)) { temp = temp.Substring(4); } + type = string.Format(System.Globalization.CultureInfo.InvariantCulture, "#TYPE {0}", temp); } @@ -1049,47 +1107,48 @@ internal class ExportCsvHelper : IDisposable /// Escapes the " in string if necessary. /// Encloses the string in double quotes if necessary. /// - /// - internal static - void - EscapeAndAppendString(StringBuilder dest, string source) + internal static void AppendStringWithEscapeAlways(StringBuilder dest, string source) { if (source == null) { return; } - //Adding Double quote to all strings + + // Adding Double quote to all strings dest.Append('"'); for (int i = 0; i < source.Length; i++) { char c = source[i]; - //Double quote in the string is escaped with double quote - if ((c == '"')) + + // Double quote in the string is escaped with double quote + if (c == '"') { dest.Append('"'); } + dest.Append(c); } + dest.Append('"'); } + #region IDisposable Members /// - /// Set to true when object is disposed + /// Set to true when object is disposed. /// private bool _disposed; /// - /// public dispose method + /// Public dispose method. /// - public - void - Dispose() + public void Dispose() { if (_disposed == false) { GC.SuppressFinalize(this); } + _disposed = true; } @@ -1101,52 +1160,64 @@ internal static #region ImportHelperConversion /// - /// Helper class to import single CSV file + /// Helper class to import single CSV file. /// internal class ImportCsvHelper { #region constructor /// - /// Reference to cmdlet which is using this helper class + /// Reference to cmdlet which is using this helper class. /// private readonly PSCmdlet _cmdlet; /// - /// CSV delimiter (default is the "comma" / "," character) + /// CSV delimiter (default is the "comma" / "," character). /// private readonly char _delimiter; /// - /// Use "UnspecifiedName" when the name is null or empty + /// Use "UnspecifiedName" when the name is null or empty. /// private const string UnspecifiedName = "H"; /// - /// Avoid writing out duplicate warning messages when there are - /// one or more unspecified names + /// Avoid writing out duplicate warning messages when there are one or more unspecified names. /// private bool _alreadyWarnedUnspecifiedName = false; /// - /// Reference to header values + /// Gets reference to header values. /// internal IList Header { get; private set; } /// - /// ETS type name from the first line / comment in the CSV + /// Gets ETS type name from the first line / comment in the CSV. /// internal string TypeName { get; private set; } /// - /// Reader of the csv content + /// Reader of the csv content. /// private readonly StreamReader _sr; + // Initial sizes of the value list and the line stringbuilder. + // Set to reasonable initial sizes. They may grow beyond these, + // but this will prevent a few reallocations. + private const int ValueCountGuestimate = 16; + private const int LineLengthGuestimate = 256; + internal ImportCsvHelper(PSCmdlet cmdlet, char delimiter, IList header, string typeName, StreamReader streamReader) { - Dbg.Assert(cmdlet != null, "Caller should verify cmdlet != null"); - Dbg.Assert(streamReader != null, "Caller should verify textReader != null"); + if (cmdlet == null) + { + throw new ArgumentNullException(nameof(cmdlet)); + } + + if (streamReader == null) + { + throw new ArgumentNullException(nameof(streamReader)); + } _cmdlet = cmdlet; _delimiter = delimiter; @@ -1160,68 +1231,59 @@ internal ImportCsvHelper(PSCmdlet cmdlet, char delimiter, IList header, #region reading helpers /// - /// This is set to true when end of file is reached + /// This is set to true when end of file is reached. /// - private - bool EOF + private bool EOF => _sr.EndOfStream; + + private char ReadChar() { - get + if (EOF) { - return _sr.EndOfStream; + throw new InvalidOperationException(CsvCommandStrings.EOFIsReached); } - } - private - char - ReadChar() - { - Dbg.Assert(!EOF, "This should not be called if EOF is reached"); int i = _sr.Read(); return (char)i; } /// - /// Peeks the next character in the stream and returns true if it is - /// same as passed in character. + /// Peeks the next character in the stream and returns true if it is same as passed in character. /// /// /// - private - bool - PeekNextChar(char c) + private bool PeekNextChar(char c) { int i = _sr.Peek(); if (i == -1) { return false; } - return (c == (char)i); + + return c == (char)i; } /// /// Reads a line from file. This consumes the end of line. /// Only use it when end of line chars are not important. /// - /// - private string - ReadLine() - { - return _sr.ReadLine(); - } + /// Line from file. + private string ReadLine() => _sr.ReadLine(); #endregion reading helpers internal void ReadHeader() { - //Read #Type record if available + // Read #Type record if available if ((TypeName == null) && (!this.EOF)) { TypeName = ReadTypeInformation(); } + var values = new List(ValueCountGuestimate); + var builder = new StringBuilder(LineLengthGuestimate); while ((Header == null) && (!this.EOF)) { - Collection values = ParseNextRecord(); + ParseNextRecord(values, builder); // Trim all trailing blankspaces and delimiters ( single/multiple ). // If there is only one element in the row and if its a blankspace we dont trim it. @@ -1237,10 +1299,12 @@ internal void ReadHeader() { values[0] = values[0].Substring(9); Header = values; - } else if (values.Count != 0 && values[0].StartsWith("#")) + } + else if (values.Count != 0 && values[0].StartsWith('#')) { // Skip all lines starting with '#' - } else + } + else { // This is not W3C Extended Log File Format // By default first line is Header @@ -1254,32 +1318,35 @@ internal void ReadHeader() } } - internal - void - Import(ref bool alreadyWriteOutWarning) + internal void Import(ref bool alreadyWriteOutWarning) { _alreadyWarnedUnspecifiedName = alreadyWriteOutWarning; ReadHeader(); + var prevalidated = false; + var values = new List(ValueCountGuestimate); + var builder = new StringBuilder(LineLengthGuestimate); while (true) { - Collection values = ParseNextRecord(); + ParseNextRecord(values, builder); if (values.Count == 0) break; - if (values.Count == 1 && String.IsNullOrEmpty(values[0])) + if (values.Count == 1 && string.IsNullOrEmpty(values[0])) { // skip the blank lines continue; } - PSObject result = BuildMshobject(TypeName, Header, values, _delimiter); + PSObject result = BuildMshobject(TypeName, Header, values, _delimiter, prevalidated); + prevalidated = true; _cmdlet.WriteObject(result); } + alreadyWriteOutWarning = _alreadyWarnedUnspecifiedName; } /// - /// Validate the names of properties + /// Validate the names of properties. /// /// private static void ValidatePropertyNames(IList names) @@ -1288,14 +1355,14 @@ private static void ValidatePropertyNames(IList names) { if (names.Count == 0) { - //If there are no names, it is an error + // If there are no names, it is an error } else { HashSet headers = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (string currentHeader in names) { - if (!String.IsNullOrEmpty(currentHeader)) + if (!string.IsNullOrEmpty(currentHeader)) { if (!headers.Contains(currentHeader)) { @@ -1305,9 +1372,10 @@ private static void ValidatePropertyNames(IList names) { // throw a terminating error as there are duplicate headers in the input. string memberAlreadyPresentMsg = - String.Format(CultureInfo.InvariantCulture, - ExtendedTypeSystem.MemberAlreadyPresent, - currentHeader); + string.Format( + CultureInfo.InvariantCulture, + ExtendedTypeSystem.MemberAlreadyPresent, + currentHeader); ExtendedTypeSystemException exception = new ExtendedTypeSystemException(memberAlreadyPresentMsg); throw exception; @@ -1317,12 +1385,12 @@ private static void ValidatePropertyNames(IList names) } } } + /// - /// Read the type information, if present + /// Read the type information, if present. /// - /// Type string if present else null - private string - ReadTypeInformation() + /// Type string if present else null. + private string ReadTypeInformation() { string type = null; if (PeekNextChar('#')) @@ -1338,83 +1406,79 @@ private string } } } + return type; } /// - /// Reads the next record from the file and returns parsed collection - /// of string. + /// Reads the next record from the file and returns parsed collection of string. /// /// /// Parsed collection of strings. /// - private Collection - ParseNextRecord() + private void ParseNextRecord(List result, StringBuilder current) { - //Collection of strings to return - Collection result = new Collection(); - //current string - StringBuilder current = new StringBuilder(); + result.Clear(); + + // current string + current.Clear(); bool seenBeginQuote = false; - // int i = 0; + while (!EOF) { - //Read the next character + // Read the next character char ch = ReadChar(); - - if ((ch == _delimiter)) + if (ch == _delimiter) { if (seenBeginQuote) { - //Delimiter inside double quotes is part of string. - //Ex: - //"foo, bar" - //is parsed as - //->foo, bar<- + // Delimiter inside double quotes is part of string. + // Ex: + // "foo, bar" + // is parsed as + // ->foo, bar<- current.Append(ch); } else { - //Delimiter outside quotes is end of current word. + // Delimiter outside quotes is end of current word. result.Add(current.ToString()); current.Remove(0, current.Length); } } - else if (ch == '"') { if (seenBeginQuote) { if (PeekNextChar('"')) { - //"" inside double quote are single quote - //ex: "foo""bar" - //is read as - //->foo"bar<- - - //PeekNextChar only peeks. Read the next char. + // "" inside double quote are single quote + // ex: "foo""bar" + // is read as + // ->foo"bar<- + // PeekNextChar only peeks. Read the next char. ReadChar(); current.Append('"'); } else { - //We have seen a matching end quote. + // We have seen a matching end quote. seenBeginQuote = false; - //Read - //everything till we hit next delimiter. - //In correct CSV,1) end quote is followed by delimiter - //2)end quote is followed some whitespaces and - //then delimiter. - //We eat the whitespaces seen after the ending quote. - //However if there are other characters, we add all of them - //to string. - //Ex: ->"foo bar"<- is read as ->foo bar<- - //->"foo bar" <- is read as ->foo bar<- - //->"foo bar" ab <- is read as ->"foo bar" ab <- + // Read + // everything till we hit next delimiter. + // In correct CSV,1) end quote is followed by delimiter + // 2)end quote is followed some whitespaces and + // then delimiter. + // We eat the whitespaces seen after the ending quote. + // However if there are other characters, we add all of them + // to string. + // Ex: ->"foo bar"<- is read as ->foo bar<- + // ->"foo bar" <- is read as ->foo bar<- + // ->"foo bar" ab <- is read as ->"foo bar" ab <- bool endofRecord = false; ReadTillNextDelimiter(current, ref endofRecord, true); result.Add(current.ToString()); @@ -1425,18 +1489,18 @@ private string } else if (current.Length == 0) { - //We are at the beginning of a new word. - //This quote is the first quote. + // We are at the beginning of a new word. + // This quote is the first quote. seenBeginQuote = true; } else { - //We are seeing a quote after the start of - //the word. This is error, however we will be - //lenient here and do what excel does: - //Ex: foo "ba,r" - //In above example word read is ->foo "ba<- - //Basically we read till next delimiter + // We are seeing a quote after the start of + // the word. This is error, however we will be + // lenient here and do what excel does: + // Ex: foo "ba,r" + // In above example word read is ->foo "ba<- + // Basically we read till next delimiter bool endOfRecord = false; current.Append(ch); ReadTillNextDelimiter(current, ref endOfRecord, false); @@ -1450,25 +1514,25 @@ private string { if (seenBeginQuote) { - //Spaces in side quote are valid + // Spaces in side quote are valid current.Append(ch); } else if (current.Length == 0) { - //ignore leading spaces + // ignore leading spaces continue; } else { - //We are not in quote and we are not at the - //beginning of a word. We should not be seeing - //spaces here. This is an error condition, however - //we will be lenient here and do what excel does, - //that is read till next delimiter. - //Ex: ->foo <- is read as ->foo<- - //Ex: ->foo bar<- is read as ->foo bar<- - //Ex: ->foo bar <- is read as ->foo bar <- - //Ex: ->foo bar "er,ror"<- is read as ->foo bar "er<- + // We are not in quote and we are not at the + // beginning of a word. We should not be seeing + // spaces here. This is an error condition, however + // we will be lenient here and do what excel does, + // that is read till next delimiter. + // Ex: ->foo <- is read as ->foo<- + // Ex: ->foo bar<- is read as ->foo bar<- + // Ex: ->foo bar <- is read as ->foo bar <- + // Ex: ->foo bar "er,ror"<- is read as ->foo bar "er<- bool endOfRecord = false; current.Append(ch); ReadTillNextDelimiter(current, ref endOfRecord, true); @@ -1476,21 +1540,24 @@ private string current.Remove(0, current.Length); if (endOfRecord) + { break; + } } } else if (IsNewLine(ch, out string newLine)) { if (seenBeginQuote) { - //newline inside quote are valid + // newline inside quote are valid current.Append(newLine); } else { result.Add(current.ToString()); current.Remove(0, current.Length); - //New line outside quote is end of word and end of record + + // New line outside quote is end of word and end of record break; } } @@ -1499,20 +1566,17 @@ private string current.Append(ch); } } + if (current.Length != 0) { result.Add(current.ToString()); } - - return result; } // If we detect a newline we return it as a string "\r", "\n" or "\r\n" - private - bool - IsNewLine(char ch, out string newLine) + private bool IsNewLine(char ch, out string newLine) { - newLine = ""; + newLine = string.Empty; if (ch == '\r') { if (PeekNextChar('\n')) @@ -1530,28 +1594,26 @@ private string newLine = "\n"; } - return newLine != ""; + return newLine != string.Empty; } /// - /// This function reads the characters till next delimiter and adds them - /// to current + /// This function reads the characters till next delimiter and adds them to current. /// /// /// - /// this is true if end of record is reached - /// when delimiter is hit. This would be true if delimiter is NewLine + /// This is true if end of record is reached + /// when delimiter is hit. This would be true if delimiter is NewLine. /// /// /// If this is true, eat the trailing blanks. Note:if there are non - /// whitespace characters present, then trailing blanks are not consumed + /// whitespace characters present, then trailing blanks are not consumed. /// - private - void - ReadTillNextDelimiter(StringBuilder current, ref bool endOfRecord, bool eatTrailingBlanks) + private void ReadTillNextDelimiter(StringBuilder current, ref bool endOfRecord, bool eatTrailingBlanks) { StringBuilder temp = new StringBuilder(); - //Did we see any non-whitespace character + + // Did we see any non-whitespace character bool nonWhiteSpace = false; while (true) @@ -1582,6 +1644,7 @@ private string } } } + if (eatTrailingBlanks && !nonWhiteSpace) { string s = temp.ToString(); @@ -1594,33 +1657,37 @@ private string } } - private - PSObject - BuildMshobject(string type, IList names, Collection values, char delimiter) + private PSObject BuildMshobject(string type, IList names, List values, char delimiter, bool preValidated = false) { - //string[] namesarray = null; - PSObject result = new PSObject(); + PSObject result = new PSObject(names.Count); char delimiterlocal = delimiter; int unspecifiedNameIndex = 1; for (int i = 0; i <= names.Count - 1; i++) { string name = names[i]; string value = null; - ////if name is null and delimiter is '"', continue + + // if name is null and delimiter is '"', use a default property name 'UnspecifiedName' if (name.Length == 0 && delimiterlocal == '"') - continue; - ////if name is null and delimiter is not '"', use a default property name 'UnspecifiedName' + { + name = UnspecifiedName + unspecifiedNameIndex; + unspecifiedNameIndex++; + } + + // if name is null and delimiter is not '"', use a default property name 'UnspecifiedName' if (string.IsNullOrEmpty(name)) { name = UnspecifiedName + unspecifiedNameIndex; unspecifiedNameIndex++; } - //If no value was present in CSV file, we write null. + + // If no value was present in CSV file, we write null. if (i < values.Count) { value = values[i]; } - result.Properties.Add(new PSNoteProperty(name, value)); + + result.Properties.Add(new PSNoteProperty(name, value), preValidated); } if (!_alreadyWarnedUnspecifiedName && unspecifiedNameIndex != 1) @@ -1629,7 +1696,7 @@ private string _alreadyWarnedUnspecifiedName = true; } - if (type != null && type.Length > 0) + if (!string.IsNullOrEmpty(type)) { result.TypeNames.Clear(); result.TypeNames.Add(type); @@ -1645,40 +1712,49 @@ private string #region ExportImport Helper /// - /// Helper class for CSV conversion + /// Helper class for CSV conversion. /// internal static class ImportExportCSVHelper { internal const char CSVDelimiter = ','; internal const string CSVTypePrefix = "CSV:"; - internal static char SetDelimiter(PSCmdlet Cmdlet, string ParameterSetName, char Delimiter, bool UseCulture) + internal static char SetDelimiter(PSCmdlet cmdlet, string parameterSetName, char explicitDelimiter, bool useCulture) { - switch (ParameterSetName) + char delimiter = explicitDelimiter; + switch (parameterSetName) { case "Delimiter": - //if delimiter is not given, it should take , as value - if (Delimiter == '\0') + case "DelimiterPath": + case "DelimiterLiteralPath": + + // if delimiter is not given, it should take , as value + if (explicitDelimiter == '\0') { - Delimiter = ImportExportCSVHelper.CSVDelimiter; + delimiter = ImportExportCSVHelper.CSVDelimiter; } break; case "UseCulture": - if (UseCulture == true) + case "CulturePath": + case "CultureLiteralPath": + if (useCulture == true) { // ListSeparator is apparently always a character even though the property returns a string, checked via: // [CultureInfo]::GetCultures("AllCultures") | % { ([CultureInfo]($_.Name)).TextInfo.ListSeparator } | ? Length -ne 1 - Delimiter = CultureInfo.CurrentCulture.TextInfo.ListSeparator[0]; + delimiter = CultureInfo.CurrentCulture.TextInfo.ListSeparator[0]; } + break; default: { - Delimiter = ImportExportCSVHelper.CSVDelimiter; + delimiter = ImportExportCSVHelper.CSVDelimiter; } + break; } - return Delimiter; + + return delimiter; } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs index c2ea77258433..16f30042200f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs @@ -1,25 +1,25 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Management.Automation.Internal; +using System.Reflection; +using System.Xml; + +using Dbg = System.Management.Automation.Diagnostics; namespace System.Management.Automation { - using System; - using System.Collections; - using System.Reflection; - using System.Xml; - using System.Management.Automation.Internal; - using System.Collections.Generic; - using Dbg = System.Management.Automation.Diagnostics; - /// - /// This class provides functionality for serializing a PSObject + /// This class provides functionality for serializing a PSObject. /// internal class CustomSerialization { #region constructor /// - /// depth of serialization + /// Depth of serialization. /// private int _depth; @@ -29,17 +29,17 @@ internal class CustomSerialization private XmlWriter _writer; /// - /// Whether type information should be included in the xml + /// Whether type information should be included in the xml. /// private bool _notypeinformation; /// - /// CustomerSerializer used for formatting the output for _writer + /// CustomerSerializer used for formatting the output for _writer. /// private CustomInternalSerializer _serializer; /// - /// Constructor + /// Constructor. /// /// /// writer to be used for serialization. @@ -57,10 +57,12 @@ internal CustomSerialization(XmlWriter writer, bool notypeinformation, int depth { throw PSTraceSource.NewArgumentException("writer"); } + if (depth < 1) { throw PSTraceSource.NewArgumentException("writer", Serialization.DepthOfOneRequired); } + _depth = depth; _writer = writer; _notypeinformation = notypeinformation; @@ -68,12 +70,12 @@ internal CustomSerialization(XmlWriter writer, bool notypeinformation, int depth } /// - /// Default depth of serialization + /// Default depth of serialization. /// public static int MshDefaultSerializationDepth { get; } = 1; /// - /// Constructor + /// Constructor. /// /// /// writer to be used for serialization. @@ -93,14 +95,14 @@ internal CustomSerialization(XmlWriter writer, bool notypeinformation) private bool _firstCall = true; /// - /// Serializes passed in object + /// Serializes passed in object. /// /// - /// object to be serialized + /// Object to be serialized. /// internal void Serialize(object source) { - //Write the root element tag before writing first object. + // Write the root element tag before writing first object. if (_firstCall) { _firstCall = false; @@ -118,10 +120,10 @@ internal void Serialize(object source) } /// - /// Serializes passed in object + /// Serializes passed in object. /// /// - /// object to be serialized + /// Object to be serialized. /// internal void SerializeAsStream(object source) { @@ -136,7 +138,7 @@ internal void SerializeAsStream(object source) } /// - /// Writes the start of root element + /// Writes the start of root element. /// private void Start() { @@ -144,7 +146,7 @@ private void Start() } /// - /// Write the end of root element + /// Write the end of root element. /// internal void Done() { @@ -153,12 +155,13 @@ internal void Done() _firstCall = false; Start(); } + _writer.WriteEndElement(); _writer.Flush(); } /// - /// Flush the writer + /// Flush the writer. /// internal void DoneAsStream() { @@ -186,36 +189,36 @@ internal class #region constructor /// - /// Xml writer to be used + /// Xml writer to be used. /// private XmlWriter _writer; /// - /// check first call for every pipeline object to write Object tag else property tag + /// Check first call for every pipeline object to write Object tag else property tag. /// private bool _firstcall; /// - /// should the type information to be shown + /// Should the type information to be shown. /// private bool _notypeinformation; /// - /// check object call + /// Check object call. /// private bool _firstobjectcall = true; /// - /// Constructor + /// Constructor. /// /// - /// Xml writer to be used + /// Xml writer to be used. /// /// - /// Xml writer to be used + /// Xml writer to be used. /// /// - /// check first call for every pipeline object to write Object tag else property tag + /// Check first call for every pipeline object to write Object tag else property tag. /// internal CustomInternalSerializer(XmlWriter writer, bool notypeinformation, bool isfirstcallforObject) { @@ -233,7 +236,7 @@ internal CustomInternalSerializer(XmlWriter writer, bool notypeinformation, bool private bool _isStopping = false; /// - /// Called from a separate thread will stop the serialization process + /// Called from a separate thread will stop the serialization process. /// internal void Stop() { @@ -279,22 +282,21 @@ internal void WriteOneObject(object source, string property, int depth) return; } - if (HandlePrimitiveKnownTypePSObject(source, property, depth)) { return; } - //Note: We donot use containers in depth calculation. i.e even if the - //current depth is zero, we serialize the container. All contained items will - //get serialized with depth zero. + // Note: We donot use containers in depth calculation. i.e even if the + // current depth is zero, we serialize the container. All contained items will + // get serialized with depth zero. if (HandleKnownContainerTypes(source, property, depth)) { return; } PSObject mshSource = PSObject.AsPSObject(source); - //If depth is zero, complex type should be serialized as string. + // If depth is zero, complex type should be serialized as string. if (depth == 0 || SerializeAsString(mshSource)) { HandlePSObjectAsString(mshSource, property, depth); @@ -315,18 +317,19 @@ private bool HandlePrimitiveKnownType(object source, string property) { Dbg.Assert(source != null, "caller should validate the parameter"); - //Check if source is of primitive known type + // Check if source is of primitive known type TypeSerializationInfo pktInfo = KnownTypes.GetTypeSerializationInfo(source.GetType()); if (pktInfo != null) { WriteOnePrimitiveKnownType(_writer, property, source, pktInfo); return true; } + return false; } /// - /// Serializes PSObject whose base objects are of primitive known type + /// Serializes PSObject whose base objects are of primitive known type. /// /// /// @@ -340,9 +343,9 @@ private bool HandlePrimitiveKnownTypePSObject(object source, string property, in bool sourceHandled = false; PSObject moSource = source as PSObject; - if (moSource != null && !moSource.immediateBaseObjectIsEmpty) + if (moSource != null && !moSource.ImmediateBaseObjectIsEmpty) { - //Check if baseObject is primitive known type + // Check if baseObject is primitive known type object baseObject = moSource.ImmediateBaseObject; TypeSerializationInfo pktInfo = KnownTypes.GetTypeSerializationInfo(baseObject.GetType()); if (pktInfo != null) @@ -351,6 +354,7 @@ private bool HandlePrimitiveKnownTypePSObject(object source, string property, in sourceHandled = true; } } + return sourceHandled; } @@ -363,13 +367,13 @@ private bool HandleKnownContainerTypes(object source, string property, int depth IEnumerable enumerable = null; IDictionary dictionary = null; - //If passed in object is PSObject with no baseobject, return false. - if (mshSource != null && mshSource.immediateBaseObjectIsEmpty) + // If passed in object is PSObject with no baseobject, return false. + if (mshSource != null && mshSource.ImmediateBaseObjectIsEmpty) { return false; } - //Check if source (or baseobject in mshSource) is known container type + // Check if source (or baseobject in mshSource) is known container type GetKnownContainerTypeInfo(mshSource != null ? mshSource.ImmediateBaseObject : source, out ct, out dictionary, out enumerable); @@ -383,6 +387,7 @@ private bool HandleKnownContainerTypes(object source, string property, int depth { WriteDictionary(dictionary, depth); } + break; case ContainerType.Stack: case ContainerType.Queue: @@ -391,31 +396,33 @@ private bool HandleKnownContainerTypes(object source, string property, int depth { WriteEnumerable(enumerable, depth); } + break; default: { Dbg.Assert(false, "All containers should be handled in the switch"); } + break; } - //An object which is original enumerable becomes an PSObject - //with arraylist on deserialization. So on roundtrip it will show up - //as List. - //We serialize properties of enumerable and on deserialization mark the object - //as Deserialized. So if object is marked deserialized, we should write properties. - //Note: we do not serialize the properties of IEnumerable if depth is zero. - if (depth != 0 && (ct == ContainerType.Enumerable || (mshSource != null && mshSource.isDeserialized))) + // An object which is original enumerable becomes an PSObject + // with arraylist on deserialization. So on roundtrip it will show up + // as List. + // We serialize properties of enumerable and on deserialization mark the object + // as Deserialized. So if object is marked deserialized, we should write properties. + // Note: we do not serialize the properties of IEnumerable if depth is zero. + if (depth != 0 && (ct == ContainerType.Enumerable || (mshSource != null && mshSource.IsDeserialized))) { - //Note:Depth is the depth for serialization of baseObject. - //Depth for serialization of each property is one less. + // Note:Depth is the depth for serialization of baseObject. + // Depth for serialization of each property is one less. WritePSObjectProperties(PSObject.AsPSObject(source), depth); } - //If source is PSObject, serialize notes + // If source is PSObject, serialize notes if (mshSource != null) { - //Serialize instanceMembers + // Serialize instanceMembers PSMemberInfoCollection instanceMembers = mshSource.InstanceMembers; if (instanceMembers != null) { @@ -428,10 +435,8 @@ private bool HandleKnownContainerTypes(object source, string property, int depth return true; } - /// - /// Checks if source is known container type and returns appropriate - /// information + /// Checks if source is known container type and returns appropriate information. /// /// /// @@ -497,7 +502,7 @@ private bool HandleKnownContainerTypes(object source, string property, int depth } } - //Check if type is IEnumerable + // Check if type is IEnumerable if (ct == ContainerType.None) { enumerable = LanguagePrimitives.GetEnumerable(source); @@ -509,7 +514,7 @@ private bool HandleKnownContainerTypes(object source, string property, int depth } /// - /// Checks if derived is of type baseType or a type derived from baseType + /// Checks if derived is of type baseType or a type derived from baseType. /// /// /// @@ -527,19 +532,21 @@ private static bool DerivesFromGenericType(Type derived, Type baseType) { return true; } + derived = derived.GetTypeInfo().BaseType; } + return false; } #region Write PSObject /// - /// Serializes an PSObject whose baseobject is of primitive type + /// Serializes an PSObject whose baseobject is of primitive type. /// and which has notes. /// /// - /// source from which notes are written + /// Source from which notes are written. /// /// /// primitive object which is written as base object. In most cases it @@ -560,8 +567,8 @@ private static bool DerivesFromGenericType(Type derived, Type baseType) { Dbg.Assert(source != null, "caller should validate the parameter"); - //Write start of PSObject. Since baseobject is primitive known - //type, we do not need TypeName information. + // Write start of PSObject. Since baseobject is primitive known + // type, we do not need TypeName information. WriteStartOfPSObject(source, property, source.ToStringFromDeserialization != null); if (pktInfo != null) @@ -569,7 +576,7 @@ private static bool DerivesFromGenericType(Type derived, Type baseType) WriteOnePrimitiveKnownType(_writer, null, primitive, pktInfo); } - //Serialize instanceMembers + // Serialize instanceMembers PSMemberInfoCollection instanceMembers = source.InstanceMembers; if (instanceMembers != null) { @@ -589,7 +596,7 @@ private void HandleComplexTypePSObject(PSObject source, string property, int dep bool isEnum = false; bool isPSObject = false; - if (!source.immediateBaseObjectIsEmpty) + if (!source.ImmediateBaseObjectIsEmpty) { isEnum = source.ImmediateBaseObject is Enum; isPSObject = source.ImmediateBaseObject is PSObject; @@ -656,7 +663,7 @@ private void HandleComplexTypePSObject(PSObject source, string property, int dep } } - Object baseObject = mshObject.BaseObject; + object baseObject = mshObject.BaseObject; if (!_notypeinformation) WriteAttribute(_writer, CustomSerializationStrings.TypeAttribute, baseObject.GetType().ToString()); } @@ -675,15 +682,16 @@ private bool PSObjectHasNotes(PSObject source) { return true; } + return false; } /// - /// Serialize member set. This method serializes without writing + /// Serialize member set. This method serializes without writing. /// enclosing tags and attributes. /// /// - /// enumerable containing members + /// Enumerable containing members /// /// /// @@ -695,7 +703,6 @@ private bool PSObjectHasNotes(PSObject source) { Dbg.Assert(me != null, "caller should validate the parameter"); - bool enclosingTagWritten = false; foreach (PSMemberInfo info in me) { if (!info.ShouldSerialize) @@ -709,15 +716,11 @@ private bool PSObjectHasNotes(PSObject source) continue; } - enclosingTagWritten = true; WriteStartElement(_writer, CustomSerializationStrings.Properties); WriteAttribute(_writer, CustomSerializationStrings.NameAttribute, info.Name); if (!_notypeinformation) WriteAttribute(_writer, CustomSerializationStrings.TypeAttribute, info.GetType().ToString()); _writer.WriteString(property.Value.ToString()); - } - if (enclosingTagWritten) - { _writer.WriteEndElement(); } } @@ -727,7 +730,7 @@ private bool PSObjectHasNotes(PSObject source) #region properties /// - /// Serializes properties of PSObject + /// Serializes properties of PSObject. /// private void WritePSObjectProperties(PSObject source, int depth) { @@ -735,7 +738,7 @@ private void WritePSObjectProperties(PSObject source, int depth) depth = GetDepthOfSerialization(source, depth); - //Depth available for each property is one less + // Depth available for each property is one less --depth; Dbg.Assert(depth >= 0, "depth should be greater or equal to zero"); if (source.GetSerializationMethod(null) == SerializationMethod.SpecificProperties) @@ -749,6 +752,7 @@ private void WritePSObjectProperties(PSObject source, int depth) specificProperties.Add(property); } } + SerializeProperties(specificProperties, CustomSerializationStrings.Properties, depth); return; } @@ -757,8 +761,8 @@ private void WritePSObjectProperties(PSObject source, int depth) { Dbg.Assert(prop != null, "propertyCollection should only have member of type PSProperty"); object value = AutomationNull.Value; - //PSObject throws GetValueException if it cannot - //get value for a property. + // PSObject throws GetValueException if it cannot + // get value for a property. try { value = prop.Value; @@ -768,7 +772,7 @@ private void WritePSObjectProperties(PSObject source, int depth) WritePropertyWithNullValue(_writer, prop, depth); continue; } - //Write the property + // Write the property if (value == null) { WritePropertyWithNullValue(_writer, prop, depth); @@ -781,17 +785,16 @@ private void WritePSObjectProperties(PSObject source, int depth) } /// - /// Serializes properties from collection + /// Serializes properties from collection. /// /// - /// Collection of properties to serialize + /// Collection of properties to serialize. /// /// - /// Name for enclosing element tag + /// Name for enclosing element tag. /// /// - /// depth to which each property should be - /// serialized + /// Depth to which each property should be serialized. /// private void SerializeProperties( PSMemberInfoInternalCollection propertyCollection, string name, int depth) @@ -807,8 +810,8 @@ private void WritePSObjectProperties(PSObject source, int depth) Dbg.Assert(prop != null, "propertyCollection should only have member of type PSProperty"); object value = AutomationNull.Value; - //PSObject throws GetValueException if it cannot - //get value for a property. + // PSObject throws GetValueException if it cannot + // get value for a property. try { value = prop.Value; @@ -817,7 +820,7 @@ private void WritePSObjectProperties(PSObject source, int depth) { continue; } - //Write the property + // Write the property WriteOneObject(value, prop.Name, depth); } } @@ -829,10 +832,10 @@ private void WritePSObjectProperties(PSObject source, int depth) #region enumerable and dictionary /// - /// Serializes IEnumerable + /// Serializes IEnumerable. /// /// - /// enumerable which is serialized + /// Enumerable which is serialized. /// /// private void WriteEnumerable(IEnumerable enumerable, int depth) @@ -850,8 +853,8 @@ private void WriteEnumerable(IEnumerable enumerable, int depth) enumerator = null; } - //AD has incorrect implementation of IEnumerable where they returned null - //for GetEnumerator instead of empty enumerator + // AD has incorrect implementation of IEnumerable where they returned null + // for GetEnumerator instead of empty enumerator if (enumerator != null) { while (true) @@ -872,15 +875,16 @@ private void WriteEnumerable(IEnumerable enumerable, int depth) { break; } + WriteOneObject(item, null, depth); } } } /// - /// Serializes IDictionary + /// Serializes IDictionary. /// - /// dictionary which is serialized + /// Dictionary which is serialized. /// private void WriteDictionary(IDictionary dictionary, int depth) { @@ -897,9 +901,9 @@ private void WriteDictionary(IDictionary dictionary, int depth) { while (dictionaryEnum.MoveNext()) { - //Write Key + // Write Key WriteOneObject(dictionaryEnum.Key, CustomSerializationStrings.DictionaryKey, depth); - //Write Value + // Write Value WriteOneObject(dictionaryEnum.Value, CustomSerializationStrings.DictionaryValue, depth); } } @@ -946,11 +950,9 @@ private void HandlePSObjectAsString(PSObject source, string property, int depth) /// Gets the string from PSObject using the information from /// types.ps1xml. This string is used for serializing the PSObject. ///
- /// /// - /// PSObject to be converted to string + /// PSObject to be converted to string. /// - /// /// /// string value to use for serializing this PSObject. /// @@ -993,11 +995,10 @@ private string GetStringFromPSObject(PSObject source) /// /// Reads the information the PSObject - /// and returns true if this object should be serialized as - /// string + /// and returns true if this object should be serialized as string. /// - /// PSObject to be serialized - /// true if the object needs to be serialized as a string + /// PSObject to be serialized. + /// True if the object needs to be serialized as a string. private static bool SerializeAsString(PSObject source) { return source.GetSerializationMethod(null) == SerializationMethod.String; @@ -1006,10 +1007,10 @@ private static bool SerializeAsString(PSObject source) #endregion serialize as string /// - /// compute the serialization depth for an PSObject instance subtree + /// Compute the serialization depth for an PSObject instance subtree. /// - /// PSObject whose serialization depth has to be computed - /// current depth + /// PSObject whose serialization depth has to be computed. + /// Current depth. /// private static int GetDepthOfSerialization(PSObject source, int depth) { @@ -1030,7 +1031,7 @@ private static int GetDepthOfSerialization(PSObject source, int depth) } /// - /// Writes null + /// Writes null. /// /// private void WriteNull(string property) @@ -1097,12 +1098,12 @@ private void WriteNull(string property) } /// - /// Writes an item or property in Monad namespace + /// Writes an item or property in Monad namespace. /// /// The XmlWriter stream to which the object is serialized. - /// name of property. Pass null for item - /// object to be written - /// serialization information about source + /// Name of property. Pass null for item. + /// Object to be written. + /// Serialization information about source. private void WriteOnePrimitiveKnownType( XmlWriter writer, string property, object source, TypeSerializationInfo entry) @@ -1115,21 +1116,21 @@ private void WriteNull(string property) #region misc /// - /// Writes start element in Monad namespace + /// Writes start element in Monad namespace. /// /// - /// tag of element + /// Tag of element. internal static void WriteStartElement(XmlWriter writer, string elementTag) { writer.WriteStartElement(elementTag); } /// - /// Writes attribute in monad namespace + /// Writes attribute in monad namespace. /// /// - /// name of attribute - /// value of attribute + /// Name of attribute. + /// Value of attribute. internal static void WriteAttribute(XmlWriter writer, string name, string value) { writer.WriteAttributeString(name, value); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerializationStrings.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerializationStrings.cs index 109880780cd5..59ec5432addc 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerializationStrings.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerializationStrings.cs @@ -1,42 +1,39 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. namespace System.Management.Automation { /// - /// This class contains strings required for serialization for Convertto-XML + /// This class contains strings required for serialization for ConvertTo-XML. /// internal static class CustomSerializationStrings { #region element tags - /// - /// Element tag for root node + /// Element tag for root node. /// internal const string RootElementTag = "Objects"; /// - /// Element tag for PSObject + /// Element tag for PSObject. /// internal const string PSObjectTag = "Object"; /// - /// Element tag for properties + /// Element tag for properties. /// internal const string Properties = "Property"; - #region attribute tags /// - /// String for name attribute + /// String for name attribute. /// internal const string NameAttribute = "Name"; /// - /// String for type attribute + /// String for type attribute. /// internal const string TypeAttribute = "Type"; @@ -45,12 +42,12 @@ internal static class CustomSerializationStrings #region known container tags /// - /// Value of name attribute for dictionary key part in dictionary entry + /// Value of name attribute for dictionary key part in dictionary entry. /// internal const string DictionaryKey = "Key"; /// - /// Value of name attribute for dictionary value part in dictionary entry + /// Value of name attribute for dictionary value part in dictionary entry. /// internal const string DictionaryValue = "Value"; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs index 0c3ef0080c72..02e6fcad671b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs @@ -1,23 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Threading; using System.Management.Automation; -using System.Management.Automation.Runspaces; using System.Management.Automation.Remoting.Internal; +using System.Management.Automation.Runspaces; +using System.Threading; namespace Microsoft.PowerShell.Commands { /// /// This cmdlet takes a Runspace object and checks to see if it is debuggable (i.e, if - /// it is running a script or is currently stopped in the debugger. If it - /// is debuggable then it breaks into the Runspace debugger in step mode. + /// it is running a script or is currently stopped in the debugger. + /// If it is debuggable then it breaks into the Runspace debugger in step mode. /// [SuppressMessage("Microsoft.PowerShell", "PS1012:CallShouldProcessOnlyIfDeclaringSupport")] [Cmdlet(VerbsDiagnostic.Debug, "Runspace", SupportsShouldProcess = true, DefaultParameterSetName = DebugRunspaceCommand.RunspaceParameterSet, @@ -101,6 +100,21 @@ public Guid InstanceId set; } + /// + /// The optional breakpoint objects to use for debugging. + /// + [Experimental("Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints", ExperimentAction.Show)] + [Parameter(Position = 1, + ParameterSetName = DebugRunspaceCommand.InstanceIdParameterSet)] + [Parameter(ParameterSetName = DebugRunspaceCommand.RunspaceParameterSet)] + [Parameter(ParameterSetName = DebugRunspaceCommand.IdParameterSet)] + [Parameter(ParameterSetName = DebugRunspaceCommand.NameParameterSet)] + public Breakpoint[] Breakpoint + { + get; + set; + } + #endregion #region Overrides @@ -261,7 +275,7 @@ private void WaitAndReceiveRunspaceOutput() _debugger.SetDebugMode(DebugModes.LocalScript | DebugModes.RemoteScript); // Set up host script debugger to debug the runspace. - _debugger.DebugRunspace(_runspace); + _debugger.DebugRunspace(_runspace, disableBreakAll: Breakpoint?.Length > 0); while (_debugging) { @@ -330,7 +344,9 @@ private void AddDataEventHandlers() { // Create new collection objects. if (_debugBlockingCollection != null) { _debugBlockingCollection.Dispose(); } + if (_debugAccumulateCollection != null) { _debugAccumulateCollection.Dispose(); } + _debugBlockingCollection = new PSDataCollection(); _debugBlockingCollection.BlockingEnumerator = true; _debugAccumulateCollection = new PSDataCollection(); @@ -342,6 +358,7 @@ private void AddDataEventHandlers() { _runningPowerShell.OutputBuffer.DataAdding += HandlePowerShellOutputBufferDataAdding; } + if (_runningPowerShell.ErrorBuffer != null) { _runningPowerShell.ErrorBuffer.DataAdding += HandlePowerShellErrorBufferDataAdding; @@ -356,6 +373,7 @@ private void AddDataEventHandlers() { _runningPipeline.Output.DataReady += HandlePipelineOutputDataReady; } + if (_runningPipeline.Error != null) { _runningPipeline.Error.DataReady += HandlePipelineErrorDataReady; @@ -514,6 +532,10 @@ private void PrepareRunspace(Runspace runspace) { SetLocalMode(runspace.Debugger, true); EnableHostDebugger(runspace, false); + if (Breakpoint?.Length > 0) + { + runspace.Debugger?.SetBreakpoints(Breakpoint); + } } private void RestoreRunspace(Runspace runspace) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Disable-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Disable-PSBreakpoint.cs index 770eae7490c1..e8008650ccb8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Disable-PSBreakpoint.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Disable-PSBreakpoint.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// This class implements Disable-PSBreakpoint + /// This class implements Disable-PSBreakpoint. /// [Cmdlet(VerbsLifecycle.Disable, "PSBreakpoint", SupportsShouldProcess = true, DefaultParameterSetName = "Breakpoint", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113294")] [OutputType(typeof(Breakpoint))] @@ -24,6 +23,7 @@ public SwitchParameter PassThru { return _passThru; } + set { _passThru = value; @@ -33,7 +33,7 @@ public SwitchParameter PassThru private bool _passThru; /// - /// Disables the given breakpoint + /// Disables the given breakpoint. /// protected override void ProcessBreakpoint(Breakpoint breakpoint) { @@ -45,4 +45,4 @@ protected override void ProcessBreakpoint(Breakpoint breakpoint) } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Enable-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Enable-PSBreakpoint.cs index 37736ca2f334..e697d36bc2be 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Enable-PSBreakpoint.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Enable-PSBreakpoint.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Diagnostics; @@ -10,12 +9,12 @@ namespace Microsoft.PowerShell.Commands { /// - /// Base class for Enable/Disable/Remove-PSBreakpoint + /// Base class for Enable/Disable/Remove-PSBreakpoint. /// public abstract class PSBreakpointCommandBase : PSCmdlet { /// - /// the breakpoint to enable + /// The breakpoint to enable. /// [Parameter(ParameterSetName = "Breakpoint", ValueFromPipeline = true, Position = 0, Mandatory = true)] [ValidateNotNull] @@ -25,15 +24,17 @@ public Breakpoint[] Breakpoint { return _breakpoints; } + set { _breakpoints = value; } } + private Breakpoint[] _breakpoints; /// - /// The Id of the breakpoint to enable + /// The Id of the breakpoint to enable. /// [Parameter(ParameterSetName = "Id", ValueFromPipelineByPropertyName = true, Position = 0, Mandatory = true)] [ValidateNotNull] @@ -43,6 +44,7 @@ public int[] Id { return _ids; } + set { _ids = value; @@ -52,7 +54,7 @@ public int[] Id private int[] _ids; /// - /// Gathers the list of breakpoints to process and calls ProcessBreakpoints + /// Gathers the list of breakpoints to process and calls ProcessBreakpoints. /// protected override void ProcessRecord() { @@ -94,7 +96,7 @@ protected override void ProcessRecord() } /// - /// Process the given breakpoint + /// Process the given breakpoint. /// protected abstract void ProcessBreakpoint(Breakpoint breakpoint); @@ -114,7 +116,7 @@ private bool ShouldProcessInternal(string target) } /// - /// This class implements Enable-PSBreakpoint + /// This class implements Enable-PSBreakpoint. /// [Cmdlet(VerbsLifecycle.Enable, "PSBreakpoint", SupportsShouldProcess = true, DefaultParameterSetName = "Id", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113295")] [OutputType(typeof(Breakpoint))] @@ -131,6 +133,7 @@ public SwitchParameter PassThru { return _passThru; } + set { _passThru = value; @@ -140,7 +143,7 @@ public SwitchParameter PassThru private bool _passThru; /// - /// Enables the given breakpoint + /// Enables the given breakpoint. /// protected override void ProcessBreakpoint(Breakpoint breakpoint) { @@ -152,4 +155,4 @@ protected override void ProcessBreakpoint(Breakpoint breakpoint) } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs index acfd146caa62..a9192ae2da9f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -15,7 +14,7 @@ namespace Microsoft.PowerShell.Commands #region PSRunspaceDebug class /// - /// Runspace Debug Options class + /// Runspace Debug Options class. /// public sealed class PSRunspaceDebug { @@ -70,10 +69,10 @@ public int RunspaceId /// /// Constructor. /// - /// Enable debugger option - /// BreakAll option - /// Runspace name - /// Runspace local Id + /// Enable debugger option. + /// BreakAll option. + /// Runspace name. + /// Runspace local Id. public PSRunspaceDebug(bool enabled, bool breakAll, string runspaceName, int runspaceId) { if (string.IsNullOrEmpty(runspaceName)) { throw new PSArgumentNullException("runspaceName"); } @@ -99,27 +98,27 @@ public abstract class CommonRunspaceCommandBase : PSCmdlet #region Strings /// - /// RunspaceParameterSet + /// RunspaceParameterSet. /// protected const string RunspaceParameterSet = "RunspaceParameterSet"; /// - /// RunspaceNameParameterSet + /// RunspaceNameParameterSet. /// protected const string RunspaceNameParameterSet = "RunspaceNameParameterSet"; /// - /// RunspaceIdParameterSet + /// RunspaceIdParameterSet. /// protected const string RunspaceIdParameterSet = "RunspaceIdParameterSet"; /// - /// RunspaceInstanceIdParameterSet + /// RunspaceInstanceIdParameterSet. /// protected const string RunspaceInstanceIdParameterSet = "RunspaceInstanceIdParameterSet"; /// - /// ProcessNameParameterSet + /// ProcessNameParameterSet. /// protected const string ProcessNameParameterSet = "ProcessNameParameterSet"; @@ -128,7 +127,7 @@ public abstract class CommonRunspaceCommandBase : PSCmdlet #region Parameters /// - /// Runspace Name + /// Runspace Name. /// [Parameter(Position = 0, ParameterSetName = CommonRunspaceCommandBase.RunspaceNameParameterSet)] @@ -141,7 +140,7 @@ public string[] RunspaceName } /// - /// Runspace + /// Runspace. /// [Parameter(Position = 0, Mandatory = true, @@ -157,7 +156,7 @@ public Runspace[] Runspace } /// - /// Runspace Id + /// Runspace Id. /// [Parameter(Position = 0, Mandatory = true, @@ -170,7 +169,7 @@ public int[] RunspaceId set; } /// - /// RunspaceInstanceId + /// RunspaceInstanceId. /// [Parameter(Position = 0, Mandatory = true, @@ -214,7 +213,7 @@ public string[] AppDomainName /// /// Returns a list of valid runspaces based on current parameter set. /// - /// IReadOnlyList + /// IReadOnlyList. protected IReadOnlyList GetRunspaces() { IReadOnlyList results = null; @@ -249,10 +248,10 @@ protected IReadOnlyList GetRunspaces() } /// - /// Returns Runspace Debugger + /// Returns Runspace Debugger. /// - /// Runspace - /// Debugger + /// Runspace. + /// Debugger. protected System.Management.Automation.Debugger GetDebuggerFromRunspace(Runspace runspace) { System.Management.Automation.Debugger debugger = null; @@ -279,8 +278,8 @@ protected System.Management.Automation.Debugger GetDebuggerFromRunspace(Runspace /// /// SetDebugPreferenceHelper is a helper method used to enable/disable debug preference. /// - /// Process Name - /// App Domain Name + /// Process Name. + /// App Domain Name. /// Indicates if debug preference has to be enabled or disabled. /// FullyQualifiedErrorId to be used on error. protected void SetDebugPreferenceHelper(string processName, string[] appDomainName, bool enable, string fullyQualifiedErrorId) @@ -296,6 +295,7 @@ protected void SetDebugPreferenceHelper(string processName, string[] appDomainNa { appDomainNames = new List(); } + appDomainNames.Add(currentAppDomainName.ToLowerInvariant()); } } @@ -350,70 +350,89 @@ public SwitchParameter BreakAll set; } + /// + /// Gets or sets the optional breakpoint objects to use for debugging. + /// + [Experimental("Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints", ExperimentAction.Show)] + [Parameter(Position = 1, + ParameterSetName = CommonRunspaceCommandBase.RunspaceParameterSet)] + [Parameter(Position = 1, + ParameterSetName = CommonRunspaceCommandBase.RunspaceNameParameterSet)] + [Parameter(Position = 1, + ParameterSetName = CommonRunspaceCommandBase.RunspaceIdParameterSet)] + public Breakpoint[] Breakpoint + { + get; + set; + } + #endregion #region Overrides /// - /// Process Record + /// Process Record. /// protected override void ProcessRecord() { if (this.ParameterSetName.Equals(CommonRunspaceCommandBase.ProcessNameParameterSet)) { SetDebugPreferenceHelper(ProcessName, AppDomainName, true, "EnableRunspaceDebugCommandPersistDebugPreferenceFailure"); + return; } - else - { - IReadOnlyList results = GetRunspaces(); - foreach (var runspace in results) + IReadOnlyList results = GetRunspaces(); + + foreach (var runspace in results) + { + if (runspace.RunspaceStateInfo.State != RunspaceState.Opened) { - if (runspace.RunspaceStateInfo.State != RunspaceState.Opened) - { - WriteError( - new ErrorRecord(new PSInvalidOperationException(string.Format(CultureInfo.InvariantCulture, Debugger.RunspaceOptionInvalidRunspaceState, runspace.Name)), - "SetRunspaceDebugOptionCommandInvalidRunspaceState", - ErrorCategory.InvalidOperation, - this) - ); + WriteError( + new ErrorRecord(new PSInvalidOperationException(string.Format(CultureInfo.InvariantCulture, Debugger.RunspaceOptionInvalidRunspaceState, runspace.Name)), + "SetRunspaceDebugOptionCommandInvalidRunspaceState", + ErrorCategory.InvalidOperation, + this)); - continue; - } + continue; + } - System.Management.Automation.Debugger debugger = GetDebuggerFromRunspace(runspace); - if (debugger == null) - { - continue; - } + System.Management.Automation.Debugger debugger = GetDebuggerFromRunspace(runspace); + if (debugger == null) + { + continue; + } - // Enable debugging by preserving debug stop events. - debugger.UnhandledBreakpointMode = UnhandledBreakpointProcessingMode.Wait; + // Enable debugging by preserving debug stop events. + debugger.UnhandledBreakpointMode = UnhandledBreakpointProcessingMode.Wait; - if (this.MyInvocation.BoundParameters.ContainsKey("BreakAll")) + if (this.MyInvocation.BoundParameters.ContainsKey(nameof(BreakAll))) + { + if (BreakAll) { - if (BreakAll) + try { - try - { - debugger.SetDebuggerStepMode(true); - } - catch (PSInvalidOperationException e) - { - WriteError( - new ErrorRecord( - e, - "SetRunspaceDebugOptionCommandCannotEnableDebuggerStepping", - ErrorCategory.InvalidOperation, - this) - ); - } + debugger.SetDebuggerStepMode(true); } - else + catch (PSInvalidOperationException e) { - debugger.SetDebuggerStepMode(false); + WriteError( + new ErrorRecord( + e, + "SetRunspaceDebugOptionCommandCannotEnableDebuggerStepping", + ErrorCategory.InvalidOperation, + this)); } } + else + { + debugger.SetDebuggerStepMode(false); + } + } + + // If any breakpoints were provided, set those in the debugger. + if (Breakpoint?.Length > 0) + { + debugger.SetBreakpoints(Breakpoint); } } } @@ -435,7 +454,7 @@ public sealed class DisableRunspaceDebugCommand : CommonRunspaceCommandBase #region Overrides /// - /// Process Record + /// Process Record. /// protected override void ProcessRecord() { @@ -492,7 +511,7 @@ public sealed class GetRunspaceDebugCommand : CommonRunspaceCommandBase #region Overrides /// - /// Process Record + /// Process Record. /// protected override void ProcessRecord() { @@ -530,25 +549,17 @@ public sealed class WaitDebuggerCommand : PSCmdlet #region Overrides /// - /// EndProcessing + /// EndProcessing. /// protected override void EndProcessing() { Runspace currentRunspace = this.Context.CurrentRunspace; - if ((currentRunspace != null) && (currentRunspace.Debugger != null)) + if (currentRunspace != null && currentRunspace.Debugger != null) { - if (!currentRunspace.Debugger.IsDebugHandlerSubscribed && - (currentRunspace.Debugger.UnhandledBreakpointMode == UnhandledBreakpointProcessingMode.Ignore)) - { - // No debugger attached and runspace debugging is not enabled. Enable runspace debugging here - // so that this command is effective. - currentRunspace.Debugger.UnhandledBreakpointMode = UnhandledBreakpointProcessingMode.Wait; - } - - // Set debugger to step mode so that a break occurs immediately. - currentRunspace.Debugger.SetDebuggerStepMode(true); WriteVerbose(string.Format(CultureInfo.InvariantCulture, Debugger.DebugBreakMessage, MyInvocation.ScriptLineNumber, MyInvocation.ScriptName)); + + currentRunspace.Debugger.Break(); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ExportAliasCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ExportAliasCommand.cs index c83b2272c2c2..489b57c736a3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ExportAliasCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ExportAliasCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -12,25 +11,24 @@ namespace Microsoft.PowerShell.Commands { /// - /// The formats that export-alias supports + /// The formats that export-alias supports. /// public enum ExportAliasFormat { /// - /// Aliases will be exported to a CSV file + /// Aliases will be exported to a CSV file. /// Csv, /// - /// Aliases will be exported as an MSH script + /// Aliases will be exported as an MSH script. /// Script } /// - /// The implementation of the "export-alias" cmdlet + /// The implementation of the "export-alias" cmdlet. /// - /// [Cmdlet(VerbsData.Export, "Alias", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113296")] [OutputType(typeof(AliasInfo))] public class ExportAliasCommand : PSCmdlet @@ -40,24 +38,25 @@ public class ExportAliasCommand : PSCmdlet /// /// The Path of the file to export the aliases to. /// - /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "ByPath")] public string Path { get { return _path; } + set { _path = value ?? "."; } } + private string _path = "."; /// /// The literal path of the file to export the aliases to. /// - /// [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { get { return _path; } + set { if (value == null) @@ -71,25 +70,25 @@ public string LiteralPath } } } + private bool _isLiteralPath = false; /// - /// The Name parameter for the command + /// The Name parameter for the command. /// - /// [Parameter(Position = 1, ValueFromPipelineByPropertyName = true)] public string[] Name { get { return _names; } + set { _names = value ?? new string[] { "*" }; } } + private string[] _names = new string[] { "*" }; /// - /// If set to true, the alias that is set is passed to the - /// pipeline. + /// If set to true, the alias that is set is passed to the pipeline. /// - /// [Parameter] public SwitchParameter PassThru { @@ -103,12 +102,12 @@ public SwitchParameter PassThru _passThru = value; } } + private bool _passThru; /// /// Parameter that determines the format of the file created. /// - /// [Parameter] public ExportAliasFormat As { get; set; } = ExportAliasFormat.Csv; @@ -122,11 +121,13 @@ public SwitchParameter Append { return _append; } + set { _append = value; } } + private bool _append; /// @@ -139,11 +140,13 @@ public SwitchParameter Force { return _force; } + set { _force = value; } } + private bool _force; /// @@ -157,15 +160,17 @@ public SwitchParameter NoClobber { return _noclobber; } + set { _noclobber = value; } } + private bool _noclobber; /// - /// The description that gets added to the file as a comment + /// The description that gets added to the file as a comment. /// /// [Parameter] @@ -175,7 +180,6 @@ public SwitchParameter NoClobber /// The scope parameter for the command determines /// which scope the aliases are retrieved from. /// - /// [Parameter] public string Scope { get; set; } @@ -186,13 +190,12 @@ public SwitchParameter NoClobber /// /// The main processing loop of the command. /// - /// protected override void ProcessRecord() { // First get the alias table (from the proper scope if necessary) IDictionary aliasTable = null; - if (!String.IsNullOrEmpty(Scope)) + if (!string.IsNullOrEmpty(Scope)) { // This can throw PSArgumentException and PSArgumentOutOfRangeException // but just let them go as this is terminal for the pipeline and the @@ -252,11 +255,10 @@ protected override void ProcessRecord() itemNotFound)); } } - } // ProcessRecord - + } /// - /// Writes the aliases to the file + /// Writes the aliases to the file. /// protected override void EndProcessing() { @@ -269,7 +271,7 @@ protected override void EndProcessing() writer = OpenFile(out readOnlyFileInfo); } - if (null != writer) + if (writer != null) WriteHeader(writer); // Now write out the aliases @@ -286,7 +288,7 @@ protected override void EndProcessing() line = GetAliasLine(alias, "set-alias -Name:\"{0}\" -Value:\"{1}\" -Description:\"{2}\" -Option:\"{3}\""); } - if (null != writer) + if (writer != null) writer.WriteLine(line); if (PassThru) @@ -297,16 +299,16 @@ protected override void EndProcessing() } finally { - if (null != writer) + if (writer != null) writer.Dispose(); // reset the read-only attribute - if (null != readOnlyFileInfo) + if (readOnlyFileInfo != null) readOnlyFileInfo.Attributes |= FileAttributes.ReadOnly; } } /// - /// Holds all the matching aliases for writing to the file + /// Holds all the matching aliases for writing to the file. /// private Collection _matchingAliases = new Collection(); @@ -316,7 +318,7 @@ private static string GetAliasLine(AliasInfo alias, string formatString) // file to vary based on locale. string result = - String.Format( + string.Format( System.Globalization.CultureInfo.InvariantCulture, formatString, alias.Name, @@ -327,7 +329,6 @@ private static string GetAliasLine(AliasInfo alias, string formatString) return result; } - private void WriteHeader(StreamWriter writer) { WriteFormattedResourceString(writer, AliasCommandStrings.ExportAliasHeaderTitle); @@ -370,7 +371,7 @@ private void WriteHeader(StreamWriter writer) } /// - /// Open the file to which aliases should be exported + /// Open the file to which aliases should be exported. /// /// /// If not null, this is the file whose read-only attribute @@ -416,6 +417,5 @@ private void ThrowFileOpenError(Exception e, string pathWithError) } #endregion Command code - } // class ExportAliasCommand -}//Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs index ad398a7e766a..9536f3d399ae 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Management.Automation; +using System.Management.Automation.Internal; namespace Microsoft.PowerShell.Commands { - using System; - using System.Management.Automation; - using System.Management.Automation.Internal; - internal abstract class ColumnInfo { protected string displayName; @@ -29,7 +28,7 @@ internal string DisplayName() return this.displayName; } - internal abstract Object GetValue(PSObject liveObject); + internal abstract object GetValue(PSObject liveObject); internal Type GetValueType(PSObject liveObject, out object columnValue) { @@ -38,14 +37,15 @@ internal Type GetValueType(PSObject liveObject, out object columnValue) { return columnValue.GetType(); } + return typeof(string); // Use the String type as default. } /// - /// Auxiliar used in GetValue methods since the list does not deal well with unlimited sized lines + /// Auxiliar used in GetValue methods since the list does not deal well with unlimited sized lines. /// - /// source string - /// the source string limited in the number of lines + /// Source string. + /// The source string limited in the number of lines. internal static object LimitString(object src) { string srcString = src as string; @@ -57,4 +57,4 @@ internal static object LimitString(object src) return HostUtilities.GetMaxLines(srcString, 10); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs index d0a4221fd811..113ba0ffabb4 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs @@ -1,27 +1,27 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Management.Automation; + +using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { - using System; - using System.Collections.Generic; - using System.Management.Automation; - using Microsoft.PowerShell.Commands.Internal.Format; - internal class ExpressionColumnInfo : ColumnInfo { - private MshExpression _expression; + private PSPropertyExpression _expression; - internal ExpressionColumnInfo(string staleObjectPropertyName, string displayName, MshExpression expression) + internal ExpressionColumnInfo(string staleObjectPropertyName, string displayName, PSPropertyExpression expression) : base(staleObjectPropertyName, displayName) { _expression = expression; } - internal override Object GetValue(PSObject liveObject) + internal override object GetValue(PSObject liveObject) { - List resList = _expression.GetValues(liveObject); + List resList = _expression.GetValues(liveObject); if (resList.Count == 0) { @@ -29,14 +29,14 @@ internal override Object GetValue(PSObject liveObject) } // Only first element is used. - MshExpressionResult result = resList[0]; + PSPropertyExpressionResult result = resList[0]; if (result.Exception != null) { return null; } object objectResult = result.Result; - return objectResult == null ? String.Empty : ColumnInfo.LimitString(objectResult.ToString()); + return objectResult == null ? string.Empty : ColumnInfo.LimitString(objectResult.ToString()); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs index 0def6c0b648d..32a61eb1f36c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands { - using System; - using System.Collections.Generic; - using System.Management.Automation; - internal class HeaderInfo { private List _columns = new List(); @@ -32,7 +31,7 @@ internal PSObject AddColumnsToWindow(OutWindowProxy windowProxy, PSObject liveOb { propertyNames[count] = column.StaleObjectPropertyName(); displayNames[count] = column.DisplayName(); - Object columnValue = null; + object columnValue = null; types[count] = column.GetValueType(liveObject, out columnValue); // Add a property to the stale object since a column value has been evaluated to get column's type. @@ -55,7 +54,8 @@ internal PSObject CreateStalePSObject(PSObject liveObject) staleObject.Properties.Add(new PSNoteProperty(column.StaleObjectPropertyName(), column.GetValue(liveObject))); } + return staleObject; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs index 7329ed8117e7..5caeaf5758be 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs @@ -1,14 +1,14 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Management.Automation; + +using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { - using System; - using System.Collections; - using System.Management.Automation; - using Microsoft.PowerShell.Commands.Internal.Format; - internal class OriginalColumnInfo : ColumnInfo { private string _liveObjectPropertyName; @@ -21,7 +21,7 @@ internal OriginalColumnInfo(string staleObjectPropertyName, string displayName, _parentCmdlet = parentCmdlet; } - internal override Object GetValue(PSObject liveObject) + internal override object GetValue(PSObject liveObject) { try { @@ -32,9 +32,9 @@ internal override Object GetValue(PSObject liveObject) } // The live object has the liveObjectPropertyName property. - Object liveObjectValue = propertyInfo.Value; + object liveObjectValue = propertyInfo.Value; ICollection collectionValue = liveObjectValue as ICollection; - if (null != collectionValue) + if (collectionValue != null) { liveObjectValue = _parentCmdlet.ConvertToString(PSObjectHelper.AsPSObject(propertyInfo.Value)); } @@ -66,6 +66,7 @@ internal override Object GetValue(PSObject liveObject) { // ignore } + return null; } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs index e3f013dd78a7..e1c26880df7c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs @@ -1,18 +1,17 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. -namespace Microsoft.PowerShell.Commands -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Management.Automation; - using System.Management.Automation.Internal; - using System.Management.Automation.Runspaces; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Management.Automation.Runspaces; - using Microsoft.PowerShell.Commands.Internal.Format; +using Microsoft.PowerShell.Commands.Internal.Format; +namespace Microsoft.PowerShell.Commands +{ /// /// Enum for SelectionMode parameter. /// @@ -21,7 +20,7 @@ public enum OutputModeOption /// /// None is the default and it means OK and Cancel will not be present /// and no objects will be written to the pipeline. - /// The selectionMode of the actual list will still be multiple + /// The selectionMode of the actual list will still be multiple. /// None, /// @@ -35,7 +34,7 @@ public enum OutputModeOption } /// - /// Implementation for the Out-GridView command + /// Implementation for the Out-GridView command. /// [Cmdlet(VerbsData.Out, "GridView", DefaultParameterSetName = "PassThru", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113364")] public class OutGridViewCommand : PSCmdlet, IDisposable @@ -45,7 +44,7 @@ public class OutGridViewCommand : PSCmdlet, IDisposable private const string DataNotQualifiedForGridView = "DataNotQualifiedForGridView"; private const string RemotingNotSupported = "RemotingNotSupported"; private TypeInfoDataBase _typeInfoDataBase; - private MshExpressionFactory _expressionFactory; + private PSPropertyExpressionFactory _expressionFactory; private OutWindowProxy _windowProxy; private GridHeader _gridHeader; @@ -54,7 +53,7 @@ public class OutGridViewCommand : PSCmdlet, IDisposable #region Constructors /// - /// Constructor for OutGridView + /// Constructor for OutGridView. /// public OutGridViewCommand() { @@ -65,7 +64,7 @@ public OutGridViewCommand() #region Input Parameters /// - /// This parameter specifies the current pipeline object + /// This parameter specifies the current pipeline object. /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { get; set; } = AutomationNull.Value; @@ -78,26 +77,27 @@ public OutGridViewCommand() public string Title { get; set; } /// - /// Get or sets a value indicating whether the cmdlet should wait for the window to be closed + /// Get or sets a value indicating whether the cmdlet should wait for the window to be closed. /// [Parameter(ParameterSetName = "Wait")] public SwitchParameter Wait { get; set; } /// /// Get or sets a value indicating whether the selected items should be written to the pipeline - /// and if it should be possible to select multiple or single list items + /// and if it should be possible to select multiple or single list items. /// [Parameter(ParameterSetName = "OutputMode")] public OutputModeOption OutputMode { set; get; } /// - /// Gets or sets a value indicating whether the selected items should be written to the pipeline - /// Setting this to true is the same as setting the OutputMode to Multiple + /// Gets or sets a value indicating whether the selected items should be written to the pipeline. + /// Setting this to true is the same as setting the OutputMode to Multiple. /// [Parameter(ParameterSetName = "PassThru")] public SwitchParameter PassThru { set { this.OutputMode = value.IsPresent ? OutputModeOption.Multiple : OutputModeOption.None; } + get { return OutputMode == OutputModeOption.Multiple ? new SwitchParameter(true) : new SwitchParameter(false); } } @@ -111,7 +111,7 @@ public SwitchParameter PassThru protected override void BeginProcessing() { // Set up the ExpressionFactory - _expressionFactory = new MshExpressionFactory(); + _expressionFactory = new PSPropertyExpressionFactory(); // If the value of the Title parameter is valid, use it as a window's title. if (this.Title != null) @@ -129,7 +129,7 @@ protected override void BeginProcessing() } /// - /// Blocks depending on the wait and selected + /// Blocks depending on the wait and selected. /// protected override void EndProcessing() { @@ -227,6 +227,7 @@ internal string ConvertToString(PSObject liveObject) liveObject) ); } + return smartToString; } @@ -235,9 +236,9 @@ internal string ConvertToString(PSObject liveObject) #region Private Methods /// - /// Execute formatting on a single object + /// Execute formatting on a single object. /// - /// object to process + /// Object to process. private void ProcessObject(PSObject input) { // Make sure the OGV window is not closed. @@ -250,10 +251,11 @@ private void ProcessObject(PSObject input) // Stop the pipeline cleanly. pipeline.StopAsync(); } + return; } - Object baseObject = input.BaseObject; + object baseObject = input.BaseObject; // Throw a terminating error for types that are not supported. if (baseObject is ScriptBlock || @@ -314,6 +316,7 @@ internal static GridHeader ConstructGridHeader(PSObject input, OutGridViewComman { return new ScalarTypeHeader(parentCmd, input); } + return new NonscalarTypeHeader(parentCmd, input); } @@ -382,6 +385,7 @@ internal NonscalarTypeHeader(OutGridViewCommand parentCmd, PSObject input) : bas { break; } + _appliesTo.AddAppliesToType(typeName); index++; } @@ -464,9 +468,9 @@ internal override void ProcessInputObject(PSObject input) } /// - /// Implements IDisposable logic + /// Implements IDisposable logic. /// - /// true if being called from Dispose + /// True if being called from Dispose. private void Dispose(bool isDisposing) { if (isDisposing) @@ -480,7 +484,7 @@ private void Dispose(bool isDisposing) } /// - /// Dispose method in IDisposable + /// Dispose method in IDisposable. /// public void Dispose() { @@ -489,7 +493,7 @@ public void Dispose() } /// - /// Finalizer + /// Finalizer. /// ~OutGridViewCommand() { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs index f6e929c5a4d9..cefb5540e87c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs @@ -1,18 +1,18 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Reflection; +using System.Threading; + +using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { - using System; - using System.Collections.Generic; - using System.IO; - using System.Threading; - using System.Reflection; - using System.Management.Automation; - using System.Management.Automation.Internal; - using Microsoft.PowerShell.Commands.Internal.Format; - internal class OutWindowProxy : IDisposable { private const string OutGridViewWindowClassName = "Microsoft.Management.UI.Internal.OutGridViewWindow"; @@ -22,7 +22,6 @@ internal class OutWindowProxy : IDisposable private const string IndexPropertyName = "IndexValue"; private int _index; - /// Columns definition of the underlying Management List private HeaderInfo _headerInfo; @@ -58,15 +57,17 @@ internal OutWindowProxy(string title, OutputModeOption outPutMode, OutGridViewCo /// An array of types to add. internal void AddColumns(string[] propertyNames, string[] displayNames, Type[] types) { - if (null == propertyNames) + if (propertyNames == null) { throw new ArgumentNullException("propertyNames"); } - if (null == displayNames) + + if (displayNames == null) { throw new ArgumentNullException("displayNames"); } - if (null == types) + + if (types == null) { throw new ArgumentNullException("types"); } @@ -175,7 +176,7 @@ private void AddExtraProperties(PSObject staleObject, PSObject liveObject) /// internal void AddItem(PSObject livePSObject) { - if (null == livePSObject) + if (livePSObject == null) { throw new ArgumentNullException("livePSObject"); } @@ -201,7 +202,7 @@ internal void AddItem(PSObject livePSObject) /// internal void AddHeteroViewItem(PSObject livePSObject) { - if (null == livePSObject) + if (livePSObject == null) { throw new ArgumentNullException("livePSObject"); } @@ -237,9 +238,9 @@ internal void BlockUntillClosed() } /// - /// Implements IDisposable logic + /// Implements IDisposable logic. /// - /// true if being called from Dispose + /// True if being called from Dispose. private void Dispose(bool isDisposing) { if (isDisposing) @@ -253,7 +254,7 @@ private void Dispose(bool isDisposing) } /// - /// Dispose method in IDisposable + /// Dispose method in IDisposable. /// public void Dispose() { @@ -261,8 +262,6 @@ public void Dispose() GC.SuppressFinalize(this); } - - /// /// Close the window if it has already been displayed. /// @@ -297,7 +296,7 @@ internal Exception GetLastException() /// Return the selected item of the OutGridView. /// /// - /// The selected item + /// The selected item. /// internal List GetSelectedItems() { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs index 62195903f2df..75adcd3cf421 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs @@ -1,12 +1,11 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands { - using System.Management.Automation; - using System; - internal class ScalarTypeColumnInfo : ColumnInfo { private Type _type; @@ -17,7 +16,7 @@ internal ScalarTypeColumnInfo(Type type) _type = type; } - internal override Object GetValue(PSObject liveObject) + internal override object GetValue(PSObject liveObject) { // Strip a wrapping PSObject. object baseObject = ((PSObject)liveObject).BaseObject; @@ -25,6 +24,7 @@ internal override Object GetValue(PSObject liveObject) { return ColumnInfo.LimitString(baseObject); } + return null; } } @@ -35,7 +35,7 @@ internal TypeNameColumnInfo(string staleObjectPropertyName, string displayName) : base(staleObjectPropertyName, displayName) { } - internal override Object GetValue(PSObject liveObject) + internal override object GetValue(PSObject liveObject) { // Strip a wrapping PSObject. object baseObject = ((PSObject)liveObject).BaseObject; @@ -53,7 +53,7 @@ internal ToStringColumnInfo(string staleObjectPropertyName, string displayName, _parentCmdlet = parentCmdlet; } - internal override Object GetValue(PSObject liveObject) + internal override object GetValue(PSObject liveObject) { // Convert to a string preserving PowerShell formatting. return ColumnInfo.LimitString(_parentCmdlet.ConvertToString(liveObject)); @@ -70,10 +70,10 @@ internal IndexColumnInfo(string staleObjectPropertyName, string displayName, int _index = index; } - internal override Object GetValue(PSObject liveObject) + internal override object GetValue(PSObject liveObject) { // Every time this method is called, another raw is added to ML. return _index++; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs index 062d5571903b..7dfda541d777 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs @@ -1,24 +1,24 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; + +using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Management.Automation; - using System.Management.Automation.Internal; - using Microsoft.PowerShell.Commands.Internal.Format; - using System.IO; - internal class TableView { - private MshExpressionFactory _expressionFactory; + private PSPropertyExpressionFactory _expressionFactory; private TypeInfoDataBase _typeInfoDatabase; private FormatErrorManager _errorManager; - internal void Initialize(MshExpressionFactory expressionFactory, + internal void Initialize(PSPropertyExpressionFactory expressionFactory, TypeInfoDataBase db) { _expressionFactory = expressionFactory; @@ -77,9 +77,10 @@ internal HeaderInfo GenerateHeaderInfo(PSObject input, TableControlBody tableBod // Database does not provide a label(DisplayName) for the current property, use the expression value instead. displayName = fpt.expression.expressionValue; } + if (fpt.expression.isScriptBlock) { - MshExpression ex = _expressionFactory.CreateFromExpressionToken(fpt.expression); + PSPropertyExpression ex = _expressionFactory.CreateFromExpressionToken(fpt.expression); // Using the displayName as a propertyName for a stale PSObject. const string LastWriteTimePropertyName = "LastWriteTime"; @@ -108,10 +109,12 @@ internal HeaderInfo GenerateHeaderInfo(PSObject input, TableControlBody tableBod } } } + if (columnInfo != null) { headerInfo.AddColumn(columnInfo); } + col++; } } @@ -133,7 +136,7 @@ internal HeaderInfo GenerateHeaderInfo(PSObject input, OutGridViewCommand parent if (PSObjectHelper.ShouldShowComputerNameProperty(input)) { activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, - new MshExpression(RemotingConstants.ComputerNameNoteProperty))); + new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty))); } } else @@ -166,14 +169,17 @@ internal HeaderInfo GenerateHeaderInfo(PSObject input, OutGridViewCommand parent if (key != AutomationNull.Value) propertyName = (string)key; } + if (propertyName == null) { propertyName = association.ResolvedExpression.ToString(); } + ColumnInfo columnInfo = new OriginalColumnInfo(propertyName, propertyName, propertyName, parentCmdlet); headerInfo.AddColumn(columnInfo); } + return headerInfo; } @@ -226,6 +232,7 @@ private List GetActiveTableRowDefinition(TableControlBod break; } } + if (matchingRowDefinition == null) { matchingRowDefinition = match.BestMatch as TableRowDefinition; @@ -234,7 +241,7 @@ private List GetActiveTableRowDefinition(TableControlBod if (matchingRowDefinition == null) { Collection typesWithoutPrefix = Deserializer.MaskDeserializationPrefix(typeNames); - if (null != typesWithoutPrefix) + if (typesWithoutPrefix != null) { match = new TypeMatch(_expressionFactory, _typeInfoDatabase, typesWithoutPrefix); @@ -246,6 +253,7 @@ private List GetActiveTableRowDefinition(TableControlBod break; } } + if (matchingRowDefinition == null) { matchingRowDefinition = match.BestMatch as TableRowDefinition; @@ -275,6 +283,7 @@ private List GetActiveTableRowDefinition(TableControlBod // Use the override activeRowItemDefinitionList.Add(rowItem); } + col++; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/GetFormatDataCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/GetFormatDataCommand.cs index e8c9142b91d8..4076327fe553 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/GetFormatDataCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/GetFormatDataCommand.cs @@ -1,20 +1,19 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Linq; -using System.Management.Automation; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Management.Automation; using System.Management.Automation.Runspaces; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// Gets formatting information from the loading - /// format information database + /// Gets formatting information from the loading format information database. /// /// Currently supports only table controls /// @@ -26,25 +25,25 @@ public class GetFormatDataCommand : PSCmdlet private WildcardPattern[] _filter = new WildcardPattern[1]; /// - /// Get Formatting information only for the specified - /// typename + /// Get Formatting information only for the specified typename. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [ValidateNotNullOrEmpty] [Parameter(Position = 0)] - public String[] TypeName + public string[] TypeName { get { return _typename; } + set { _typename = value; if (_typename == null) { - _filter = Utils.EmptyArray(); + _filter = Array.Empty(); } else { @@ -66,7 +65,7 @@ public String[] TypeName public Version PowerShellVersion { get; set; } /// - /// set the default filter + /// Set the default filter. /// protected override void BeginProcessing() { @@ -76,7 +75,6 @@ protected override void BeginProcessing() } } - private static Dictionary> GetTypeGroupMap(IEnumerable groupDefinitions) { var typeGroupMap = new Dictionary>(); @@ -95,14 +93,13 @@ protected override void BeginProcessing() } /// - /// Takes out the content from the database and writes them - /// out + /// Takes out the content from the database and writes them out. /// protected override void ProcessRecord() { bool writeOldWay = PowerShellVersion == null || PowerShellVersion.Major < 5 || - PowerShellVersion.Build < 11086; + (PowerShellVersion.Major == 5 && PowerShellVersion.Minor < 1); TypeInfoDataBase db = this.Context.FormatDBManager.Database; @@ -171,8 +168,9 @@ protected override void ProcessRecord() viewList = new List(); typedefs.Add(consolidatedTypeName, viewList); } + viewList.Add(formatdef); - }// foreach(ViewDefinition... + } // write out all the available type definitions foreach (var pair in typedefs) @@ -194,6 +192,7 @@ protected override void ProcessRecord() { etd.TypeNames.Add(typeNames[i]); } + WriteObject(etd); } } @@ -224,6 +223,7 @@ private static ConsolidatedString CreateConsolidatedTypeName(ViewDefinition defi consolidatedTypeName.Add(item.name); } } + return consolidatedTypeName; } @@ -239,6 +239,7 @@ private bool ShouldGenerateView(ConsolidatedString consolidatedTypeName) } } } + return false; } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/WriteFormatDataCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/WriteFormatDataCommand.cs index 609253074fdd..91ba42aa4985 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/WriteFormatDataCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/common/WriteFormatDataCommand.cs @@ -1,17 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// Cmdlet used to write a collection of formatting directives to - /// an XML file + /// Cmdlet used to write a collection of formatting directives to an XML file. /// [Cmdlet(VerbsData.Export, "FormatData", DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=144302")] public class ExportFormatDataCommand : PSCmdlet @@ -19,7 +17,7 @@ public class ExportFormatDataCommand : PSCmdlet private ExtendedTypeDefinition[] _typeDefinition; /// - /// type definition to include in export + /// Type definition to include in export. /// [Parameter(Mandatory = true, ValueFromPipeline = true)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] @@ -29,6 +27,7 @@ public ExtendedTypeDefinition[] InputObject { return _typeDefinition; } + set { _typeDefinition = value; @@ -38,16 +37,17 @@ public ExtendedTypeDefinition[] InputObject private string _filepath; /// - /// Path of the XML file + /// Path of the XML file. /// [Parameter(ParameterSetName = "ByPath", Mandatory = true)] [Alias("FilePath")] - public String Path + public string Path { get { return _filepath; } + set { _filepath = value; @@ -55,22 +55,24 @@ public String Path } /// - /// Literal path of the XML file + /// Literal path of the XML file. /// [Parameter(ParameterSetName = "ByLiteralPath", Mandatory = true)] - [Alias("PSPath")] - public String LiteralPath + [Alias("PSPath", "LP")] + public string LiteralPath { get { return _filepath; } + set { _filepath = value; _isLiteralPath = true; } } + private bool _isLiteralPath = false; private List _typeDefinitions = new List(); @@ -78,7 +80,7 @@ public String LiteralPath private bool _force; /// - /// Force writing a file + /// Force writing a file. /// [Parameter()] public SwitchParameter Force @@ -87,6 +89,7 @@ public SwitchParameter Force { return _force; } + set { _force = value; @@ -94,7 +97,7 @@ public SwitchParameter Force } /// - /// Do not overwrite file if exists + /// Do not overwrite file if exists. /// [Parameter()] [Alias("NoOverwrite")] @@ -104,15 +107,17 @@ public SwitchParameter NoClobber { return _noclobber; } + set { _noclobber = value; } } + private bool _noclobber; /// - /// Include scriptblocks for export + /// Include scriptblocks for export. /// [Parameter()] public SwitchParameter IncludeScriptBlock @@ -121,15 +126,17 @@ public SwitchParameter IncludeScriptBlock { return _includescriptblock; } + set { _includescriptblock = value; } } + private bool _includescriptblock; /// - /// Adds the type to the collection + /// Adds the type to the collection. /// protected override void ProcessRecord() { @@ -140,8 +147,8 @@ protected override void ProcessRecord() } /// - /// writes out the formatting directives from the - /// collection to the specified XML file + /// Writes out the formatting directives from the + /// collection to the specified XML file. /// protected override void EndProcessing() { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs index bc90a9536bad..6bb1f37a9cd2 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs @@ -1,20 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; +using System.Collections.Generic; using System.IO; -using System.Text; -using System.Security; using System.Management.Automation; -using System.Collections.Generic; using System.Management.Automation.Internal; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; // Once Serialization is available on CoreCLR: using System.Runtime.Serialization.Formatters.Binary; namespace Microsoft.PowerShell.Commands { /// - /// Displays the hexidecimal equivalent of the input data. + /// Displays the hexadecimal equivalent of the input data. /// - [Cmdlet(VerbsCommon.Format, "Hex", SupportsShouldProcess = true, HelpUri ="https://go.microsoft.com/fwlink/?LinkId=526919")] + [Cmdlet(VerbsCommon.Format, "Hex", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526919")] [OutputType(typeof(Microsoft.PowerShell.Commands.ByteCollection))] - [Alias ("fhx")] + [Alias("fhx")] public sealed class FormatHex : PSCmdlet { private const int BUFFERSIZE = 16; @@ -22,49 +26,54 @@ public sealed class FormatHex : PSCmdlet #region Parameters /// - /// Path of file(s) to process + /// Gets or sets the path of file(s) to process. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "Path")] [ValidateNotNullOrEmpty()] public string[] Path { get; set; } /// - /// Literal path of file to process + /// Gets or sets the literal path of file to process. /// [Parameter(Mandatory = true, ParameterSetName = "LiteralPath")] [ValidateNotNullOrEmpty()] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string[] LiteralPath { get; set; } /// - /// Ojbect to process + /// Gets or sets the object to process. /// [Parameter(Mandatory = true, ParameterSetName = "ByInputObject", ValueFromPipeline = true)] public PSObject InputObject { get; set; } /// - /// Type of character encoding for InputObject + /// Gets or sets the type of character encoding for InputObject. /// [Parameter(ParameterSetName = "ByInputObject")] [ArgumentToEncodingTransformationAttribute()] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] + [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); /// - /// This parameter is no-op + /// Gets or sets count of bytes to read from the input stream. /// - [Parameter(ParameterSetName = "ByInputObject")] + [Parameter] + [ValidateRange(ValidateRangeKind.Positive)] + public long Count { get; set; } = long.MaxValue; + + /// + /// Gets or sets offset of bytes to start reading the input stream from. + /// + [Parameter] + [ValidateRange(ValidateRangeKind.NonNegative)] + public long Offset { get; set; } + + /// + /// Gets or sets whether the file input should be swallowed as is. This parameter is no-op, deprecated. + /// + [Parameter(ParameterSetName = "ByInputObject", DontShow = true)] + [Obsolete("Raw parameter is deprecated.", true)] public SwitchParameter Raw { get; set; } #endregion @@ -76,15 +85,15 @@ public sealed class FormatHex : PSCmdlet /// protected override void ProcessRecord() { - if (String.Equals(this.ParameterSetName, "ByInputObject", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(this.ParameterSetName, "ByInputObject", StringComparison.OrdinalIgnoreCase)) { ProcessObjectContent(InputObject); } else { - List pathsToProcess = String.Equals(this.ParameterSetName, "LiteralPath", StringComparison.OrdinalIgnoreCase) ? + List pathsToProcess = string.Equals(this.ParameterSetName, "LiteralPath", StringComparison.OrdinalIgnoreCase) ? ResolvePaths(LiteralPath, true) : ResolvePaths(Path, false); - + ProcessPath(pathsToProcess); } } @@ -98,8 +107,8 @@ protected override void ProcessRecord() /// If path is a literal path it is added to the array to process; we cannot validate them until we /// try to process file contents. /// - /// - /// + /// The file path to resolve. + /// The paths to process. /// private List ResolvePaths(string[] path, bool literalPath) { @@ -136,10 +145,11 @@ private List ResolvePaths(string[] path, bool literalPath) { // Write a non-terminating error message indicating that path specified is not supported. string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexOnlySupportsFileSystemPaths, currentPath); - ErrorRecord errorRecord = new ErrorRecord(new ArgumentException(errorMessage), - "FormatHexOnlySupportsFileSystemPaths", - ErrorCategory.InvalidArgument, - currentPath); + ErrorRecord errorRecord = new ErrorRecord( + new ArgumentException(errorMessage), + "FormatHexOnlySupportsFileSystemPaths", + ErrorCategory.InvalidArgument, + currentPath); WriteError(errorRecord); continue; } @@ -153,7 +163,7 @@ private List ResolvePaths(string[] path, bool literalPath) /// /// Pass each valid path on to process its contents. /// - /// + /// The paths to process. private void ProcessPath(List pathsToProcess) { foreach (string path in pathsToProcess) @@ -164,42 +174,36 @@ private void ProcessPath(List pathsToProcess) /// /// Creates a binary reader that reads the file content into a buffer (byte[]) 16 bytes at a time, and - /// passes a copy of that array on to the ConvertToHexidecimal method to output. + /// passes a copy of that array on to the WriteHexadecimal method to output. /// - /// + /// The file path to retrieve content from for processing. private void ProcessFileContent(string path) { - byte[] buffer = new byte[BUFFERSIZE]; + Span buffer = stackalloc byte[BUFFERSIZE]; try { - using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read))) + using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))) { - UInt32 offset = 0; - Int32 bytesRead = 0; + long offset = Offset; + int bytesRead = 0; + long count = 0; - while ((bytesRead = reader.Read(buffer, 0, BUFFERSIZE)) > 0) + reader.BaseStream.Position = Offset; + + while ((bytesRead = reader.Read(buffer)) > 0) { - if (bytesRead == BUFFERSIZE) - { - // We are reusing the same buffer so if we save the output to a variable, the variable - // will just contain multiple references to the same buffer memory space (containing only the - // last bytes of the file read). Copying the buffer allows us to pass the values on without - // overwriting previous values. - byte[] copyOfBuffer = new byte[16]; - Array.Copy(buffer, 0, copyOfBuffer, 0, bytesRead); - ConvertToHexidecimal(copyOfBuffer, path, offset); - } - else + count += bytesRead; + if (count > Count) { - // Handle the case of a partial (and probably last) buffer. Copies the bytes read into a new, - // shorter array so we do not have the extra bytes from the previous pass through at the end. - byte[] remainingBytes = new byte[bytesRead]; - Array.Copy(buffer, 0, remainingBytes, 0, bytesRead); - ConvertToHexidecimal(remainingBytes, path, offset); + bytesRead -= (int)(count - Count); + WriteHexadecimal(buffer.Slice(0, bytesRead), path, offset); + break; } - // Update offset value. - offset += (UInt32)bytesRead; + + WriteHexadecimal(buffer.Slice(0, bytesRead), path, offset); + + offset += bytesRead; } } } @@ -228,86 +232,131 @@ private void ProcessFileContent(string path) /// /// Creates a byte array from the object passed to the cmdlet (based on type) and passes - /// that array on to the ConvertToHexidecimal method to output. + /// that array on to the WriteHexadecimal method to output. /// - /// + /// The pipeline input object being processed. private void ProcessObjectContent(PSObject inputObject) { - Object obj = inputObject.BaseObject; - byte[] inputBytes = null; - if (obj is System.IO.FileSystemInfo) + object obj = inputObject.BaseObject; + + if (obj is System.IO.FileSystemInfo fsi) { - string[] path = { ((FileSystemInfo)obj).FullName }; + string[] path = { fsi.FullName }; List pathsToProcess = ResolvePaths(path, true); ProcessPath(pathsToProcess); + return; } - - else if (obj is string) - { - string inputString = obj.ToString(); - inputBytes = Encoding.GetBytes(inputString); - } - - else if (obj is byte) + + byte[] inputBytes = ConvertToByteArray(obj); + + if (inputBytes != null) { - inputBytes = new byte[] { (byte)obj }; + int offset = Math.Min(inputBytes.Length, Offset < (long)int.MaxValue ? (int)Offset : int.MaxValue); + int count = Math.Min(inputBytes.Length - offset, Count < (long)int.MaxValue ? (int)Count : int.MaxValue); + if (offset != 0 || count != inputBytes.Length) + { + WriteHexadecimal(inputBytes.AsSpan().Slice(offset, count), null, 0); + } + else + { + WriteHexadecimal(inputBytes, null, 0); + } } - - else if (obj is byte[]) + else { - inputBytes = ((byte[])obj); + string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexTypeNotSupported, obj.GetType()); + ErrorRecord errorRecord = new ErrorRecord( + new ArgumentException(errorMessage), + "FormatHexTypeNotSupported", + ErrorCategory.InvalidArgument, + obj.GetType()); + WriteError(errorRecord); } + } - else if (obj is Int32) + /// + /// Converts the input object to a byte array based on the underlying type for basic value types and strings, + /// as well as enum values or arrays. + /// + /// The object to convert. + /// Returns a byte array of the input values, or null if there is no available conversion path. + private byte[] ConvertToByteArray(object inputObject) + { + if (inputObject is string str) { - inputBytes = BitConverter.GetBytes((Int32)obj); + return Encoding.GetBytes(str); } - else if (obj is Int32[]) + var baseType = inputObject.GetType(); + byte[] result = null; + int elements = 1; + bool isArray = false; + bool isBool = false; + bool isEnum = false; + if (baseType.IsArray) { - List inputStreamArray = new List(); - Int32[] inputInts = (Int32[])obj; - foreach (Int32 value in inputInts) - { - byte[] tempBytes = BitConverter.GetBytes(value); - inputStreamArray.AddRange(tempBytes); - } - inputBytes = inputStreamArray.ToArray(); + baseType = baseType.GetElementType(); + dynamic dynamicObject = inputObject; + elements = (int)dynamicObject.Length; + isArray = true; } - else if (obj is Int64) + if (baseType.IsEnum) { - inputBytes = BitConverter.GetBytes((Int64)obj); + baseType = baseType.GetEnumUnderlyingType(); + isEnum = true; } - - else if (obj is Int64[]) + + if (baseType.IsPrimitive && elements > 0) { - List inputStreamArray = new List(); - Int64[] inputInts = (Int64[])obj; - foreach (Int64 value in inputInts) + if (baseType == typeof(bool)) { - byte[] tempBytes = BitConverter.GetBytes(value); - inputStreamArray.AddRange(tempBytes); + isBool = true; } - inputBytes = inputStreamArray.ToArray(); - } - // If the object type is not supported, throw an error. Once Serialization is - // available on CoreCLR, other types will be supported. - else - { - string errorMessage = StringUtil.Format(UtilityCommonStrings.FormatHexTypeNotSupported, obj.GetType()); - ErrorRecord errorRecord = new ErrorRecord(new ArgumentException(errorMessage), - "FormatHexTypeNotSupported", - ErrorCategory.InvalidArgument, - obj.GetType()); - WriteError(errorRecord); - } + var elementSize = Marshal.SizeOf(baseType); + result = new byte[elementSize * elements]; + if (!isArray) + { + inputObject = new object[] { inputObject }; + } - if (inputBytes != null) - { - ConvertToHexidecimal(inputBytes, null, 0); + int index = 0; + foreach (dynamic obj in (Array)inputObject) + { + if (elementSize == 1) + { + result[index] = (byte)obj; + } + else + { + dynamic toBytes; + if (isEnum) + { + toBytes = Convert.ChangeType(obj, baseType); + } + else if (isBool) + { + // bool is 1 byte apparently + toBytes = Convert.ToByte(obj); + } + else + { + toBytes = obj; + } + + var bytes = BitConverter.GetBytes(toBytes); + for (int i = 0; i < bytes.Length; i++) + { + result[i + index] = bytes[i]; + } + } + + index += elementSize; + } } + + return result; } #endregion @@ -315,18 +364,21 @@ private void ProcessObjectContent(PSObject inputObject) #region Output /// - /// Outputs the hexadecimial representaion of the of the input data. + /// Outputs the hexadecimial representation of the input data. /// - /// - /// - /// - private void ConvertToHexidecimal(byte[] inputBytes, string path, UInt32 offset) + /// Bytes for the hexadecimial representation. + /// File path. + /// Offset in the file. + private void WriteHexadecimal(Span inputBytes, string path, long offset) { - if (inputBytes != null) - { - ByteCollection byteCollectionObject = new ByteCollection(offset, inputBytes, path); - WriteObject(byteCollectionObject); - } + ByteCollection byteCollectionObject = new ByteCollection((ulong)offset, inputBytes.ToArray(), path); + WriteObject(byteCollectionObject); + } + + private void WriteHexadecimal(byte[] inputBytes, string path, long offset) + { + ByteCollection byteCollectionObject = new ByteCollection((ulong)offset, inputBytes, path); + WriteObject(byteCollectionObject); } #endregion diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-list/Format-List.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-list/Format-List.cs index 3cd9ed9d607d..e0f5e13c712d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-list/Format-List.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-list/Format-List.cs @@ -1,20 +1,20 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// implementation for the format-table command + /// Implementation for the format-table command. /// [Cmdlet(VerbsCommon.Format, "List", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113302")] public class FormatListCommand : OuterFormatTableAndListBase { /// - /// constructor to set the inner command + /// Constructor to set the inner command. /// public FormatListCommand() { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/format-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs similarity index 88% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/format-object.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs index 266a5d65b688..7d789539e70e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/format-object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs @@ -1,32 +1,30 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// implementation for the format-custom command. It just calls the formatting - /// engine on complex shape + /// Implementation for the format-custom command. It just calls the formatting engine on complex shape. /// [Cmdlet(VerbsCommon.Format, "Custom", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113301")] public class FormatCustomCommand : OuterFormatShapeCommandBase { /// - /// constructor to se the inner command + /// Constructor to se the inner command. /// public FormatCustomCommand() { this.implementation = new InnerFormatShapeCommand(FormatShape.Complex); } - #region Command Line Switches /// - /// Positional parameter for properties, property sets and table sets + /// Positional parameter for properties, property sets and table sets. /// specified on the command line. /// The parameter is optional, since the defaults /// will be determined using property sets, etc. @@ -35,13 +33,13 @@ public FormatCustomCommand() public object[] Property { get { return _props; } + set { _props = value; } } private object[] _props; /// - /// /// /// [ValidateRangeAttribute(1, int.MaxValue)] @@ -49,6 +47,7 @@ public object[] Property public int Depth { get { return _depth; } + set { _depth = value; } } @@ -74,6 +73,7 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() { ReportCannotSpecifyViewAndProperty(); } + parameters.viewName = this.View; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-table/Format-Table.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-table/Format-Table.cs index 06dce665064c..d066ee844e8b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-table/Format-Table.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-table/Format-Table.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; @@ -9,13 +8,13 @@ namespace Microsoft.PowerShell.Commands { /// - /// implementation for the format-table command + /// Implementation for the format-table command. /// [Cmdlet(VerbsCommon.Format, "Table", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113303")] public class FormatTableCommand : OuterFormatTableBase { /// - /// constructor to set the inner command + /// Constructor to set the inner command. /// public FormatTableCommand() { @@ -24,4 +23,3 @@ public FormatTableCommand() } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs index 6a68001373bf..e50331c8eec6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.IO; @@ -12,39 +11,37 @@ namespace Microsoft.PowerShell.Commands { /// - /// implementation for the format-table command + /// Implementation for the format-table command. /// [Cmdlet(VerbsCommon.Format, "Wide", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113304")] public class FormatWideCommand : OuterFormatShapeCommandBase { /// - /// constructor to se the inner command + /// Constructor to se the inner command. /// public FormatWideCommand() { this.implementation = new InnerFormatShapeCommand(FormatShape.Wide); } - #region Command Line Switches /// - /// Positional parameter for properties, property sets and table sets - /// specified on the command line. - /// The parameter is optional, since the defaults - /// will be determined using property sets, etc. + /// Positional parameter for properties, property sets and table sets specified on the command line. + /// The parameter is optional, since the defaults will be determined using property sets, etc. /// [Parameter(Position = 0)] public object Property { get { return _prop; } + set { _prop = value; } } private object _prop; /// - /// optional, non positional parameter + /// Optional, non positional parameter. /// /// [Parameter] @@ -56,13 +53,14 @@ public SwitchParameter AutoSize return _autosize.Value; return false; } + set { _autosize = value; } } - private Nullable _autosize = null; + private bool? _autosize = null; /// - /// optional, non positional parameter + /// Optional, non positional parameter. /// /// [Parameter] @@ -75,9 +73,11 @@ public int Column return _column.Value; return -1; } + set { _column = value; } } - private Nullable _column = null; + + private int? _column = null; #endregion @@ -99,6 +99,7 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() { ReportCannotSpecifyViewAndProperty(); } + parameters.viewName = this.View; } @@ -110,7 +111,6 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() // the user specified -autosize:true AND a column number string msg = StringUtil.Format(FormatAndOut_format_xxx.CannotSpecifyAutosizeAndColumnsError); - ErrorRecord errorRecord = new ErrorRecord( new InvalidDataException(), "FormatCannotSpecifyAutosizeAndColumns", @@ -140,6 +140,7 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() { wideSpecific.columns = _column.Value; } + return parameters; } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs index 3b01c1b57fbc..5c729d177a50 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs @@ -1,13 +1,13 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; +using System.IO; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; -using System.IO; +using System.Management.Automation.Internal; +using System.Text; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands @@ -21,13 +21,13 @@ internal static FileMode Convert(OpenMode openMode) } /// - /// implementation for the out-file command + /// Implementation for the out-file command. /// [Cmdlet(VerbsData.Out, "File", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113363")] public class OutFileCommand : FrontEndCommandBase { /// - /// set inner command + /// Set inner command. /// public OutFileCommand() { @@ -37,54 +37,46 @@ public OutFileCommand() #region Command Line Parameters /// - /// mandatory file name to write to + /// Mandatory file name to write to. /// [Alias("Path")] [Parameter(Mandatory = true, Position = 0, ParameterSetName = "ByPath")] public string FilePath { get { return _fileName; } + set { _fileName = value; } } private string _fileName; /// - /// mandatory file name to write to + /// Mandatory file name to write to. /// [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { get { return _fileName; } + set { _fileName = value; _isLiteralPath = true; } } + private bool _isLiteralPath = false; /// - /// Encoding optional flag + /// Encoding optional flag. /// - /// [Parameter(Position = 1)] [ArgumentToEncodingTransformationAttribute()] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] + [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); @@ -95,8 +87,10 @@ public string LiteralPath public SwitchParameter Append { get { return _append; } + set { _append = value; } } + private bool _append; /// @@ -106,8 +100,10 @@ public SwitchParameter Append public SwitchParameter Force { get { return _force; } + set { _force = value; } } + private bool _force; /// @@ -118,22 +114,25 @@ public SwitchParameter Force public SwitchParameter NoClobber { get { return _noclobber; } + set { _noclobber = value; } } + private bool _noclobber; /// - /// optional, number of columns to use when writing to device + /// Optional, number of columns to use when writing to device. /// [ValidateRangeAttribute(2, int.MaxValue)] [Parameter] public int Width { get { return (_width != null) ? _width.Value : 0; } + set { _width = value; } } - private Nullable _width = null; + private int? _width = null; /// /// False to add a newline to the end of the output string, true if not. @@ -145,6 +144,7 @@ public SwitchParameter NoNewline { return _suppressNewline; } + set { _suppressNewline = value; @@ -156,7 +156,7 @@ public SwitchParameter NoNewline #endregion /// - /// read command line parameters + /// Read command line parameters. /// protected override void BeginProcessing() { @@ -167,7 +167,7 @@ protected override void BeginProcessing() // cleanup code will be called in IDisposable.Dispose() outInner.LineOutput = InstantiateLineOutputInterface(); - if (null == _sw) + if (_sw == null) { return; } @@ -176,13 +176,12 @@ protected override void BeginProcessing() base.BeginProcessing(); } - /// - /// one time initialization: acquire a screen host interface - /// by creating one on top of a file + /// One-time initialization: acquire a screen host interface + /// by creating one on top of a file. /// NOTICE: we assume that at this time the file name is /// available in the CRO. JonN recommends: file name has to be - /// a MANDATORY parameter on the command line + /// a MANDATORY parameter on the command line. /// private LineOutput InstantiateLineOutputInterface() { @@ -223,12 +222,12 @@ private LineOutput InstantiateLineOutputInterface() } /// - /// execution entry point + /// Execution entry point. /// protected override void ProcessRecord() { _processRecordExecuted = true; - if (null == _sw) + if (_sw == null) { return; } @@ -240,7 +239,7 @@ protected override void ProcessRecord() } /// - /// execution entry point + /// Execution entry point. /// protected override void EndProcessing() { @@ -255,7 +254,7 @@ protected override void EndProcessing() return; } - if (null == _sw) + if (_sw == null) { return; } @@ -270,7 +269,7 @@ protected override void EndProcessing() } /// - /// + /// InternalDispose. /// protected override void InternalDispose() { @@ -287,7 +286,7 @@ private void CleanUp() } // reset the read-only attribute - if (null != _readOnlyFileInfo) + if (_readOnlyFileInfo != null) { _readOnlyFileInfo.Attributes |= FileAttributes.ReadOnly; _readOnlyFileInfo = null; @@ -295,17 +294,17 @@ private void CleanUp() } /// - /// handle to file stream + /// Handle to file stream. /// private FileStream _fs; /// - /// stream writer used to write to file + /// Stream writer used to write to file. /// private StreamWriter _sw = null; /// - /// indicate whether the ProcessRecord method was executed. + /// Indicate whether the ProcessRecord method was executed. /// When the Out-File is used in a redirection pipelineProcessor, /// its ProcessRecord method may not be called when nothing is written to the /// output pipe, for example: @@ -316,9 +315,8 @@ private void CleanUp() private bool _processRecordExecuted = false; /// - /// FileInfo of file to clear read-only flag when operation is complete + /// FileInfo of file to clear read-only flag when operation is complete. /// private FileInfo _readOnlyFileInfo = null; } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/out-printer.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/Out-Printer.cs similarity index 72% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/out-printer.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/Out-Printer.cs index b1c0944133f9..b72af15c4316 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/out-printer.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/Out-Printer.cs @@ -1,20 +1,20 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// implementation for the out-printer command + /// Implementation for the out-printer command. /// [Cmdlet(VerbsData.Out, "Printer", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113367")] public class OutPrinterCommand : FrontEndCommandBase { /// - /// set inner command + /// Set inner command. /// public OutPrinterCommand() { @@ -22,21 +22,22 @@ public OutPrinterCommand() } /// - /// optional name of the printer to print to - /// The alias allows "lp -P printer" + /// Optional name of the printer to print to. + /// The alias allows "lp -P printer". /// [Parameter(Position = 0)] [Alias("PrinterName")] public string Name { get { return _printerName; } + set { _printerName = value; } } private string _printerName; /// - /// read command line parameters + /// Read command line parameters. /// protected override void BeginProcessing() { @@ -50,8 +51,7 @@ protected override void BeginProcessing() } /// - /// one time initialization: acquire a screen host interface - /// by creating one on top of a memory buffer + /// One-time initialization: acquire a screen host interface by creating one on top of a memory buffer. /// private LineOutput InstantiateLineOutputInterface() { @@ -60,7 +60,3 @@ private LineOutput InstantiateLineOutputInterface() } } } - - - - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/PrinterLineOutput.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/PrinterLineOutput.cs index 910e8906dcd5..312734c043eb 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/PrinterLineOutput.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-printer/PrinterLineOutput.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -10,19 +9,19 @@ namespace Microsoft.PowerShell.Commands.Internal.Format { /// - /// Implementation of the LineOutput interface for printer + /// Implementation of the LineOutput interface for printer. /// internal sealed class PrinterLineOutput : LineOutput { #region LineOutput implementation /// - /// full buffering for printer + /// Full buffering for printer. /// internal override bool RequiresBuffering { get { return true; } } /// - /// do the printing on playback + /// Do the printing on playback. /// internal override void ExecuteBufferPlayBack(DoPlayBackCall playback) { @@ -31,7 +30,7 @@ internal override void ExecuteBufferPlayBack(DoPlayBackCall playback) } /// - /// the # of columns for the printer + /// The # of columns for the printer. /// /// internal override int ColumnNumber @@ -44,7 +43,7 @@ internal override int ColumnNumber } /// - /// the # of rows for the printer + /// The # of rows for the printer. /// /// internal override int RowNumber @@ -57,9 +56,9 @@ internal override int RowNumber } /// - /// write a line to the output device + /// Write a line to the output device. /// - /// line to write + /// Line to write. internal override void WriteLine(string s) { CheckStopProcessing(); @@ -71,7 +70,7 @@ internal override void WriteLine(string s) #endregion /// - /// Used for static initializations like DefaultPrintFontName + /// Used for static initializations like DefaultPrintFontName. /// static PrinterLineOutput() { @@ -82,9 +81,9 @@ static PrinterLineOutput() } /// - /// constructor for the class + /// Constructor for the class. /// - /// name of printer, if null use default printer + /// Name of printer, if null use default printer. internal PrinterLineOutput(string printerName) { _printerName = printerName; @@ -97,27 +96,27 @@ internal PrinterLineOutput(string printerName) } /// - /// callback to be called when IConsole.WriteLine() is called by WriteLineHelper + /// Callback to be called when IConsole.WriteLine() is called by WriteLineHelper. /// - /// string to write + /// String to write. private void OnWriteLine(string s) { _lines.Enqueue(s); } /// - /// callback to be called when Console.Write() is called by WriteLineHelper + /// Callback to be called when Console.Write() is called by WriteLineHelper. /// This is called when the WriteLineHelper needs to write a line whose length - /// is the same as the width of the screen buffer + /// is the same as the width of the screen buffer. /// - /// string to write + /// String to write. private void OnWrite(string s) { _lines.Enqueue(s); } /// - /// do the printing + /// Do the printing. /// private void DoPrint() { @@ -149,11 +148,11 @@ private void DoPrint() } /// - /// helper to create a font. + /// Helper to create a font. /// If the font object exists, it does nothing. - /// Else, the a new object is created and verified + /// Else, the a new object is created and verified. /// - /// GDI+ graphics object needed for verification + /// GDI+ graphics object needed for verification. private void CreateFont(Graphics g) { if (_printFont != null) @@ -177,10 +176,10 @@ private void CreateFont(Graphics g) } /// - /// internal helper to verify that the font is fixed pitch. If the test fails, - /// it reverts to the default font + /// Internal helper to verify that the font is fixed pitch. If the test fails, + /// it reverts to the default font. /// - /// GDI+ graphics object needed for verification + /// GDI+ graphics object needed for verification. private void VerifyFont(Graphics g) { // check if the font is fixed pitch @@ -205,10 +204,10 @@ private void VerifyFont(Graphics g) } /// - /// Event fired for each page to print + /// Event fired for each page to print. /// - /// sender, not used - /// print page event + /// Sender, not used. + /// Print page event. private void pd_PrintPage(object sender, PrintPageEventArgs ev) { float yPos = 0; // GDI+ coordinate down the page @@ -250,7 +249,7 @@ private void pd_PrintPage(object sender, PrintPageEventArgs ev) while ((linesPrinted < linesPerPage) && (_lines.Count > 0)) { // get the string to be printed - String line = _lines.Dequeue(); + string line = _lines.Dequeue(); // compute the Y position where to draw yPos = topMargin + (linesPrinted * lineHeight); @@ -260,39 +259,37 @@ private void pd_PrintPage(object sender, PrintPageEventArgs ev) linesPrinted++; } - //If we have more lines then print another page + // If we have more lines then print another page ev.HasMorePages = _lines.Count > 0; } - /// - /// flag for one time initialization of the interface (columns, etc.) + /// Flag for one-time initialization of the interface (columns, etc.). /// private bool _printingInitialized = false; /// - /// callback to ask the outputter to playback its cache + /// Callback to ask the outputter to playback its cache. /// private DoPlayBackCall _playbackCall; /// - /// name of the printer to print to. Null means default printer + /// Name of the printer to print to. Null means default printer. /// private string _printerName = null; /// - /// name of the font to use, if null the default is used + /// Name of the font to use, if null the default is used. /// private string _printFontName = null; /// - /// font size + /// Font size. /// private int _printFontSize = 0; - /// - /// default font, used if the printFont is not specified or if the + /// Default font, used if the printFont is not specified or if the /// printFont is not fixed pitch. /// /// @@ -303,12 +300,12 @@ private void pd_PrintPage(object sender, PrintPageEventArgs ev) private static readonly string s_defaultPrintFontName; /// - /// default size for the default font + /// Default size for the default font. /// private const int DefaultPrintFontSize = 8; /// - /// number of columns on the sheet + /// Number of columns on the sheet. /// private int _deviceColumns = 80; @@ -316,12 +313,12 @@ private void pd_PrintPage(object sender, PrintPageEventArgs ev) private int _deviceRows = 40; /// - /// text lines ready to print (after output cache playback) + /// Text lines ready to print (after output cache playback). /// private Queue _lines = new Queue(); /// - /// cached font object + /// Cached font object. /// private Font _printFont = null; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-string/out-string.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-string/Out-String.cs similarity index 77% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-string/out-string.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-string/Out-String.cs index 55f3db8f07d7..e5284986a21f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-string/out-string.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-string/Out-String.cs @@ -1,17 +1,17 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; using System.Management.Automation; using System.Management.Automation.Host; +using System.Text; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// implementation for the out-string command + /// Implementation for the out-string command. /// [Cmdlet(VerbsData.Out, "String", DefaultParameterSetName = "NoNewLineFormatting", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113368", RemotingCapability = RemotingCapability.None)] [OutputType(typeof(string))] @@ -19,41 +19,43 @@ public class OutStringCommand : FrontEndCommandBase { #region Command Line Parameters /// - /// optional, non positional parameter to specify the - /// streaming behavior - /// FALSE: accumulate all the data, then write a single string - /// TRUE: write one line at the time + /// Optional, non positional parameter to specify the streaming behavior. + /// FALSE: accumulate all the data, then write a single string. + /// TRUE: write one line at the time. /// - [Parameter(ParameterSetName="StreamFormatting")] + [Parameter(ParameterSetName = "StreamFormatting")] public SwitchParameter Stream { get { return _stream; } + set { _stream = value; } } private bool _stream; /// - /// optional, number of columns to use when writing to device + /// Optional, number of columns to use when writing to device. /// [ValidateRangeAttribute(2, int.MaxValue)] [Parameter] public int Width { get { return (_width != null) ? _width.Value : 0; } + set { _width = value; } } - private Nullable _width = null; + private int? _width = null; /// /// False to add a newline to the end of the output string, true if not. /// - [Parameter(ParameterSetName="NoNewLineFormatting")] + [Parameter(ParameterSetName = "NoNewLineFormatting")] public SwitchParameter NoNewline { get { return _noNewLine; } - set { _noNewLine = value;} + + set { _noNewLine = value; } } private bool _noNewLine = false; @@ -61,7 +63,7 @@ public SwitchParameter NoNewline #endregion /// - /// set inner command + /// Set inner command. /// public OutStringCommand() { @@ -69,7 +71,7 @@ public OutStringCommand() } /// - /// read command line parameters + /// Read command line parameters. /// protected override void BeginProcessing() { @@ -83,8 +85,8 @@ protected override void BeginProcessing() } /// - /// one time initialization: acquire a screen host interface - /// by creating one on top of a stream + /// One-time initialization: acquire a screen host interface + /// by creating one on top of a stream. /// private LineOutput InstantiateLineOutputInterface() { @@ -110,8 +112,7 @@ private LineOutput InstantiateLineOutputInterface() } /// - /// callback to add lines to the buffer or to write them to - /// the output stream + /// Callback to add lines to the buffer or to write them to the output stream. /// /// private void OnWriteLine(string s) @@ -134,7 +135,7 @@ private void OnWriteLine(string s) } /// - /// execution entry point + /// Execution entry point. /// protected override void ProcessRecord() { @@ -143,13 +144,13 @@ protected override void ProcessRecord() } /// - /// execution entry point + /// Execution entry point. /// protected override void EndProcessing() { base.EndProcessing(); - //close the writer + // close the writer _writer.Flush(); _writer.Dispose(); @@ -158,14 +159,13 @@ protected override void EndProcessing() } /// - /// writer used by the LineOutput + /// Writer used by the LineOutput. /// private StreamingTextWriter _writer = null; /// - /// buffer used when buffering until the end + /// Buffer used when buffering until the end. /// private StringBuilder _buffer = new StringBuilder(); } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs index 3701640e2410..49693b16b41f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs @@ -1,16 +1,15 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; -using System.Management.Automation; using System.Diagnostics.CodeAnalysis; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// Types of breakpoints + /// Types of breakpoints. /// public enum BreakpointType { @@ -26,7 +25,7 @@ public enum BreakpointType }; /// - /// This class implements Remove-PSBreakpoint + /// This class implements Remove-PSBreakpoint. /// [Cmdlet(VerbsCommon.Get, "PSBreakpoint", DefaultParameterSetName = "Script", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113325")] [OutputType(typeof(Breakpoint))] @@ -34,7 +33,7 @@ public class GetPSBreakpointCommand : PSCmdlet { #region parameters /// - /// Scripts of the breakpoints to output + /// Scripts of the breakpoints to output. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "It's OK to use arrays for cmdlet parameters")] [Parameter(ParameterSetName = "Script", Position = 0, ValueFromPipeline = true)] @@ -48,15 +47,17 @@ public string[] Script { return _script; } + set { _script = value; } } + private string[] _script; /// - /// IDs of the breakpoints to output + /// IDs of the breakpoints to output. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "It's OK to use arrays for cmdlet parameters")] [Parameter(ParameterSetName = "Id", Mandatory = true, Position = 0, ValueFromPipeline = true)] @@ -67,15 +68,17 @@ public int[] Id { return _id; } + set { _id = value; } } + private int[] _id; /// - /// Variables of the breakpoints to output + /// Variables of the breakpoints to output. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "It's OK to use arrays for cmdlet parameters")] [Parameter(ParameterSetName = "Variable", Mandatory = true)] @@ -86,15 +89,17 @@ public string[] Variable { return _variable; } + set { _variable = value; } } + private string[] _variable; /// - /// Commands of the breakpoints to output + /// Commands of the breakpoints to output. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "It's OK to use arrays for cmdlet parameters")] [Parameter(ParameterSetName = "Command", Mandatory = true)] @@ -105,15 +110,17 @@ public string[] Command { return _command; } + set { _command = value; } } + private string[] _command; /// - /// Commands of the breakpoints to output + /// Commands of the breakpoints to output. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "It's OK to use arrays for cmdlet parameters")] [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Type is OK for a cmdlet parameter")] @@ -125,17 +132,19 @@ public BreakpointType[] Type { return _type; } + set { _type = value; } } + private BreakpointType[] _type; #endregion parameters /// - /// remove breakpoints + /// Remove breakpoints. /// protected override void ProcessRecord() { @@ -207,6 +216,7 @@ protected override void ProcessRecord() { return true; } + break; case BreakpointType.Command: @@ -214,6 +224,7 @@ protected override void ProcessRecord() { return true; } + break; case BreakpointType.Variable: @@ -221,6 +232,7 @@ protected override void ProcessRecord() { return true; } + break; } @@ -264,9 +276,8 @@ protected override void ProcessRecord() } } - /// - /// Gives the criteria to filter breakpoints + /// Gives the criteria to filter breakpoints. /// private delegate bool FilterSelector(Breakpoint breakpoint, T target); @@ -293,4 +304,4 @@ private List Filter(List input, T[] filter, FilterSel return output; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSCallStack.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSCallStack.cs index 54a12b175bcd..7f7df6a0444e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSCallStack.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSCallStack.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; @@ -14,7 +13,7 @@ namespace Microsoft.PowerShell.Commands public class GetPSCallStackCommand : PSCmdlet { /// - /// Get the call stack + /// Get the call stack. /// protected override void ProcessRecord() { @@ -24,4 +23,4 @@ protected override void ProcessRecord() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetAliasCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetAliasCommand.cs index a9e35503eec9..e080803e39dc 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetAliasCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetAliasCommand.cs @@ -1,20 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.Management.Automation; using System.Management.Automation.Internal; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.PowerShell.Commands { /// - /// The implementation of the "get-alias" cmdlet + /// The implementation of the "get-alias" cmdlet. /// - /// [Cmdlet(VerbsCommon.Get, "Alias", DefaultParameterSetName = "Default", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113306")] [OutputType(typeof(AliasInfo))] public class GetAliasCommand : PSCmdlet @@ -22,35 +20,36 @@ public class GetAliasCommand : PSCmdlet #region Parameters /// - /// The Name parameter for the command + /// The Name parameter for the command. /// - /// [Parameter(ParameterSetName = "Default", Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty()] public string[] Name { get { return _names; } + set { _names = value ?? new string[] { "*" }; } } + private string[] _names = new string[] { "*" }; /// - /// The Exclude parameter for the command + /// The Exclude parameter for the command. /// - /// [Parameter] public string[] Exclude { get { return _excludes; } - set { _excludes = value ?? new string[0]; } + + set { _excludes = value ?? Array.Empty(); } } - private string[] _excludes = new string[0]; + + private string[] _excludes = Array.Empty(); /// /// The scope parameter for the command determines /// which scope the aliases are retrieved from. /// - /// [Parameter] public string Scope { get; set; } @@ -60,7 +59,7 @@ public string[] Exclude [Parameter(ParameterSetName = "Definition")] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Definition { get; set; } + public string[] Definition { get; set; } #endregion Parameters @@ -69,7 +68,6 @@ public string[] Exclude /// /// The main processing loop of the command. /// - /// protected override void ProcessRecord() { if (ParameterSetName.Equals("Definition")) @@ -85,8 +83,8 @@ protected override void ProcessRecord() { WriteMatches(aliasName, "Default"); } - }//parameterset else - } // ProcessRecord + } + } #endregion Command code private void WriteMatches(string value, string parametersetname) @@ -94,10 +92,10 @@ private void WriteMatches(string value, string parametersetname) // First get the alias table (from the proper scope if necessary) IDictionary aliasTable = null; - //get the command origin + // get the command origin CommandOrigin origin = MyInvocation.CommandOrigin; string displayString = "name"; - if (!String.IsNullOrEmpty(Scope)) + if (!string.IsNullOrEmpty(Scope)) { // This can throw PSArgumentException and PSArgumentOutOfRangeException // but just let them go as this is terminal for the pipeline and the @@ -110,8 +108,6 @@ private void WriteMatches(string value, string parametersetname) aliasTable = SessionState.Internal.GetAliasTable(); } - - bool matchfound = false; bool ContainsWildcard = WildcardPattern.ContainsWildcardCharacters(value); WildcardPattern wcPattern = WildcardPattern.Get(value, WildcardOptions.IgnoreCase); @@ -132,6 +128,7 @@ private void WriteMatches(string value, string parametersetname) { continue; } + if (SessionStateUtilities.MatchesAnyWildcardPattern(tableEntry.Value.Definition, excludePatterns, false)) { continue; @@ -143,12 +140,13 @@ private void WriteMatches(string value, string parametersetname) { continue; } - //excludes pattern + // excludes pattern if (SessionStateUtilities.MatchesAnyWildcardPattern(tableEntry.Key, excludePatterns, false)) { continue; } } + if (ContainsWildcard) { // Only write the command if it is visible to the requestor @@ -202,6 +200,5 @@ private void WriteMatches(string value, string parametersetname) WriteError(er); } } - } // class GetAliasCommand -}//Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetCultureCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetCultureCommand.cs index a370026e5154..e1fa41889810 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetCultureCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetCultureCommand.cs @@ -1,26 +1,124 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Collections.Generic; +using System.Globalization; using System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// Returns the thread's current culture. + /// Returns: + /// - the thread's current culture + /// - culture by name + /// - list of all supported cultures. /// - [Cmdlet(VerbsCommon.Get, "Culture", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113312")] + [Cmdlet(VerbsCommon.Get, "Culture", DefaultParameterSetName = CurrentCultureParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113312")] [OutputType(typeof(System.Globalization.CultureInfo))] public sealed class GetCultureCommand : PSCmdlet { + private const string CurrentCultureParameterSet = "CurrentCulture"; + private const string NameParameterSet = "Name"; + private const string ListAvailableParameterSet = "ListAvailable"; + + /// + /// Gets or sets culture names for which CultureInfo values are returned. + /// Empty string matches Invariant culture. + /// + [Parameter(ParameterSetName = NameParameterSet, Position = 0, ValueFromPipeline = true)] + [ValidateSet(typeof(ValidateCultureNamesGenerator))] + [ValidateNotNull] + public string[] Name { get; set; } + + /// + /// Gets or sets a switch to return current culture with user overrides (by default). + /// With the switch on, we return current culture without user overrides. + /// + [Parameter(ParameterSetName = CurrentCultureParameterSet)] + [Parameter(ParameterSetName = NameParameterSet)] + public SwitchParameter NoUserOverrides { get; set; } + + /// + /// Gets or sets a switch to list all available cultures. + /// + [Parameter(ParameterSetName = ListAvailableParameterSet)] + public SwitchParameter ListAvailable { get; set; } + /// - /// Output the current Culture info object + /// Output: + /// - the thread's current culture + /// - culture by name + /// - list of all supported cultures. /// - protected override void BeginProcessing() + protected override void ProcessRecord() { - WriteObject(Host.CurrentCulture); - } // EndProcessing - } // GetCultureCommand -} // Microsoft.PowerShell.Commands + CultureInfo ci; + switch (ParameterSetName) + { + case CurrentCultureParameterSet: + if (NoUserOverrides) + { + ci = CultureInfo.GetCultureInfo(Host.CurrentCulture.Name); + } + else + { + ci = Host.CurrentCulture; + } + + WriteObject(ci); + + break; + case NameParameterSet: + try + { + foreach (var cultureName in Name) + { + if (!NoUserOverrides && string.Equals(cultureName, Host.CurrentCulture.Name, StringComparison.CurrentCultureIgnoreCase)) + { + ci = Host.CurrentCulture; + } + else + { + ci = CultureInfo.GetCultureInfo(cultureName); + } + + WriteObject(ci); + } + } + catch (CultureNotFoundException exc) + { + WriteError(new ErrorRecord(exc, "ItemNotFoundException", ErrorCategory.ObjectNotFound, Name)); + } + + break; + case ListAvailableParameterSet: + foreach (var cultureInfo in CultureInfo.GetCultures(CultureTypes.AllCultures)) + { + WriteObject(cultureInfo); + } + + break; + } + } + } + + /// + /// Get list of valid culture names for ValidateSet attribute. + /// + public class ValidateCultureNamesGenerator : IValidateSetValuesGenerator + { + string[] IValidateSetValuesGenerator.GetValidValues() + { + var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures); + var result = new List(cultures.Length); + foreach (var cultureInfo in cultures) + { + result.Add(cultureInfo.Name); + } + return result.ToArray(); + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs index 9f9da1ed28ab..0d0c317b970e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs @@ -1,19 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Globalization; -using System.Text; using System.Management.Automation; using System.Management.Automation.Internal; +using System.Text; namespace Microsoft.PowerShell.Commands { #region get-date /// - /// implementation for the get-date command + /// Implementation for the get-date command. /// [Cmdlet(VerbsCommon.Get, "Date", DefaultParameterSetName = "net", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113313")] [OutputType(typeof(string), ParameterSetName = new string[] { "UFormat", "net" })] @@ -23,7 +22,7 @@ public sealed class GetDateCommand : Cmdlet #region parameters /// - /// Allows user to override the date/time object that will be processed + /// Allows user to override the date/time object that will be processed. /// [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [Alias("LastWriteTime")] @@ -33,18 +32,19 @@ public DateTime Date { return _date; } + set { _date = value; _dateSpecified = true; } } + private DateTime _date; private bool _dateSpecified; - /// - /// Allows the user to override the year + /// Allows the user to override the year. /// [Parameter] [ValidateRangeAttribute(1, 9999)] @@ -54,18 +54,19 @@ public int Year { return _year; } + set { _year = value; _yearSpecified = true; } } + private int _year; private bool _yearSpecified; - /// - /// Allows the user to override the month + /// Allows the user to override the month. /// [Parameter] [ValidateRangeAttribute(1, 12)] @@ -75,18 +76,19 @@ public int Month { return _month; } + set { _month = value; _monthSpecified = true; } } + private int _month; private bool _monthSpecified; - /// - /// Allows the user to override the day + /// Allows the user to override the day. /// [Parameter] [ValidateRangeAttribute(1, 31)] @@ -96,18 +98,19 @@ public int Day { return _day; } + set { _day = value; _daySpecified = true; } } + private int _day; private bool _daySpecified; - /// - /// Allows the user to override the hour + /// Allows the user to override the hour. /// [Parameter] [ValidateRangeAttribute(0, 23)] @@ -117,18 +120,19 @@ public int Hour { return _hour; } + set { _hour = value; _hourSpecified = true; } } + private int _hour; private bool _hourSpecified; - /// - /// Allows the user to override the minute + /// Allows the user to override the minute. /// [Parameter] [ValidateRangeAttribute(0, 59)] @@ -138,18 +142,19 @@ public int Minute { return _minute; } + set { _minute = value; _minuteSpecified = true; } } + private int _minute; private bool _minuteSpecified; - /// - /// Allows the user to override the second + /// Allows the user to override the second. /// [Parameter] [ValidateRangeAttribute(0, 59)] @@ -159,17 +164,19 @@ public int Second { return _second; } + set { _second = value; _secondSpecified = true; } } + private int _second; private bool _secondSpecified; /// - /// Allows the user to override the millisecond + /// Allows the user to override the millisecond. /// [Parameter] [ValidateRangeAttribute(0, 999)] @@ -179,32 +186,32 @@ public int Millisecond { return _millisecond; } + set { _millisecond = value; _millisecondSpecified = true; } } + private int _millisecond; private bool _millisecondSpecified; /// - /// This option determines the default output format used to display the object get-date emits + /// This option determines the default output format used to display the object get-date emits. /// [Parameter] public DisplayHintType DisplayHint { get; set; } = DisplayHintType.DateTime; - /// - /// Unix format string + /// Unix format string. /// [Parameter(ParameterSetName = "UFormat")] [ValidateNotNullOrEmpty] public string UFormat { get; set; } - /// - /// Unix format string + /// Unix format string. /// [Parameter(ParameterSetName = "net")] [ArgumentCompletions("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal")] @@ -215,7 +222,7 @@ public int Millisecond #region methods /// - /// get the time + /// Get the time. /// protected override void ProcessRecord() { @@ -228,49 +235,49 @@ protected override void ProcessRecord() dateToUse = Date; } - //use passed year if specified + // use passed year if specified if (_yearSpecified) { offset = Year - dateToUse.Year; dateToUse = dateToUse.AddYears(offset); } - //use passed month if specified + // use passed month if specified if (_monthSpecified) { offset = Month - dateToUse.Month; dateToUse = dateToUse.AddMonths(offset); } - //use passed day if specified + // use passed day if specified if (_daySpecified) { offset = Day - dateToUse.Day; dateToUse = dateToUse.AddDays(offset); } - //use passed hour if specified + // use passed hour if specified if (_hourSpecified) { offset = Hour - dateToUse.Hour; dateToUse = dateToUse.AddHours(offset); } - //use passed minute if specified + // use passed minute if specified if (_minuteSpecified) { offset = Minute - dateToUse.Minute; dateToUse = dateToUse.AddMinutes(offset); } - //use passed second if specified + // use passed second if specified if (_secondSpecified) { offset = Second - dateToUse.Second; dateToUse = dateToUse.AddSeconds(offset); } - //use passed millisecond if specified + // use passed millisecond if specified if (_millisecondSpecified) { offset = Millisecond - dateToUse.Millisecond; @@ -280,31 +287,31 @@ protected override void ProcessRecord() if (UFormat != null) { - //format according to UFormat string + // format according to UFormat string WriteObject(UFormatDateString(dateToUse)); } else if (Format != null) { - //format according to Format string + // format according to Format string // Special case built-in primitives: FileDate, FileDateTime. // These are the ISO 8601 "basic" formats, dropping dashes and colons // so that they can be used in file names - if (String.Equals("FileDate", Format, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("FileDate", Format, StringComparison.OrdinalIgnoreCase)) { Format = "yyyyMMdd"; } - else if (String.Equals("FileDateUniversal", Format, StringComparison.OrdinalIgnoreCase)) + else if (string.Equals("FileDateUniversal", Format, StringComparison.OrdinalIgnoreCase)) { dateToUse = dateToUse.ToUniversalTime(); Format = "yyyyMMddZ"; } - else if (String.Equals("FileDateTime", Format, StringComparison.OrdinalIgnoreCase)) + else if (string.Equals("FileDateTime", Format, StringComparison.OrdinalIgnoreCase)) { Format = "yyyyMMddTHHmmssffff"; } - else if (String.Equals("FileDateTimeUniversal", Format, StringComparison.OrdinalIgnoreCase)) + else if (string.Equals("FileDateTimeUniversal", Format, StringComparison.OrdinalIgnoreCase)) { dateToUse = dateToUse.ToUniversalTime(); Format = "yyyyMMddTHHmmssffffZ"; @@ -314,22 +321,22 @@ protected override void ProcessRecord() } else { - //output DateTime object wrapped in an PSObject with DisplayHint attached + // output DateTime object wrapped in an PSObject with DisplayHint attached PSObject outputObj = new PSObject(dateToUse); PSNoteProperty note = new PSNoteProperty("DisplayHint", DisplayHint); outputObj.Properties.Add(note); WriteObject(outputObj); } - } // EndProcessing + } + private static readonly DateTime s_epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); /// - /// This is more an implementation of the UNIX strftime + /// This is more an implementation of the UNIX strftime. /// private string UFormatDateString(DateTime dateTime) { - DateTime epoch = DateTime.Parse("January 1, 1970", System.Globalization.CultureInfo.InvariantCulture); int offset = 0; StringBuilder sb = new StringBuilder(); @@ -338,6 +345,7 @@ private string UFormatDateString(DateTime dateTime) { offset++; } + for (int i = offset; i < UFormat.Length; i++) { if (UFormat[i] == '%') @@ -361,18 +369,12 @@ private string UFormatDateString(DateTime dateTime) sb.Append("{0:MMM}"); break; - case 'h': - sb.Append("{0:MMM}"); - break; - case 'C': sb.Append(dateTime.Year / 100); break; case 'c': - sb.Append("{0:ddd} {0:MMM} "); - sb.Append(StringUtil.Format("{0,2} ", dateTime.Day)); - sb.Append("{0:HH}:{0:mm}:{0:ss} {0:yyyy}"); + sb.Append("{0:ddd} {0:dd} {0:MMM} {0:yyyy} {0:HH}:{0:mm}:{0:ss}"); break; case 'D': @@ -387,24 +389,40 @@ private string UFormatDateString(DateTime dateTime) sb.Append(StringUtil.Format("{0,2}", dateTime.Day)); break; + case 'F': + sb.Append("{0:yyyy}-{0:MM}-{0:dd}"); + break; + + case 'G': + sb.Append("{0:yyyy}"); + break; + + case 'g': + sb.Append("{0:yy}"); + break; + case 'H': sb.Append("{0:HH}"); break; + case 'h': + sb.Append("{0:MMM}"); + break; + case 'I': sb.Append("{0:hh}"); break; case 'j': - sb.Append(dateTime.DayOfYear); + sb.Append(StringUtil.Format("{0:000}", dateTime.DayOfYear)); break; case 'k': - sb.Append("{0:HH}"); + sb.Append(StringUtil.Format("{0,2:0}", dateTime.Hour)); break; case 'l': - sb.Append("{0:hh}"); + sb.Append("{0,2:%h}"); break; case 'M': @@ -436,39 +454,54 @@ private string UFormatDateString(DateTime dateTime) break; case 's': - sb.Append(dateTime.Subtract(epoch).TotalSeconds); + sb.Append(StringUtil.Format("{0:0}", dateTime.ToUniversalTime().Subtract(s_epoch).TotalSeconds)); break; case 'T': sb.Append("{0:HH:mm:ss}"); break; - case 'X': - sb.Append("{0:HH:mm:ss}"); - break; - case 't': sb.Append("\t"); break; - case 'u': - sb.Append((int)dateTime.DayOfWeek); - break; - case 'U': sb.Append(dateTime.DayOfYear / 7); break; - case 'V': - sb.Append((dateTime.DayOfYear / 7) + 1); - break; - - case 'G': - sb.Append("{0:yyyy}"); + case 'u': + sb.Append((int)dateTime.DayOfWeek); break; - case 'g': - sb.Append("{0:yy}"); + case 'V': + // .Net Core doesn't implement ISO 8601. + // So we use workaround from https://blogs.msdn.microsoft.com/shawnste/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net/ + // with corrections from comments + + // Culture doesn't matter since we specify start day of week + var calender = CultureInfo.InvariantCulture.Calendar; + var day = calender.GetDayOfWeek(dateTime); + var normalizedDatetime = dateTime; + + switch (day) + { + case DayOfWeek.Monday: + case DayOfWeek.Tuesday: + case DayOfWeek.Wednesday: + normalizedDatetime = dateTime.AddDays(3); + break; + + case DayOfWeek.Friday: + case DayOfWeek.Saturday: + case DayOfWeek.Sunday: + normalizedDatetime = dateTime.AddDays(-3); + break; + } + + // FirstFourDayWeek and DayOfWeek.Monday is from ISO 8601 + sb.Append(StringUtil.Format("{0:00}", calender.GetWeekOfYear(normalizedDatetime, + CalendarWeekRule.FirstFourDayWeek, + DayOfWeek.Monday))); break; case 'W': @@ -479,18 +512,22 @@ private string UFormatDateString(DateTime dateTime) sb.Append((int)dateTime.DayOfWeek); break; - case 'x': - sb.Append("{0:MM/dd/yy}"); + case 'X': + sb.Append("{0:HH:mm:ss}"); break; - case 'y': - sb.Append("{0:yy}"); + case 'x': + sb.Append("{0:MM/dd/yy}"); break; case 'Y': sb.Append("{0:yyyy}"); break; + case 'y': + sb.Append("{0:yy}"); + break; + case 'Z': sb.Append("{0:zz}"); break; @@ -508,35 +545,32 @@ private string UFormatDateString(DateTime dateTime) } return StringUtil.Format(sb.ToString(), dateTime); - } // UFormatDateString + } #endregion - } // GetDateCommand + } #endregion #region DisplayHintType enum /// - /// Display Hint type + /// Display Hint type. /// public enum DisplayHintType { /// - /// Display preference Date-Only + /// Display preference Date-Only. /// Date, /// - /// Display preference Time-Only + /// Display preference Time-Only. /// Time, /// - /// Display preference Date and Time + /// Display preference Date and Time. /// DateTime } - #endregion -} // namespace Microsoft.PowerShell.Commands - - +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventCommand.cs index cac484db50e5..32668b34353f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -18,7 +17,7 @@ public class GetEventCommand : PSCmdlet #region parameters /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "BySource")] [ValidateNotNullOrEmpty()] @@ -28,6 +27,7 @@ public string SourceIdentifier { return _sourceIdentifier; } + set { _sourceIdentifier = value; @@ -38,10 +38,11 @@ public string SourceIdentifier } } } + private string _sourceIdentifier = null; /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "ById")] [Alias("Id")] @@ -51,20 +52,21 @@ public int EventIdentifier { return _eventId; } + set { _eventId = value; } } - private int _eventId = -1; + private int _eventId = -1; #endregion parameters private WildcardPattern _matchPattern; /// - /// Get the requested events + /// Get the requested events. /// protected override void EndProcessing() { @@ -123,7 +125,7 @@ protected override void EndProcessing() } ErrorRecord errorRecord = new ErrorRecord( - new ArgumentException(String.Format(System.Globalization.CultureInfo.CurrentCulture, error, identifier)), + new ArgumentException(string.Format(System.Globalization.CultureInfo.CurrentCulture, error, identifier)), "INVALID_SOURCE_IDENTIFIER", ErrorCategory.InvalidArgument, null); @@ -133,4 +135,4 @@ protected override void EndProcessing() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventSubscriberCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventSubscriberCommand.cs index 3e00f79679d1..b1c1eb09b1ee 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventSubscriberCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetEventSubscriberCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -18,7 +17,7 @@ public class GetEventSubscriberCommand : PSCmdlet #region parameters /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "BySource")] [ValidateNotNullOrEmpty()] @@ -28,6 +27,7 @@ public string SourceIdentifier { return _sourceIdentifier; } + set { _sourceIdentifier = value; @@ -38,18 +38,18 @@ public string SourceIdentifier } } } + private string _sourceIdentifier = null; /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "ById")] [Alias("Id")] public int SubscriptionId { get; set; } = -1; - /// - /// Also show supporting events + /// Also show supporting events. /// [Parameter(Position = 1)] public SwitchParameter Force { get; set; } @@ -59,7 +59,7 @@ public string SourceIdentifier private WildcardPattern _matchPattern; /// - /// Get the subscribers + /// Get the subscribers. /// protected override void ProcessRecord() { @@ -119,7 +119,7 @@ protected override void ProcessRecord() } ErrorRecord errorRecord = new ErrorRecord( - new ArgumentException(String.Format(System.Globalization.CultureInfo.CurrentCulture, error, identifier)), + new ArgumentException(string.Format(System.Globalization.CultureInfo.CurrentCulture, error, identifier)), "INVALID_SOURCE_IDENTIFIER", ErrorCategory.InvalidArgument, null); @@ -129,4 +129,4 @@ protected override void ProcessRecord() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs index 336c4829d420..14dd99dcd112 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs @@ -1,32 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; -using System.Management.Automation; using System.Collections.ObjectModel; -using System.Security.Cryptography; using System.IO; +using System.Management.Automation; +using System.Security.Cryptography; namespace Microsoft.PowerShell.Commands { /// - /// This class implements Get-FileHash + /// This class implements Get-FileHash. /// [Cmdlet(VerbsCommon.Get, "FileHash", DefaultParameterSetName = PathParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkId=517145")] [OutputType(typeof(FileHashInfo))] public class GetFileHashCommand : HashCmdletBase { /// - /// Path parameter - /// The paths of the files to calculate a hashs - /// Resolved wildcards + /// Path parameter. + /// The paths of the files to calculate hash values. + /// Resolved wildcards. /// /// [Parameter(Mandatory = true, ParameterSetName = PathParameterSet, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] - public String[] Path + public string[] Path { get { return _paths; } + set { _paths = value; @@ -34,38 +38,39 @@ public String[] Path } /// - /// LiteralPath parameter - /// The literal paths of the files to calculate a hashs - /// Don't resolved wildcards + /// LiteralPath parameter. + /// The literal paths of the files to calculate a hashs. + /// Don't resolved wildcards. /// /// [Parameter(Mandatory = true, ParameterSetName = LiteralPathParameterSet, Position = 0, ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] - public String[] LiteralPath + [Alias("PSPath", "LP")] + public string[] LiteralPath { get { return _paths; } + set { _paths = value; } } - private String[] _paths; + private string[] _paths; /// - /// InputStream parameter - /// The stream of the file to calculate a hash + /// InputStream parameter. + /// The stream of the file to calculate a hash. /// /// [Parameter(Mandatory = true, ParameterSetName = StreamParameterSet, Position = 0)] public Stream InputStream { get; set; } /// - /// BeginProcessing() override - /// This is for hash function init + /// BeginProcessing() override. + /// This is for hash function init. /// protected override void BeginProcessing() { @@ -73,8 +78,8 @@ protected override void BeginProcessing() } /// - /// ProcessRecord() override - /// This is for paths collecting from pipe + /// ProcessRecord() override. + /// This is for paths collecting from pipe. /// protected override void ProcessRecord() { @@ -107,6 +112,7 @@ protected override void ProcessRecord() } } } + break; case LiteralPathParameterSet: foreach (string path in _paths) @@ -114,13 +120,14 @@ protected override void ProcessRecord() string newPath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path); pathsToProcess.Add(newPath); } + break; } foreach (string path in pathsToProcess) { byte[] bytehash = null; - String hash = null; + string hash = null; Stream openfilestream = null; try @@ -128,7 +135,7 @@ protected override void ProcessRecord() openfilestream = File.OpenRead(path); bytehash = hasher.ComputeHash(openfilestream); - hash = BitConverter.ToString(bytehash).Replace("-",""); + hash = BitConverter.ToString(bytehash).Replace("-", string.Empty); WriteHashResult(Algorithm, hash, path); } catch (FileNotFoundException ex) @@ -147,25 +154,25 @@ protected override void ProcessRecord() } /// - /// Perform common error checks - /// Populate source code + /// Perform common error checks. + /// Populate source code. /// protected override void EndProcessing() { if (ParameterSetName == StreamParameterSet) { byte[] bytehash = null; - String hash = null; + string hash = null; bytehash = hasher.ComputeHash(InputStream); - hash = BitConverter.ToString(bytehash).Replace("-",""); - WriteHashResult(Algorithm, hash, ""); + hash = BitConverter.ToString(bytehash).Replace("-", string.Empty); + WriteHashResult(Algorithm, hash, string.Empty); } } /// - /// Create FileHashInfo object and output it + /// Create FileHashInfo object and output it. /// private void WriteHashResult(string Algorithm, string hash, string path) { @@ -177,22 +184,21 @@ private void WriteHashResult(string Algorithm, string hash, string path) } /// - /// Parameter set names + /// Parameter set names. /// private const string PathParameterSet = "Path"; private const string LiteralPathParameterSet = "LiteralPath"; private const string StreamParameterSet = "StreamParameterSet"; - } /// - /// Base Cmdlet for cmdlets which deal with crypto hashes + /// Base Cmdlet for cmdlets which deal with crypto hashes. /// public class HashCmdletBase : PSCmdlet { /// - /// Algorithm parameter - /// The hash algorithm name: "SHA1", "SHA256", "SHA384", "SHA512", "MD5" + /// Algorithm parameter. + /// The hash algorithm name: "SHA1", "SHA256", "SHA384", "SHA512", "MD5". /// /// [Parameter(Position = 1)] @@ -201,12 +207,13 @@ public class HashCmdletBase : PSCmdlet HashAlgorithmNames.SHA384, HashAlgorithmNames.SHA512, HashAlgorithmNames.MD5)] - public String Algorithm + public string Algorithm { get { return _Algorithm; } + set { // A hash algorithm name is case sensitive @@ -215,15 +222,15 @@ public String Algorithm } } - private String _Algorithm = HashAlgorithmNames.SHA256; + private string _Algorithm = HashAlgorithmNames.SHA256; /// - /// Hash algorithm is used + /// Hash algorithm is used. /// protected HashAlgorithm hasher; /// - /// Hash algorithm names + /// Hash algorithm names. /// internal static class HashAlgorithmNames { @@ -235,7 +242,7 @@ internal static class HashAlgorithmNames } /// - /// Init a hash algorithm + /// Init a hash algorithm. /// protected void InitHasher(String Algorithm) { @@ -263,30 +270,30 @@ protected void InitHasher(String Algorithm) catch { // Seems it will never throw! Remove? - Exception exc = new NotSupportedException(UtilityResources.AlgorithmTypeNotSupported); + Exception exc = new NotSupportedException(UtilityCommonStrings.AlgorithmTypeNotSupported); ThrowTerminatingError(new ErrorRecord(exc, "AlgorithmTypeNotSupported", ErrorCategory.NotImplemented, null)); } } } /// - /// FileHashInfo class contains information about a file hash + /// FileHashInfo class contains information about a file hash. /// - public class FileHashInfo - { + public class FileHashInfo + { /// - /// Hash algorithm name + /// Hash algorithm name. /// - public string Algorithm { get; set;} + public string Algorithm { get; set; } /// - /// Hash value + /// Hash value. /// - public string Hash { get; set;} + public string Hash { get; set; } /// - /// File path + /// File path. /// - public string Path { get; set;} - } + public string Path { get; set; } + } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHostCmdlet.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHostCmdlet.cs index c4906048279b..637bb85f437a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHostCmdlet.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHostCmdlet.cs @@ -1,7 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; @@ -10,9 +8,7 @@ namespace Microsoft.PowerShell.Commands { /// - /// - /// Writes the PSHost object to the success stream - /// + /// Writes the PSHost object to the success stream. /// [Cmdlet(VerbsCommon.Get, "Host", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113318", RemotingCapability = RemotingCapability.None)] @@ -21,9 +17,7 @@ namespace Microsoft.PowerShell.Commands class GetHostCommand : PSCmdlet { /// - /// - /// See base class - /// + /// See base class. /// protected override void BeginProcessing() { @@ -31,4 +25,3 @@ protected override void BeginProcessing() } } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetMember.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetMember.cs index bee70b23fa63..a40ccf798b1f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetMember.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetMember.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.ObjectModel; @@ -12,19 +11,19 @@ namespace Microsoft.PowerShell.Commands { /// - /// Class with member information that this cmdlet writes to the pipeline + /// Class with member information that this cmdlet writes to the pipeline. /// public class MemberDefinition { /// - /// returns the member definition + /// Returns the member definition. /// public override string ToString() { return Definition; } /// - /// Initializes a new instance of this class + /// Initializes a new instance of this class. /// public MemberDefinition(string typeName, string name, PSMemberTypes memberType, string definition) { @@ -35,22 +34,22 @@ public MemberDefinition(string typeName, string name, PSMemberTypes memberType, } /// - /// type name + /// Type name. /// public string TypeName { get; } /// - /// member name + /// Member name. /// public string Name { get; } /// - /// member type + /// Member type. /// public PSMemberTypes MemberType { get; } /// - /// member definition + /// Member definition. /// public string Definition { get; } } @@ -63,28 +62,25 @@ public MemberDefinition(string typeName, string name, PSMemberTypes memberType, public class GetMemberCommand : PSCmdlet { /// - /// The object to retrieve properties from + /// The object to retrieve properties from. /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { set; get; } - /// - /// The member names to be retrieved + /// The member names to be retrieved. /// [Parameter(Position = 0)] [ValidateNotNullOrEmpty] public string[] Name { set; get; } = new string[] { "*" }; - /// - /// The member types to be retrieved + /// The member types to be retrieved. /// [Parameter] [Alias("Type")] public PSMemberTypes MemberType { set; get; } = PSMemberTypes.All; - /// /// View from which the members are retrieved. /// @@ -93,24 +89,24 @@ public class GetMemberCommand : PSCmdlet private bool _staticParameter = false; /// - /// True if we should return static members + /// True if we should return static members. /// [Parameter] public SwitchParameter Static { set { _staticParameter = value; } + get { return _staticParameter; } } /// - /// Gets or sets the force property + /// Gets or sets the force property. /// /// /// Gives the Member matcher guidance on how vigorous the Match should be. /// If set to true all members in a given view + membertype are displayed. - /// This parameter is added to hide Get/Set property accessor methods by - /// default. If a user wants to see these methods, -force should be set to - /// true. + /// This parameter is added to hide Get/Set property accessor methods by default. + /// If a user wants to see these methods, -force should be set to true. /// [Parameter] public SwitchParameter Force @@ -119,6 +115,7 @@ public SwitchParameter Force { return (_matchOptions == MshMemberMatchOptions.IncludeHidden); } + set { if (value) @@ -132,12 +129,13 @@ public SwitchParameter Force } } } + private MshMemberMatchOptions _matchOptions = MshMemberMatchOptions.None; private HybridDictionary _typesAlreadyDisplayed = new HybridDictionary(); /// - /// This method implements the ProcessRecord method for get-member command + /// This method implements the ProcessRecord method for get-member command. /// protected override void ProcessRecord() { @@ -152,7 +150,7 @@ protected override void ProcessRecord() Adapter staticAdapter = null; if (this.Static == true) { - staticAdapter = PSObject.dotNetStaticAdapter; + staticAdapter = PSObject.DotNetStaticAdapter; object baseObject = this.InputObject.BaseObject; baseObjectAsType = baseObject as System.Type ?? baseObject.GetType(); typeName = baseObjectAsType.FullName; @@ -166,7 +164,7 @@ protected override void ProcessRecord() } else { - //This is never used for display. It is used only as a key to typesAlreadyDisplayed + // This is never used for display. It is used only as a key to typesAlreadyDisplayed typeName = ""; } } @@ -177,7 +175,7 @@ protected override void ProcessRecord() } else { - _typesAlreadyDisplayed.Add(typeName, ""); + _typesAlreadyDisplayed.Add(typeName, string.Empty); } PSMemberTypes memberTypeToSearch = MemberType; @@ -190,7 +188,6 @@ protected override void ProcessRecord() // PSMemberSet instance is created to represent PSExtended, PSAdapted, PSBase, PSObject hidden // properties. We should honor extended properties for such case. - // request is to search dotnet or adapted or both members. // dotnet,adapted members cannot be Script*,Note*,Code* memberTypeToSearch ^= (PSMemberTypes.AliasProperty | PSMemberTypes.CodeMethod | PSMemberTypes.CodeProperty @@ -235,14 +232,16 @@ protected override void ProcessRecord() if (!Force) { PSMethod memberAsPSMethod = member as PSMethod; - if ((null != memberAsPSMethod) && (memberAsPSMethod.IsSpecial)) + if ((memberAsPSMethod != null) && (memberAsPSMethod.IsSpecial)) { continue; } } + members[resultCount] = new MemberDefinition(typeName, member.Name, member.MemberType, member.ToString()); resultCount++; } + Array.Sort(members, 0, resultCount, new MemberComparer()); for (int index = 0; index < resultCount; index++) { @@ -255,19 +254,19 @@ private class MemberComparer : System.Collections.Generic.IComparer - /// This method implements the End method for get-member command + /// This method implements the End method for get-member command. /// protected override void EndProcessing() { @@ -283,4 +282,3 @@ protected override void EndProcessing() } } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs index 35bba80c9dfa..1a7c4b1a8d67 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -9,9 +8,10 @@ using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Numerics; +using System.Security.Cryptography; using System.Threading; + using Debug = System.Management.Automation.Diagnostics; -using System.Security.Cryptography; namespace Microsoft.PowerShell.Commands { @@ -45,7 +45,7 @@ private MyParameterSet EffectiveParameterSet // cache MyParameterSet enum instead of doing string comparison every time if (_effectiveParameterSet == MyParameterSet.Unknown) { - if ((this.MyInvocation.ExpectingInput) && (this.Maximum == null) && (this.Minimum == null)) + if ((MyInvocation.ExpectingInput) && (Maximum == null) && (Minimum == null)) { _effectiveParameterSet = MyParameterSet.RandomListItem; } @@ -53,11 +53,11 @@ private MyParameterSet EffectiveParameterSet { _effectiveParameterSet = MyParameterSet.RandomListItem; } - else if (this.ParameterSetName.Equals(GetRandomCommand.RandomNumberParameterSet, StringComparison.OrdinalIgnoreCase)) + else if (ParameterSetName.Equals(GetRandomCommand.RandomNumberParameterSet, StringComparison.OrdinalIgnoreCase)) { - if ((this.Maximum != null) && (this.Maximum.GetType().IsArray)) + if ((Maximum != null) && (Maximum.GetType().IsArray)) { - this.InputObject = (object[])this.Maximum; + InputObject = (object[])Maximum; _effectiveParameterSet = MyParameterSet.RandomListItem; } else @@ -79,26 +79,26 @@ private MyParameterSet EffectiveParameterSet #region Error handling - private void ThrowMinGreaterThanOrEqualMax(object min, object max) + private void ThrowMinGreaterThanOrEqualMax(object minValue, object maxValue) { - if (min == null) + if (minValue == null) { throw PSTraceSource.NewArgumentNullException("min"); } - if (max == null) + if (maxValue == null) { throw PSTraceSource.NewArgumentNullException("max"); } ErrorRecord errorRecord = new ErrorRecord( - new ArgumentException(String.Format( - CultureInfo.InvariantCulture, GetRandomCommandStrings.MinGreaterThanOrEqualMax, min, max)), + new ArgumentException(string.Format( + CultureInfo.InvariantCulture, GetRandomCommandStrings.MinGreaterThanOrEqualMax, minValue, maxValue)), "MinGreaterThanOrEqualMax", ErrorCategory.InvalidArgument, null); - this.ThrowTerminatingError(errorRecord); + ThrowTerminatingError(errorRecord); } #endregion @@ -125,6 +125,7 @@ private static void CurrentRunspace_StateChanged(object sender, RunspaceStateEve { GetRandomCommand.s_runspaceGeneratorMapLock.ExitWriteLock(); } + break; } } @@ -132,7 +133,7 @@ private static void CurrentRunspace_StateChanged(object sender, RunspaceStateEve private PolymorphicRandomNumberGenerator _generator; /// - /// Gets and sets generator associated with the current runspace + /// Gets and sets generator associated with the current runspace. /// private PolymorphicRandomNumberGenerator Generator { @@ -140,7 +141,7 @@ private PolymorphicRandomNumberGenerator Generator { if (_generator == null) { - Guid runspaceId = this.Context.CurrentRunspace.InstanceId; + Guid runspaceId = Context.CurrentRunspace.InstanceId; bool needToInitialize = false; try @@ -155,16 +156,17 @@ private PolymorphicRandomNumberGenerator Generator if (needToInitialize) { - this.Generator = new PolymorphicRandomNumberGenerator(); + Generator = new PolymorphicRandomNumberGenerator(); } } return _generator; } + set { _generator = value; - Runspace myRunspace = this.Context.CurrentRunspace; + Runspace myRunspace = Context.CurrentRunspace; try { @@ -174,6 +176,7 @@ private PolymorphicRandomNumberGenerator Generator // make sure we won't leave the generator around after runspace exits myRunspace.StateChanged += CurrentRunspace_StateChanged; } + GetRandomCommand.s_runspaceGeneratorMap[myRunspace.InstanceId] = _generator; } finally @@ -188,7 +191,7 @@ private PolymorphicRandomNumberGenerator Generator #region Common parameters /// - /// Seed used to reinitialize random numbers generator + /// Seed used to reinitialize random numbers generator. /// [Parameter] [ValidateNotNull] @@ -199,13 +202,13 @@ private PolymorphicRandomNumberGenerator Generator #region Parameters for RandomNumberParameterSet /// - /// Maximum number to generate + /// Maximum number to generate. /// [Parameter(ParameterSetName = RandomNumberParameterSet, Position = 0)] public object Maximum { get; set; } /// - /// Minimum number to generate + /// Minimum number to generate. /// [Parameter(ParameterSetName = RandomNumberParameterSet)] public object Minimum { get; set; } @@ -216,6 +219,7 @@ private bool IsInt(object o) { return true; } + return false; } @@ -225,6 +229,7 @@ private bool IsInt64(object o) { return true; } + return false; } @@ -267,7 +272,7 @@ private double ConvertToDouble(object o, double defaultIfNull) private int _numberOfProcessedListItems; /// - /// List from which random elements are chosen + /// List from which random elements are chosen. /// [Parameter(ParameterSetName = RandomListItemParameterSet, ValueFromPipeline = true, Position = 0, Mandatory = true)] [ValidateNotNullOrEmpty] @@ -275,20 +280,20 @@ private double ConvertToDouble(object o, double defaultIfNull) public object[] InputObject { get; set; } /// - /// Number of items to output (number of list items or of numbers) + /// Number of items to output (number of list items or of numbers). /// - [Parameter(ParameterSetName = GetRandomCommand.RandomListItemParameterSet)] + [Parameter] [ValidateRange(1, int.MaxValue)] - public int Count { get; set; } + public int Count { get; set; } = 1; #endregion #region Cmdlet processing methods - private double GetRandomDouble(double min, double max) + private double GetRandomDouble(double minValue, double maxValue) { double randomNumber; - double diff = max - min; + double diff = maxValue - minValue; // I couldn't find a better fix for bug #216893 then // to test and retry if a random number falls outside the bounds @@ -302,44 +307,44 @@ private double GetRandomDouble(double min, double max) { do { - double r = this.Generator.NextDouble(); - randomNumber = min + r * max - r * min; + double r = Generator.NextDouble(); + randomNumber = minValue + r * maxValue - r * minValue; } - while (randomNumber >= max); + while (randomNumber >= maxValue); } else { do { - double r = this.Generator.NextDouble(); - randomNumber = min + r * diff; + double r = Generator.NextDouble(); + randomNumber = minValue + r * diff; diff = diff * r; } - while (randomNumber >= max); + while (randomNumber >= maxValue); } return randomNumber; } /// - /// Get a random Int64 type number + /// Get a random Int64 type number. /// - /// - /// + /// + /// /// - private Int64 GetRandomInt64(Int64 min, Int64 max) + private Int64 GetRandomInt64(Int64 minValue, Int64 maxValue) { // Randomly generate eight bytes and convert the byte array to UInt64 var buffer = new byte[sizeof(UInt64)]; UInt64 randomUint64; - BigInteger bigIntegerDiff = (BigInteger)max - (BigInteger)min; + BigInteger bigIntegerDiff = (BigInteger)maxValue - (BigInteger)minValue; // When the difference is less than int.MaxValue, use Random.Next(int, int) if (bigIntegerDiff <= int.MaxValue) { - int randomDiff = this.Generator.Next(0, (int)(max - min)); - return min + randomDiff; + int randomDiff = Generator.Next(0, (int)(maxValue - minValue)); + return minValue + randomDiff; } // The difference of two Int64 numbers would not exceed UInt64.MaxValue, so it can be represented by a UInt64 number. @@ -357,113 +362,118 @@ private Int64 GetRandomInt64(Int64 min, Int64 max) do { // Randomly fill the buffer - this.Generator.NextBytes(buffer); + Generator.NextBytes(buffer); randomUint64 = BitConverter.ToUInt64(buffer, 0); - // Get the last 'bitsToRepresentDiff' number of randon bits + + // Get the last 'bitsToRepresentDiff' number of random bits randomUint64 &= mask; } while (uint64Diff <= randomUint64); - double result = min * 1.0 + randomUint64 * 1.0; - return (Int64)result; + double randomNumber = minValue * 1.0 + randomUint64 * 1.0; + return (Int64)randomNumber; } /// - /// This method implements the BeginProcessing method for get-random command + /// This method implements the BeginProcessing method for get-random command. /// protected override void BeginProcessing() { - if (this.SetSeed.HasValue) + if (SetSeed.HasValue) { - this.Generator = new PolymorphicRandomNumberGenerator(this.SetSeed.Value); + Generator = new PolymorphicRandomNumberGenerator(SetSeed.Value); } - if (this.EffectiveParameterSet == MyParameterSet.RandomNumber) + if (EffectiveParameterSet == MyParameterSet.RandomNumber) { - object maxOperand = ProcessOperand(this.Maximum); - object minOperand = ProcessOperand(this.Minimum); + object maxOperand = ProcessOperand(Maximum); + object minOperand = ProcessOperand(Minimum); if (IsInt(maxOperand) && IsInt(minOperand)) { - int min = minOperand != null ? (int)minOperand : 0; - int max = maxOperand != null ? (int)maxOperand : int.MaxValue; + int minValue = minOperand != null ? (int)minOperand : 0; + int maxValue = maxOperand != null ? (int)maxOperand : int.MaxValue; - if (min >= max) + if (minValue >= maxValue) { - this.ThrowMinGreaterThanOrEqualMax(min, max); + ThrowMinGreaterThanOrEqualMax(minValue, maxValue); } - int randomNumber = this.Generator.Next(min, max); - Debug.Assert(min <= randomNumber, "lower bound <= random number"); - Debug.Assert(randomNumber < max, "random number < upper bound"); + for (int i = 0; i < Count; i++) + { + int randomNumber = Generator.Next(minValue, maxValue); + Debug.Assert(minValue <= randomNumber, "lower bound <= random number"); + Debug.Assert(randomNumber < maxValue, "random number < upper bound"); - this.WriteObject(randomNumber); + WriteObject(randomNumber); + } } else if ((IsInt64(maxOperand) || IsInt(maxOperand)) && (IsInt64(minOperand) || IsInt(minOperand))) { - Int64 min = minOperand != null ? ((minOperand is Int64) ? (Int64)minOperand : (int)minOperand) : 0; - Int64 max = maxOperand != null ? ((maxOperand is Int64) ? (Int64)maxOperand : (int)maxOperand) : Int64.MaxValue; + Int64 minValue = minOperand != null ? ((minOperand is Int64) ? (Int64)minOperand : (int)minOperand) : 0; + Int64 maxValue = maxOperand != null ? ((maxOperand is Int64) ? (Int64)maxOperand : (int)maxOperand) : Int64.MaxValue; - if (min >= max) + if (minValue >= maxValue) { - this.ThrowMinGreaterThanOrEqualMax(min, max); + ThrowMinGreaterThanOrEqualMax(minValue, maxValue); } - Int64 randomNumber = this.GetRandomInt64(min, max); - Debug.Assert(min <= randomNumber, "lower bound <= random number"); - Debug.Assert(randomNumber < max, "random number < upper bound"); + for (int i = 0; i < Count; i++) + { + Int64 randomNumber = GetRandomInt64(minValue, maxValue); + Debug.Assert(minValue <= randomNumber, "lower bound <= random number"); + Debug.Assert(randomNumber < maxValue, "random number < upper bound"); - this.WriteObject(randomNumber); + WriteObject(randomNumber); + } } else { - double min = (minOperand is double) ? (double)minOperand : this.ConvertToDouble(this.Minimum, 0.0); - double max = (maxOperand is double) ? (double)maxOperand : this.ConvertToDouble(this.Maximum, double.MaxValue); + double minValue = (minOperand is double) ? (double)minOperand : ConvertToDouble(Minimum, 0.0); + double maxValue = (maxOperand is double) ? (double)maxOperand : ConvertToDouble(Maximum, double.MaxValue); - if (min >= max) + if (minValue >= maxValue) { - this.ThrowMinGreaterThanOrEqualMax(min, max); + ThrowMinGreaterThanOrEqualMax(minValue, maxValue); } - double randomNumber = this.GetRandomDouble(min, max); - Debug.Assert(min <= randomNumber, "lower bound <= random number"); - Debug.Assert(randomNumber < max, "random number < upper bound"); + for (int i = 0; i < Count; i++) + { + double randomNumber = GetRandomDouble(minValue, maxValue); + Debug.Assert(minValue <= randomNumber, "lower bound <= random number"); + Debug.Assert(randomNumber < maxValue, "random number < upper bound"); - this.WriteObject(randomNumber); + WriteObject(randomNumber); + } } } - else if (this.EffectiveParameterSet == MyParameterSet.RandomListItem) + else if (EffectiveParameterSet == MyParameterSet.RandomListItem) { _chosenListItems = new List(); _numberOfProcessedListItems = 0; - - if (this.Count == 0) // -Count not specified - { - this.Count = 1; // default to one random item by default - } } } // rough proof that when choosing random K items out of N items // each item has got K/N probability of being included in the final list // - // probability that a particular item in this.chosenListItems is NOT going to be replaced + // probability that a particular item in chosenListItems is NOT going to be replaced // when processing I-th input item [assumes I > K]: // P_one_step(I) = 1 - ((K / I) * ((K - 1) / K) + ((I - K) / I) = (I - 1) / I // <--A--> <-----B-----> <-----C-----> - // A - probability that I-th element is going to be replacing an element from this.chosenListItems + // A - probability that I-th element is going to be replacing an element from chosenListItems // (see (1) in the code below) - // B - probability that a particular element from this.chosenListItems is NOT going to be replaced + // B - probability that a particular element from chosenListItems is NOT going to be replaced // (see (2) in the code below) - // C - probability that I-th element is NOT going to be replacing an element from this.chosenListItems + // C - probability that I-th element is NOT going to be replacing an element from chosenListItems // (see (1) in the code below) // - // probability that a particular item in this.chosenListItems is NOT going to be replaced + // probability that a particular item in chosenListItems is NOT going to be replaced // when processing input items J through N [assumes J > K] // P_removal(J) = Multiply(for I = J to N) P(I) = // = ((J - 1) / J) * (J / (J + 1)) * ... * ((N - 2) / (N - 1)) * ((N - 1) / N) = // = (J - 1) / N // - // probability that when processing an element it is going to be put into this.chosenListItems + // probability that when processing an element it is going to be put into chosenListItems // P_insertion(I) = 1.0 when I <= K - see (3) in the code below // P_insertion(I) = K/N otherwise - see (1) in the code below // @@ -475,25 +485,25 @@ protected override void BeginProcessing() // which proves that P_final(I) = K / N for all values of I. QED. /// - /// This method implements the ProcessRecord method for get-random command + /// This method implements the ProcessRecord method for get-random command. /// protected override void ProcessRecord() { - if (this.EffectiveParameterSet == MyParameterSet.RandomListItem) + if (EffectiveParameterSet == MyParameterSet.RandomListItem) { - foreach (object item in this.InputObject) + foreach (object item in InputObject) { - if (_numberOfProcessedListItems < this.Count) // (3) + if (_numberOfProcessedListItems < Count) // (3) { - Debug.Assert(_chosenListItems.Count == _numberOfProcessedListItems, "Initial K elements should all be included in this.chosenListItems"); + Debug.Assert(_chosenListItems.Count == _numberOfProcessedListItems, "Initial K elements should all be included in chosenListItems"); _chosenListItems.Add(item); } else { - Debug.Assert(_chosenListItems.Count == this.Count, "After processing K initial elements, the length of this.chosenItems should stay equal to K"); - if (this.Generator.Next(_numberOfProcessedListItems + 1) < this.Count) // (1) + Debug.Assert(_chosenListItems.Count == Count, "After processing K initial elements, the length of chosenItems should stay equal to K"); + if (Generator.Next(_numberOfProcessedListItems + 1) < Count) // (1) { - int indexToReplace = this.Generator.Next(_chosenListItems.Count); // (2) + int indexToReplace = Generator.Next(_chosenListItems.Count); // (2) _chosenListItems[indexToReplace] = item; } } @@ -504,11 +514,11 @@ protected override void ProcessRecord() } /// - /// This method implements the EndProcessing method for get-random command + /// This method implements the EndProcessing method for get-random command. /// protected override void EndProcessing() { - if (this.EffectiveParameterSet == MyParameterSet.RandomListItem) + if (EffectiveParameterSet == MyParameterSet.RandomListItem) { // make sure the order is truly random // (all permutations with the same probability) @@ -516,23 +526,17 @@ protected override void EndProcessing() int n = _chosenListItems.Count; for (int i = 0; i < n; i++) { - // randomly choose an item to go into the i-th position - int j = this.Generator.Next(i, n); + // randomly choose j from [i...n) + int j = Generator.Next(i, n); + + WriteObject(_chosenListItems[j]); - // swap j-th item into i-th position + // remove the output object from consideration in the next iteration. if (i != j) { - object tmp = _chosenListItems[i]; - _chosenListItems[i] = _chosenListItems[j]; - _chosenListItems[j] = tmp; + _chosenListItems[j] = _chosenListItems[i]; } } - - // output all items - foreach (object chosenItem in _chosenListItems) - { - this.WriteObject(chosenItem); - } } } @@ -543,12 +547,12 @@ protected override void EndProcessing() /// Provides an adapter API for random numbers that may be either cryptographically random, or /// generated with the regular pseudo-random number generator. Re-implementations of /// methods using the NextBytes() primitive based on the CLR implementation: - /// http://referencesource.microsoft.com/#mscorlib/system/random.cs + /// https://referencesource.microsoft.com/#mscorlib/system/random.cs. /// internal class PolymorphicRandomNumberGenerator { /// - /// Constructor + /// Constructor. /// public PolymorphicRandomNumberGenerator() { @@ -568,7 +572,7 @@ internal PolymorphicRandomNumberGenerator(int seed) /// /// Generates a random floating-point number that is greater than or equal to 0.0, and less than 1.0. /// - /// A random floating-point number that is greater than or equal to 0.0, and less than 1.0 + /// A random floating-point number that is greater than or equal to 0.0, and less than 1.0. internal double NextDouble() { // According to the CLR source: @@ -582,23 +586,23 @@ internal double NextDouble() /// A non-negative random integer. internal int Next() { - int result; + int randomNumber; // The CLR implementation just fudges // Int32.MaxValue down to (Int32.MaxValue - 1). This implementation // errs on the side of correctness. do { - result = InternalSample(); + randomNumber = InternalSample(); } - while (result == Int32.MaxValue); + while (randomNumber == Int32.MaxValue); - if (result < 0) + if (randomNumber < 0) { - result += Int32.MaxValue; + randomNumber += Int32.MaxValue; } - return result; + return randomNumber; } /// @@ -620,7 +624,7 @@ internal int Next(int maxValue) /// Returns a random integer that is within a specified range. /// /// The inclusive lower bound of the random number returned. - /// The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue + /// The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue. /// public int Next(int minValue, int maxValue) { @@ -629,24 +633,26 @@ public int Next(int minValue, int maxValue) throw new ArgumentOutOfRangeException("minValue", GetRandomCommandStrings.MinGreaterThanOrEqualMaxApi); } + int randomNumber = 0; + long range = (long)maxValue - (long)minValue; if (range <= int.MaxValue) { - return ((int)(NextDouble() * range) + minValue); + randomNumber = ((int)(NextDouble() * range) + minValue); } else { double largeSample = InternalSampleLargeRange() * (1.0 / (2 * ((uint)Int32.MaxValue))); - int result = (int)((long)(largeSample * range) + minValue); - - return result; + randomNumber = (int)((long)(largeSample * range) + minValue); } + + return randomNumber; } /// /// Fills the elements of a specified array of bytes with random numbers. /// - /// The array to be filled + /// The array to be filled. internal void NextBytes(byte[] buffer) { if (_cryptographicGenerator != null) @@ -660,37 +666,37 @@ internal void NextBytes(byte[] buffer) } /// - /// Samples a random integer + /// Samples a random integer. /// - /// A random integer, using the full range of Int32 + /// A random integer, using the full range of Int32. private int InternalSample() { - int result; + int randomNumber; byte[] data = new byte[sizeof(int)]; NextBytes(data); - result = BitConverter.ToInt32(data, 0); + randomNumber = BitConverter.ToInt32(data, 0); - return result; + return randomNumber; } /// /// Samples a random int when the range is large. This does /// not need to be in the range of -Double.MaxValue .. Double.MaxValue, - /// just 0.. (2 * Int32.MaxValue) - 1 + /// just 0.. (2 * Int32.MaxValue) - 1 . /// /// private double InternalSampleLargeRange() { - double result; + double randomNumber; do { - result = InternalSample(); - } while (result == Int32.MaxValue); + randomNumber = InternalSample(); + } while (randomNumber == Int32.MaxValue); - result += Int32.MaxValue; - return result; + randomNumber += Int32.MaxValue; + return randomNumber; } } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRunspaceCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRunspaceCommand.cs index 65fc5cb7be94..e388e6609ecd 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRunspaceCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRunspaceCommand.cs @@ -1,12 +1,12 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; using System.Management.Automation.Runspaces; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Commands @@ -73,7 +73,7 @@ public Guid[] InstanceId #region Overrides /// - /// Process record + /// Process record. /// protected override void ProcessRecord() { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUICultureCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUICultureCommand.cs index 6f8693e4b357..37a0a80bd7fd 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUICultureCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUICultureCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; @@ -14,13 +13,11 @@ namespace Microsoft.PowerShell.Commands public sealed class GetUICultureCommand : PSCmdlet { /// - /// Output the current UI Culture info object + /// Output the current UI Culture info object. /// protected override void BeginProcessing() { WriteObject(Host.CurrentUICulture); - } // EndProcessing - } // GetUICultureCommand -} // Microsoft.PowerShell.Commands - - + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUnique.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUnique.cs index 4b9e68af7700..baf6f16bff08 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUnique.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUnique.cs @@ -1,16 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Globalization; using System.Management.Automation; using System.Management.Automation.Internal; -using System.Globalization; namespace Microsoft.PowerShell.Commands { /// - /// /// [Cmdlet(VerbsCommon.Get, "Unique", DefaultParameterSetName = "AsString", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113335", RemotingCapability = RemotingCapability.None)] @@ -18,13 +16,11 @@ public sealed class GetUniqueCommand : PSCmdlet { #region Parameters /// - /// /// /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { set; get; } = AutomationNull.Value; - /// /// This parameter specifies that objects should be converted to /// strings and the strings should be compared. @@ -34,10 +30,11 @@ public sealed class GetUniqueCommand : PSCmdlet public SwitchParameter AsString { get { return _asString; } + set { _asString = value; } } - private bool _asString; + private bool _asString; /// /// This parameter specifies that just the types of the objects @@ -48,19 +45,20 @@ public SwitchParameter AsString public SwitchParameter OnType { get { return _onType; } + set { _onType = value; } } + private bool _onType = false; #endregion Parameters #region Overrides /// - /// /// protected override void ProcessRecord() { bool isUnique = true; - if (null == _lastObject) + if (_lastObject == null) { // always write first object, but return nothing // on "MSH> get-unique" @@ -74,11 +72,12 @@ protected override void ProcessRecord() else if (AsString) { string inputString = InputObject.ToString(); - if (null == _lastObjectAsString) + if (_lastObjectAsString == null) { _lastObjectAsString = _lastObject.ToString(); } - if (0 == String.Compare( + + if (0 == string.Compare( inputString, _lastObjectAsString, StringComparison.CurrentCulture)) @@ -92,13 +91,14 @@ protected override void ProcessRecord() } else // compare as objects { - if (null == _comparer) + if (_comparer == null) { _comparer = new ObjectCommandComparer( true, // ascending (doesn't matter) CultureInfo.CurrentCulture, true); // case-sensitive } + isUnique = (0 != _comparer.Compare(InputObject, _lastObject)); } @@ -117,4 +117,3 @@ protected override void ProcessRecord() #endregion Internal } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs index 609df1d6558b..0527ed8fce83 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; using System.Diagnostics; +using System.Management.Automation; using System.Management.Automation.Internal; namespace Microsoft.PowerShell.Commands { /// - /// This class implements Get-Uptime + /// This class implements Get-Uptime. /// [Cmdlet(VerbsCommon.Get, "Uptime", DefaultParameterSetName = TimespanParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?linkid=834862")] [OutputType(typeof(TimeSpan), ParameterSetName = new string[] { TimespanParameterSet })] @@ -18,16 +17,14 @@ namespace Microsoft.PowerShell.Commands public class GetUptimeCommand : PSCmdlet { /// - /// Since parameter - /// The system startup time + /// The system startup time. /// /// [Parameter(ParameterSetName = SinceParameterSet)] public SwitchParameter Since { get; set; } = new SwitchParameter(); /// - /// ProcessRecord() override - /// This is the main entry point for the cmdlet + /// This is the main entry point for the cmdlet. /// protected override void ProcessRecord() { @@ -37,7 +34,7 @@ protected override void ProcessRecord() // InternalTestHooks.StopwatchIsNotHighResolution is used as test hook. if (Stopwatch.IsHighResolution && !InternalTestHooks.StopwatchIsNotHighResolution) { - TimeSpan uptime = TimeSpan.FromSeconds(Stopwatch.GetTimestamp()/Stopwatch.Frequency); + TimeSpan uptime = TimeSpan.FromSeconds(Stopwatch.GetTimestamp() / Stopwatch.Frequency); switch (ParameterSetName) { @@ -68,5 +65,5 @@ protected override void ProcessRecord() /// Parameter set name for DateTime OutputType. /// private const string SinceParameterSet = "Since"; - } + } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetVerbCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetVerbCommand.cs index 384c10300855..b661d67f4af0 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetVerbCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetVerbCommand.cs @@ -1,21 +1,23 @@ -using System; -using System.Management.Automation; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Management.Automation; using System.Reflection; namespace Microsoft.PowerShell.Commands { - /// - /// Implementation of the Get Verb Command + /// Implementation of the Get Verb Command. /// [Cmdlet(VerbsCommon.Get, "Verb", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=160712")] [OutputType(typeof(VerbInfo))] public class GetVerbCommand : Cmdlet { /// - /// Optional Verb filter + /// Optional Verb filter. /// [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, Position = 0)] public string[] Verb @@ -24,7 +26,7 @@ public string[] Verb } /// - /// Optional Group filter + /// Optional Group filter. /// [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, Position = 1)] [ValidateSet("Common", "Communications", "Data", "Diagnostic", "Lifecycle", "Other", "Security")] @@ -34,11 +36,10 @@ public string[] Group } /// - /// Returns a list of verbs + /// Returns a list of verbs. /// protected override void ProcessRecord() { - Type[] verbTypes = new Type[] { typeof(VerbsCommon), typeof(VerbsCommunications), typeof(VerbsData), typeof(VerbsDiagnostic), typeof(VerbsLifecycle), typeof(VerbsOther), typeof(VerbsSecurity) }; @@ -57,6 +58,7 @@ protected override void ProcessRecord() continue; } } + foreach (FieldInfo field in type.GetFields()) { if (field.IsLiteral) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs new file mode 100644 index 000000000000..3b9a558663cf --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs @@ -0,0 +1,554 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Text; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// PSTuple is a helper class used to create Tuple from an input array. + /// + internal static class PSTuple + { + /// + /// ArrayToTuple is a helper method used to create a tuple for the supplied input array. + /// + /// The first generic type parameter. + /// Input objects used to create a tuple. + /// Tuple object. + internal static object ArrayToTuple(IList inputObjects) + { + return ArrayToTuple(inputObjects, 0); + } + + /// + /// ArrayToTuple is a helper method used to create a tuple for the supplied input array. + /// + /// The first generic type parameter. + /// Input objects used to create a tuple. + /// Start index of the array from which the objects have to considered for the tuple creation. + /// Tuple object. + private static object ArrayToTuple(IList inputObjects, int startIndex) + { + Diagnostics.Assert(inputObjects != null, "inputObjects is null"); + Diagnostics.Assert(inputObjects.Count > 0, "inputObjects is empty"); + + switch (inputObjects.Count - startIndex) + { + case 0: + return null; + case 1: + return Tuple.Create(inputObjects[startIndex]); + case 2: + return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1]); + case 3: + return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2]); + case 4: + return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2], inputObjects[startIndex + 3]); + case 5: + return Tuple.Create( + inputObjects[startIndex], + inputObjects[startIndex + 1], + inputObjects[startIndex + 2], + inputObjects[startIndex + 3], + inputObjects[startIndex + 4]); + case 6: + return Tuple.Create( + inputObjects[startIndex], + inputObjects[startIndex + 1], + inputObjects[startIndex + 2], + inputObjects[startIndex + 3], + inputObjects[startIndex + 4], + inputObjects[startIndex + 5]); + case 7: + return Tuple.Create( + inputObjects[startIndex], + inputObjects[startIndex + 1], + inputObjects[startIndex + 2], + inputObjects[startIndex + 3], + inputObjects[startIndex + 4], + inputObjects[startIndex + 5], + inputObjects[startIndex + 6]); + case 8: + return Tuple.Create( + inputObjects[startIndex], + inputObjects[startIndex + 1], + inputObjects[startIndex + 2], + inputObjects[startIndex + 3], + inputObjects[startIndex + 4], + inputObjects[startIndex + 5], + inputObjects[startIndex + 6], + inputObjects[startIndex + 7]); + default: + return Tuple.Create( + inputObjects[startIndex], + inputObjects[startIndex + 1], + inputObjects[startIndex + 2], + inputObjects[startIndex + 3], + inputObjects[startIndex + 4], + inputObjects[startIndex + 5], + inputObjects[startIndex + 6], + ArrayToTuple(inputObjects, startIndex + 7)); + } + } + } + + /// + /// Emitted by Group-Object when the NoElement option is true. + /// + public sealed class GroupInfoNoElement : GroupInfo + { + internal GroupInfoNoElement(OrderByPropertyEntry groupValue) : base(groupValue) + { + } + + internal override void Add(PSObject groupValue) + { + Count++; + } + } + + /// + /// Emitted by Group-Object. + /// + [DebuggerDisplay("{Name} ({Count})")] + public class GroupInfo + { + internal GroupInfo(OrderByPropertyEntry groupValue) + { + Group = new Collection(); + this.Add(groupValue.inputObject); + GroupValue = groupValue; + Name = BuildName(groupValue.orderValues); + } + + internal virtual void Add(PSObject groupValue) + { + Group.Add(groupValue); + Count++; + } + + private static string BuildName(List propValues) + { + StringBuilder sb = new StringBuilder(); + foreach (ObjectCommandPropertyValue propValue in propValues) + { + var propValuePropertyValue = propValue?.PropertyValue; + if (propValuePropertyValue != null) + { + if (propValuePropertyValue is ICollection propertyValueItems) + { + sb.Append("{"); + var length = sb.Length; + + foreach (object item in propertyValueItems) + { + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}, ", item.ToString()); + } + + sb = sb.Length > length ? sb.Remove(sb.Length - 2, 2) : sb; + sb.Append("}, "); + } + else + { + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}, ", propValuePropertyValue.ToString()); + } + } + } + + return sb.Length >= 2 ? sb.Remove(sb.Length - 2, 2).ToString() : string.Empty; + } + + /// + /// Gets the values of the group. + /// + public ArrayList Values + { + get + { + ArrayList values = new ArrayList(); + foreach (ObjectCommandPropertyValue propValue in GroupValue.orderValues) + { + values.Add(propValue.PropertyValue); + } + + return values; + } + } + + /// + /// Gets the number of objects in the group. + /// + public int Count { get; internal set; } + + /// + /// Gets the list of objects in this group. + /// + public Collection Group { get; } + + /// + /// Gets the name of the group. + /// + public string Name { get; } + + /// + /// Gets the OrderByPropertyEntry used to build this group object. + /// + internal OrderByPropertyEntry GroupValue { get; } + } + + /// + /// Group-Object implementation. + /// + [Cmdlet(VerbsData.Group, "Object", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113338", RemotingCapability = RemotingCapability.None)] + [OutputType(typeof(Hashtable), typeof(GroupInfo))] + public class GroupObjectCommand : ObjectBase + { + #region tracer + + /// + /// An instance of the PSTraceSource class used for trace output. + /// + [TraceSource("GroupObjectCommand", "Class that has group base implementation")] + private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("GroupObjectCommand", "Class that has group base implementation"); + + #endregion tracer + + #region Command Line Switches + + /// + /// Gets or sets the NoElement parameter indicating of the groups should be flattened. + /// + /// + [Parameter] + public SwitchParameter NoElement { get; set; } + + /// + /// Gets or sets the AsHashTable parameter. + /// + /// + [Parameter(ParameterSetName = "HashTable")] + [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "HashTable")] + [Alias("AHT")] + public SwitchParameter AsHashTable { get; set; } + + /// + /// Gets or sets the AsString parameter. + /// + [Parameter(ParameterSetName = "HashTable")] + public SwitchParameter AsString { get; set; } + + private readonly List _groups = new List(); + private readonly OrderByProperty _orderByProperty = new OrderByProperty(); + private readonly Dictionary _tupleToGroupInfoMappingDictionary = new Dictionary(); + private readonly List _entriesToOrder = new List(); + private OrderByPropertyComparer _orderByPropertyComparer; + private bool _hasProcessedFirstInputObject; + private bool _hasDifferentValueTypes; + private Type[] _propertyTypesCandidate; + + #endregion + + #region utils + + /// + /// Utility function called by Group-Object to create Groups. + /// + /// Input object that needs to be grouped. + /// True if we are not accumulating objects. + /// List containing Groups. + /// Dictionary used to keep track of the groups with hash of the property values being the key. + /// The Comparer to be used while comparing to check if new group has to be created. + private static void DoGrouping( + OrderByPropertyEntry currentObjectEntry, + bool noElement, + List groups, + Dictionary groupInfoDictionary, + OrderByPropertyComparer orderByPropertyComparer) + { + var currentObjectOrderValues = currentObjectEntry.orderValues; + if (currentObjectOrderValues != null && currentObjectOrderValues.Count > 0) + { + object currentTupleObject = PSTuple.ArrayToTuple(currentObjectOrderValues); + + if (groupInfoDictionary.TryGetValue(currentTupleObject, out var currentGroupInfo)) + { + // add this inputObject to an existing group + currentGroupInfo.Add(currentObjectEntry.inputObject); + } + else + { + bool isCurrentItemGrouped = false; + + for (int groupsIndex = 0; groupsIndex < groups.Count; groupsIndex++) + { + // Check if the current input object can be converted to one of the already known types + // by looking up in the type to GroupInfo mapping. + if (orderByPropertyComparer.Compare(groups[groupsIndex].GroupValue, currentObjectEntry) == 0) + { + groups[groupsIndex].Add(currentObjectEntry.inputObject); + isCurrentItemGrouped = true; + break; + } + } + + if (!isCurrentItemGrouped) + { + // create a new group + s_tracer.WriteLine("Create a new group: {0}", currentObjectOrderValues); + GroupInfo newObjGrp = noElement ? new GroupInfoNoElement(currentObjectEntry) : new GroupInfo(currentObjectEntry); + groups.Add(newObjGrp); + + groupInfoDictionary.Add(currentTupleObject, newObjGrp); + } + } + } + } + + /// + /// Utility function called by Group-Object to create Groups. + /// + /// Input object that needs to be grouped. + /// True if we are not accumulating objects. + /// List containing Groups. + /// Dictionary used to keep track of the groups with hash of the property values being the key. + /// The Comparer to be used while comparing to check if new group has to be created. + private static void DoOrderedGrouping( + OrderByPropertyEntry currentObjectEntry, + bool noElement, + List groups, + Dictionary groupInfoDictionary, + OrderByPropertyComparer orderByPropertyComparer) + { + var currentObjectOrderValues = currentObjectEntry.orderValues; + if (currentObjectOrderValues != null && currentObjectOrderValues.Count > 0) + { + object currentTupleObject = PSTuple.ArrayToTuple(currentObjectOrderValues); + + if (groupInfoDictionary.TryGetValue(currentTupleObject, out var currentGroupInfo)) + { + // add this inputObject to an existing group + currentGroupInfo.Add(currentObjectEntry.inputObject); + } + else + { + bool isCurrentItemGrouped = false; + + if (groups.Count > 0) + { + var lastGroup = groups[groups.Count - 1]; + + // Check if the current input object can be converted to one of the already known types + // by looking up in the type to GroupInfo mapping. + if (orderByPropertyComparer.Compare(lastGroup.GroupValue, currentObjectEntry) == 0) + { + lastGroup.Add(currentObjectEntry.inputObject); + isCurrentItemGrouped = true; + } + } + + if (!isCurrentItemGrouped) + { + // create a new group + s_tracer.WriteLine("Create a new group: {0}", currentObjectOrderValues); + GroupInfo newObjGrp = noElement + ? new GroupInfoNoElement(currentObjectEntry) + : new GroupInfo(currentObjectEntry); + + groups.Add(newObjGrp); + + groupInfoDictionary.Add(currentTupleObject, newObjGrp); + } + } + } + } + + private void WriteNonTerminatingError(Exception exception, string resourceIdAndErrorId, ErrorCategory category) + { + Exception ex = new Exception(StringUtil.Format(resourceIdAndErrorId), exception); + WriteError(new ErrorRecord(ex, resourceIdAndErrorId, category, null)); + } + + #endregion utils + + /// + /// Process every input object to group them. + /// + protected override void ProcessRecord() + { + if (InputObject != null && InputObject != AutomationNull.Value) + { + OrderByPropertyEntry currentEntry; + + if (!_hasProcessedFirstInputObject) + { + if (Property == null) + { + Property = OrderByProperty.GetDefaultKeyPropertySet(InputObject); + } + + _orderByProperty.ProcessExpressionParameter(this, Property); + + if (AsString && !AsHashTable) + { + ArgumentException ex = new ArgumentException(UtilityCommonStrings.GroupObjectWithHashTable); + ErrorRecord er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidArgument, AsString); + ThrowTerminatingError(er); + } + + if (AsHashTable && !AsString && (Property != null && (Property.Length > 1 || _orderByProperty.MshParameterList.Count > 1))) + { + ArgumentException ex = new ArgumentException(UtilityCommonStrings.GroupObjectSingleProperty); + ErrorRecord er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidArgument, Property); + ThrowTerminatingError(er); + } + + currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo); + bool[] ascending = new bool[currentEntry.orderValues.Count]; + for (int index = 0; index < currentEntry.orderValues.Count; index++) + { + ascending[index] = true; + } + + _orderByPropertyComparer = new OrderByPropertyComparer(ascending, _cultureInfo, CaseSensitive); + + _hasProcessedFirstInputObject = true; + } + else + { + currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo); + } + + _entriesToOrder.Add(currentEntry); + + var currentEntryOrderValues = currentEntry.orderValues; + if (!_hasDifferentValueTypes) + { + UpdateOrderPropertyTypeInfo(currentEntryOrderValues); + } + } + } + + private void UpdateOrderPropertyTypeInfo(List currentEntryOrderValues) + { + if (_propertyTypesCandidate == null) + { + _propertyTypesCandidate = currentEntryOrderValues.Select(c => PSObject.Base(c.PropertyValue)?.GetType()).ToArray(); + return; + } + + if (_propertyTypesCandidate.Length != currentEntryOrderValues.Count) + { + _hasDifferentValueTypes = true; + return; + } + + // check all the types we group on. + // if we find more than one set of types, _hasDifferentValueTypes is set to true, + // and we are forced to take a slower code path when we group our objects + for (int i = 0; i < _propertyTypesCandidate.Length; i++) + { + var candidateType = _propertyTypesCandidate[i]; + var propertyType = PSObject.Base(currentEntryOrderValues[i].PropertyValue)?.GetType(); + if (propertyType == null) + { + // we ignore properties without values. We can always compare against null. + continue; + } + + // if we haven't gotten a type for a property yet, update it when we do get a value + if (propertyType != candidateType) + { + if (candidateType == null) + { + _propertyTypesCandidate[i] = propertyType; + } + else + { + _hasDifferentValueTypes = true; + break; + } + } + } + } + + /// + /// Completes the processing of the gathered group objects. + /// + protected override void EndProcessing() + { + if (!_hasDifferentValueTypes) + { + // using OrderBy to get stable sort. + // fast path when we only have the same object types to group + foreach (var entry in _entriesToOrder.OrderBy(e => e, _orderByPropertyComparer)) + { + DoOrderedGrouping(entry, NoElement, _groups, _tupleToGroupInfoMappingDictionary, _orderByPropertyComparer); + if (Stopping) + { + return; + } + } + } + else + { + foreach (var entry in _entriesToOrder) + { + DoGrouping(entry, NoElement, _groups, _tupleToGroupInfoMappingDictionary, _orderByPropertyComparer); + if (Stopping) + { + return; + } + } + } + + s_tracer.WriteLine(_groups.Count); + if (_groups.Count > 0) + { + if (AsHashTable) + { + Hashtable hashtable = CollectionsUtil.CreateCaseInsensitiveHashtable(); + try + { + if (AsString) + { + foreach (GroupInfo grp in _groups) + { + hashtable.Add(grp.Name, grp.Group); + } + } + else + { + foreach (GroupInfo grp in _groups) + { + hashtable.Add(PSObject.Base(grp.Values[0]), grp.Group); + } + } + } + catch (ArgumentException e) + { + WriteNonTerminatingError(e, UtilityCommonStrings.InvalidOperation, ErrorCategory.InvalidArgument); + return; + } + + WriteObject(hashtable); + } + else + { + WriteObject(_groups, true); + } + } + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs index e2217f688e7b..17a6f3f540ef 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs @@ -1,30 +1,25 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Management.Automation; -using System.Management.Automation.Language; using System.Management.Automation.Internal; +using System.Management.Automation.Language; using System.Management.Automation.Remoting; using System.Management.Automation.Runspaces; using System.Reflection; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; using System.Xml; -using System.Security.Cryptography.X509Certificates; using Dbg = System.Management.Automation.Diagnostics; -// FxCop suppressions for resource strings: -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "ImplicitRemotingStrings.resources", MessageId = "runspace")] -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "ImplicitRemotingStrings.resources", MessageId = "Runspace")] namespace Microsoft.PowerShell.Commands { @@ -32,7 +27,7 @@ namespace Microsoft.PowerShell.Commands /// /// This class implements Export-PSSession cmdlet. - /// Spec: TBD + /// Spec: TBD. /// [Cmdlet(VerbsData.Export, "PSSession", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135213")] [OutputType(typeof(FileInfo))] @@ -41,15 +36,15 @@ public sealed class ExportPSSessionCommand : ImplicitRemotingCommandBase /// /// Version of the script generator used (by this Export-PSSession cmdlet) to generate psm1 and psd1 files. /// Generated script checks this version to see if it needs to be regenerated. There are 2 situations where this is needed - /// 1. the script needs to be regenerated because a bug fix made previous versions incompatible with the rest of the system (i.e. with ObjectModelWrapper) - /// 2. ths script needs to be regenerated because a security vulnerability was found inside generated code (there is no way to service generated code, but we can service the dll that reports the version that the generated script checks against) + /// 1. the script needs to be regenerated because a bug fix made previous versions incompatible with the rest of the system (i.e. with ObjectModelWrapper). + /// 2. ths script needs to be regenerated because a security vulnerability was found inside generated code (there is no way to service generated code, but we can service the dll that reports the version that the generated script checks against). /// public static Version VersionOfScriptGenerator { get { return ImplicitRemotingCodeGenerator.VersionOfScriptWriter; } } #region Parameters /// - /// Mandatory file name to write to + /// Mandatory file name to write to. /// [Parameter(Mandatory = true, Position = 1)] [ValidateNotNullOrEmpty] @@ -66,29 +61,21 @@ public SwitchParameter Force { return new SwitchParameter(_force); } + set { _force = value.IsPresent; } } + private bool _force; /// - /// Encoding optional flag + /// Encoding optional flag. /// [Parameter] [ArgumentToEncodingTransformationAttribute()] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] + [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); @@ -126,7 +113,7 @@ protected override void BeginProcessing() // Throw out terminating error if this is the case. if (IsModuleSpecified && IsFullyQualifiedModuleSpecified) { - string errMsg = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, "Module", "FullyQualifiedModule"); + string errMsg = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, nameof(Module), nameof(FullyQualifiedModule)); ErrorRecord error = new ErrorRecord(new InvalidOperationException(errMsg), "ModuleAndFullyQualifiedModuleCannotBeSpecifiedTogether", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(error); } @@ -163,7 +150,7 @@ protected override void BeginProcessing() /// /// This class implements Import-PSSession cmdlet. - /// Spec: http://cmdletdesigner/SpecViewer/Default.aspx?Project=PowerShell&Cmdlet=Import-Command + /// Spec: http://cmdletdesigner/SpecViewer/Default.aspx?Project=PowerShell&Cmdlet=Import-Command . /// [Cmdlet(VerbsData.Import, "PSSession", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135221")] [OutputType(typeof(PSModuleInfo))] @@ -251,13 +238,14 @@ private PSModuleInfo CreateModule(string manifestFile) #region Extra parameters /// - /// This parameter specified a prefix used to modify names of imported commands + /// This parameter specified a prefix used to modify names of imported commands. /// [Parameter] [ValidateNotNullOrEmpty] public new string Prefix { set { base.Prefix = value; } + get { return base.Prefix; } } @@ -270,6 +258,7 @@ public new string Prefix public SwitchParameter DisableNameChecking { get { return _disableNameChecking; } + set { _disableNameChecking = value; } } @@ -286,7 +275,7 @@ protected override void BeginProcessing() // Throw out terminating error if this is the case. if (IsModuleSpecified && IsFullyQualifiedModuleSpecified) { - string errMsg = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, "Module", "FullyQualifiedModule"); + string errMsg = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, nameof(Module), nameof(FullyQualifiedModule)); ErrorRecord error = new ErrorRecord(new InvalidOperationException(errMsg), "ModuleAndFullyQualifiedModuleCannotBeSpecifiedTogether", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(error); } @@ -314,6 +303,7 @@ protected override void BeginProcessing() manifestFile = file; } } + Dbg.Assert(manifestFile != null, "A psd1 file should always be generated"); PSModuleInfo moduleInfo = this.CreateModule(manifestFile); @@ -324,7 +314,7 @@ protected override void BeginProcessing() } /// - /// Base class for implicit remoting cmdlets + /// Base class for implicit remoting cmdlets. /// public class ImplicitRemotingCommandBase : PSCmdlet { @@ -350,10 +340,9 @@ internal ImplicitRemotingCommandBase() #region related to Get-Command /// - /// Gets or sets the path(s) or name(s) of the commands to retrieve + /// Gets or sets the path(s) or name(s) of the commands to retrieve. /// [Parameter(Position = 2)] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Alias("Name")] public string[] CommandName { @@ -361,6 +350,7 @@ public string[] CommandName { return _commandNameParameter; } + set { _commandNameParameter = value; @@ -370,11 +360,12 @@ public string[] CommandName WildcardOptions.CultureInvariant | WildcardOptions.IgnoreCase); } } + private string[] _commandNameParameter; private Collection _commandNamePatterns; // initialized to default value in the constructor /// - /// Allows shadowing and/or overwriting of existing local/client commands + /// Allows shadowing and/or overwriting of existing local/client commands. /// [Parameter] public SwitchParameter AllowClobber { get; set; } = new SwitchParameter(false); @@ -387,23 +378,24 @@ public string[] CommandName [AllowNull] [AllowEmptyCollection] [Alias("Args")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public object[] ArgumentList { get { return _commandArgs; } + set { _commandArgs = value; _commandParameterSpecified = true; } } + private object[] _commandArgs; /// - /// Gets or sets the type of the command to get + /// Gets or sets the type of the command to get. /// [Parameter] [Alias("Type")] @@ -413,6 +405,7 @@ public CommandTypes CommandType { return _commandType; } + set { _commandType = value; @@ -423,11 +416,9 @@ public CommandTypes CommandType private CommandTypes _commandType = CommandTypes.All & (~(CommandTypes.Application | CommandTypes.Script | CommandTypes.ExternalScript)); /// - /// Gets or sets the PSSnapin parameter to the cmdlet + /// Gets or sets the PSSnapin parameter to the cmdlet. /// [Parameter] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Snapin")] [Alias("PSSnapin")] [ValidateNotNull] public string[] Module @@ -441,20 +432,21 @@ public string[] Module { if (value == null) { - value = new string[0]; + value = Array.Empty(); } + _PSSnapins = value; _commandParameterSpecified = true; IsModuleSpecified = true; } } - private string[] _PSSnapins = new string[0]; + + private string[] _PSSnapins = Array.Empty(); internal bool IsModuleSpecified = false; /// - /// Gets or sets the FullyQualifiedModule parameter to the cmdlet + /// Gets or sets the FullyQualifiedModule parameter to the cmdlet. /// [Parameter] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [ValidateNotNull] public ModuleSpecification[] FullyQualifiedModule { @@ -469,10 +461,12 @@ public ModuleSpecification[] FullyQualifiedModule { _moduleSpecifications = value; } + _commandParameterSpecified = true; IsFullyQualifiedModuleSpecified = true; } } + private ModuleSpecification[] _moduleSpecifications = new ModuleSpecification[0]; internal bool IsFullyQualifiedModuleSpecified = false; @@ -483,9 +477,8 @@ public ModuleSpecification[] FullyQualifiedModule #region related to F&O /// - /// Gets or sets the types for which we should get formatting and output data + /// Gets or sets the types for which we should get formatting and output data. /// - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Parameter(Position = 3)] public string[] FormatTypeName { @@ -493,6 +486,7 @@ public string[] FormatTypeName { return _formatTypeNameParameter; } + set { _formatTypeNameParameter = value; @@ -502,6 +496,7 @@ public string[] FormatTypeName WildcardOptions.CultureInvariant | WildcardOptions.IgnoreCase); } } + private string[] _formatTypeNameParameter; // initialized to default value in the constructor private Collection _formatTypeNamePatterns; private bool _formatTypeNamesSpecified; // initialized to default value in the constructor @@ -511,7 +506,7 @@ public string[] FormatTypeName #region Related to modules /// - /// This parameter specified a prefix used to modify names of imported commands + /// This parameter specified a prefix used to modify names of imported commands. /// internal string Prefix { set; get; } = string.Empty; @@ -525,11 +520,10 @@ public string[] FormatTypeName /// /// The PSSession object describing the remote runspace - /// using which the specified cmdlet operation will be performed + /// using which the specified cmdlet operation will be performed. /// [Parameter(Mandatory = true, Position = 0)] [ValidateNotNull] - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspace")] public PSSession Session { get; set; } #endregion Parameters @@ -677,10 +671,12 @@ private ErrorRecord GetErrorSkippedUnsafeNameInMetadata(string commandName, stri { throw PSTraceSource.NewArgumentNullException("commandName"); } + if (string.IsNullOrEmpty(nameType)) { throw PSTraceSource.NewArgumentNullException("nameType"); } + Dbg.Assert(nameType.Equals("Alias") || nameType.Equals("ParameterSet") || nameType.Equals("Parameter"), "nameType matches resource names"); if (string.IsNullOrEmpty(name)) { @@ -707,6 +703,7 @@ private ErrorRecord GetErrorFromRemoteCommand(string commandName, RuntimeExcepti { throw PSTraceSource.NewArgumentNullException("commandName"); } + if (runtimeException == null) { throw PSTraceSource.NewArgumentNullException("runtimeException"); @@ -845,6 +842,7 @@ private bool IsCommandNameMatchingParameters(string commandName) _existingCommands[commandInfo.Name] = null; } } + return _existingCommands; } } @@ -866,7 +864,7 @@ private bool IsShadowingExistingCommands(string commandName) } /// - /// Returns true if command doesn't shadow OR is in the -AllowShadowing parameter + /// Returns true if command doesn't shadow OR is in the -AllowShadowing parameter. /// /// /// @@ -1011,6 +1009,7 @@ private T GetPropertyValue(string commandName, PSObject pso, string propertyN { this.ThrowTerminatingError(this.GetErrorMalformedDataFromRemoteCommand(commandName)); } + return ConvertTo(commandName, property.Value, nullOk); } @@ -1090,10 +1089,10 @@ private List RehydrateList(string commandName, object deserializedList, Fu /// /// Validates that a name or identifier is safe to use in generated code - /// (i.e. it can't be used for code injection attacks) + /// (i.e. it can't be used for code injection attacks). /// - /// name to validate - /// true if the name is safe; false otherwise + /// Name to validate. + /// true if the name is safe; false otherwise. private static bool IsSafeNameOrIdentifier(string name) { // '.' is needed for stuff like net.exe @@ -1108,10 +1107,10 @@ private static bool IsSafeNameOrIdentifier(string name) /// /// Validates that a parameter name is safe to use in generated code - /// (i.e. it can't be used for code injection attacks) + /// (i.e. it can't be used for code injection attacks). /// - /// parameter name to validate - /// true if the name is safe; false otherwise + /// Parameter name to validate. + /// true if the name is safe; false otherwise. private static bool IsSafeParameterName(string parameterName) { return IsSafeNameOrIdentifier(parameterName) && !parameterName.Contains(":"); @@ -1119,10 +1118,10 @@ private static bool IsSafeParameterName(string parameterName) /// /// Validates that a type can be safely used as a type constraint - /// (i.e. it doesn't introduce any side effects on the client) + /// (i.e. it doesn't introduce any side effects on the client). /// - /// type to validate - /// true if the type is safe; false otherwise + /// Type to validate. + /// true if the type is safe; false otherwise. private static bool IsSafeTypeConstraint(Type type) { if (type == null) @@ -1164,8 +1163,8 @@ private static bool IsSafeTypeConstraint(Type type) /// Validates that command metadata returned from the (potentially malicious) server is safe. /// Writes error messages if necessary. Modifies command metadata to make it safe if necessary. /// - /// command metadata to verify - /// true if the command metadata is safe; false otherwise + /// Command metadata to verify. + /// true if the command metadata is safe; false otherwise. private bool IsSafeCommandMetadata(CommandMetadata commandMetadata) { if (!IsCommandNameMatchingParameters(commandMetadata.Name)) @@ -1362,7 +1361,6 @@ private int GetCommandTypePriority(CommandTypes commandType) case CommandTypes.Filter: case CommandTypes.Function: case CommandTypes.Script: - case CommandTypes.Workflow: return 20; case CommandTypes.Cmdlet: @@ -1380,12 +1378,12 @@ private int GetCommandTypePriority(CommandTypes commandType) } /// - /// Converts remote (deserialized) CommandInfo objects into CommandMetadata equivalents + /// Converts remote (deserialized) CommandInfo objects into CommandMetadata equivalents. /// - /// Dictionary where rehydrated CommandMetadata are going to be stored - /// Dictionary mapping alias names to resolved command names - /// Remote (deserialized) CommandInfo object - /// CommandMetadata equivalents + /// Dictionary where rehydrated CommandMetadata are going to be stored. + /// Dictionary mapping alias names to resolved command names. + /// Remote (deserialized) CommandInfo object. + /// CommandMetadata equivalents. private void AddRemoteCommandMetadata( Dictionary name2commandMetadata, Dictionary alias2resolvedCommandName, @@ -1401,15 +1399,18 @@ private int GetCommandTypePriority(CommandTypes commandType) { return; } + if (resolvedCommandName != null && !IsSafeNameOrIdentifier(commandMetadata.Name)) { this.WriteError(this.GetErrorSkippedUnsafeCommandName(resolvedCommandName)); return; } + if (IsCommandSkippedByServerDeclaration(commandMetadata.Name)) { return; } + if (!IsCommandNameAllowedForImport(commandMetadata.Name)) { return; @@ -1577,9 +1578,9 @@ private PowerShell BuildPowerShellForGetFormatData() } /// - /// Gets CommandMetadata objects from remote runspace + /// Gets CommandMetadata objects from remote runspace. /// - /// (rehydrated) CommandMetadata objects + /// (rehydrated) CommandMetadata objects. internal List GetRemoteFormatData() { if ((this.FormatTypeName == null) || (this.FormatTypeName.Length == 0) || @@ -1618,6 +1619,7 @@ internal List GetRemoteFormatData() this.DuplicatePowerShellStreams(powerShell); this.WriteProgress(startTime, ++numberOfReceivedObjects, expectedCount, ImplicitRemotingStrings.ProgressStatusGetFormatDataProgress); } + this.DuplicatePowerShellStreams(powerShell); powerShell.EndInvoke(asyncResult); @@ -1625,6 +1627,7 @@ internal List GetRemoteFormatData() { this.ThrowTerminatingError(this.GetErrorNoResultsFromRemoteEnd("Get-FormatData")); } + return result; } } @@ -1654,11 +1657,13 @@ private PowerShell BuildPowerShellForGetCommand() { powerShell.AddParameter("Name", this.CommandName); } - powerShell.AddParameter("Module", this.Module); + + powerShell.AddParameter(nameof(Module), this.Module); if (IsFullyQualifiedModuleSpecified) { - powerShell.AddParameter("FullyQualifiedModule", this.FullyQualifiedModule); + powerShell.AddParameter(nameof(FullyQualifiedModule), this.FullyQualifiedModule); } + powerShell.AddParameter("ArgumentList", this.ArgumentList); powerShell.Runspace = Session.Runspace; @@ -1667,7 +1672,6 @@ private PowerShell BuildPowerShellForGetCommand() } /// - /// /// /// /// @@ -1677,9 +1681,9 @@ private void HandleHostCallReceived(object sender, RemoteDataEventArgs - /// Gets CommandMetadata objects from remote runspace + /// Gets CommandMetadata objects from remote runspace. /// - /// (rehydrated) CommandMetadata objects + /// (rehydrated) CommandMetadata objects. internal List GetRemoteCommandMetadata(out Dictionary alias2resolvedCommandName) { bool isReleaseCandidateBackcompatibilityMode = @@ -1741,6 +1745,7 @@ internal List GetRemoteCommandMetadata(out Dictionary GetRemoteCommandMetadata(out Dictionary(name2commandMetadata.Values); } } @@ -1790,6 +1796,7 @@ private void WriteProgress(string statusDescription, int? percentComplete, int? return; } } + _lastTimeProgressWasWritten = DateTime.UtcNow; string activityDescription = StringUtil.Format(ImplicitRemotingStrings.ProgressActivity); @@ -1840,17 +1847,17 @@ private void WriteProgress(DateTime startTime, int currentCount, int expectedCou /// /// Generates a proxy module in the given directory. /// - /// base directory for the module - /// fileName prefix for module files - /// encoding of generated files - /// whether to overwrite files - /// remote commands to generate proxies for - /// dictionary mapping alias names to resolved command names - /// remote format data to generate format.ps1xml for - /// Paths to generated files + /// Base directory for the module. + /// FileName prefix for module files. + /// Encoding of generated files. + /// Whether to overwrite files. + /// Remote commands to generate proxies for. + /// Dictionary mapping alias names to resolved command names. + /// Remote format data to generate format.ps1xml for. + /// Paths to generated files. internal List GenerateProxyModule( DirectoryInfo moduleRootDirectory, - String moduleNamePrefix, + string moduleNamePrefix, Encoding encoding, bool force, List listOfCommandMetadata, @@ -1920,9 +1927,9 @@ internal class ImplicitRemotingCodeGenerator #region Code generation helpers /// - /// Gets a connection URI associated with the remote runspace + /// Gets a connection URI associated with the remote runspace. /// - /// Connection URI associated with the remote runspace + /// Connection URI associated with the remote runspace. private string GetConnectionString() { WSManConnectionInfo connectionInfo = _remoteRunspaceInfo.Runspace.ConnectionInfo as WSManConnectionInfo; @@ -1970,6 +1977,7 @@ private string EscapeFunctionNameForRemoteHelp(string name) result.Append(c); } } + return result.ToString(); } @@ -1997,6 +2005,7 @@ private void GenerateSectionSeparator(TextWriter writer) PrivateData = @{{ ImplicitRemoting = $true + ImplicitSessionId = '{4}' }} }} "; @@ -2015,7 +2024,8 @@ private void GenerateManifest(TextWriter writer, string psm1fileName, string for CodeGeneration.EscapeSingleQuotedStringContent(_moduleGuid.ToString()), CodeGeneration.EscapeSingleQuotedStringContent(StringUtil.Format(ImplicitRemotingStrings.ProxyModuleDescription, this.GetConnectionString())), CodeGeneration.EscapeSingleQuotedStringContent(Path.GetFileName(psm1fileName)), - CodeGeneration.EscapeSingleQuotedStringContent(Path.GetFileName(formatPs1xmlFileName))); + CodeGeneration.EscapeSingleQuotedStringContent(Path.GetFileName(formatPs1xmlFileName)), + _remoteRunspaceInfo.InstanceId); } #endregion @@ -2054,7 +2064,6 @@ private void GenerateTopComment(TextWriter writer) throw '{3}' }} - $script:WriteHost = $executionContext.InvokeCommand.GetCommand('Write-Host', [System.Management.Automation.CommandTypes]::Cmdlet) $script:WriteWarning = $executionContext.InvokeCommand.GetCommand('Write-Warning', [System.Management.Automation.CommandTypes]::Cmdlet) $script:WriteInformation = $executionContext.InvokeCommand.GetCommand('Write-Information', [System.Management.Automation.CommandTypes]::Cmdlet) @@ -2238,12 +2247,17 @@ private string GenerateNewPSSessionOption() if (wsmanConnectionInfo != null) { if (!wsmanConnectionInfo.UseCompression) { result.Append("-NoCompression "); } + if (wsmanConnectionInfo.NoEncryption) { result.Append("-NoEncryption "); } + if (wsmanConnectionInfo.NoMachineProfile) { result.Append("-NoMachineProfile "); } + if (wsmanConnectionInfo.UseUTF16) { result.Append("-UseUTF16 "); } if (wsmanConnectionInfo.SkipCACheck) { result.Append("-SkipCACheck "); } + if (wsmanConnectionInfo.SkipCNCheck) { result.Append("-SkipCNCheck "); } + if (wsmanConnectionInfo.SkipRevocationCheck) { result.Append("-SkipRevocationCheck "); } if (wsmanConnectionInfo.MaximumReceivedDataSizePerCommand.HasValue) @@ -2253,6 +2267,7 @@ private string GenerateNewPSSessionOption() "-MaximumReceivedDataSizePerCommand {0} ", wsmanConnectionInfo.MaximumReceivedDataSizePerCommand.Value); } + if (wsmanConnectionInfo.MaximumReceivedObjectSize.HasValue) { result.AppendFormat( @@ -2260,6 +2275,7 @@ private string GenerateNewPSSessionOption() "-MaximumReceivedObjectSize {0} ", wsmanConnectionInfo.MaximumReceivedObjectSize.Value); } + result.AppendFormat( CultureInfo.InvariantCulture, "-MaximumRedirection {0} ", @@ -2344,6 +2360,7 @@ private string GenerateProxyCredentialParameter(WSManConnectionInfo wsmanConnect -InstanceId {0} ` -ErrorAction SilentlyContinue ) }} + if (($null -ne $script:PSSession) -and ($script:PSSession.Runspace.RunspaceStateInfo.State -eq 'Disconnected')) {{ # If we are handed a disconnected session, try re-connecting it before creating a new session. @@ -2352,6 +2369,7 @@ private string GenerateProxyCredentialParameter(WSManConnectionInfo wsmanConnect -Session $script:PSSession ` -ErrorAction SilentlyContinue) }} + if (($null -eq $script:PSSession) -or ($script:PSSession.Runspace.RunspaceStateInfo.State -ne 'Opened')) {{ Write-PSImplicitRemotingMessage ('{1}' -f $commandName) @@ -2371,10 +2389,12 @@ private string GenerateProxyCredentialParameter(WSManConnectionInfo wsmanConnect {8} }} + if (($null -eq $script:PSSession) -or ($script:PSSession.Runspace.RunspaceStateInfo.State -ne 'Opened')) {{ throw '{3}' }} + return [Management.Automation.Runspaces.PSSession]$script:PSSession }} "; @@ -2418,9 +2438,9 @@ private string GenerateReimportingOfModules() { StringBuilder result = new StringBuilder(); - if (_invocationInfo.BoundParameters.ContainsKey("Module")) + if (_invocationInfo.BoundParameters.ContainsKey(nameof(Module))) { - string[] moduleNames = (string[])_invocationInfo.BoundParameters["Module"]; + string[] moduleNames = (string[])_invocationInfo.BoundParameters[nameof(Module)]; foreach (string moduleName in moduleNames) { result.AppendFormat( @@ -2491,7 +2511,7 @@ private string GenerateNewRunspaceExpression() NewVMRunspaceTemplate, /* 0 */ this.GenerateConnectionStringForNewRunspace(), /* 1 */ this.GenerateCredentialParameter(), - /* 2 */ String.IsNullOrEmpty(vmConfigurationName) ? String.Empty : String.Concat("-ConfigurationName ", vmConfigurationName)); + /* 2 */ string.IsNullOrEmpty(vmConfigurationName) ? string.Empty : string.Concat("-ConfigurationName ", vmConfigurationName)); } else { @@ -2504,7 +2524,7 @@ private string GenerateNewRunspaceExpression() NewContainerRunspaceTemplate, /* 0 */ this.GenerateConnectionStringForNewRunspace(), /* 1 */ containerConnectionInfo.ContainerProc.RunAsAdmin ? "-RunAsAdministrator" : string.Empty, - /* 2 */ String.IsNullOrEmpty(containerConfigurationName) ? String.Empty : String.Concat("-ConfigurationName ", containerConfigurationName)); + /* 2 */ string.IsNullOrEmpty(containerConfigurationName) ? string.Empty : string.Concat("-ConfigurationName ", containerConfigurationName)); } else { @@ -2538,7 +2558,7 @@ private string GenerateNewRunspaceExpression() private string GenerateConnectionStringForNewRunspace() { WSManConnectionInfo connectionInfo = _remoteRunspaceInfo.Runspace.ConnectionInfo as WSManConnectionInfo; - if (null == connectionInfo) + if (connectionInfo == null) { VMConnectionInfo vmConnectionInfo = _remoteRunspaceInfo.Runspace.ConnectionInfo as VMConnectionInfo; if (vmConnectionInfo != null) @@ -2706,6 +2726,7 @@ private string GenerateCertificateThumbprintParameter() $proxyForCmdlet) $clientSideParameters = @{} + $parametersToLeaveRemote = 'ErrorAction', 'WarningAction', 'InformationAction' Modify-PSImplicitRemotingParameters $clientSideParameters $PSBoundParameters 'AsJob' @@ -2776,6 +2797,7 @@ private void GenerateHelperFunctions(TextWriter writer) $null = $positionalArguments.Add( $PSBoundParameters[$parameterName] ) $null = $PSBoundParameters.Remove($parameterName) }} + $positionalArguments.AddRange($args) $clientSideParameters = Get-PSImplicitRemotingClientSideParameters $PSBoundParameters ${8} @@ -2794,7 +2816,9 @@ private void GenerateHelperFunctions(TextWriter writer) throw }} }} + Process {{ {6} }} + End {{ {7} }} # .ForwardHelpTargetName {1} @@ -2831,6 +2855,7 @@ private void GenerateCommandProxy(TextWriter writer, IEnumerable GetListOfCommandNames(IEnumerable listOfCo { listOfCommandNames.Add(commandMetadata.Name); } + return listOfCommandNames; } @@ -2898,6 +2925,7 @@ private string GenerateArrayString(IEnumerable listOfStrings) { arrayString.Append(", "); } + arrayString.Append('\''); arrayString.Append(CodeGeneration.EscapeSingleQuotedStringContent(s)); arrayString.Append('\''); @@ -2950,6 +2978,7 @@ private void GenerateFormatFile(TextWriter writer, List { throw PSTraceSource.NewArgumentNullException("writer"); } + if (listOfFormatData == null) { throw PSTraceSource.NewArgumentNullException("listOfFormatData"); @@ -2971,18 +3000,18 @@ private void GenerateFormatFile(TextWriter writer, List /// /// Generates a proxy module in the given directory. /// - /// base directory for the module - /// filename prefix for module files - /// encoding of generated files - /// whether to overwrite files - /// remote commands to generate proxies for - /// dictionary mapping alias names to resolved command names - /// remote format data to generate format.ps1xml for - /// certificate with which to sign the format files - /// Path to the created files + /// Base directory for the module. + /// Filename prefix for module files. + /// Encoding of generated files. + /// Whether to overwrite files. + /// Remote commands to generate proxies for. + /// Dictionary mapping alias names to resolved command names. + /// Remote format data to generate format.ps1xml for. + /// Certificate with which to sign the format files. + /// Path to the created files. internal List GenerateProxyModule( DirectoryInfo moduleRootDirectory, - String fileNamePrefix, + string fileNamePrefix, Encoding encoding, bool force, List listOfCommandMetadata, @@ -3050,7 +3079,7 @@ private void GenerateFormatFile(TextWriter writer, List } else { - String currentFile = baseName + ".psm1"; + string currentFile = baseName + ".psm1"; try { SignatureHelper.SignFile(SigningOption.Default, currentFile, certificate, string.Empty, null); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs index ea6fb4dc21e0..2087676b0e30 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs @@ -1,29 +1,26 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; -using System.Management.Automation.Internal; using System.Management.Automation; -using System.Diagnostics.CodeAnalysis; +using System.Management.Automation.Internal; namespace Microsoft.PowerShell.Commands { /// - /// The implementation of the "import-localizeddata" cmdlet + /// The implementation of the "import-localizeddata" cmdlet. /// - /// [Cmdlet(VerbsData.Import, "LocalizedData", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113342")] public sealed class ImportLocalizedData : PSCmdlet { #region Parameters /// - /// The path from which to import the aliases + /// The path from which to import the aliases. /// - /// [Parameter(Position = 0)] [Alias("Variable")] [ValidateNotNullOrEmpty] @@ -39,12 +36,12 @@ public string BindingVariable _bindingVariable = value; } } + private string _bindingVariable; /// /// The scope to import the aliases to. /// - /// [Parameter(Position = 1)] public string UICulture { @@ -58,12 +55,12 @@ public string UICulture _uiculture = value; } } + private string _uiculture; /// /// The scope to import the aliases to. /// - /// [Parameter] public string BaseDirectory { @@ -77,12 +74,12 @@ public string BaseDirectory _baseDirectory = value; } } + private string _baseDirectory; /// /// The scope to import the aliases to. /// - /// [Parameter] public string FileName { @@ -96,13 +93,14 @@ public string FileName _fileName = value; } } + private string _fileName; /// - /// The command allowed in the data file. If unspecified, then ConvertFrom-StringData - /// is allowed. + /// The command allowed in the data file. If unspecified, then ConvertFrom-StringData is allowed. /// [Parameter] + [ValidateTrustedData] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")] public string[] SupportedCommand { @@ -110,12 +108,14 @@ public string[] SupportedCommand { return _commandsAllowed; } + set { _setSupportedCommand = true; _commandsAllowed = value; } } + private string[] _commandsAllowed = new string[] { "ConvertFrom-StringData" }; private bool _setSupportedCommand = false; @@ -126,7 +126,6 @@ public string[] SupportedCommand /// /// The main processing loop of the command. /// - /// protected override void ProcessRecord() { string path = GetFilePath(); @@ -213,8 +212,15 @@ protected override void ProcessRecord() else { variable.Value = result; + + if (Context.LanguageMode == PSLanguageMode.ConstrainedLanguage) + { + // Mark untrusted values for assignments to 'Global:' variables, and 'Script:' variables in + // a module scope, if it's necessary. + ExecutionContext.MarkObjectAsUntrustedForVariableAssignment(variable, scope, Context.EngineSessionState); + } } - } // end _bindingvariable != null + } // If binding variable is null, write the object to stream else @@ -233,13 +239,13 @@ protected override void ProcessRecord() } return; - } // ProcessRecord + } private string GetFilePath() { - if (String.IsNullOrEmpty(_fileName)) + if (string.IsNullOrEmpty(_fileName)) { - if (InvocationExtent == null || String.IsNullOrEmpty(InvocationExtent.File)) + if (InvocationExtent == null || string.IsNullOrEmpty(InvocationExtent.File)) { throw PSTraceSource.NewInvalidOperationException(ImportLocalizedDataStrings.NotCalledFromAScriptFile); } @@ -247,9 +253,9 @@ private string GetFilePath() string dir = _baseDirectory; - if (String.IsNullOrEmpty(dir)) + if (string.IsNullOrEmpty(dir)) { - if (InvocationExtent != null && !String.IsNullOrEmpty(InvocationExtent.File)) + if (InvocationExtent != null && !string.IsNullOrEmpty(InvocationExtent.File)) { dir = Path.GetDirectoryName(InvocationExtent.File); } @@ -262,13 +268,13 @@ private string GetFilePath() dir = PathUtils.ResolveFilePath(dir, this); string fileName = _fileName; - if (String.IsNullOrEmpty(fileName)) + if (string.IsNullOrEmpty(fileName)) { fileName = InvocationExtent.File; } else { - if (!String.IsNullOrEmpty(Path.GetDirectoryName(fileName))) + if (!string.IsNullOrEmpty(Path.GetDirectoryName(fileName))) { throw PSTraceSource.NewInvalidOperationException(ImportLocalizedDataStrings.FileNameParameterCannotHavePath); } @@ -296,7 +302,7 @@ private string GetFilePath() CultureInfo currentCulture = culture; string filePath; string fullFileName = fileName + ".psd1"; - while (currentCulture != null && !String.IsNullOrEmpty(currentCulture.Name)) + while (currentCulture != null && !string.IsNullOrEmpty(currentCulture.Name)) { filePath = Path.Combine(dir, currentCulture.Name, fullFileName); @@ -374,6 +380,5 @@ private string GetScript(string filePath) } #endregion Command code - } // class ImportLocalizedData -}//Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportAliasCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportAliasCommand.cs index 332742d08d7a..8ccd9a3a8340 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportAliasCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportAliasCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -13,9 +12,8 @@ namespace Microsoft.PowerShell.Commands { /// - /// The implementation of the "import-alias" cmdlet + /// The implementation of the "import-alias" cmdlet. /// - /// [Cmdlet(VerbsData.Import, "Alias", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113339")] [OutputType(typeof(AliasInfo))] public class ImportAliasCommand : PSCmdlet @@ -29,18 +27,16 @@ public class ImportAliasCommand : PSCmdlet #region Parameters /// - /// The path from which to import the aliases + /// The path from which to import the aliases. /// - /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")] public string Path { get; set; } /// - /// The literal path from which to import the aliases + /// The literal path from which to import the aliases. /// - /// [Parameter(Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = LiteralPathParameterSetName)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { get @@ -57,16 +53,13 @@ public string LiteralPath /// /// The scope to import the aliases to. /// - /// [Parameter] [ValidateNotNullOrEmpty] public string Scope { get; set; } /// - /// If set to true, the alias that is set is passed to the - /// pipeline. + /// If set to true, the alias that is set is passed to the pipeline. /// - /// [Parameter] public SwitchParameter PassThru { @@ -80,13 +73,13 @@ public SwitchParameter PassThru _passThru = value; } } + private bool _passThru; /// /// If set to true and an existing alias of the same name exists /// and is ReadOnly, the alias will be overwritten. /// - /// [Parameter] public SwitchParameter Force { @@ -100,6 +93,7 @@ public SwitchParameter Force _force = value; } } + private bool _force; #endregion Parameters @@ -109,7 +103,6 @@ public SwitchParameter Force /// /// The main processing loop of the command. /// - /// protected override void ProcessRecord() { Collection importedAliases = GetAliasesFromFile(this.ParameterSetName.Equals(LiteralPathParameterSetName, @@ -132,7 +125,7 @@ protected override void ProcessRecord() if (!Force) { AliasInfo existingAlias = null; - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { existingAlias = SessionState.Internal.GetAlias(alias.Name); } @@ -179,7 +172,7 @@ protected override void ProcessRecord() { continue; } - } // if (!Force) + } // Set the alias in the specified scope or the // current scope. @@ -188,7 +181,7 @@ protected override void ProcessRecord() try { - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { result = SessionState.Internal.SetAliasItem(alias, Force, MyInvocation.CommandOrigin); } @@ -229,7 +222,7 @@ protected override void ProcessRecord() WriteObject(result); } } - } // ProcessRecord + } private Dictionary _existingCommands; private Dictionary ExistingCommands @@ -259,6 +252,7 @@ protected override void ProcessRecord() } } } + return _existingCommands; } } @@ -375,15 +369,17 @@ private Collection GetAliasesFromFile(bool isLiteralPath) Context, options); - if (!String.IsNullOrEmpty(values[2])) + if (!string.IsNullOrEmpty(values[2])) { newAlias.Description = values[2]; } result.Add(newAlias); } + reader.Dispose(); } + return result; } @@ -478,9 +474,9 @@ private static bool OnlyContainsWhitespace(string line) result = false; break; } + return result; } #endregion Command code - } // class ImportAliasCommand -}//Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs index d0418892bdbe..1edac5515843 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; @@ -12,39 +15,39 @@ namespace Microsoft.PowerShell.Commands HelpUri = "https://go.microsoft.com/fwlink/?LinkID=623621", RemotingCapability = RemotingCapability.None)] public class ImportPowerShellDataFileCommand : PSCmdlet { - bool _isLiteralPath; + private bool _isLiteralPath; /// - /// Path specified, using globbing to resolve + /// Path specified, using globbing to resolve. /// - [Parameter(Mandatory = true, Position = 0, ParameterSetName = "ByPath")] + [Parameter(Mandatory = true, Position = 0, ParameterSetName = "ByPath")] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] Path { get; set; } /// - /// Specifies a path to one or more locations, without globbing + /// Specifies a path to one or more locations, without globbing. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "ByLiteralPath", ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] - [Alias("PSPath")] + [Alias("PSPath", "LP")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] LiteralPath { get { return _isLiteralPath ? Path : null; } + set { _isLiteralPath = true; Path = value; } } /// - /// For each path, resolve it, parse it and write all hashtables - /// to the output stream + /// For each path, resolve it, parse it and write all hashtables to the output stream. /// protected override void ProcessRecord() { foreach (var path in Path) { var resolved = PathUtils.ResolveFilePath(path, this, _isLiteralPath); - if(!string.IsNullOrEmpty(resolved) && System.IO.File.Exists(resolved)) + if (!string.IsNullOrEmpty(resolved) && System.IO.File.Exists(resolved)) { Token[] tokens; ParseError[] errors; @@ -77,16 +80,16 @@ private void WritePathNotFoundError(string path) { var errorId = "PathNotFound"; var errorCategory = ErrorCategory.InvalidArgument; - var errorMessage = string.Format(UtilityResources.PathDoesNotExist, path); + var errorMessage = string.Format(UtilityCommonStrings.PathDoesNotExist, path); var exception = new ArgumentException(errorMessage); var errorRecord = new ErrorRecord(exception, errorId, errorCategory, path); WriteError(errorRecord); } - void WriteInvalidDataFileError(string resolvedPath, string errorId) - { + private void WriteInvalidDataFileError(string resolvedPath, string errorId) + { var errorCategory = ErrorCategory.InvalidData; - var errorMessage = string.Format(UtilityResources.CouldNotParseAsPowerShellDataFile, resolvedPath); + var errorMessage = string.Format(UtilityCommonStrings.CouldNotParseAsPowerShellDataFile, resolvedPath); var exception = new InvalidOperationException(errorMessage); var errorRecord = new ErrorRecord(exception, errorId, errorCategory, resolvedPath); WriteError(errorRecord); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/InvokeCommandCmdlet.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/InvokeCommandCmdlet.cs index e415dc7de24a..df80155c4c46 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/InvokeCommandCmdlet.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/InvokeCommandCmdlet.cs @@ -1,14 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; using System.Management.Automation; using System.Management.Automation.Internal; namespace Microsoft.PowerShell.Commands { /// - /// Class implementing Invoke-Expression + /// Class implementing Invoke-Expression. /// [Cmdlet(VerbsLifecycle.Invoke, "Expression", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113343")] public sealed @@ -21,17 +21,17 @@ public sealed /// Command to execute. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] + [ValidateTrustedData] public string Command { get; set; } #endregion parameters /// - /// For each record, execute it, and push the results into the - /// success stream. + /// For each record, execute it, and push the results into the success stream. /// protected override void ProcessRecord() { - Diagnostics.Assert(null != Command, "Command is null"); + Diagnostics.Assert(Command != null, "Command is null"); ScriptBlock myScriptBlock = InvokeCommand.NewScriptBlock(Command); @@ -43,7 +43,7 @@ protected override void ProcessRecord() myScriptBlock.LanguageMode = PSLanguageMode.ConstrainedLanguage; } - var emptyArray = Utils.EmptyArray(); + var emptyArray = Array.Empty(); myScriptBlock.InvokeUsingCmdlet( contextCmdlet: this, useLocalScope: false, @@ -54,4 +54,4 @@ protected override void ProcessRecord() args: emptyArray); } } -} // namespace Microsoft.PowerShell.Commands +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Join-String.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Join-String.cs new file mode 100644 index 000000000000..c1971c3da114 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Join-String.cs @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Management.Automation.Language; +using System.Text; + +namespace Microsoft.PowerShell.Commands.Utility +{ + /// + /// Join-Object implementation. + /// + [Cmdlet(VerbsCommon.Join, "String", RemotingCapability = RemotingCapability.None, DefaultParameterSetName = "default")] + [OutputType(typeof(string))] + public sealed class JoinStringCommand : PSCmdlet + { + /// A bigger default to not get re-allocations in common use cases. + private const int DefaultOutputStringCapacity = 256; + private readonly StringBuilder _outputBuilder = new StringBuilder(DefaultOutputStringCapacity); + private CultureInfo _cultureInfo = CultureInfo.InvariantCulture; + private string _separator; + private char _quoteChar; + private bool _firstInputObject = true; + + /// + /// Gets or sets the property name or script block to use as the value to join. + /// + [Parameter(Position = 0)] + [ArgumentCompleter(typeof(PropertyNameCompleter))] + public PSPropertyExpression Property { get; set; } + + /// + /// Gets or sets the delimiter to join the output with. + /// + [Parameter(Position = 1)] + [ArgumentCompleter(typeof(JoinItemCompleter))] + [AllowEmptyString] + public string Separator + { + get => _separator ?? LanguagePrimitives.ConvertTo(GetVariableValue("OFS")); + set => _separator = value; + } + + /// + /// Gets or sets text to include before the joined input text. + /// + [Parameter] + [Alias("op")] + public string OutputPrefix { get; set; } + + /// + /// Gets or sets text to include after the joined input text. + /// + [Parameter] + [Alias("os")] + public string OutputSuffix { get; set; } + + /// + /// Gets or sets if the output items should we wrapped in single quotes. + /// + [Parameter(ParameterSetName = "SingleQuote")] + public SwitchParameter SingleQuote { get; set; } + + /// + /// Gets or sets if the output items should we wrapped in double quotes. + /// + [Parameter(ParameterSetName = "DoubleQuote")] + public SwitchParameter DoubleQuote { get; set; } + + /// + /// Gets or sets a format string that is applied to each input object. + /// + [Parameter(ParameterSetName = "Format")] + [ArgumentCompleter(typeof(JoinItemCompleter))] + public string FormatString { get; set; } + + /// + /// Gets or sets if the current culture should be used with formatting instead of the invariant culture. + /// + [Parameter] + public SwitchParameter UseCulture { get; set; } + + /// + /// Gets or sets the input object to join into text. + /// + [Parameter(ValueFromPipeline = true)] + public PSObject[] InputObject { get; set; } + + /// + protected override void BeginProcessing() + { + _quoteChar = SingleQuote ? '\'' : DoubleQuote ? '"' : char.MinValue; + _outputBuilder.Append(OutputPrefix); + if (UseCulture) + { + _cultureInfo = CultureInfo.CurrentCulture; + } + } + + /// + protected override void ProcessRecord() + { + if (InputObject != null) + { + foreach (PSObject inputObject in InputObject) + { + if (inputObject != null && inputObject != AutomationNull.Value) + { + var inputValue = Property == null + ? inputObject + : Property.GetValues(inputObject, false, true).FirstOrDefault()?.Result; + + // conversion to string always succeeds. + if (!LanguagePrimitives.TryConvertTo(inputValue, _cultureInfo, out var stringValue)) + { + throw new PSInvalidCastException("InvalidCastFromAnyTypeToString", ExtendedTypeSystem.InvalidCastCannotRetrieveString, null); + } + + if (_firstInputObject) + { + _firstInputObject = false; + } + else + { + _outputBuilder.Append(Separator); + } + + if (_quoteChar != char.MinValue) + { + _outputBuilder.Append(_quoteChar); + _outputBuilder.Append(stringValue); + _outputBuilder.Append(_quoteChar); + } + else if (string.IsNullOrEmpty(FormatString)) + { + _outputBuilder.Append(stringValue); + } + else + { + _outputBuilder.AppendFormat(_cultureInfo, FormatString, inputValue); + } + } + } + } + } + + /// + protected override void EndProcessing() + { + _outputBuilder.Append(OutputSuffix); + WriteObject(_outputBuilder.ToString()); + } + } + + internal class JoinItemCompleter : IArgumentCompleter + { + public IEnumerable CompleteArgument( + string commandName, + string parameterName, + string wordToComplete, + CommandAst commandAst, + IDictionary fakeBoundParameters) + { + switch (parameterName) + { + case "Separator": return CompleteSeparator(wordToComplete); + case "FormatString": return CompleteFormatString(wordToComplete); + } + + return null; + } + + private IEnumerable CompleteFormatString(string wordToComplete) + { + var res = new List(); + void AddMatching(string completionText) + { + if (completionText.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase)) + { + res.Add(new CompletionResult(completionText)); + } + } + + AddMatching("'[{0}]'"); + AddMatching("'{0:N2}'"); + AddMatching("\"`r`n `${0}\""); + AddMatching("\"`r`n [string] `${0}\""); + + return res; + } + + private IEnumerable CompleteSeparator(string wordToComplete) + { + var res = new List(10); + + void AddMatching(string completionText, string listText, string toolTip) + { + if (completionText.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase)) + { + res.Add(new CompletionResult(completionText, listText, CompletionResultType.ParameterValue, toolTip)); + } + } + + AddMatching("', '", "Comma-Space", "', ' - Comma-Space"); + AddMatching("';'", "Semi-Colon", "';' - Semi-Colon "); + AddMatching("'; '", "Semi-Colon-Space", "'; ' - Semi-Colon-Space"); + AddMatching($"\"{NewLineText}\"", "Newline", $"{NewLineText} - Newline"); + AddMatching("','", "Comma", "',' - Comma"); + AddMatching("'-'", "Dash", "'-' - Dash"); + AddMatching("' '", "Space", "' ' - Space"); + return res; + } + + public string NewLineText + { + get + { +#if UNIX + return "`n"; +#else + return "`r`n"; +#endif + } + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs new file mode 100644 index 000000000000..61953205445c --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs @@ -0,0 +1,317 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Management.Automation.Runspaces; +using System.Threading.Tasks; + +using Microsoft.PowerShell.MarkdownRender; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// Class for implementing Set-MarkdownOption cmdlet. + /// + [Cmdlet( + VerbsCommon.Set, "MarkdownOption", + DefaultParameterSetName = IndividualSetting, + HelpUri = "https://go.microsoft.com/fwlink/?linkid=2006265")] + [OutputType(typeof(Microsoft.PowerShell.MarkdownRender.PSMarkdownOptionInfo))] + public class SetMarkdownOptionCommand : PSCmdlet + { + /// + /// Gets or sets the VT100 escape sequence for Header Level 1. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string Header1Color { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for Header Level 2. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string Header2Color { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for Header Level 3. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string Header3Color { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for Header Level 4. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string Header4Color { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for Header Level 5. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string Header5Color { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for Header Level 6. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string Header6Color { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for code block background. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string Code { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for image alt text foreground. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string ImageAltTextForegroundColor { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for link foreground. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string LinkForegroundColor { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for italics text foreground. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string ItalicsForegroundColor { get; set; } + + /// + /// Gets or sets the VT100 escape sequence for bold text foreground. + /// + [ValidatePattern(@"^\[*[0-9;]*?m{1}")] + [Parameter(ParameterSetName = IndividualSetting)] + public string BoldForegroundColor { get; set; } + + /// + /// Gets or sets the switch to PassThru the values set. + /// + [Parameter] + public SwitchParameter PassThru { get; set; } + + /// + /// Gets or sets the Theme. + /// + [ValidateNotNullOrEmpty] + [Parameter(ParameterSetName = ThemeParamSet, Mandatory = true)] + [ValidateSet(DarkThemeName, LightThemeName)] + public string Theme { get; set; } + + /// + /// Gets or sets InputObject. + /// + [ValidateNotNullOrEmpty] + [Parameter(ParameterSetName = InputObjectParamSet, Mandatory = true, ValueFromPipeline = true, Position = 0)] + public PSObject InputObject { get; set; } + + private const string IndividualSetting = "IndividualSetting"; + private const string InputObjectParamSet = "InputObject"; + private const string ThemeParamSet = "Theme"; + private const string LightThemeName = "Light"; + private const string DarkThemeName = "Dark"; + + /// + /// Override EndProcessing. + /// + protected override void EndProcessing() + { + PSMarkdownOptionInfo mdOptionInfo = null; + + switch (ParameterSetName) + { + case ThemeParamSet: + mdOptionInfo = new PSMarkdownOptionInfo(); + if (string.Equals(Theme, LightThemeName, StringComparison.OrdinalIgnoreCase)) + { + mdOptionInfo.SetLightTheme(); + } + else if (string.Equals(Theme, DarkThemeName, StringComparison.OrdinalIgnoreCase)) + { + mdOptionInfo.SetDarkTheme(); + } + + break; + + case InputObjectParamSet: + object baseObj = InputObject.BaseObject; + mdOptionInfo = baseObj as PSMarkdownOptionInfo; + + if (mdOptionInfo == null) + { + var errorMessage = StringUtil.Format(ConvertMarkdownStrings.InvalidInputObjectType, baseObj.GetType()); + + ErrorRecord errorRecord = new ErrorRecord( + new ArgumentException(errorMessage), + "InvalidObject", + ErrorCategory.InvalidArgument, + InputObject); + } + + break; + + case IndividualSetting: + mdOptionInfo = new PSMarkdownOptionInfo(); + SetOptions(mdOptionInfo); + break; + } + + var setOption = PSMarkdownOptionInfoCache.Set(this.CommandInfo, mdOptionInfo); + + if (PassThru.IsPresent) + { + WriteObject(setOption); + } + } + + private void SetOptions(PSMarkdownOptionInfo mdOptionInfo) + { + if (!string.IsNullOrEmpty(Header1Color)) + { + mdOptionInfo.Header1 = Header1Color; + } + + if (!string.IsNullOrEmpty(Header2Color)) + { + mdOptionInfo.Header2 = Header2Color; + } + + if (!string.IsNullOrEmpty(Header3Color)) + { + mdOptionInfo.Header3 = Header3Color; + } + + if (!string.IsNullOrEmpty(Header4Color)) + { + mdOptionInfo.Header4 = Header4Color; + } + + if (!string.IsNullOrEmpty(Header5Color)) + { + mdOptionInfo.Header5 = Header5Color; + } + + if (!string.IsNullOrEmpty(Header6Color)) + { + mdOptionInfo.Header6 = Header6Color; + } + + if (!string.IsNullOrEmpty(Code)) + { + mdOptionInfo.Code = Code; + } + + if (!string.IsNullOrEmpty(ImageAltTextForegroundColor)) + { + mdOptionInfo.Image = ImageAltTextForegroundColor; + } + + if (!string.IsNullOrEmpty(LinkForegroundColor)) + { + mdOptionInfo.Link = LinkForegroundColor; + } + + if (!string.IsNullOrEmpty(ItalicsForegroundColor)) + { + mdOptionInfo.EmphasisItalics = ItalicsForegroundColor; + } + + if (!string.IsNullOrEmpty(BoldForegroundColor)) + { + mdOptionInfo.EmphasisBold = BoldForegroundColor; + } + } + } + + /// + /// Implements the cmdlet for getting the Markdown options that are set. + /// + [Cmdlet( + VerbsCommon.Get, "MarkdownOption", + HelpUri = "https://go.microsoft.com/fwlink/?linkid=2006371")] + [OutputType(typeof(Microsoft.PowerShell.MarkdownRender.PSMarkdownOptionInfo))] + public class GetMarkdownOptionCommand : PSCmdlet + { + private const string MarkdownOptionInfoVariableName = "PSMarkdownOptionInfo"; + + /// + /// Override EndProcessing. + /// + protected override void EndProcessing() + { + WriteObject(PSMarkdownOptionInfoCache.Get(this.CommandInfo)); + } + } + + /// + /// The class manages whether we should use a module scope variable or concurrent dictionary for storing the set PSMarkdownOptions. + /// When we have a moduleInfo available we use the module scope variable. + /// In case of built-in modules, they are loaded as snapins when we are hosting PowerShell. + /// We use runspace Id as the key for the concurrent dictionary to have the functionality of separate settings per runspace. + /// Force loading the module does not unload the nested modules and hence we cannot use IModuleAssemblyCleanup to remove items from the dictionary. + /// Because of these reason, we continue using module scope variable when moduleInfo is available. + /// + internal static class PSMarkdownOptionInfoCache + { + private static ConcurrentDictionary markdownOptionInfoCache; + private const string MarkdownOptionInfoVariableName = "PSMarkdownOptionInfo"; + + static PSMarkdownOptionInfoCache() + { + markdownOptionInfoCache = new ConcurrentDictionary(); + } + + internal static PSMarkdownOptionInfo Get(CommandInfo command) + { + // If we have the moduleInfo then store are module scope variable + if (command.Module != null) + { + return command.Module.SessionState.PSVariable.GetValue(MarkdownOptionInfoVariableName, new PSMarkdownOptionInfo()) as PSMarkdownOptionInfo; + } + + // If we don't have a moduleInfo, like in PowerShell hosting scenarios, use a concurrent dictionary. + if (markdownOptionInfoCache.TryGetValue(Runspace.DefaultRunspace.InstanceId, out PSMarkdownOptionInfo cachedOption)) + { + // return the cached options for the runspaceId + return cachedOption; + } + else + { + // no option cache so cache and return the default PSMarkdownOptionInfo + var newOptionInfo = new PSMarkdownOptionInfo(); + return markdownOptionInfoCache.GetOrAdd(Runspace.DefaultRunspace.InstanceId, newOptionInfo); + } + } + + internal static PSMarkdownOptionInfo Set(CommandInfo command, PSMarkdownOptionInfo optionInfo) + { + // If we have the moduleInfo then store are module scope variable + if (command.Module != null) + { + command.Module.SessionState.PSVariable.Set(MarkdownOptionInfoVariableName, optionInfo); + return optionInfo; + } + + // If we don't have a moduleInfo, like in PowerShell hosting scenarios with modules loaded as snapins, use a concurrent dictionary. + return markdownOptionInfoCache.AddOrUpdate(Runspace.DefaultRunspace.InstanceId, optionInfo, (key, oldvalue) => optionInfo); + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs index 17adfd80f859..110dea324d33 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs @@ -1,18 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; -using System.Text.RegularExpressions; -using System.IO; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; using System.Management.Automation; using System.Management.Automation.Internal; -using System.Globalization; -using System.Diagnostics.CodeAnalysis; +using System.Text; +using System.Text.RegularExpressions; namespace Microsoft.PowerShell.Commands { @@ -26,40 +24,33 @@ internal MatchInfoContext() } /// - /// Lines found before a match. + /// Gets or sets the lines found before a match. /// - - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] PreContext { get; set; } /// - /// Lines found after a match. + /// Gets or sets the lines found after a match. /// - - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] PostContext { get; set; } /// - /// Lines found before a match. Does not include + /// Gets or sets the lines found before a match. Does not include /// overlapping context and thus can be used to /// display contiguous match regions. /// - - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] DisplayPreContext { get; set; } /// - /// Lines found after a match. Does not include + /// Gets or sets the lines found after a match. Does not include /// overlapping context and thus can be used to /// display contiguous match regions. /// - - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] DisplayPostContext { get; set; } /// /// Produce a deep copy of this object. /// + /// A new object that is a copy of this instance. public object Clone() { return new MatchInfoContext() @@ -77,79 +68,78 @@ public object Clone() /// public class MatchInfo { - private static string s_inputStream = "InputStream"; + private static readonly string s_inputStream = "InputStream"; /// - /// Indicates if the match was done ignoring case. + /// Gets or sets a value indicating whether the match was done ignoring case. /// /// True if case was ignored. public bool IgnoreCase { get; set; } /// - /// Returns the number of the matching line. + /// Gets or sets the number of the matching line. /// /// The number of the matching line. public int LineNumber { get; set; } /// - /// Returns the text of the matching line. + /// Gets or sets the text of the matching line. /// /// The text of the matching line. - public string Line { get; set; } = ""; + public string Line { get; set; } = string.Empty; /// - /// Returns the base name of the file containing the matching line. + /// Gets the base name of the file containing the matching line. /// /// It will be the string "InputStream" if the object came from the input stream. - /// This is a readonly property calculated from the path. + /// This is a readonly property calculated from the path . /// /// - /// The file name + /// The file name. public string Filename { get { if (!_pathSet) + { return s_inputStream; + } + return _filename ?? (_filename = System.IO.Path.GetFileName(_path)); } } - private string _filename; + private string _filename; /// - /// The full path of the file containing the matching line. + /// Gets or sets the full path of the file containing the matching line. /// /// It will be "InputStream" if the object came from the input stream. /// /// - /// The path name + /// The path name. public string Path { - get - { - if (!_pathSet) - return s_inputStream; - return _path; - } + get => _pathSet ? _path : s_inputStream; set { _path = value; _pathSet = true; } } + private string _path = s_inputStream; + private bool _pathSet; /// - /// Returns the pattern that was used in the match. + /// Gets or sets the pattern that was used in the match. /// - /// The pattern string + /// The pattern string. public string Pattern { get; set; } /// - /// The context for the match, or null if -context was not - /// specified. + /// Gets or sets context for the match, or null if -context was not specified. /// public MatchInfoContext Context { get; set; } @@ -157,7 +147,7 @@ public string Path /// Returns the path of the matching file truncated relative to the parameter. /// /// For example, if the matching path was c:\foo\bar\baz.c and the directory argument was c:\foo - /// the routine would return bar\baz.c + /// the routine would return bar\baz.c . /// /// /// The directory base the truncation on. @@ -165,10 +155,12 @@ public string Path public string RelativePath(string directory) { if (!_pathSet) + { return this.Path; + } string relPath = _path; - if (!String.IsNullOrEmpty(directory)) + if (!string.IsNullOrEmpty(directory)) { if (relPath.StartsWith(directory, StringComparison.OrdinalIgnoreCase)) { @@ -176,12 +168,17 @@ public string RelativePath(string directory) if (offset < relPath.Length) { if (directory[offset - 1] == '\\' || directory[offset - 1] == '/') + { relPath = relPath.Substring(offset); + } else if (relPath[offset] == '\\' || relPath[offset] == '/') + { relPath = relPath.Substring(offset + 1); + } } } } + return relPath; } @@ -204,7 +201,7 @@ public string RelativePath(string directory) /// If path is not set, then just the line text is presented. /// /// - /// The string representation of the match object + /// The string representation of the match object. public override string ToString() { return ToString(null); @@ -214,8 +211,8 @@ public override string ToString() /// Returns the string representation of the match object same format as ToString() /// but trims the path to be relative to the argument. /// - /// Directory to use as the root when calculating the relative path - /// The string representation of the match object + /// Directory to use as the root when calculating the relative path. + /// The string representation of the match object. public string ToString(string directory) { string displayPath = (directory != null) ? RelativePath(directory) : _path; @@ -243,7 +240,7 @@ public string ToString(string directory) lines.Add(FormatLine(contextLine, displayLineNumber++, displayPath, ContextPrefix)); } - return String.Join(System.Environment.NewLine, lines.ToArray()); + return string.Join(System.Environment.NewLine, lines.ToArray()); } /// @@ -256,21 +253,20 @@ public string ToString(string directory) /// The formatted line as a string. private string FormatLine(string lineStr, int displayLineNumber, string displayPath, string prefix) { - if (_pathSet) - return StringUtil.Format(MatchFormat, prefix, displayPath, displayLineNumber, lineStr); - else - return StringUtil.Format(SimpleFormat, prefix, lineStr); + return _pathSet + ? StringUtil.Format(MatchFormat, prefix, displayPath, displayLineNumber, lineStr) + : StringUtil.Format(SimpleFormat, prefix, lineStr); } /// - /// A list of all Regex matches on the matching line. + /// Gets or sets a list of all Regex matches on the matching line. /// - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public Match[] Matches { get; set; } = new Match[] { }; /// /// Create a deep copy of this MatchInfo instance. /// + /// A new object that is a copy of this instance. internal MatchInfo Clone() { // Just do a shallow copy and then deep-copy the @@ -293,17 +289,27 @@ internal MatchInfo Clone() /// /// A cmdlet to search through strings and files for particular patterns. /// - [Cmdlet(VerbsCommon.Select, "String", DefaultParameterSetName = "File", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113388")] - [OutputType(typeof(MatchInfo), typeof(bool))] + [Cmdlet(VerbsCommon.Select, "String", DefaultParameterSetName = ParameterSetFile, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113388")] + [OutputType(typeof(bool), typeof(MatchInfo), ParameterSetName = new[] { ParameterSetFile, ParameterSetObject, ParameterSetLiteralFile })] + [OutputType(typeof(string), ParameterSetName = new[] { ParameterSetFileRaw, ParameterSetObjectRaw, ParameterSetLiteralFileRaw })] public sealed class SelectStringCommand : PSCmdlet { + private const string ParameterSetFile = "File"; + private const string ParameterSetFileRaw = "FileRaw"; + private const string ParameterSetObject = "Object"; + private const string ParameterSetObjectRaw = "ObjectRaw"; + private const string ParameterSetLiteralFile = "LiteralFile"; + private const string ParameterSetLiteralFileRaw = "LiteralFileRaw"; + /// /// A generic circular buffer. /// + /// The type of items that are buffered. private class CircularBuffer : ICollection { // Ring of items - private T[] _items; + private readonly T[] _items; + // Current length, as opposed to the total capacity // Current start of the list. Starts at 0, but may // move forwards or wrap around back to 0 due to @@ -311,43 +317,33 @@ private class CircularBuffer : ICollection private int _firstIndex; /// - /// Construct a new buffer of the specified capacity. + /// Initializes a new instance of the class. /// /// The maximum capacity of the buffer. /// If is negative. public CircularBuffer(int capacity) { if (capacity < 0) - throw new ArgumentOutOfRangeException("capacity"); + { + throw new ArgumentOutOfRangeException(nameof(capacity)); + } _items = new T[capacity]; Clear(); } /// - /// The maximum capacity of the buffer. If more items + /// Gets the maximum capacity of the buffer. If more items /// are added than the buffer has capacity for, then /// older items will be removed from the buffer with /// a first-in, first-out policy. /// - public int Capacity - { - get - { - return _items.Length; - } - } + public int Capacity => _items.Length; /// /// Whether or not the buffer is at capacity. /// - public bool IsFull - { - get - { - return Count == Capacity; - } - } + public bool IsFull => Count == Capacity; /// /// Convert from a 0-based index to a buffer index which @@ -363,7 +359,7 @@ private int WrapIndex(int zeroBasedIndex) { if (Capacity == 0 || zeroBasedIndex < 0) { - throw new ArgumentOutOfRangeException("zeroBasedIndex"); + throw new ArgumentOutOfRangeException(nameof(zeroBasedIndex)); } return (zeroBasedIndex + _firstIndex) % Capacity; @@ -387,13 +383,7 @@ IEnumerator IEnumerable.GetEnumerator() #region ICollection implementation public int Count { get; private set; } - public bool IsReadOnly - { - get - { - return false; - } - } + public bool IsReadOnly => false; /// /// Adds an item to the buffer. If the buffer is already @@ -435,18 +425,22 @@ public bool Contains(T item) throw new NotImplementedException(); } - - [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")] public void CopyTo(T[] array, int arrayIndex) { if (array == null) - throw new ArgumentNullException("array"); + { + throw new ArgumentNullException(nameof(array)); + } if (arrayIndex < 0) - throw new ArgumentOutOfRangeException("arrayIndex"); + { + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + } if (Count > (array.Length - arrayIndex)) + { throw new ArgumentException("arrayIndex"); + } // Iterate through the buffer in correct order. foreach (T item in this) @@ -479,13 +473,14 @@ public T[] ToArray() /// internal ordering the buffer may be maintaining. /// /// The index of the item to access. + /// The buffered item at index . public T this[int index] { get { if (!(index >= 0 && index < Count)) { - throw new ArgumentOutOfRangeException("index"); + throw new ArgumentOutOfRangeException(nameof(index)); } return _items[WrapIndex(index)]; @@ -499,7 +494,7 @@ public T[] ToArray() private interface IContextTracker { /// - /// Matches with completed context information + /// Gets matches with completed context information /// that are ready to be emitted into the pipeline. /// IList EmitQueue { get; } @@ -537,14 +532,14 @@ private enum ContextState } private ContextState _contextState = ContextState.InitialState; - private int _preContext = 0; - private int _postContext = 0; + private readonly int _preContext; + private readonly int _postContext; // The context leading up to the match. - private CircularBuffer _collectedPreContext = null; + private readonly CircularBuffer _collectedPreContext; // The context after the match. - private List _collectedPostContext = null; + private readonly List _collectedPostContext; // Current match info we are tracking postcontext for. // At any given time, if set, this value will not be @@ -552,10 +547,10 @@ private enum ContextState private MatchInfo _matchInfo = null; /// - /// Constructor for DisplayContextTracker. + /// Initializes a new instance of the class. /// - /// How much precontext to collect at most. - /// How much precontext to collect at most. + /// How much preContext to collect at most. + /// How much postContext to collect at most. public DisplayContextTracker(int preContext, int postContext) { _preContext = preContext; @@ -568,14 +563,9 @@ public DisplayContextTracker(int preContext, int postContext) } #region IContextTracker implementation - public IList EmitQueue - { - get - { - return _emitQueue; - } - } - private List _emitQueue = null; + public IList EmitQueue => _emitQueue; + + private readonly List _emitQueue; // Track non-matching line public void TrackLine(string line) @@ -596,6 +586,7 @@ public void TrackLine(string line) // Now we're done. UpdateQueue(); } + break; } } @@ -606,7 +597,9 @@ public void TrackMatch(MatchInfo match) // Update the queue in case we were in the middle // of collecting postcontext for an older match... if (_contextState == ContextState.CollectPost) + { UpdateQueue(); + } // Update the current matchInfo. _matchInfo = match; @@ -616,9 +609,13 @@ public void TrackMatch(MatchInfo match) // Otherwise, immediately move the match onto the queue // and let UpdateQueue update our state instead. if (_postContext > 0) + { _contextState = ContextState.CollectPost; + } else + { UpdateQueue(); + } } // Track having reached the end of the file. @@ -629,7 +626,9 @@ public void TrackEOF() // early since there are no more lines to track context // for. if (_contextState == ContextState.CollectPost) + { UpdateQueue(); + } } #endregion @@ -648,6 +647,7 @@ private void UpdateQueue() _matchInfo.Context.DisplayPreContext = _collectedPreContext.ToArray(); _matchInfo.Context.DisplayPostContext = _collectedPostContext.ToArray(); } + Reset(); } } @@ -677,7 +677,7 @@ private void Reset() /// a possibly-continuous set of matches by excluding /// overlapping context (lines will only appear once) /// and other matching lines (since they will appear - /// as their own match entries.) + /// as their own match entries.). /// private class LogicalContextTracker : IContextTracker { @@ -686,8 +686,8 @@ private class LogicalContextTracker : IContextTracker // or non-matching lines. private class ContextEntry { - public string Line = null; - public MatchInfo Match = null; + public readonly string Line; + public readonly MatchInfo Match; public ContextEntry(string line) { @@ -699,20 +699,18 @@ public ContextEntry(MatchInfo match) Match = match; } - public override string ToString() - { - return (Match != null) ? Match.Line : Line; - } + public override string ToString() => Match?.Line ?? Line; } // Whether or not early entries found // while still filling up the context buffer // have been added to the emit queue. // Used by UpdateQueue. - private bool _hasProcessedPreEntries = false; + private bool _hasProcessedPreEntries; + + private readonly int _preContext; + private readonly int _postContext; - private int _preContext; - private int _postContext; // A circular buffer tracking both precontext and postcontext. // // Essentially, the buffer is separated into regions: @@ -726,13 +724,13 @@ public override string ToString() // enough context to populate the Context properties of the // match. At that point, we will add the match object // to the emit queue. - private CircularBuffer _collectedContext = null; + private readonly CircularBuffer _collectedContext; /// - /// Constructor for LogicalContextTracker. + /// Initializes a new instance of the class. /// - /// How much precontext to collect at most. - /// How much postcontext to collect at most. + /// How much preContext to collect at most. + /// How much postContext to collect at most. public LogicalContextTracker(int preContext, int postContext) { _preContext = preContext; @@ -742,14 +740,9 @@ public LogicalContextTracker(int preContext, int postContext) } #region IContextTracker implementation - public IList EmitQueue - { - get - { - return _emitQueue; - } - } - private List _emitQueue = null; + public IList EmitQueue => _emitQueue; + + private readonly List _emitQueue; public void TrackLine(string line) { @@ -777,8 +770,7 @@ public void TrackEOF() // If the buffer isn't full, then nothing will have // ever been emitted and everything is still waiting // on postcontext. So process the whole buffer. - - int startIndex = (_collectedContext.IsFull) ? _preContext + 1 : 0; + int startIndex = _collectedContext.IsFull ? _preContext + 1 : 0; EmitAllInRange(startIndex, _collectedContext.Count - 1); } #endregion @@ -786,7 +778,7 @@ public void TrackEOF() /// /// Add all matches found in the specified range /// to the emit queue, collecting as much context - /// as possible up to the limits specified in the ctor. + /// as possible up to the limits specified in the constructor. /// /// /// The range is inclusive; the entries at @@ -849,14 +841,13 @@ private void UpdateQueue() /// and adds it to the emit queue. /// /// - /// Context ranges must be within the bounds of the context - /// buffer. + /// Context ranges must be within the bounds of the context buffer. /// /// The match to operate on. - /// The start index of the precontext range. - /// The length of the precontext range. - /// The start index of the postcontext range. - /// The length of the precontext range. + /// The start index of the preContext range. + /// The length of the preContext range. + /// The start index of the postContext range. + /// The length of the postContext range. private void Emit(MatchInfo match, int preStartIndex, int preLength, int postStartIndex, int postLength) { if (match.Context != null) @@ -876,6 +867,7 @@ private void Emit(MatchInfo match, int preStartIndex, int preLength, int postSta /// /// The index to start at. /// The length of the range. + /// String representation of the collected context at the specified range. private string[] CopyContext(int startIndex, int length) { string[] result = new string[length]; @@ -894,14 +886,14 @@ private string[] CopyContext(int startIndex, int length) /// private class ContextTracker : IContextTracker { - private IContextTracker _displayTracker; - private IContextTracker _logicalTracker; + private readonly IContextTracker _displayTracker; + private readonly IContextTracker _logicalTracker; /// - /// Constructor for LogicalContextTracker. + /// Initializes a new instance of the class. /// - /// How much precontext to collect at most. - /// How much postcontext to collect at most. + /// How much preContext to collect at most. + /// How much postContext to collect at most. public ContextTracker(int preContext, int postContext) { _displayTracker = new DisplayContextTracker(preContext, postContext); @@ -948,7 +940,6 @@ private void UpdateQueue() // time as the logical tracker, so we can // be sure the matches will have both logical // and display context already populated. - foreach (MatchInfo match in _logicalTracker.EmitQueue) { EmitQueue.Add(match); @@ -960,265 +951,199 @@ private void UpdateQueue() } /// - /// This parameter specifies the current pipeline object + /// ContextTracker that does not work for the case when pre- and post context is 0. /// - [Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = "Object")] - [AllowNull] - [AllowEmptyString] - public PSObject InputObject + private class NoContextTracker : IContextTracker { - get + private readonly IList _matches = new List(1); + + IList IContextTracker.EmitQueue => _matches; + + void IContextTracker.TrackLine(string line) { - return _inputObject; } - set + + void IContextTracker.TrackMatch(MatchInfo match) => _matches.Add(match); + + void IContextTracker.TrackEOF() { - _inputObject = LanguagePrimitives.IsNull(value) ? PSObject.AsPSObject("") : value; } } + + /// + /// Gets or sets the current pipeline object. + /// + [Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = ParameterSetObject)] + [Parameter(ValueFromPipeline = true, Mandatory = true, ParameterSetName = ParameterSetObjectRaw)] + [AllowNull] + [AllowEmptyString] + public PSObject InputObject + { + get => _inputObject; + set => _inputObject = LanguagePrimitives.IsNull(value) ? PSObject.AsPSObject(string.Empty) : value; + } + private PSObject _inputObject = AutomationNull.Value; /// - /// String index to start from the beginning. - /// - /// If the value is negative, the length is counted from the - /// end of the string. + /// Gets or sets the patterns to find. /// - /// [Parameter(Mandatory = true, Position = 0)] public string[] Pattern { get; set; } private Regex[] _regexPattern; /// - /// file to read from - /// Globbing is done on these + /// Gets or sets files to read from. + /// Globbing is done on these. /// - [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "File")] + [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetFile)] + [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetFileRaw)] [FileinfoToString] public string[] Path { get; set; } /// - /// Literal file to read from - /// Globbing is not done on these + /// Gets or sets literal files to read from. + /// Globbing is not done on these. /// - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "LiteralFile")] + [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetLiteralFile)] + [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = ParameterSetLiteralFileRaw)] [FileinfoToString] - [Alias("PSPath")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] + [Alias("PSPath", "LP")] public string[] LiteralPath { - get - { - return Path; - } + get => Path; set { Path = value; _isLiteralPath = true; } } - private bool _isLiteralPath = false; - /// If set, match pattern string literally. - /// If not (default) search using pattern as a Regular Expression + private bool _isLiteralPath; + + /// + /// Gets or sets a value indicating if only string values containing matched lines should be returned. + /// If not (default) return MatchInfo (or bool objects, when Quiet is passed). + /// + [Parameter(Mandatory = true, ParameterSetName = ParameterSetObjectRaw)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSetFileRaw)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSetLiteralFileRaw)] + public SwitchParameter Raw { get; set; } + + /// + /// Gets or sets a value indicating if a pattern string should be matched literally. + /// If not (default) search using pattern as a Regular Expression. /// [Parameter] - public SwitchParameter SimpleMatch - { - get - { - return _simpleMatch; - } - set - { - _simpleMatch = value; - } - } - private bool _simpleMatch; + public SwitchParameter SimpleMatch { get; set; } - /// - /// If true, then do case-sensitive searches... + /// + /// Gets or sets a value indicating if the search is case sensitive.If true, then do case-sensitive searches. /// [Parameter] - public SwitchParameter CaseSensitive - { - get - { - return _caseSensitive; - } - set - { - _caseSensitive = value; - } - } - private bool _caseSensitive; + public SwitchParameter CaseSensitive { get; set; } /// - /// If true the cmdlet will stop processing at the first successful match and + /// Gets or sets a value indicating if the cmdlet will stop processing at the first successful match and /// return true. If both List and Quiet parameters are given, an exception is thrown. /// - [Parameter] - public SwitchParameter Quiet - { - get - { - return _quiet; - } - set - { - _quiet = value; - } - } - private bool _quiet; + [Parameter(ParameterSetName = ParameterSetObject)] + [Parameter(ParameterSetName = ParameterSetFile)] + [Parameter(ParameterSetName = ParameterSetLiteralFile)] + public SwitchParameter Quiet { get; set; } /// - /// list files where a match is found + /// Gets or sets a value indicating if matching files should be listed. /// This is the Unix functionality this switch is intended to mimic; /// the actual action of this option is to stop after the first match /// is found and returned from any particular file. /// [Parameter] - public SwitchParameter List - { - get - { - return _list; - } - set - { - _list = value; - } - } - private bool _list; + public SwitchParameter List { get; set; } /// - /// Lets you include particular files. Files not matching - /// one of these (if specified) are excluded. + /// Gets or sets files to include. Files matching + /// one of these (if specified) are included. /// /// Invalid wildcard pattern was specified. [Parameter] [ValidateNotNullOrEmpty] public string[] Include { - get - { - return includeStrings; - } + get => _includeStrings; set { // null check is not needed (because of ValidateNotNullOrEmpty), // but we have to include it to silence OACR - if (value == null) - { - throw PSTraceSource.NewArgumentNullException("value"); - } + _includeStrings = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value)); - includeStrings = value; - - this.include = new WildcardPattern[includeStrings.Length]; - for (int i = 0; i < includeStrings.Length; i++) + _include = new WildcardPattern[_includeStrings.Length]; + for (int i = 0; i < _includeStrings.Length; i++) { - this.include[i] = WildcardPattern.Get(includeStrings[i], WildcardOptions.IgnoreCase); + _include[i] = WildcardPattern.Get(_includeStrings[i], WildcardOptions.IgnoreCase); } } } - internal string[] includeStrings = null; - internal WildcardPattern[] include = null; + + private string[] _includeStrings; + + private WildcardPattern[] _include; /// - /// Lets you exclude particular files. Files matching + /// Gets or sets files to exclude. Files matching /// one of these (if specified) are excluded. /// [Parameter] [ValidateNotNullOrEmpty] public string[] Exclude { - get - { - return excludeStrings; - } + get => _excludeStrings; set { // null check is not needed (because of ValidateNotNullOrEmpty), // but we have to include it to silence OACR - if (value == null) - { - throw PSTraceSource.NewArgumentNullException("value"); - } + _excludeStrings = value ?? throw PSTraceSource.NewArgumentNullException("value"); - excludeStrings = value; - - this.exclude = new WildcardPattern[excludeStrings.Length]; - for (int i = 0; i < excludeStrings.Length; i++) + _exclude = new WildcardPattern[_excludeStrings.Length]; + for (int i = 0; i < _excludeStrings.Length; i++) { - this.exclude[i] = WildcardPattern.Get(excludeStrings[i], WildcardOptions.IgnoreCase); + _exclude[i] = WildcardPattern.Get(_excludeStrings[i], WildcardOptions.IgnoreCase); } } } - internal string[] excludeStrings; - internal WildcardPattern[] exclude; + + private string[] _excludeStrings; + + private WildcardPattern[] _exclude; /// - /// Only show lines which do not match. + /// Gets or sets a value indicating whether to only show lines which do not match. /// Equivalent to grep -v/findstr -v. /// [Parameter] - public SwitchParameter NotMatch - { - get - { - return _notMatch; - } - set - { - _notMatch = value; - } - } - private bool _notMatch; + public SwitchParameter NotMatch { get; set; } /// - /// If set, sets the Matches property of MatchInfo to the result - /// of calling System.Text.RegularExpressions.Regex.Matches() on + /// Gets or sets a value indicating whether the Matches property of MatchInfo should be set + /// to the result of calling System.Text.RegularExpressions.Regex.Matches() on /// the corresponding line. - /// /// Has no effect if -SimpleMatch is also specified. /// [Parameter] - public SwitchParameter AllMatches - { - get - { - return _allMatches; - } - set - { - _allMatches = value; - } - } - private bool _allMatches; + public SwitchParameter AllMatches { get; set; } /// - /// The text encoding to process each file as. + /// Gets or sets the text encoding to process each file as. /// [Parameter] [ArgumentToEncodingTransformationAttribute()] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] + [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); /// - /// The number of context lines to collect. If set to a + /// Gets or sets the number of context lines to collect. If set to a /// single integer value N, collects N lines each of pre- /// and post- context. If set to a 2-tuple B,A, collects B /// lines of pre- and A lines of post- context. @@ -1231,20 +1156,12 @@ public SwitchParameter AllMatches [ValidateRange(0, Int32.MaxValue)] public new int[] Context { - get - { - return _context; - } + get => _context; set { // null check is not needed (because of ValidateNotNullOrEmpty), // but we have to include it to silence OACR - if (value == null) - { - throw PSTraceSource.NewArgumentNullException("value"); - } - - _context = value; + _context = value ?? throw PSTraceSource.NewArgumentNullException("value"); if (_context.Length == 1) { @@ -1258,10 +1175,18 @@ public new int[] Context } } } + private int[] _context; + private int _preContext = 0; + private int _postContext = 0; + // When we are in Raw mode or pre- and postcontext are zero, use the _noContextTracker, since we will not be needing trackedLines. + private IContextTracker GetContextTracker() => (Raw || (_preContext == 0 && _postContext == 0)) + ? _noContextTracker + : new ContextTracker(_preContext, _postContext); + // This context tracker is only used for strings which are piped // directly into the cmdlet. File processing doesn't need // to track state between calls to ProcessRecord, and so @@ -1269,7 +1194,9 @@ public new int[] Context // use a single global tracker for both is that in the case of // a mixed list of strings and FileInfo, the context tracker // would get reset after each file. - private ContextTracker _globalContextTracker = null; + private IContextTracker _globalContextTracker; + + private IContextTracker _noContextTracker; /// /// This is used to handle the case were we're done processing input objects. @@ -1284,9 +1211,9 @@ public new int[] Context /// protected override void BeginProcessing() { - if (!_simpleMatch) + if (!SimpleMatch) { - RegexOptions regexOptions = (_caseSensitive) ? RegexOptions.None : RegexOptions.IgnoreCase; + RegexOptions regexOptions = CaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase; _regexPattern = new Regex[Pattern.Length]; for (int i = 0; i < Pattern.Length; i++) { @@ -1302,61 +1229,68 @@ protected override void BeginProcessing() } } - _globalContextTracker = new ContextTracker(_preContext, _postContext); + _noContextTracker = new NoContextTracker(); + _globalContextTracker = GetContextTracker(); } + private readonly List _inputObjectFileList = new List(1) { string.Empty }; + /// - /// process the input + /// Process the input. /// - /// - /// Does not return a value - /// - /// Regular expression parsing error, path error + /// Regular expression parsing error, path error. /// A file cannot be found. /// A file cannot be found. protected override void ProcessRecord() { if (_doneProcessing) + { return; + } + // We may only have directories when we have resolved wildcards + var expandedPathsMaybeDirectory = false; List expandedPaths = null; if (Path != null) { expandedPaths = ResolveFilePaths(Path, _isLiteralPath); if (expandedPaths == null) + { return; + } + + expandedPathsMaybeDirectory = true; } else { - FileInfo fileInfo = _inputObject.BaseObject as FileInfo; - if (fileInfo != null) + if (_inputObject.BaseObject is FileInfo fileInfo) { - expandedPaths = new List(); - expandedPaths.Add(fileInfo.FullName); + _inputObjectFileList[0] = fileInfo.FullName; + expandedPaths = _inputObjectFileList; } } if (expandedPaths != null) { - foreach (string filename in expandedPaths) + foreach (var filename in expandedPaths) { - if (Directory.Exists(filename)) + if (expandedPathsMaybeDirectory && Directory.Exists(filename)) { continue; } - bool foundMatch = ProcessFile(filename); - if (_quiet && foundMatch) + var foundMatch = ProcessFile(filename); + if (Quiet && foundMatch) + { return; + } } // No results in any files. - if (_quiet) + if (Quiet) { - if (_list) - WriteObject(null); - else - WriteObject(false); + var res = List ? null : Boxed.False; + WriteObject(res); } } else @@ -1367,16 +1301,15 @@ protected override void ProcessRecord() bool matched; MatchInfo result; MatchInfo matchInfo = null; - var line = _inputObject.BaseObject as string; - if (line != null) + if (_inputObject.BaseObject is string line) { - matched = doMatch(line, out result); + matched = DoMatch(line, out result); } else { matchInfo = _inputObject.BaseObject as MatchInfo; object objectToCheck = matchInfo ?? (object)_inputObject; - matched = doMatch(objectToCheck, out result, out line); + matched = DoMatch(objectToCheck, out result, out line); } if (matched) @@ -1386,6 +1319,7 @@ protected override void ProcessRecord() { result.LineNumber = _inputRecordNumber; } + // doMatch will have already set the pattern and line text... _globalContextTracker.TrackMatch(result); } @@ -1399,8 +1333,10 @@ protected override void ProcessRecord() { // If we're in quiet mode, go ahead and stop processing // now. - if (_quiet) + if (Quiet) + { _doneProcessing = true; + } } } } @@ -1413,7 +1349,7 @@ protected override void ProcessRecord() /// True if a match was found; otherwise false. private bool ProcessFile(string filename) { - ContextTracker contextTracker = new ContextTracker(_preContext, _postContext); + var contextTracker = GetContextTracker(); bool foundMatch = false; @@ -1421,14 +1357,16 @@ private bool ProcessFile(string filename) try { // see if the file is one the include exclude list... - if (!meetsIncludeExcludeCriteria(filename)) + if (!MeetsIncludeExcludeCriteria(filename)) + { return false; + } using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (StreamReader sr = new StreamReader(fs, Encoding)) { - String line; + string line; int lineNo = 0; // Read and display lines from the file until the end of @@ -1437,9 +1375,7 @@ private bool ProcessFile(string filename) { lineNo++; - MatchInfo result; - - if (doMatch(line, out result)) + if (DoMatch(line, out MatchInfo result)) { result.Path = filename; result.LineNumber = lineNo; @@ -1460,15 +1396,12 @@ private bool ProcessFile(string filename) // this file. It's done this way so the file is closed before emitting // the result so the downstream cmdlet can actually manipulate the file // that was found. - - if (_quiet || _list) + if (Quiet || List) { break; } - else - { - FlushTrackerQueue(contextTracker); - } + + FlushTrackerQueue(contextTracker); } } } @@ -1480,7 +1413,9 @@ private bool ProcessFile(string filename) // our postcontext. contextTracker.TrackEOF(); if (FlushTrackerQueue(contextTracker)) + { foundMatch = true; + } } catch (System.NotSupportedException nse) { @@ -1503,23 +1438,30 @@ private bool ProcessFile(string filename) } /// - /// Emit any objects which have been queued up, and clear - /// the queue. + /// Emit any objects which have been queued up, and clear the queue. /// /// The context tracker to operate on. /// Whether or not any objects were emitted. - private bool FlushTrackerQueue(ContextTracker contextTracker) + private bool FlushTrackerQueue(IContextTracker contextTracker) { // Do we even have any matches to emit? if (contextTracker.EmitQueue.Count < 1) + { return false; + } - // If -quiet is specified but not -list return true on first match - if (_quiet && !_list) + if (Raw) + { + foreach (MatchInfo match in contextTracker.EmitQueue) + { + WriteObject(match.Line); + } + } + else if (Quiet && !List) { WriteObject(true); } - else if (_list) + else if (List) { WriteObject(contextTracker.EmitQueue[0]); } @@ -1544,15 +1486,17 @@ protected override void EndProcessing() // Check for a leftover match that was still tracking context. _globalContextTracker.TrackEOF(); if (!_doneProcessing) + { FlushTrackerQueue(_globalContextTracker); + } } - private bool doMatch(string operandString, out MatchInfo matchResult) + private bool DoMatch(string operandString, out MatchInfo matchResult) { - return doMatchWorker(operandString, null, out matchResult); + return DoMatchWorker(operandString, null, out matchResult); } - private bool doMatch(object operand, out MatchInfo matchResult, out string operandString) + private bool DoMatch(object operand, out MatchInfo matchResult, out string operandString) { MatchInfo matchInfo = operand as MatchInfo; if (matchInfo != null) @@ -1579,28 +1523,25 @@ private bool doMatch(object operand, out MatchInfo matchResult, out string opera operandString = (string)LanguagePrimitives.ConvertTo(operand, typeof(string), CultureInfo.InvariantCulture); } - return doMatchWorker(operandString, matchInfo, out matchResult); + return DoMatchWorker(operandString, matchInfo, out matchResult); } /// /// Check the operand and see if it matches, if this.quiet is not set, then - /// return a partially populated MatchInfo object with Line, Pattern, IgnoreCase - /// set. + /// return a partially populated MatchInfo object with Line, Pattern, IgnoreCase set. /// - /// - /// the match info object - this will be - /// null if this.quiet is set. - /// the result of converting operand to - /// a string. - /// true if the input object matched - private bool doMatchWorker(string operandString, MatchInfo matchInfo, out MatchInfo matchResult) + /// The result of converting operand to a string. + /// The input object in filter mode. + /// The match info object - this will be null if this.quiet is set. + /// True if the input object matched. + private bool DoMatchWorker(string operandString, MatchInfo matchInfo, out MatchInfo matchResult) { bool gotMatch = false; Match[] matches = null; int patternIndex = 0; matchResult = null; - if (!_simpleMatch) + if (!SimpleMatch) { while (patternIndex < Pattern.Length) { @@ -1609,7 +1550,7 @@ private bool doMatchWorker(string operandString, MatchInfo matchInfo, out MatchI // Only honor allMatches if notMatch is not set, // since it's a fairly expensive operation and // notMatch takes precedent over allMatch. - if (_allMatches && !_notMatch) + if (AllMatches && !NotMatch) { MatchCollection mc = r.Matches(operandString); if (mc.Count > 0) @@ -1631,14 +1572,16 @@ private bool doMatchWorker(string operandString, MatchInfo matchInfo, out MatchI } if (gotMatch) + { break; + } patternIndex++; } } else { - StringComparison compareOption = _caseSensitive ? + StringComparison compareOption = CaseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase; while (patternIndex < Pattern.Length) { @@ -1654,9 +1597,10 @@ private bool doMatchWorker(string operandString, MatchInfo matchInfo, out MatchI } } - if (_notMatch) + if (NotMatch) { gotMatch = !gotMatch; + // If notMatch was specified with multiple // patterns, then *none* of the patterns // matched and any pattern could be picked @@ -1693,10 +1637,12 @@ private bool doMatchWorker(string operandString, MatchInfo matchInfo, out MatchI } // otherwise construct and populate a new MatchInfo object - matchResult = new MatchInfo(); - matchResult.IgnoreCase = !_caseSensitive; - matchResult.Line = operandString; - matchResult.Pattern = Pattern[patternIndex]; + matchResult = new MatchInfo + { + IgnoreCase = !CaseSensitive, + Line = operandString, + Pattern = Pattern[patternIndex] + }; if (_preContext > 0 || _postContext > 0) { @@ -1709,23 +1655,28 @@ private bool doMatchWorker(string operandString, MatchInfo matchInfo, out MatchI return true; } + return false; - } // end doMatch + } + /// /// Get a list or resolved file paths. + /// + /// The filePaths to resolve. + /// True if the wildcard resolution should not be attempted. + /// The resolved (absolute) paths. private List ResolveFilePaths(string[] filePaths, bool isLiteralPath) { - ProviderInfo provider; List allPaths = new List(); foreach (string path in filePaths) { Collection resolvedPaths; + ProviderInfo provider; if (isLiteralPath) { resolvedPaths = new Collection(); - PSDriveInfo drive; - string resolvedPath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out drive); + string resolvedPath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out _); resolvedPaths.Add(resolvedPath); } else @@ -1733,12 +1684,13 @@ private List ResolveFilePaths(string[] filePaths, bool isLiteralPath) resolvedPaths = GetResolvedProviderPathFromPSPath(path, out provider); } - if (!provider.NameEquals(((PSCmdlet)this).Context.ProviderNames.FileSystem)) + if (!provider.NameEquals(base.Context.ProviderNames.FileSystem)) { // "The current provider ({0}) cannot open a file" WriteError(BuildErrorRecord(MatchStringStrings.FileOpenError, provider.FullName, "ProcessingFile", null)); continue; } + allPaths.AddRange(resolvedPaths); } @@ -1777,15 +1729,15 @@ public override object Transform(EngineIntrinsics engineIntrinsics, object input { object result = inputData; - PSObject mso = result as PSObject; - if (mso != null) + if (result is PSObject mso) + { result = mso.BaseObject; + } - IList argList = result as IList; FileInfo fileInfo; // Handle an array of elements... - if (argList != null) + if (result is IList argList) { object[] resultList = new object[argList.Count]; @@ -1795,21 +1747,23 @@ public override object Transform(EngineIntrinsics engineIntrinsics, object input mso = element as PSObject; if (mso != null) + { element = mso.BaseObject; + } fileInfo = element as FileInfo; - - if (fileInfo != null) - resultList[i] = fileInfo.FullName; - else resultList[i] = element; + resultList[i] = fileInfo?.FullName ?? element; } + return resultList; } // Handle the singleton case... fileInfo = result as FileInfo; if (fileInfo != null) + { return fileInfo.FullName; + } return inputData; } @@ -1820,16 +1774,16 @@ public override object Transform(EngineIntrinsics engineIntrinsics, object input /// That is - it's on the include list if there is one and not on /// the exclude list if there was one of those. /// - /// + /// The filename to test. /// True if the filename is acceptable. - private bool meetsIncludeExcludeCriteria(string filename) + private bool MeetsIncludeExcludeCriteria(string filename) { bool ok = false; // see if the file is on the include list... - if (this.include != null) + if (_include != null) { - foreach (WildcardPattern patternItem in this.include) + foreach (WildcardPattern patternItem in _include) { if (patternItem.IsMatch(filename)) { @@ -1844,12 +1798,14 @@ private bool meetsIncludeExcludeCriteria(string filename) } if (!ok) + { return false; + } // now see if it's on the exclude list... - if (this.exclude != null) + if (_exclude != null) { - foreach (WildcardPattern patternItem in this.exclude) + foreach (WildcardPattern patternItem in _exclude) { if (patternItem.IsMatch(filename)) { @@ -1861,6 +1817,5 @@ private bool meetsIncludeExcludeCriteria(string filename) return ok; } - } // end class SelectStringCommand + } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs index 06b77334d7a5..687b1cdc9a77 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -8,78 +7,71 @@ using System.Globalization; using System.Management.Automation; using System.Management.Automation.Internal; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// Class output by Measure-Object + /// Class output by Measure-Object. /// public abstract class MeasureInfo { /// - /// - /// property name - /// + /// Property name. /// public string Property { get; set; } = null; } /// - /// Class output by Measure-Object + /// Class output by Measure-Object. /// public sealed class GenericMeasureInfo : MeasureInfo { /// - /// default ctor + /// Default ctor. /// public GenericMeasureInfo() { - Average = Sum = Maximum = Minimum = null; + Average = Sum = Maximum = Minimum = StandardDeviation = null; } /// - /// - /// Keeping track of number of objects with a certain property - /// + /// Keeping track of number of objects with a certain property. /// public int Count { get; set; } /// - /// - /// The average of property values - /// + /// The average of property values. /// public double? Average { get; set; } /// - /// - /// The sum of property values - /// + /// The sum of property values. /// public double? Sum { get; set; } /// - /// - /// The max of property values - /// + /// The max of property values. /// public double? Maximum { get; set; } /// - /// - /// The min of property values - /// + /// The min of property values. /// public double? Minimum { get; set; } + + /// + /// The Standard Deviation of property values. + /// + public double? StandardDeviation { get; set; } } /// /// Class output by Measure-Object. /// /// - /// This class is created for fixing "Measure-Object -MAX -MIN should work with ANYTHING that supports CompareTo" - /// bug (Win8:343911). + /// This class is created to make 'Measure-Object -MAX -MIN' work with ANYTHING that supports 'CompareTo'. /// GenericMeasureInfo class is shipped with PowerShell V2. Fixing this bug requires, changing the type of /// Maximum and Minimum properties which would be a breaking change. Hence created a new class to not /// have an appcompat issues with PS V2. @@ -87,58 +79,52 @@ public GenericMeasureInfo() public sealed class GenericObjectMeasureInfo : MeasureInfo { /// - /// default ctor + /// Default ctor. /// public GenericObjectMeasureInfo() { - Average = Sum = null; + Average = Sum = StandardDeviation = null; Maximum = Minimum = null; } /// - /// - /// Keeping track of number of objects with a certain property - /// + /// Keeping track of number of objects with a certain property. /// public int Count { get; set; } /// - /// - /// The average of property values - /// + /// The average of property values. /// public double? Average { get; set; } /// - /// - /// The sum of property values - /// + /// The sum of property values. /// public double? Sum { get; set; } /// - /// - /// The max of property values - /// + /// The max of property values. /// public object Maximum { get; set; } /// - /// - /// The min of property values - /// + /// The min of property values. /// public object Minimum { get; set; } - } + /// + /// The Standard Deviation of property values. + /// + public double? StandardDeviation { get; set; } + } /// - /// Class output by Measure-Object + /// Class output by Measure-Object. /// public sealed class TextMeasureInfo : MeasureInfo { /// - /// default ctor + /// Default ctor. /// public TextMeasureInfo() { @@ -146,29 +132,23 @@ public TextMeasureInfo() } /// - /// - /// Keeping track of number of objects with a certain property - /// + /// Keeping track of number of objects with a certain property. /// public int? Lines { get; set; } /// - /// - /// The average of property values - /// + /// The average of property values. /// public int? Words { get; set; } /// - /// - /// The sum of property values - /// + /// The sum of property values. /// public int? Characters { get; set; } } /// - /// measure object cmdlet + /// Measure object cmdlet. /// [Cmdlet(VerbsDiagnostic.Measure, "Object", DefaultParameterSetName = GenericParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113349", RemotingCapability = RemotingCapability.None)] @@ -176,7 +156,7 @@ public TextMeasureInfo() public sealed class MeasureObjectCommand : PSCmdlet { /// - /// Dictionary to be used by Measure-Object implementation + /// Dictionary to be used by Measure-Object implementation. /// Keys are strings. Keys are compared with OrdinalIgnoreCase. /// /// Value type. @@ -184,7 +164,7 @@ private class MeasureObjectDictionary : Dictionary where V : new() { /// - /// default ctor + /// Default ctor. /// internal MeasureObjectDictionary() : base(StringComparer.OrdinalIgnoreCase) { @@ -196,7 +176,7 @@ internal MeasureObjectDictionary() : base(StringComparer.OrdinalIgnoreCase) /// the key with a new value created via the value type's /// default constructor. /// - /// The key to look up + /// The key to look up. /// /// The existing value, or a newly-created value. /// @@ -227,6 +207,8 @@ private class Statistics // Generic/Numeric statistics internal double sum = 0.0; + internal double sumPrevious = 0.0; + internal double variance = 0.0; internal object max = null; internal object min = null; @@ -237,7 +219,7 @@ private class Statistics } /// - /// default constructor + /// Default constructor. /// public MeasureObjectCommand() : base() @@ -249,24 +231,43 @@ public MeasureObjectCommand() #region Common parameters in both sets /// - /// incoming object + /// Incoming object. /// /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { set; get; } = AutomationNull.Value; /// - /// Properties to be examined + /// Properties to be examined. /// /// [ValidateNotNullOrEmpty] [Parameter(Position = 0)] - public string[] Property { get; set; } = null; + public PSPropertyExpression[] Property { get; set; } = null; #endregion Common parameters in both sets /// - /// Set to true is Sum is to be returned + /// Set to true if Standard Deviation is to be returned. + /// + [Parameter(ParameterSetName = GenericParameterSet)] + public SwitchParameter StandardDeviation + { + get + { + return _measureStandardDeviation; + } + + set + { + _measureStandardDeviation = value; + } + } + + private bool _measureStandardDeviation; + + /// + /// Set to true is Sum is to be returned. /// /// [Parameter(ParameterSetName = GenericParameterSet)] @@ -276,15 +277,37 @@ public SwitchParameter Sum { return _measureSum; } + set { _measureSum = value; } } + private bool _measureSum; /// - /// Set to true is Average is to be returned + /// Gets or sets the value indicating if all statistics should be returned. + /// + /// + [Parameter(ParameterSetName = GenericParameterSet)] + public SwitchParameter AllStats + { + get + { + return _allStats; + } + + set + { + _allStats = value; + } + } + + private bool _allStats; + + /// + /// Set to true is Average is to be returned. /// /// [Parameter(ParameterSetName = GenericParameterSet)] @@ -294,15 +317,17 @@ public SwitchParameter Average { return _measureAverage; } + set { _measureAverage = value; } } + private bool _measureAverage; /// - /// Set to true is Max is to be returned + /// Set to true is Max is to be returned. /// /// [Parameter(ParameterSetName = GenericParameterSet)] @@ -312,15 +337,17 @@ public SwitchParameter Maximum { return _measureMax; } + set { _measureMax = value; } } + private bool _measureMax; /// - /// Set to true is Min is to be returned + /// Set to true is Min is to be returned. /// /// [Parameter(ParameterSetName = GenericParameterSet)] @@ -330,16 +357,17 @@ public SwitchParameter Minimum { return _measureMin; } + set { _measureMin = value; } } + private bool _measureMin; #region TextMeasure ParameterSet /// - /// /// /// [Parameter(ParameterSetName = TextParameterSet)] @@ -349,15 +377,16 @@ public SwitchParameter Line { return _measureLines; } + set { _measureLines = value; } } + private bool _measureLines = false; /// - /// /// /// [Parameter(ParameterSetName = TextParameterSet)] @@ -367,15 +396,16 @@ public SwitchParameter Word { return _measureWords; } + set { _measureWords = value; } } + private bool _measureWords = false; /// - /// /// /// [Parameter(ParameterSetName = TextParameterSet)] @@ -385,15 +415,16 @@ public SwitchParameter Character { return _measureCharacters; } + set { _measureCharacters = value; } } + private bool _measureCharacters = false; /// - /// /// /// [Parameter(ParameterSetName = TextParameterSet)] @@ -403,17 +434,18 @@ public SwitchParameter IgnoreWhiteSpace { return _ignoreWhiteSpace; } + set { _ignoreWhiteSpace = value; } } + private bool _ignoreWhiteSpace; #endregion TextMeasure ParameterSet #endregion Command Line Switches - /// /// Which parameter set the Cmdlet is in. /// @@ -421,8 +453,23 @@ private bool IsMeasuringGeneric { get { - return String.Compare(ParameterSetName, GenericParameterSet, StringComparison.Ordinal) == 0; + return string.Compare(ParameterSetName, GenericParameterSet, StringComparison.Ordinal) == 0; + } + } + + /// + /// Does the begin part of the cmdlet. + /// + protected override void BeginProcessing() + { + // Sets all other generic parameters to true to get all statistics. + if (_allStats) + { + _measureSum = _measureStandardDeviation = _measureAverage = _measureMax = _measureMin = true; } + + // finally call the base class. + base.BeginProcessing(); } /// @@ -459,10 +506,9 @@ private void AnalyzeObjectProperties(PSObject inObj) // First iterate over the user-specified list of // properties... - foreach (string p in Property) + foreach (var expression in Property) { - MshExpression expression = new MshExpression(p); - List resolvedNames = expression.ResolveNames(inObj); + List resolvedNames = expression.ResolveNames(inObj); if (resolvedNames == null || resolvedNames.Count == 0) { // Insert a blank entry so we can track @@ -479,7 +525,7 @@ private void AnalyzeObjectProperties(PSObject inObj) // Each property value can potentially refer // to multiple properties via globbing. Iterate over // the actual property names. - foreach (MshExpression resolvedName in resolvedNames) + foreach (PSPropertyExpression resolvedName in resolvedNames) { string propertyName = resolvedName.ToString(); // skip duplicated properties @@ -488,7 +534,7 @@ private void AnalyzeObjectProperties(PSObject inObj) continue; } - List tempExprRes = resolvedName.GetValues(inObj); + List tempExprRes = resolvedName.GetValues(inObj); if (tempExprRes == null || tempExprRes.Count == 0) { // Shouldn't happen - would somehow mean @@ -524,11 +570,11 @@ private void AnalyzeValue(string propertyName, object objValue) if (_measureCharacters || _measureWords || _measureLines) { - string strValue = (objValue == null) ? "" : objValue.ToString(); + string strValue = (objValue == null) ? string.Empty : objValue.ToString(); AnalyzeString(strValue, stat); } - if (_measureAverage || _measureSum) + if (_measureAverage || _measureSum || _measureStandardDeviation) { double numValue = 0.0; if (!LanguagePrimitives.TryConvertTo(objValue, out numValue)) @@ -546,7 +592,7 @@ private void AnalyzeValue(string propertyName, object objValue) AnalyzeNumber(numValue, stat); } - // Win8:343911 Measure-Object -MAX -MIN should work with ANYTHING that supports CompareTo + // Measure-Object -MAX -MIN should work with ANYTHING that supports CompareTo if (_measureMin) { stat.min = Compare(objValue, stat.min, true); @@ -598,26 +644,28 @@ private object Compare(object objValue, object statMinOrMaxValue, bool isMin) } /// - /// Class contains util static functions + /// Class contains util static functions. /// private static class TextCountUtilities { /// - /// count chars in inStr + /// Count chars in inStr. /// - /// string whose chars are counted - /// true to discount white space - /// number of chars in inStr + /// String whose chars are counted. + /// True to discount white space. + /// Number of chars in inStr. internal static int CountChar(string inStr, bool ignoreWhiteSpace) { - if (String.IsNullOrEmpty(inStr)) + if (string.IsNullOrEmpty(inStr)) { return 0; } + if (!ignoreWhiteSpace) { return inStr.Length; } + int len = 0; foreach (char c in inStr) { @@ -626,20 +674,22 @@ internal static int CountChar(string inStr, bool ignoreWhiteSpace) len++; } } + return len; } /// - /// count words in inStr + /// Count words in inStr. /// - /// string whose words are counted - /// number of words in inStr + /// String whose words are counted. + /// Number of words in inStr. internal static int CountWord(string inStr) { - if (String.IsNullOrEmpty(inStr)) + if (string.IsNullOrEmpty(inStr)) { return 0; } + int wordCount = 0; bool wasAWhiteSpace = true; foreach (char c in inStr) @@ -654,23 +704,26 @@ internal static int CountWord(string inStr) { wordCount++; } + wasAWhiteSpace = false; } } + return wordCount; } /// - /// count lines in inStr + /// Count lines in inStr. /// - /// string whose lines are counted - /// number of lines in inStr + /// String whose lines are counted. + /// Number of lines in inStr. internal static int CountLine(string inStr) { - if (String.IsNullOrEmpty(inStr)) + if (string.IsNullOrEmpty(inStr)) { return 0; } + int numberOfLines = 0; foreach (char c in inStr) { @@ -685,6 +738,7 @@ internal static int CountLine(string inStr) { numberOfLines++; } + return numberOfLines; } } @@ -711,12 +765,24 @@ private void AnalyzeString(string strValue, Statistics stat) /// private void AnalyzeNumber(double numValue, Statistics stat) { - if (_measureSum || _measureAverage) + if (_measureSum || _measureAverage || _measureStandardDeviation) + { + stat.sumPrevious = stat.sum; stat.sum += numValue; + } + + if (_measureStandardDeviation && stat.count > 1) + { + // Based off of iterative method of calculating variance on + // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm + double avgPrevious = stat.sumPrevious / (stat.count - 1); + stat.variance *= (stat.count - 2.0) / (stat.count - 1); + stat.variance += (numValue - avgPrevious) * (numValue - avgPrevious) / stat.count; + } } /// - /// WriteError when a property is not found + /// WriteError when a property is not found. /// /// The missing property. /// The error ID to write. @@ -793,6 +859,7 @@ private MeasureInfo CreateGenericMeasureInfo(Statistics stat, bool shouldUseGene { double? sum = null; double? average = null; + double? StandardDeviation = null; object max = null; object min = null; @@ -800,8 +867,14 @@ private MeasureInfo CreateGenericMeasureInfo(Statistics stat, bool shouldUseGene { if (_measureSum) sum = stat.sum; + if (_measureAverage && stat.count > 0) average = stat.sum / stat.count; + + if (_measureStandardDeviation) + { + StandardDeviation = Math.Sqrt(stat.variance); + } } if (_measureMax) @@ -838,11 +911,13 @@ private MeasureInfo CreateGenericMeasureInfo(Statistics stat, bool shouldUseGene gmi.Count = stat.count; gmi.Sum = sum; gmi.Average = average; - if (null != max) + gmi.StandardDeviation = StandardDeviation; + if (max != null) { gmi.Maximum = (double)max; } - if (null != min) + + if (min != null) { gmi.Minimum = (double)min; } @@ -882,15 +957,14 @@ private TextMeasureInfo CreateTextMeasureInfo(Statistics stat) } /// - /// The observed statistics keyed by property name. If - /// Property is not set, then the key used will be the - /// value of thisObject. + /// The observed statistics keyed by property name. + /// If Property is not set, then the key used will be the value of thisObject. /// private MeasureObjectDictionary _statistics = new MeasureObjectDictionary(); /// /// Whether or not a numeric conversion error occurred. - /// If true, then average/sum will not be output. + /// If true, then average/sum/standard deviation will not be output. /// private bool _nonNumericError = false; @@ -915,4 +989,3 @@ private TextMeasureInfo CreateTextMeasureInfo(Statistics stat) private const string thisObject = "$_"; } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/new-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-Object.cs similarity index 90% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/new-object.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-Object.cs index 89f7bccf9772..3f7173184ede 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/new-object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-Object.cs @@ -1,20 +1,20 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; -using System.Reflection; using System.Collections; -using System.Runtime.InteropServices; -using System.Threading; -using System.Management.Automation; -using System.Management.Automation.Security; -using System.Management.Automation.Internal; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Management.Automation; +using System.Management.Automation.Internal; using System.Management.Automation.Language; +using System.Management.Automation.Security; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; + using Dbg = System.Management.Automation.Diagnostics; #endregion @@ -29,38 +29,44 @@ public sealed class NewObjectCommand : PSCmdlet /// the number [Parameter(ParameterSetName = netSetName, Mandatory = true, Position = 0)] + [ValidateTrustedData] public string TypeName { get; set; } = null; #if !UNIX private Guid _comObjectClsId = Guid.Empty; - /// the ProgID of the Com object + /// + /// The ProgID of the Com object. + /// [Parameter(ParameterSetName = "Com", Mandatory = true, Position = 0)] + [ValidateTrustedData] public string ComObject { get; set; } = null; #endif /// - /// The parameters for the constructor + /// The parameters for the constructor. /// /// [Parameter(ParameterSetName = netSetName, Mandatory = false, Position = 1)] + [ValidateTrustedData] [Alias("Args")] public object[] ArgumentList { get; set; } = null; /// - /// True if we should have an error when Com objects will use an interop assembly + /// True if we should have an error when Com objects will use an interop assembly. /// [Parameter(ParameterSetName = "Com")] public SwitchParameter Strict { get; set; } // Updated from Hashtable to IDictionary to support the work around ordered hashtables. /// - /// gets the properties to be set. + /// Gets the properties to be set. /// [Parameter] + [ValidateTrustedData] [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public IDictionary Property { get; set; } - # endregion parameters + #endregion parameters #region private private object CallConstructor(Type type, ConstructorInfo[] constructors, object[] args) @@ -101,7 +107,6 @@ private void CreateMemberSetValueError(SetValueException e) new ErrorRecord(ex, "SetValueException", ErrorCategory.InvalidData, null)); } - private static string ParameterSet2ResourceString(string parameterSet) { if (parameterSet.Equals(netSetName, StringComparison.OrdinalIgnoreCase)) @@ -143,27 +148,43 @@ protected override void BeginProcessing() if (e.InnerException != null && e.InnerException is TypeResolver.AmbiguousTypeException) { ThrowTerminatingError( - new ErrorRecord( - e, - "AmbiguousTypeReference", - ErrorCategory.InvalidType, null)); + new ErrorRecord( + e, + "AmbiguousTypeReference", + ErrorCategory.InvalidType, + targetObject: null)); } mshArgE = PSTraceSource.NewArgumentException( - "TypeName", - NewObjectStrings.TypeNotFound, - TypeName); + "TypeName", + NewObjectStrings.TypeNotFound, + TypeName); + ThrowTerminatingError( new ErrorRecord( mshArgE, "TypeNotFound", - ErrorCategory.InvalidType, null)); + ErrorCategory.InvalidType, + targetObject: null)); } + throw e; } Diagnostics.Assert(type != null, "LanguagePrimitives.TryConvertTo failed but returned true"); + if (type.IsByRefLike) + { + ThrowTerminatingError( + new ErrorRecord( + PSTraceSource.NewInvalidOperationException( + NewObjectStrings.CannotInstantiateBoxedByRefLikeType, + type), + nameof(NewObjectStrings.CannotInstantiateBoxedByRefLikeType), + ErrorCategory.InvalidOperation, + targetObject: null)); + } + if (Context.LanguageMode == PSLanguageMode.ConstrainedLanguage) { if (!CoreTypes.Contains(type)) @@ -174,7 +195,7 @@ protected override void BeginProcessing() } } - //WinRT does not support creating instances of attribute & delegate WinRT types. + // WinRT does not support creating instances of attribute & delegate WinRT types. if (WinRTHelper.IsWinRTType(type) && ((typeof(System.Attribute)).IsAssignableFrom(type) || (typeof(System.Delegate)).IsAssignableFrom(type))) { ThrowTerminatingError(new ErrorRecord(new InvalidOperationException(NewObjectStrings.CannotInstantiateWinRTType), @@ -183,7 +204,7 @@ protected override void BeginProcessing() if (ArgumentList == null || ArgumentList.Length == 0) { - ConstructorInfo ci = type.GetConstructor(PSTypeExtensions.EmptyTypes); + ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes); if (ci != null && ci.IsPublic) { _newObject = CallConstructor(type, new ConstructorInfo[] { ci }, new object[] { }); @@ -192,6 +213,7 @@ protected override void BeginProcessing() // The method invocation is disabled for "Hashtable to Object conversion" (Win8:649519), but we need to keep it enabled for New-Object for compatibility to PSv2 _newObject = LanguagePrimitives.SetObjectProperties(_newObject, Property, type, CreateMemberNotFoundError, CreateMemberSetValueError, enableMethodCall: true); } + WriteObject(_newObject); return; } @@ -216,6 +238,7 @@ protected override void BeginProcessing() "ConstructorCalledThrowException", ErrorCategory.InvalidOperation, null)); } + WriteObject(_newObject); return; } @@ -232,6 +255,7 @@ protected override void BeginProcessing() // Win8:649519 _newObject = LanguagePrimitives.SetObjectProperties(_newObject, Property, type, CreateMemberNotFoundError, CreateMemberSetValueError, enableMethodCall: true); } + WriteObject(_newObject); return; } @@ -289,15 +313,17 @@ protected override void BeginProcessing() ErrorCategory.InvalidArgument, comObject)); } } + if (comObject != null && Property != null) { // Win8:649519 comObject = LanguagePrimitives.SetObjectProperties(comObject, Property, type, CreateMemberNotFoundError, CreateMemberSetValueError, enableMethodCall: true); } + WriteObject(comObject); } #endif - }//protected override void BeginProcessing() + } #endregion Overrides @@ -369,10 +395,9 @@ private object SafeCreateInstance(Type t, object[] args) return result; } -#if !CORECLR private class ComCreateInfo { - public Object objectCreated; + public object objectCreated; public bool success; public Exception e; } @@ -399,6 +424,7 @@ private void STAComCreateThreadProc(Object createstruct) info.success = false; return; } + info.objectCreated = SafeCreateInstance(type, ArgumentList); info.success = true; } @@ -408,7 +434,6 @@ private void STAComCreateThreadProc(Object createstruct) info.success = false; } } -#endif private object CreateComObject() { @@ -424,20 +449,14 @@ private object CreateComObject() ThrowTerminatingError( new ErrorRecord(mshArgE, "CannotLoadComObjectType", ErrorCategory.InvalidType, null)); } + return SafeCreateInstance(type, ArgumentList); } catch (COMException e) { - //Check Error Code to see if Error is because of Com apartment Mismatch. + // Check Error Code to see if Error is because of Com apartment Mismatch. if (e.HResult == RPC_E_CHANGED_MODE) { -#if CORECLR - ThrowTerminatingError( - new ErrorRecord( - new COMException(StringUtil.Format(NewObjectStrings.ApartmentNotSupported, e.Message), e), - "NoCOMClassIdentified", - ErrorCategory.ResourceUnavailable, null)); -#else createInfo = new ComCreateInfo(); Thread thread = new Thread(new ParameterizedThreadStart(STAComCreateThreadProc)); @@ -454,7 +473,6 @@ private object CreateComObject() ThrowTerminatingError( new ErrorRecord(createInfo.e, "NoCOMClassIdentified", ErrorCategory.ResourceUnavailable, null)); -#endif } else { @@ -475,10 +493,10 @@ private object CreateComObject() // HResult code '-2147417850' - Cannot change thread mode after it is set. private const int RPC_E_CHANGED_MODE = unchecked((int)0x80010106); private const string netSetName = "Net"; - }//internal class NewObjectCommand: PSCmdlet + } /// - /// Native methods for dealing with COM objects + /// Native methods for dealing with COM objects. /// internal class NewObjectNativeMethods { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-PSBreakpoint.cs new file mode 100644 index 000000000000..b5837cc0da3c --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-PSBreakpoint.cs @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// This class implements New-PSBreakpoint command. + /// + [Experimental("Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints", ExperimentAction.Show)] + [Cmdlet(VerbsCommon.New, "PSBreakpoint", DefaultParameterSetName = LineParameterSetName, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113449")] + [OutputType(typeof(VariableBreakpoint), typeof(CommandBreakpoint), typeof(LineBreakpoint))] + public class NewPSBreakpointCommand : PSBreakpointCreationBase + { + /// + /// Create a new breakpoint. + /// + protected override void ProcessRecord() + { + // If there is a script, resolve its path + Collection scripts = ResolveScriptPaths(); + + // If it is a command breakpoint... + if (ParameterSetName.Equals(CommandParameterSetName, StringComparison.OrdinalIgnoreCase)) + { + for (int i = 0; i < Command.Length; i++) + { + if (scripts.Count > 0) + { + foreach (string path in scripts) + { + WildcardPattern pattern = WildcardPattern.Get(Command[i], WildcardOptions.Compiled | WildcardOptions.IgnoreCase); + WriteObject(new CommandBreakpoint(path, pattern, Command[i], Action)); + } + } + else + { + WildcardPattern pattern = WildcardPattern.Get(Command[i], WildcardOptions.Compiled | WildcardOptions.IgnoreCase); + WriteObject(new CommandBreakpoint(null, pattern, Command[i], Action)); + } + } + } + else if (ParameterSetName.Equals(VariableParameterSetName, StringComparison.OrdinalIgnoreCase)) + { + // If it is a variable breakpoint... + for (int i = 0; i < Variable.Length; i++) + { + if (scripts.Count > 0) + { + foreach (string path in scripts) + { + WriteObject(new VariableBreakpoint(path, Variable[i], Mode, Action)); + } + } + else + { + WriteObject(new VariableBreakpoint(null, Variable[i], Mode, Action)); + } + } + } + else + { + // Else it is the default parameter set (Line breakpoint)... + Debug.Assert(ParameterSetName.Equals(LineParameterSetName, StringComparison.OrdinalIgnoreCase)); + + for (int i = 0; i < Line.Length; i++) + { + if (Line[i] < 1) + { + WriteError( + new ErrorRecord( + new ArgumentException(Debugger.LineLessThanOne), + "NewPSBreakpoint:LineLessThanOne", + ErrorCategory.InvalidArgument, + null)); + + continue; + } + + foreach (string path in scripts) + { + if (Column != 0) + { + WriteObject(new LineBreakpoint(path, Line[i], Column, Action)); + } + else + { + WriteObject(new LineBreakpoint(path, Line[i], Action)); + } + } + } + } + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewAliasCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewAliasCommand.cs index 64f3d2934fc4..f810f555d972 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewAliasCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewAliasCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -9,10 +8,10 @@ namespace Microsoft.PowerShell.Commands { /// - /// The implementation of the "new-alias" cmdlet + /// The implementation of the "new-alias" cmdlet. /// - /// - [Cmdlet(VerbsCommon.New, "Alias", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113352")] + [Cmdlet(VerbsCommon.New, "Alias", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low, + HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113352")] [OutputType(typeof(AliasInfo))] public class NewAliasCommand : WriteAliasCommandBase { @@ -21,7 +20,6 @@ public class NewAliasCommand : WriteAliasCommandBase /// /// The main processing loop of the command. /// - /// protected override void ProcessRecord() { // If not force, then see if the alias already exists @@ -29,7 +27,7 @@ protected override void ProcessRecord() if (!Force) { AliasInfo existingAlias = null; - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { existingAlias = SessionState.Internal.GetAlias(Name); } @@ -38,7 +36,6 @@ protected override void ProcessRecord() existingAlias = SessionState.Internal.GetAliasAtScope(Name, Scope); } - if (existingAlias != null) { // Throw if alias exists and is private... @@ -88,7 +85,7 @@ protected override void ProcessRecord() try { - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { result = SessionState.Internal.SetAliasItem(newAlias, Force, MyInvocation.CommandOrigin); } @@ -129,8 +126,7 @@ protected override void ProcessRecord() WriteObject(result); } } - } // ProcessRecord + } #endregion Command code - } // class NewAliasCommand -}//Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/neweventcommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewEventCommand.cs similarity index 87% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/neweventcommand.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewEventCommand.cs index 29ac9dfa987b..3b6b0d6f765f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/neweventcommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewEventCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Diagnostics.CodeAnalysis; @@ -18,7 +17,7 @@ public class NewEventCommand : PSCmdlet #region parameters /// - /// Adds an event to the event queue + /// Adds an event to the event queue. /// [Parameter(Position = 0, Mandatory = true)] public string SourceIdentifier @@ -27,15 +26,17 @@ public string SourceIdentifier { return _sourceIdentifier; } + set { _sourceIdentifier = value; } } + private string _sourceIdentifier = null; /// - /// Data relating to this event + /// Data relating to this event. /// [Parameter(Position = 1)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] @@ -45,15 +46,17 @@ public PSObject Sender { return _sender; } + set { _sender = value; } } + private PSObject _sender = null; /// - /// Data relating to this event + /// Data relating to this event. /// [Parameter(Position = 2)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] @@ -63,6 +66,7 @@ public PSObject[] EventArguments { return _eventArguments; } + set { if (_eventArguments != null) @@ -71,10 +75,11 @@ public PSObject[] EventArguments } } } - private PSObject[] _eventArguments = new PSObject[0]; + + private PSObject[] _eventArguments = Array.Empty(); /// - /// Data relating to this event + /// Data relating to this event. /// [Parameter(Position = 3)] public PSObject MessageData @@ -83,18 +88,19 @@ public PSObject MessageData { return _messageData; } + set { _messageData = value; } } + private PSObject _messageData = null; #endregion parameters - /// - /// Add the event to the event queue + /// Add the event to the event queue. /// protected override void EndProcessing() { @@ -114,11 +120,11 @@ protected override void EndProcessing() } } - Object messageSender = null; + object messageSender = null; if (_sender != null) { messageSender = _sender.BaseObject; } // And then generate the event WriteObject(Events.GenerateEvent(_sourceIdentifier, messageSender, baseEventArgs, _messageData, true, false)); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs index b4a80fd63fc0..289fba78039c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs @@ -1,7 +1,5 @@ - -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -9,14 +7,14 @@ namespace Microsoft.PowerShell.Commands { /// - /// The implementation of the "new-guid" cmdlet + /// The implementation of the "new-guid" cmdlet. /// [Cmdlet(VerbsCommon.New, "Guid", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526920")] [OutputType(typeof(Guid))] public class NewGuidCommand : Cmdlet { /// - /// returns a guid + /// Returns a guid. /// protected override void EndProcessing() { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTemporaryFileCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTemporaryFileCommand.cs index 2ea913390379..47925b8b8157 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTemporaryFileCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTemporaryFileCommand.cs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.IO; @@ -6,35 +8,37 @@ namespace Microsoft.PowerShell.Commands { /// - /// The implementation of the "New-TemporaryFile" cmdlet + /// The implementation of the "New-TemporaryFile" cmdlet. /// - [Cmdlet(VerbsCommon.New, "TemporaryFile", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526726")] + [Cmdlet(VerbsCommon.New, "TemporaryFile", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low, + HelpUri = "https://go.microsoft.com/fwlink/?LinkId=821836")] [OutputType(typeof(System.IO.FileInfo))] public class NewTemporaryFileCommand : Cmdlet { /// - /// returns a TemporaryFile + /// Returns a TemporaryFile. /// protected override void EndProcessing() { string filePath = null; - string tempPath = System.Environment.GetEnvironmentVariable("TEMP"); + string tempPath = Path.GetTempPath(); if (ShouldProcess(tempPath)) { try { filePath = Path.GetTempFileName(); } - catch (Exception e) + catch (IOException ioException) { - WriteError( + ThrowTerminatingError( new ErrorRecord( - e, + ioException, "NewTemporaryFileWriteError", ErrorCategory.WriteError, tempPath)); return; } + if (!string.IsNullOrEmpty(filePath)) { FileInfo file = new FileInfo(filePath); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTimeSpanCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTimeSpanCommand.cs index 71504e063b47..1cbbce4e286e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTimeSpanCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewTimeSpanCommand.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// implementation for the new-timespan command + /// Implementation for the new-timespan command. /// [Cmdlet(VerbsCommon.New, "TimeSpan", DefaultParameterSetName = "Date", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113360", RemotingCapability = RemotingCapability.None)] @@ -20,7 +20,7 @@ public sealed class NewTimeSpanCommand : PSCmdlet /// /// This parameter indicates the date the time span begins; - /// it is used if two times are being compared + /// it is used if two times are being compared. /// [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "Date")] [Alias("LastWriteTime")] @@ -30,16 +30,17 @@ public DateTime Start { return _start; } + set { _start = value; _startSpecified = true; } } + private DateTime _start; private bool _startSpecified; - /// /// This parameter indicates the end of a time span. It is used if two /// times are being compared. If one of the times is not specified, @@ -52,39 +53,37 @@ public DateTime End { return _end; } + set { _end = value; _endSpecified = true; } } + private DateTime _end; private bool _endSpecified = false; - /// - /// Allows the user to override the day + /// Allows the user to override the day. /// [Parameter(ParameterSetName = "Time")] public int Days { get; set; } = 0; - /// - /// Allows the user to override the hour + /// Allows the user to override the hour. /// [Parameter(ParameterSetName = "Time")] public int Hours { get; set; } = 0; - /// - /// Allows the user to override the minute + /// Allows the user to override the minute. /// [Parameter(ParameterSetName = "Time")] public int Minutes { get; set; } = 0; - /// - /// Allows the user to override the second + /// Allows the user to override the second. /// [Parameter(ParameterSetName = "Time")] public int Seconds { get; set; } = 0; @@ -94,7 +93,7 @@ public DateTime End #region methods /// - /// Calculate and write out the appropriate timespan + /// Calculate and write out the appropriate timespan. /// protected override void ProcessRecord() { @@ -110,6 +109,7 @@ protected override void ProcessRecord() { startTime = Start; } + if (_endSpecified) { endTime = End; @@ -128,10 +128,7 @@ protected override void ProcessRecord() } WriteObject(result); - } // EndProcessing - + } #endregion - } // NewTimeSpanCommand -} // namespace Microsoft.PowerShell.Commands - - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs index 77df4fa926ae..3a9a42c4b2ed 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs @@ -1,13 +1,12 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives using System; using System.Collections; -using System.Management.Automation; using System.Globalization; +using System.Management.Automation; #endregion @@ -17,8 +16,8 @@ namespace Microsoft.PowerShell.Commands /// /// Keeps the property value of inputObject. Because the value of a non-existing property is null, - /// isExistingProperty is needed to distinguish whether a property exists and its value is null or - /// the property does not exist at all. + /// isExistingProperty is needed to distinguish whether a property exists and its value is null or + /// the property does not exist at all. /// internal class ObjectCommandPropertyValue { @@ -43,7 +42,6 @@ internal ObjectCommandPropertyValue(object propVal, bool isCaseSensitive, Cultur this.cultureInfo = cultureInfo; } - internal object PropertyValue { get; } internal bool IsExistingProperty { get; } @@ -81,31 +79,31 @@ public override bool Equals(Object inputObject) { ObjectCommandPropertyValue objectCommandPropertyValueObject = inputObject as ObjectCommandPropertyValue; if (objectCommandPropertyValueObject == null) + { return false; + } object baseObject = PSObject.Base(PropertyValue); object inComingbaseObjectPropertyValue = PSObject.Base(objectCommandPropertyValueObject.PropertyValue); - IComparable baseObjectComparable = baseObject as IComparable; - - if (baseObjectComparable != null) + if (baseObject is IComparable) { - return (LanguagePrimitives.Compare(baseObject, inComingbaseObjectPropertyValue, CaseSensitive, Culture) == 0); + var success = LanguagePrimitives.TryCompare(baseObject, inComingbaseObjectPropertyValue, CaseSensitive, Culture, out int result); + return success && result == 0; } - else + + if (baseObject == null && inComingbaseObjectPropertyValue == null) { - if (baseObject == null && inComingbaseObjectPropertyValue == null) - { - return true; - } - if (baseObject != null && inComingbaseObjectPropertyValue != null) - { - return baseObject.ToString().Equals(inComingbaseObjectPropertyValue.ToString(), StringComparison.OrdinalIgnoreCase); - } + return true; + } - // One of the property values being compared is null. - return false; + if (baseObject != null && inComingbaseObjectPropertyValue != null) + { + return baseObject.ToString().Equals(inComingbaseObjectPropertyValue.ToString(), StringComparison.OrdinalIgnoreCase); } + + // One of the property values being compared is null. + return false; } /// @@ -115,12 +113,17 @@ public override bool Equals(Object inputObject) public override int GetHashCode() { if (PropertyValue == null) + { return 0; + } object baseObject = PSObject.Base(PropertyValue); - IComparable baseObjectComparable = baseObject as IComparable; + if (baseObject == null) + { + return 0; + } - if (baseObjectComparable != null) + if (baseObject is IComparable) { return baseObject.GetHashCode(); } @@ -132,7 +135,7 @@ public override int GetHashCode() } /// - /// + /// ObjectCommandComparer class. /// internal class ObjectCommandComparer : IComparer { @@ -154,7 +157,6 @@ private static bool IsValueNull(object value) return (val == null); } - internal int Compare(ObjectCommandPropertyValue first, ObjectCommandPropertyValue second) { if (first.IsExistingProperty && second.IsExistingProperty) @@ -173,57 +175,50 @@ internal int Compare(ObjectCommandPropertyValue first, ObjectCommandPropertyValu { return 1; } - //both are nonexisting + // both are nonexisting return 0; } /// - /// Main method that will compare first and second by - /// their keys considering case and order + /// Main method that will compare first and second by their keys considering case and order. /// /// - /// first object to extract value + /// First object to extract value. /// /// - /// second object to extract value + /// Second object to extract value. /// /// - /// 0 if they are the same, less than 0 if first is smaller, more than 0 if first is greater + /// 0 if they are the same, less than 0 if first is smaller, more than 0 if first is greater. /// public int Compare(object first, object second) { // This method will never throw exceptions, two null // objects are considered the same - if (IsValueNull(first) && IsValueNull(second)) return 0; - + if (IsValueNull(first) && IsValueNull(second)) + { + return 0; + } - PSObject firstMsh = first as PSObject; - if (firstMsh != null) + if (first is PSObject firstMsh) { first = firstMsh.BaseObject; } - PSObject secondMsh = second as PSObject; - if (secondMsh != null) + if (second is PSObject secondMsh) { second = secondMsh.BaseObject; } - try + if (LanguagePrimitives.TryCompare(first, second, !_caseSensitive, _cultureInfo, out int result)) { - return LanguagePrimitives.Compare(first, second, !_caseSensitive, _cultureInfo) * (_ascendingOrder ? 1 : -1); - } - catch (InvalidCastException) - { - } - catch (ArgumentException) - { - // Note that this will occur if the objects do not support - // IComparable. We fall back to comparing as strings. + return result * (_ascendingOrder ? 1 : -1); } + // Note that this will occur if the objects do not support + // IComparable. We fall back to comparing as strings. + // being here means the first object doesn't support ICompare - // or an Exception was raised win Compare string firstString = PSObject.AsPSObject(first).ToString(); string secondString = PSObject.AsPSObject(second).ToString(); @@ -236,7 +231,5 @@ public int Compare(object first, object second) private bool _caseSensitive = false; } - #endregion } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs index 6b726c1deacf..a7258cb1bb08 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs @@ -1,20 +1,20 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Collections.Generic; using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Management.Automation; using System.Management.Automation.Internal; -using System.Globalization; + using Microsoft.PowerShell.Commands.Internal.Format; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.PowerShell.Commands { /// - /// definitions for hash table keys + /// Definitions for hash table keys. /// internal static class SortObjectParameterDefinitionKeys { @@ -45,13 +45,12 @@ protected override void SetEntries() } /// - /// Base Cmdlet for cmdlets which deal with raw objects + /// Base Cmdlet for cmdlets which deal with raw objects. /// public class ObjectCmdletBase : PSCmdlet { #region Parameters /// - /// /// /// [Parameter] @@ -59,6 +58,7 @@ public class ObjectCmdletBase : PSCmdlet public string Culture { get { return _cultureInfo != null ? _cultureInfo.ToString() : null; } + set { if (string.IsNullOrEmpty(value)) @@ -85,21 +85,24 @@ public string Culture _cultureInfo = new CultureInfo(cultureNumber); return; } + _cultureInfo = new CultureInfo(value); } } + internal CultureInfo _cultureInfo = null; /// - /// /// /// [Parameter] public SwitchParameter CaseSensitive { get { return _caseSensitive; } + set { _caseSensitive = value; } } + private bool _caseSensitive; #endregion Parameters } @@ -112,7 +115,6 @@ public abstract class ObjectBase : ObjectCmdletBase #region Parameters /// - /// /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { set; get; } = AutomationNull.Value; @@ -140,14 +142,16 @@ public class OrderObjectBase : ObjectBase internal SwitchParameter DescendingOrder { get { return !_ascending; } + set { _ascending = !value; } } + private bool _ascending = true; internal List InputObjects { get; } = new List(); /// - /// CultureInfo converted from the Culture Cmdlet parameter + /// CultureInfo converted from the Culture Cmdlet parameter. /// internal CultureInfo ConvertedCulture { @@ -160,9 +164,7 @@ internal CultureInfo ConvertedCulture #endregion Internal Properties /// - /// - /// Simply accumulates the incoming objects - /// + /// Simply accumulates the incoming objects. /// protected override void ProcessRecord() { @@ -178,7 +180,7 @@ internal sealed class OrderByProperty #region Internal properties /// - /// a logical matrix where each row is an input object and its property values specified by Properties + /// A logical matrix where each row is an input object and its property values specified by Properties. /// internal List OrderMatrix { get; } = null; @@ -200,7 +202,7 @@ internal List MshParameterList // a string array and allows wildcard. // Yes, the Cmdlet is needed. It's used to get the TerminatingErrorContext, WriteError and WriteDebug. - #region process MshExpression and MshParameter + #region process PSPropertyExpression and MshParameter private static void ProcessExpressionParameter( List inputObjects, @@ -219,6 +221,7 @@ internal List MshParameterList { expr = GetDefaultKeyPropertySet(inputObjects[0]); } + if (expr != null) { List unexpandedParameterList = processor.ProcessParameters(expr, invocationContext); @@ -246,7 +249,7 @@ internal List MshParameterList foreach (MshParameter unexpandedParameter in _unexpandedParameterList) { - MshExpression mshExpression = (MshExpression)unexpandedParameter.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey); + PSPropertyExpression mshExpression = (PSPropertyExpression)unexpandedParameter.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey); if (!mshExpression.HasWildCardCharacters) // this special cases 1) script blocks and 2) wildcard-less strings { _mshParameterList.Add(unexpandedParameter); @@ -275,14 +278,14 @@ private static List ExpandExpressions(List inputObjects, { foreach (MshParameter unexpandedParameter in unexpandedParameterList) { - MshExpression ex = (MshExpression)unexpandedParameter.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey); + PSPropertyExpression ex = (PSPropertyExpression)unexpandedParameter.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey); if (!ex.HasWildCardCharacters) // this special cases 1) script blocks and 2) wildcard-less strings { expandedParameterList.Add(unexpandedParameter); } else { - SortedDictionary expandedPropertyNames = new SortedDictionary(StringComparer.OrdinalIgnoreCase); + SortedDictionary expandedPropertyNames = new SortedDictionary(StringComparer.OrdinalIgnoreCase); if (inputObjects != null) { foreach (object inputObject in inputObjects) @@ -292,14 +295,14 @@ private static List ExpandExpressions(List inputObjects, continue; } - foreach (MshExpression resolvedName in ex.ResolveNames(PSObject.AsPSObject(inputObject))) + foreach (PSPropertyExpression resolvedName in ex.ResolveNames(PSObject.AsPSObject(inputObject))) { expandedPropertyNames[resolvedName.ToString()] = resolvedName; } } } - foreach (MshExpression expandedExpression in expandedPropertyNames.Values) + foreach (PSPropertyExpression expandedExpression in expandedPropertyNames.Values) { MshParameter expandedParameter = new MshParameter(); expandedParameter.hash = (Hashtable)unexpandedParameter.hash.Clone(); @@ -322,20 +325,20 @@ private static void ExpandExpressions(PSObject inputObject, List U { foreach (MshParameter unexpandedParameter in UnexpandedParametersWithWildCardPattern) { - MshExpression ex = (MshExpression)unexpandedParameter.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey); + PSPropertyExpression ex = (PSPropertyExpression)unexpandedParameter.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey); - SortedDictionary expandedPropertyNames = new SortedDictionary(StringComparer.OrdinalIgnoreCase); + SortedDictionary expandedPropertyNames = new SortedDictionary(StringComparer.OrdinalIgnoreCase); if (inputObject == null) { continue; } - foreach (MshExpression resolvedName in ex.ResolveNames(PSObject.AsPSObject(inputObject))) + foreach (PSPropertyExpression resolvedName in ex.ResolveNames(PSObject.AsPSObject(inputObject))) { expandedPropertyNames[resolvedName.ToString()] = resolvedName; } - foreach (MshExpression expandedExpression in expandedPropertyNames.Values) + foreach (PSPropertyExpression expandedExpression in expandedPropertyNames.Values) { MshParameter expandedParameter = new MshParameter(); expandedParameter.hash = (Hashtable)unexpandedParameter.hash.Clone(); @@ -354,18 +357,20 @@ internal static string[] GetDefaultKeyPropertySet(PSObject mshObj) { return null; } + PSPropertySet defaultKeys = standardNames.Members["DefaultKeyPropertySet"] as PSPropertySet; if (defaultKeys == null) { return null; } + string[] props = new string[defaultKeys.ReferencedPropertyNames.Count]; defaultKeys.ReferencedPropertyNames.CopyTo(props, 0); return props; } - #endregion process MshExpression and MshParameter + #endregion process PSPropertyExpression and MshParameter internal static List CreateOrderMatrix( PSCmdlet cmdlet, @@ -387,10 +392,12 @@ List mshParameterList { cmdlet.WriteError(err); } + foreach (string debugMsg in propertyNotFoundMsgs) { cmdlet.WriteDebug(debugMsg); } + orderMatrixToCreate.Add(result); } @@ -413,10 +420,11 @@ private static bool isOrderEntryKeyDefined(object orderEntryKey) { return null; } - Nullable[] ascendingOverrides = null; + + bool?[] ascendingOverrides = null; if (mshParameterList != null && mshParameterList.Count != 0) { - ascendingOverrides = new Nullable[mshParameterList.Count]; + ascendingOverrides = new bool?[mshParameterList.Count]; for (int k = 0; k < ascendingOverrides.Length; k++) { object ascendingVal = mshParameterList[k].GetEntry( @@ -447,6 +455,7 @@ private static bool isOrderEntryKeyDefined(object orderEntryKey) } } } + OrderByPropertyComparer comparer = OrderByPropertyComparer.CreateComparer(orderMatrix, ascending, ascendingOverrides, cultureInfo, caseSensitive); @@ -482,7 +491,7 @@ internal OrderByProperty() /// /// Utility function used to create OrderByPropertyEntry for the supplied input object. /// - /// PSCmdlet + /// PSCmdlet. /// Input Object. /// Indicates if the Property value comparisons need to be case sensitive or not. /// Culture Info that needs to be used for comparison. @@ -508,6 +517,7 @@ internal OrderByProperty() { cmdlet.WriteError(err); } + foreach (string debugMsg in propertyNotFoundMsgs) { cmdlet.WriteDebug(debugMsg); @@ -570,10 +580,10 @@ internal static class OrderByPropertyEntryEvaluationHelper ref bool comparable) { // NOTE: we assume globbing was not allowed in input - MshExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as MshExpression; + PSPropertyExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as PSPropertyExpression; // get the values, but do not expand aliases - List expressionResults = ex.GetValues(inputObject, false, true); + List expressionResults = ex.GetValues(inputObject, false, true); if (expressionResults.Count == 0) { @@ -583,9 +593,10 @@ internal static class OrderByPropertyEntryEvaluationHelper propertyNotFoundMsg = StringUtil.Format(SortObjectStrings.PropertyNotFound, ex.ToString()); return; } + propertyNotFoundMsg = null; // we obtained some results, enter them into the list - foreach (MshExpressionResult r in expressionResults) + foreach (PSPropertyExpressionResult r in expressionResults) { if (r.Exception == null) { @@ -601,13 +612,14 @@ internal static class OrderByPropertyEntryEvaluationHelper errors.Add(errorRecord); orderValues.Add(ObjectCommandPropertyValue.ExistingNullProperty); } + comparable = true; } } } /// - /// This is the row of the OrderMatrix + /// This is the row of the OrderMatrix. /// internal sealed class OrderByPropertyEntry { @@ -651,7 +663,7 @@ public int Compare(OrderByPropertyEntry firstEntry, OrderByPropertyEntry secondE return order; } - internal static OrderByPropertyComparer CreateComparer(List orderMatrix, bool ascendingFlag, Nullable[] ascendingOverrides, CultureInfo cultureInfo, bool caseSensitive) + internal static OrderByPropertyComparer CreateComparer(List orderMatrix, bool ascendingFlag, bool?[] ascendingOverrides, CultureInfo cultureInfo, bool caseSensitive) { if (orderMatrix.Count == 0) return null; @@ -664,6 +676,7 @@ internal static OrderByPropertyComparer CreateComparer(List maxEntries) maxEntries = entry.orderValues.Count; } + if (maxEntries == 0) return null; @@ -702,6 +715,7 @@ public int Compare(OrderByPropertyEntry lhs, OrderByPropertyEntry rhs) { return lhs.comparable.CompareTo(rhs.comparable) * -1; } + int result = _orderByPropertyComparer.Compare(lhs, rhs); // When items are identical according to the internal comparison, compare by index // to preserve the original order @@ -713,7 +727,6 @@ public int Compare(OrderByPropertyEntry lhs, OrderByPropertyEntry rhs) return result; } - OrderByPropertyComparer _orderByPropertyComparer = null; + private OrderByPropertyComparer _orderByPropertyComparer = null; } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/PSBreakpointCreationBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/PSBreakpointCreationBase.cs new file mode 100644 index 000000000000..43e3e93839d6 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/PSBreakpointCreationBase.cs @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.ObjectModel; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// Base class for Set/New-PSBreakpoint. + /// + public class PSBreakpointCreationBase : PSCmdlet + { + internal const string CommandParameterSetName = "Command"; + internal const string LineParameterSetName = "Line"; + internal const string VariableParameterSetName = "Variable"; + + #region parameters + + /// + /// The action to take when hitting this breakpoint. + /// + [Parameter(ParameterSetName = CommandParameterSetName)] + [Parameter(ParameterSetName = LineParameterSetName)] + [Parameter(ParameterSetName = VariableParameterSetName)] + public ScriptBlock Action { get; set; } + + /// + /// The column to set the breakpoint on. + /// + [Parameter(Position = 2, ParameterSetName = LineParameterSetName)] + [ValidateRange(1, int.MaxValue)] + public int Column { get; set; } + + /// + /// The command(s) to set the breakpoint on. + /// + [Alias("C")] + [Parameter(ParameterSetName = CommandParameterSetName, Mandatory = true)] + public string[] Command { get; set; } + + /// + /// The line to set the breakpoint on. + /// + [Parameter(Position = 1, ParameterSetName = LineParameterSetName, Mandatory = true)] + public int[] Line { get; set; } + + /// + /// The script to set the breakpoint on. + /// + [Parameter(ParameterSetName = CommandParameterSetName, Position = 0)] + [Parameter(ParameterSetName = LineParameterSetName, Mandatory = true, Position = 0)] + [Parameter(ParameterSetName = VariableParameterSetName, Position = 0)] + [ValidateNotNull] + public string[] Script { get; set; } + + /// + /// The variables to set the breakpoint(s) on. + /// + [Alias("V")] + [Parameter(ParameterSetName = VariableParameterSetName, Mandatory = true)] + public string[] Variable { get; set; } + + /// + /// The access type for variable breakpoints to break on. + /// + [Parameter(ParameterSetName = VariableParameterSetName)] + public VariableAccessMode Mode { get; set; } = VariableAccessMode.Write; + + #endregion parameters + + internal Collection ResolveScriptPaths() + { + Collection scripts = new Collection(); + + if (Script != null) + { + foreach (string script in Script) + { + Collection scriptPaths = SessionState.Path.GetResolvedPSPathFromPSPath(script); + + for (int i = 0; i < scriptPaths.Count; i++) + { + string providerPath = scriptPaths[i].ProviderPath; + + if (!File.Exists(providerPath)) + { + WriteError( + new ErrorRecord( + new ArgumentException(StringUtil.Format(Debugger.FileDoesNotExist, providerPath)), + "NewPSBreakpoint:FileDoesNotExist", + ErrorCategory.InvalidArgument, + null)); + + continue; + } + + string extension = Path.GetExtension(providerPath); + + if (!extension.Equals(".ps1", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".psm1", StringComparison.OrdinalIgnoreCase)) + { + WriteError( + new ErrorRecord( + new ArgumentException(StringUtil.Format(Debugger.WrongExtension, providerPath)), + "NewPSBreakpoint:WrongExtension", + ErrorCategory.InvalidArgument, + null)); + continue; + } + + scripts.Add(Path.GetFullPath(providerPath)); + } + } + } + + return scripts; + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ReadConsoleCmdlet.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ReadConsoleCmdlet.cs index f37c274aadfa..49af92fffd41 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ReadConsoleCmdlet.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ReadConsoleCmdlet.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -15,19 +14,15 @@ namespace Microsoft.PowerShell.Commands { /// - /// /// Retrieves input from the host virtual console and writes it to the pipeline output. - /// /// [Cmdlet(VerbsCommunications.Read, "Host", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113371")] - [OutputType(typeof(String), typeof(SecureString))] + [OutputType(typeof(string), typeof(SecureString))] public sealed class ReadHostCommand : PSCmdlet { /// - /// /// Constructs a new instance. - /// /// public @@ -39,9 +34,7 @@ public sealed class ReadHostCommand : PSCmdlet #region Parameters /// - /// /// The objects to display on the host before collecting input. - /// /// [Parameter(Position = 0, ValueFromRemainingArguments = true)] @@ -62,9 +55,7 @@ public sealed class ReadHostCommand : PSCmdlet } /// - /// /// Set to no echo the input as is is typed. - /// /// [Parameter] @@ -84,14 +75,10 @@ public sealed class ReadHostCommand : PSCmdlet } #endregion Parameters - #region Cmdlet Overrides /// - /// - /// Write the prompt, then collect a line of input from the host, then - /// output it to the output stream. - /// + /// Write the prompt, then collect a line of input from the host, then output it to the output stream. /// protected override void BeginProcessing() { @@ -113,7 +100,7 @@ protected override void BeginProcessing() string element = (string)LanguagePrimitives.ConvertTo(e.Current, typeof(string), CultureInfo.InvariantCulture); - if (!String.IsNullOrEmpty(element)) + if (!string.IsNullOrEmpty(element)) { // Prepend a space if the stringbuilder isn't empty... // We could consider using $OFS here but that's probably more @@ -123,6 +110,7 @@ protected override void BeginProcessing() sb.Append(element); } } + promptString = sb.ToString(); } else @@ -137,13 +125,13 @@ protected override void BeginProcessing() } else { - fd.SetParameterType(typeof(String)); + fd.SetParameterType(typeof(string)); } Collection fdc = new Collection(); fdc.Add(fd); - Dictionary result = Host.UI.Prompt("", "", fdc); + Dictionary result = Host.UI.Prompt(string.Empty, string.Empty, fdc); // Result can be null depending on the host implementation. One typical // example of a null return is for a canceled dialog. if (result != null) @@ -165,16 +153,14 @@ protected override void BeginProcessing() { result = Host.UI.ReadLine(); } + WriteObject(result); } } #endregion Cmdlet Overrides - - private object _prompt = null; - private Boolean _safe = false; + private bool _safe = false; } -} // namespace Microsoft.PowerShell.Commands - +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterObjectEventCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterObjectEventCommand.cs index 01bc5af44244..430ee1c71546 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterObjectEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterObjectEventCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -17,7 +16,7 @@ public class RegisterObjectEventCommand : ObjectEventRegistrationBase #region parameters /// - /// The object on which to subscribe + /// The object on which to subscribe. /// [Parameter(Mandatory = true, Position = 0)] public PSObject InputObject @@ -26,15 +25,17 @@ public PSObject InputObject { return _inputObject; } + set { _inputObject = value; } } + private PSObject _inputObject = null; /// - /// The event name to subscribe + /// The event name to subscribe. /// [Parameter(Mandatory = true, Position = 1)] public string EventName @@ -43,29 +44,31 @@ public string EventName { return _eventName; } + set { _eventName = value; } } + private string _eventName = null; #endregion parameters /// - /// Returns the object that generates events to be monitored + /// Returns the object that generates events to be monitored. /// - protected override Object GetSourceObject() + protected override object GetSourceObject() { return _inputObject; } /// - /// Returns the event name to be monitored on the input object + /// Returns the event name to be monitored on the input object. /// - protected override String GetSourceObjectEventName() + protected override string GetSourceObjectEventName() { return _eventName; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterPSEventCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterPSEventCommand.cs index 48a3fe8a09c9..b182f694cbcb 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterPSEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RegisterPSEventCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -15,7 +14,7 @@ namespace Microsoft.PowerShell.Commands public class RegisterEngineEventCommand : ObjectEventRegistrationBase { /// - /// Parameter for an identifier for this event subscription + /// Parameter for an identifier for this event subscription. /// [Parameter(Mandatory = true, Position = 100)] public new string SourceIdentifier @@ -24,6 +23,7 @@ public new string SourceIdentifier { return base.SourceIdentifier; } + set { base.SourceIdentifier = value; @@ -31,9 +31,9 @@ public new string SourceIdentifier } /// - /// Returns the object that generates events to be monitored + /// Returns the object that generates events to be monitored. /// - protected override Object GetSourceObject() + protected override object GetSourceObject() { // If it's not a forwarded event, the user must specify // an action @@ -55,11 +55,11 @@ protected override Object GetSourceObject() } /// - /// Returns the event name to be monitored on the input object + /// Returns the event name to be monitored on the input object. /// - protected override String GetSourceObjectEventName() + protected override string GetSourceObjectEventName() { return null; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Remove-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Remove-PSBreakpoint.cs index 286c79437a27..a02f9dec0598 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Remove-PSBreakpoint.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Remove-PSBreakpoint.cs @@ -1,24 +1,23 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// This class implements Remove-PSBreakpoint + /// This class implements Remove-PSBreakpoint. /// [Cmdlet(VerbsCommon.Remove, "PSBreakpoint", SupportsShouldProcess = true, DefaultParameterSetName = "Breakpoint", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113375")] public class RemovePSBreakpointCommand : PSBreakpointCommandBase { /// - /// Removes the given breakpoint + /// Removes the given breakpoint. /// protected override void ProcessBreakpoint(Breakpoint breakpoint) { this.Context.Debugger.RemoveBreakpoint(breakpoint); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveAliasCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveAliasCommand.cs index 92f0c1fbf2e8..8a32bfa30c5e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveAliasCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveAliasCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Management.Automation; using System.Management.Automation.Internal; @@ -7,32 +10,30 @@ namespace Microsoft.PowerShell.Commands /// /// The implementation of the "Remove-Alias" cmdlet. /// - /// [Cmdlet(VerbsCommon.Remove, "Alias", DefaultParameterSetName = "Default", HelpUri = "")] [Alias("ral")] public class RemoveAliasCommand : PSCmdlet { - #region Parameters + #region Parameters /// /// The alias name to remove. - /// + /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Name { get; set; } - + /// - /// The scope parameter for the command determines - /// which scope the alias is removed from. - /// + /// The scope parameter for the command determines which scope the alias is removed from. + /// [Parameter] public string Scope { get; set; } /// /// If set to true and an existing alias of the same name exists /// and is ReadOnly, it will still be deleted. - /// + /// [Parameter] - public SwitchParameter Force { get; set; } + public SwitchParameter Force { get; set; } #endregion Parameters @@ -40,13 +41,13 @@ public class RemoveAliasCommand : PSCmdlet /// /// The main processing loop of the command. - /// + /// protected override void ProcessRecord() { - foreach(string aliasName in Name) - { - AliasInfo existingAlias = null; - if (String.IsNullOrEmpty(Scope)) + foreach (string aliasName in Name) + { + AliasInfo existingAlias = null; + if (string.IsNullOrEmpty(Scope)) { existingAlias = SessionState.Internal.GetAlias(aliasName); } @@ -62,7 +63,7 @@ protected override void ProcessRecord() else { ItemNotFoundException notAliasFound = new ItemNotFoundException(StringUtil.Format(AliasCommandStrings.NoAliasFound, "name", aliasName)); - ErrorRecord error = new ErrorRecord(notAliasFound, "ItemNotFoundException",ErrorCategory.ObjectNotFound, aliasName); + ErrorRecord error = new ErrorRecord(notAliasFound, "ItemNotFoundException", ErrorCategory.ObjectNotFound, aliasName); WriteError(error); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveEventCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveEventCommand.cs index e50431aaf63b..83aa745ed2c8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/RemoveEventCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -16,7 +15,7 @@ public class RemoveEventCommand : PSCmdlet #region parameters /// - /// A source identifier for this event subscription + /// A source identifier for this event subscription. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "BySource")] public string SourceIdentifier @@ -25,6 +24,7 @@ public string SourceIdentifier { return _sourceIdentifier; } + set { _sourceIdentifier = value; @@ -35,10 +35,11 @@ public string SourceIdentifier } } } + private string _sourceIdentifier = null; /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByIdentifier")] public int EventIdentifier @@ -47,11 +48,13 @@ public int EventIdentifier { return _eventIdentifier; } + set { _eventIdentifier = value; } } + private int _eventIdentifier = -1; #endregion parameters @@ -59,7 +62,7 @@ public int EventIdentifier private WildcardPattern _matchPattern; /// - /// Remove the event from the queue + /// Remove the event from the queue. /// protected override void ProcessRecord() { @@ -91,7 +94,7 @@ protected override void ProcessRecord() foundMatch = true; if (ShouldProcess( - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, EventingStrings.EventResource, currentEvent.SourceIdentifier), @@ -110,7 +113,7 @@ protected override void ProcessRecord() { ErrorRecord errorRecord = new ErrorRecord( new ArgumentException( - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, EventingStrings.SourceIdentifierNotFound, _sourceIdentifier)), "INVALID_SOURCE_IDENTIFIER", @@ -123,7 +126,7 @@ protected override void ProcessRecord() { ErrorRecord errorRecord = new ErrorRecord( new ArgumentException( - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, EventingStrings.EventIdentifierNotFound, _eventIdentifier)), "INVALID_EVENT_IDENTIFIER", @@ -134,4 +137,4 @@ protected override void ProcessRecord() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/select-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs similarity index 82% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/select-object.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs index b5c4f0a35819..eaf065eaaf3c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/select-object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs @@ -1,27 +1,27 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Management.Automation; -using Microsoft.PowerShell.Commands.Internal.Format; using System.Management.Automation.Internal; -using System.Diagnostics.CodeAnalysis; + +using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// helper class to do wildcard matching on MshExpressions + /// Helper class to do wildcard matching on PSPropertyExpressions. /// - internal sealed class MshExpressionFilter + internal sealed class PSPropertyExpressionFilter { /// - /// construct the class, using an array of patterns + /// Construct the class, using an array of patterns. /// - /// array of pattern strings to use - internal MshExpressionFilter(string[] wildcardPatternsStrings) + /// Array of pattern strings to use. + internal PSPropertyExpressionFilter(string[] wildcardPatternsStrings) { if (wildcardPatternsStrings == null) { @@ -36,18 +36,19 @@ internal MshExpressionFilter(string[] wildcardPatternsStrings) } /// - /// try to match the expression against the array of wildcard patterns. - /// the first match shortcircuits the search + /// Try to match the expression against the array of wildcard patterns. + /// The first match shortcircuits the search. /// - /// MshExpression to test against - /// true if there is a match, else false - internal bool IsMatch(MshExpression expression) + /// PSPropertyExpression to test against. + /// True if there is a match, else false. + internal bool IsMatch(PSPropertyExpression expression) { for (int k = 0; k < _wildcardPatterns.Length; k++) { if (_wildcardPatterns[k].IsMatch(expression.ToString())) return true; } + return false; } @@ -64,7 +65,6 @@ protected override void SetEntries() } /// - /// /// [Cmdlet(VerbsCommon.Select, "Object", DefaultParameterSetName = "DefaultParameter", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113387", RemotingCapability = RemotingCapability.None)] @@ -73,15 +73,12 @@ public sealed class SelectObjectCommand : PSCmdlet #region Command Line Switches /// - /// /// /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { set; get; } = AutomationNull.Value; - /// - /// /// /// [Parameter(Position = 0, ParameterSetName = "DefaultParameter")] @@ -89,7 +86,6 @@ public sealed class SelectObjectCommand : PSCmdlet public object[] Property { get; set; } /// - /// /// /// [Parameter(ParameterSetName = "DefaultParameter")] @@ -97,7 +93,6 @@ public sealed class SelectObjectCommand : PSCmdlet public string[] ExcludeProperty { get; set; } = null; /// - /// /// /// [Parameter(ParameterSetName = "DefaultParameter")] @@ -105,19 +100,19 @@ public sealed class SelectObjectCommand : PSCmdlet public string ExpandProperty { get; set; } = null; /// - /// /// /// [Parameter] public SwitchParameter Unique { get { return _unique; } + set { _unique = value; } } + private bool _unique; /// - /// /// /// [Parameter(ParameterSetName = "DefaultParameter")] @@ -127,12 +122,13 @@ public SwitchParameter Unique public int Last { get { return _last; } + set { _last = value; _firstOrLastSpecified = true; } } + private int _last = 0; /// - /// /// /// [Parameter(ParameterSetName = "DefaultParameter")] @@ -142,14 +138,15 @@ public int Last public int First { get { return _first; } + set { _first = value; _firstOrLastSpecified = true; } } + private int _first = 0; private bool _firstOrLastSpecified; - /// - /// Skips the specified number of items from top when used with First,from end when used with Last + /// Skips the specified number of items from top when used with First, from end when used with Last. /// /// [Parameter(ParameterSetName = "DefaultParameter")] @@ -165,14 +162,14 @@ public int First /// /// With this switch present, the cmdlet won't "short-circuit" - /// (i.e. won't stop upstream cmdlets after it knows that no further objects will be emitted downstream) + /// (i.e. won't stop upstream cmdlets after it knows that no further objects will be emitted downstream). /// [Parameter(ParameterSetName = "DefaultParameter")] [Parameter(ParameterSetName = "IndexParameter")] public SwitchParameter Wait { get; set; } /// - /// Used to display the object at specified index + /// Used to display the object at the specified index. /// /// [Parameter(ParameterSetName = "IndexParameter")] @@ -184,15 +181,42 @@ public int[] Index { return _index; } + set { _index = value; _indexSpecified = true; + _isIncludeIndex = true; Array.Sort(_index); } } + + /// + /// Used to display all objects at the specified indices. + /// + /// + [Parameter(ParameterSetName = "SkipIndexParameter")] + [ValidateRangeAttribute(0, int.MaxValue)] + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] + public int[] SkipIndex + { + get + { + return _index; + } + + set + { + _index = value; + _indexSpecified = true; + _isIncludeIndex = false; + Array.Sort(_index); + } + } + private int[] _index; private bool _indexSpecified; + private bool _isIncludeIndex; #endregion @@ -227,12 +251,13 @@ public new void Enqueue(PSObject obj) { base.Dequeue(); } + base.Enqueue(obj); } public PSObject StreamingDequeue() { - //if skip parameter is not mentioned or there are no more objects to skip + // if skip parameter is not mentioned or there are no more objects to skip if (_skip == 0) { if (_skipLast > 0) @@ -262,7 +287,7 @@ public PSObject StreamingDequeue() } else { - //if last parameter is not mentioned,remove the objects and decrement the skip + // if last parameter is not mentioned,remove the objects and decrement the skip if (_last == 0) { Dequeue(); @@ -279,23 +304,21 @@ public PSObject StreamingDequeue() } private int _streamedObjectCount; - private int _first,_last,_skip,_skipLast; + private int _first, _last, _skip, _skipLast; private bool _firstOrLastSpecified; } /// - /// list of processed parameters obtained from the Expression array + /// List of processed parameters obtained from the Expression array. /// private List _propertyMshParameterList; /// - /// singleton list of process parameters obtained from ExpandProperty + /// Singleton list of process parameters obtained from ExpandProperty. /// private List _expandMshParameterList; - - - private MshExpressionFilter _exclusionFilter; + private PSPropertyExpressionFilter _exclusionFilter; private class UniquePSObjectHelper { @@ -304,6 +327,7 @@ internal UniquePSObjectHelper(PSObject o, int notePropertyCount) WrittenObject = o; NotePropertyCount = notePropertyCount; } + internal readonly PSObject WrittenObject; internal int NotePropertyCount { get; } } @@ -318,6 +342,7 @@ private void ProcessExpressionParameter() if ((Property != null) && (Property.Length != 0)) { // Build property list taking into account the wildcards and @{name=;expression=} + _propertyMshParameterList = processor.ProcessParameters(Property, invocationContext); } else @@ -333,11 +358,11 @@ private void ProcessExpressionParameter() if (ExcludeProperty != null) { - _exclusionFilter = new MshExpressionFilter(ExcludeProperty); + _exclusionFilter = new PSPropertyExpressionFilter(ExcludeProperty); // ExcludeProperty implies -Property * for better UX if ((Property == null) || (Property.Length == 0)) { - Property = new Object[]{"*"}; + Property = new object[] { "*" }; _propertyMshParameterList = processor.ProcessParameters(Property, invocationContext); } } @@ -351,8 +376,7 @@ private void ProcessObject(PSObject inputObject) return; } - - //If property parameter is mentioned + // If property parameter is mentioned List matchedProperties = new List(); foreach (MshParameter p in _propertyMshParameterList) { @@ -388,6 +412,7 @@ private void ProcessObject(PSObject inputObject) } } } + FilteredWriteObject(result, matchedProperties); } else @@ -396,21 +421,19 @@ private void ProcessObject(PSObject inputObject) } } - - private void ProcessParameter(MshParameter p, PSObject inputObject, List result) { string name = p.GetEntry(NameEntryDefinition.NameEntryKey) as string; - MshExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as MshExpression; - List expressionResults = new List(); - foreach (MshExpression resolvedName in ex.ResolveNames(inputObject)) + PSPropertyExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as PSPropertyExpression; + List expressionResults = new List(); + foreach (PSPropertyExpression resolvedName in ex.ResolveNames(inputObject)) { if (_exclusionFilter == null || !_exclusionFilter.IsMatch(resolvedName)) { - List tempExprResults = resolvedName.GetValues(inputObject); + List tempExprResults = resolvedName.GetValues(inputObject); if (tempExprResults == null) continue; - foreach (MshExpressionResult mshExpRes in tempExprResults) + foreach (PSPropertyExpressionResult mshExpRes in tempExprResults) { expressionResults.Add(mshExpRes); } @@ -421,7 +444,7 @@ private void ProcessParameter(MshParameter p, PSObject inputObject, List matchedProperties) { - MshExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as MshExpression; - List expressionResults = ex.GetValues(inputObject); - + PSPropertyExpression ex = p.GetEntry(FormatParameterDefinitionKeys.ExpressionEntryKey) as PSPropertyExpression; + List expressionResults = ex.GetValues(inputObject); if (expressionResults.Count == 0) { @@ -483,6 +508,7 @@ private void ProcessParameter(MshParameter p, PSObject inputObject, List 1) { ErrorRecord errorRecord = new ErrorRecord( @@ -493,7 +519,7 @@ private void ProcessParameter(MshParameter p, PSObject inputObject, List addedNoteProperties) { Diagnostics.Assert(obj != null, "This command should never write null"); @@ -583,9 +610,10 @@ private void FilteredWriteObject(PSObject obj, List addedNotePro SetPSCustomObject(obj); WriteObject(obj); } + return; } - //if only unique is mentioned + // if only unique is mentioned else if ((_unique)) { bool isObjUnique = true; @@ -605,6 +633,7 @@ private void FilteredWriteObject(PSObject obj, List addedNotePro break; } } + if (found) { isObjUnique = false; @@ -616,6 +645,7 @@ private void FilteredWriteObject(PSObject obj, List addedNotePro continue; } } + if (isObjUnique) { SetPSCustomObject(obj); @@ -645,7 +675,6 @@ private void ProcessObjectAndHandleErrors(PSObject pso) } /// - /// /// protected override void BeginProcessing() { @@ -659,16 +688,18 @@ protected override void BeginProcessing() _selectObjectQueue = new SelectObjectQueue(_first, _last, Skip, SkipLast, _firstOrLastSpecified); } - private int _indexOfCurrentObject = 0; - private int _indexCount = 0; /// - /// + /// Handles processing of InputObject. /// protected override void ProcessRecord() { if (InputObject != AutomationNull.Value && InputObject != null) { - if (!_indexSpecified) + if (_indexSpecified) + { + ProcessIndexed(); + } + else { _selectObjectQueue.Enqueue(InputObject); PSObject streamingInputObject = _selectObjectQueue.StreamingDequeue(); @@ -676,40 +707,82 @@ protected override void ProcessRecord() { ProcessObjectAndHandleErrors(streamingInputObject); } + if (_selectObjectQueue.AllRequestedObjectsProcessed && !this.Wait) { this.EndProcessing(); throw new StopUpstreamCommandsException(this); } } - else + } + } + + /// + /// The index of the active index filter. + /// + private int _currentFilterIndex; + + /// + /// The index of the object being processed. + /// + private int _currentObjectIndex; + + /// + /// Handles processing of InputObject if -Index or -SkipIndex is specified. + /// + private void ProcessIndexed() + { + if (_isIncludeIndex) + { + if (_currentFilterIndex < _index.Length) { - if (_indexOfCurrentObject < _index.Length) + int nextIndexToOutput = _index[_currentFilterIndex]; + if (_currentObjectIndex == nextIndexToOutput) { - int currentlyRequestedIndex = _index[_indexOfCurrentObject]; - if (_indexCount == currentlyRequestedIndex) + ProcessObjectAndHandleErrors(InputObject); + while ((_currentFilterIndex < _index.Length) && (_index[_currentFilterIndex] == nextIndexToOutput)) { - ProcessObjectAndHandleErrors(InputObject); - while ((_indexOfCurrentObject < _index.Length) && (_index[_indexOfCurrentObject] == currentlyRequestedIndex)) - { - _indexOfCurrentObject++; - } + _currentFilterIndex++; } } + } + + if (!Wait && _currentFilterIndex >= _index.Length) + { + EndProcessing(); + throw new StopUpstreamCommandsException(this); + } - if (!this.Wait && _indexOfCurrentObject >= _index.Length) + _currentObjectIndex++; + } + else + { + if (_currentFilterIndex < _index.Length) + { + int nextIndexToSkip = _index[_currentFilterIndex]; + if (_currentObjectIndex != nextIndexToSkip) { - this.EndProcessing(); - throw new StopUpstreamCommandsException(this); + ProcessObjectAndHandleErrors(InputObject); + } + else + { + while ((_currentFilterIndex < _index.Length) && (_index[_currentFilterIndex] == nextIndexToSkip)) + { + _currentFilterIndex++; + } } - - _indexCount++; } + else + { + ProcessObjectAndHandleErrors(InputObject); + } + + _currentObjectIndex++; } } /// - /// + /// Completes the processing of Input. /// protected override void EndProcessing() { @@ -758,7 +831,7 @@ protected override void EndProcessing() } /// - /// Used only internally for select-object + /// Used only internally for select-object. /// [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "This exception is internal and never thrown by any public API")] [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception is internal and never thrown by any public API")] @@ -773,4 +846,3 @@ internal SelectObjectException(ErrorRecord errorRecord) } } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs index df2014d9fc2d..5e91d0fdc434 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs @@ -1,280 +1,162 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; -using System.Globalization; -using System.Net.Mail; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Management.Automation; - +using System.Net.Mail; +using System.Text; namespace Microsoft.PowerShell.Commands { #region SendMailMessage /// - /// implementation for the Send-MailMessage command + /// Implementation for the Send-MailMessage command. /// + [Obsolete("This cmdlet does not guarantee secure connections to SMTP servers. While there is no immediate replacement available in PowerShell, we recommend you do not use Send-MailMessage at this time. See https://aka.ms/SendMailMessage for more information.")] [Cmdlet(VerbsCommunications.Send, "MailMessage", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135256")] public sealed class SendMailMessage : PSCmdlet { #region Command Line Parameters /// - /// Specifies the files names to be attached to the email. + /// Gets or sets the files names to be attached to the email. /// If the filename specified can not be found, then the relevant error /// message should be thrown. /// - [Parameter(ValueFromPipeline = true)] + [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] [Alias("PsPath")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Attachments - { - get { return _attachments; } - set - { - _attachments = value; - } - } - private String[] _attachments; + public string[] Attachments { get; set; } /// - /// Specifies the address collection that contains the + /// Gets or sets the address collection that contains the /// blind carbon copy (BCC) recipients for the e-mail message. /// - [Parameter] + [Parameter(ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Bcc - { - get { return _bcc; } - set - { - _bcc = value; - } - } - private String[] _bcc; + public string[] Bcc { get; set; } /// - /// Specifies the body (content) of the message + /// Gets or sets the body (content) of the message. /// - [Parameter(Position = 2)] + [Parameter(Position = 2, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] - public String Body - { - get { return _body; } - set - { - _body = value; - } - } - private String _body; + public string Body { get; set; } /// - /// Specifies a value indicating whether the mail message body is in Html. + /// Gets or sets the value indicating whether the mail message body is in Html. /// - [Parameter] + [Parameter(ValueFromPipelineByPropertyName = true)] [Alias("BAH")] - public SwitchParameter BodyAsHtml - { - get { return _bodyashtml; } - set - { - _bodyashtml = value; - } - } - private SwitchParameter _bodyashtml; + public SwitchParameter BodyAsHtml { get; set; } /// - /// Specifies the encoding used for the content of the body and also the subject. - /// This is set to ASCII to ensure there are no problems with any email server + /// Gets or sets the encoding used for the content of the body and also the subject. + /// This is set to ASCII to ensure there are no problems with any email server. /// - [Parameter()] + [Parameter(ValueFromPipelineByPropertyName = true)] [Alias("BE")] [ValidateNotNullOrEmpty] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] - [ArgumentToEncodingTransformationAttribute()] + [ArgumentEncodingCompletionsAttribute] + [ArgumentToEncodingTransformationAttribute] public Encoding Encoding { get; set; } = Encoding.ASCII; /// - /// Specifies the address collection that contains the + /// Gets or sets the address collection that contains the /// carbon copy (CC) recipients for the e-mail message. /// - [Parameter] + [Parameter(ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Cc")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] Cc - { - get { return _cc; } - set - { - _cc = value; - } - } - private String[] _cc; + public string[] Cc { get; set; } /// - /// Specifies the delivery notifications options for the e-mail message. The various - /// option available for this parameter are None, OnSuccess, OnFailure, Delay and Never + /// Gets or sets the delivery notifications options for the e-mail message. The various + /// options available for this parameter are None, OnSuccess, OnFailure, Delay and Never. /// - [Parameter()] + [Parameter(ValueFromPipelineByPropertyName = true)] [Alias("DNO")] [ValidateNotNullOrEmpty] - public DeliveryNotificationOptions DeliveryNotificationOption - { - get { return _deliverynotification; } - set - { - _deliverynotification = value; - } - } - private DeliveryNotificationOptions _deliverynotification; + public DeliveryNotificationOptions DeliveryNotificationOption { get; set; } /// - /// Specifies the from address for this e-mail message. The default value for - /// this parameter is the email address of the currently logged on user + /// Gets or sets the from address for this e-mail message. The default value for + /// this parameter is the email address of the currently logged on user. /// - [Parameter(Mandatory = true)] + [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] - public String From - { - get { return _from; } - set - { - _from = value; - } - } - private String _from; + public string From { get; set; } /// - /// Specifies the name of the Host used to send the email. This host name will be assigned - /// to the Powershell variable PSEmailServer,if this host can not reached an appropriate error + /// Gets or sets the name of the Host used to send the email. This host name will be assigned + /// to the Powershell variable PSEmailServer, if this host can not reached an appropriate error. /// message will be displayed. /// - [Parameter(Position = 3)] + [Parameter(Position = 3, ValueFromPipelineByPropertyName = true)] [Alias("ComputerName")] [ValidateNotNullOrEmpty] - public String SmtpServer - { - get { return _smtpserver; } - set - { - _smtpserver = value; - } - } - private String _smtpserver; + public string SmtpServer { get; set; } /// - /// Specifies the priority of the email message. The valid values for this are Normal, High and Low + /// Gets or sets the priority of the email message. The valid values for this are Normal, High and Low. /// - [Parameter] + [Parameter(ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] - public MailPriority Priority - { - get { return _priority; } - set - { - _priority = value; - } - } - private MailPriority _priority; + public MailPriority Priority { get; set; } /// - /// Specifies the subject of the email message. + /// Gets or sets the Reply-To field for this e-mail message. /// - [Parameter(Mandatory = true, Position = 1)] - [Alias("sub")] - [ValidateNotNullOrEmpty] - public String Subject - { - get { return _subject; } - set - { - _subject = value; - } - } - private String _subject; + [Parameter(ValueFromPipelineByPropertyName = true)] + public string[] ReplyTo { get; set; } + /// + /// Gets or sets the subject of the email message. + /// + [Parameter(Mandatory = false, Position = 1, ValueFromPipelineByPropertyName = true)] + [Alias("sub")] + public string Subject { get; set; } /// - /// Specifies the To address for this e-mail message. + /// Gets or sets the To address for this e-mail message. /// - [Parameter(Mandatory = true, Position = 0)] + [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] To - { - get { return _to; } - set - { - _to = value; - } - } - private String[] _to; + public string[] To { get; set; } /// - /// Specifies the credential for this e-mail message. + /// Gets or sets the credential for this e-mail message. /// - [Parameter()] + [Parameter(ValueFromPipelineByPropertyName = true)] [Credential] [ValidateNotNullOrEmpty] - public PSCredential Credential - { - get { return _credential; } - set - { - _credential = value; - } - } - private PSCredential _credential; + public PSCredential Credential { get; set; } /// - /// Specifies if Secured layer is required or not + /// Gets or sets if Secured layer is required or not. /// - [Parameter()] - public SwitchParameter UseSsl - { - get { return _usessl; } - set - { - _usessl = value; - } - } - private SwitchParameter _usessl; + [Parameter(ValueFromPipelineByPropertyName = true)] + public SwitchParameter UseSsl { get; set; } /// - /// Specifies the Port to be used on the server. + /// Gets or sets the Port to be used on the server. /// /// /// Value must be greater than zero. /// - [Parameter()] + [Parameter(ValueFromPipelineByPropertyName = true)] [ValidateRange(0, Int32.MaxValue)] - public int Port - { - get { return _port; } - set { _port = value; } - } - private int _port = 0; + public int Port { get; set; } #endregion - - #region private variables and methods - + #region Private variables and methods // Instantiate a new instance of MailMessage private MailMessage _mMailMessage = new MailMessage(); @@ -282,12 +164,11 @@ public int Port private SmtpClient _mSmtpClient = null; /// - /// Add the input addresses which are either string or hashtable to the MailMessage - /// It returns true if the from parameter has more than one value + /// Add the input addresses which are either string or hashtable to the MailMessage. + /// It returns true if the from parameter has more than one value. /// /// /// - /// private void AddAddressesToMailMessage(object address, string param) { string[] objEmailAddresses = address as string[]; @@ -312,6 +193,11 @@ private void AddAddressesToMailMessage(object address, string param) _mMailMessage.Bcc.Add(new MailAddress(strEmailAddress)); break; } + case "replyTo": + { + _mMailMessage.ReplyToList.Add(new MailAddress(strEmailAddress)); + break; + } } } catch (FormatException e) @@ -328,110 +214,111 @@ private void AddAddressesToMailMessage(object address, string param) #region Overrides /// - /// ProcessRecord override + /// BeginProcessing override. /// - protected override - void - BeginProcessing() + protected override void BeginProcessing() { try { // Set the sender address of the mail message - _mMailMessage.From = new MailAddress(_from); + _mMailMessage.From = new MailAddress(From); } catch (FormatException e) { - ErrorRecord er = new ErrorRecord(e, "FormatException", ErrorCategory.InvalidType, _from); + ErrorRecord er = new ErrorRecord(e, "FormatException", ErrorCategory.InvalidType, From); ThrowTerminatingError(er); - // return; } // Set the recipient address of the mail message - AddAddressesToMailMessage(_to, "to"); + AddAddressesToMailMessage(To, "to"); // Set the BCC address of the mail message - if (_bcc != null) + if (Bcc != null) { - AddAddressesToMailMessage(_bcc, "bcc"); + AddAddressesToMailMessage(Bcc, "bcc"); } // Set the CC address of the mail message - if (_cc != null) + if (Cc != null) { - AddAddressesToMailMessage(_cc, "cc"); + AddAddressesToMailMessage(Cc, "cc"); } + // Set the Reply-To address of the mail message + if (ReplyTo != null) + { + AddAddressesToMailMessage(ReplyTo, "replyTo"); + } - - //set the delivery notification - _mMailMessage.DeliveryNotificationOptions = _deliverynotification; + // Set the delivery notification + _mMailMessage.DeliveryNotificationOptions = DeliveryNotificationOption; // Set the subject of the mail message - _mMailMessage.Subject = _subject; + _mMailMessage.Subject = Subject; // Set the body of the mail message - _mMailMessage.Body = _body; + _mMailMessage.Body = Body; - //set the subject and body encoding + // Set the subject and body encoding _mMailMessage.SubjectEncoding = Encoding; _mMailMessage.BodyEncoding = Encoding; // Set the format of the mail message body as HTML - _mMailMessage.IsBodyHtml = _bodyashtml; + _mMailMessage.IsBodyHtml = BodyAsHtml; // Set the priority of the mail message to normal - _mMailMessage.Priority = _priority; + _mMailMessage.Priority = Priority; - - //get the PowerShell environment variable - //globalEmailServer might be null if it is deleted by: PS> del variable:PSEmailServer + // Get the PowerShell environment variable + // globalEmailServer might be null if it is deleted by: PS> del variable:PSEmailServer PSVariable globalEmailServer = SessionState.Internal.GetVariable(SpecialVariables.PSEmailServer); - if (_smtpserver == null && globalEmailServer != null) + if (SmtpServer == null && globalEmailServer != null) { - _smtpserver = Convert.ToString(globalEmailServer.Value, CultureInfo.InvariantCulture); + SmtpServer = Convert.ToString(globalEmailServer.Value, CultureInfo.InvariantCulture); } - if (string.IsNullOrEmpty(_smtpserver)) + + if (string.IsNullOrEmpty(SmtpServer)) { ErrorRecord er = new ErrorRecord(new InvalidOperationException(SendMailMessageStrings.HostNameValue), null, ErrorCategory.InvalidArgument, null); this.ThrowTerminatingError(er); } - if (0 == _port) + if (Port == 0) { - _mSmtpClient = new SmtpClient(_smtpserver); + _mSmtpClient = new SmtpClient(SmtpServer); } else { - _mSmtpClient = new SmtpClient(_smtpserver, _port); + _mSmtpClient = new SmtpClient(SmtpServer, Port); } - if (_usessl) + if (UseSsl) { _mSmtpClient.EnableSsl = true; } - if (_credential != null) + if (Credential != null) { _mSmtpClient.UseDefaultCredentials = false; - _mSmtpClient.Credentials = _credential.GetNetworkCredential(); + _mSmtpClient.Credentials = Credential.GetNetworkCredential(); } - else if (!_usessl) + else if (!UseSsl) { _mSmtpClient.UseDefaultCredentials = true; } } /// - /// ProcessRecord override + /// ProcessRecord override. /// protected override void ProcessRecord() { - //add the attachments - if (_attachments != null) + // Add the attachments + if (Attachments != null) { string filepath = string.Empty; - foreach (string attachFile in _attachments) + foreach (string attachFile in Attachments) { try { @@ -439,9 +326,10 @@ protected override void ProcessRecord() } catch (ItemNotFoundException e) { - //NOTE: This will throw + // NOTE: This will throw PathUtils.ReportFileOpenFailure(this, filepath, e); } + Attachment mailAttachment = new Attachment(filepath); _mMailMessage.Attachments.Add(mailAttachment); } @@ -449,7 +337,7 @@ protected override void ProcessRecord() } /// - /// EndProcessing + /// EndProcessing override. /// protected override void EndProcessing() { @@ -487,12 +375,11 @@ protected override void EndProcessing() WriteError(er); } - //if we don't dispose the attachments, the sender can't modify or use the files sent. + // If we don't dispose the attachments, the sender can't modify or use the files sent. _mMailMessage.Attachments.Dispose(); } #endregion } - #endregion } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs index 1371eec048ae..23773fd4477f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.ObjectModel; @@ -14,88 +13,17 @@ namespace Microsoft.PowerShell.Commands /// /// This class implements Set-PSBreakpoint command. /// - [Cmdlet(VerbsCommon.Set, "PSBreakpoint", DefaultParameterSetName = "Line", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113449")] + [Cmdlet(VerbsCommon.Set, "PSBreakpoint", DefaultParameterSetName = LineParameterSetName, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113449")] [OutputType(typeof(VariableBreakpoint), typeof(CommandBreakpoint), typeof(LineBreakpoint))] - public class SetPSBreakpointCommand : PSCmdlet + public class SetPSBreakpointCommand : PSBreakpointCreationBase { - #region parameters - - /// - /// the action to take when hitting this breakpoint - /// - [Parameter(ParameterSetName = "Command")] - [Parameter(ParameterSetName = "Line")] - [Parameter(ParameterSetName = "Variable")] - public ScriptBlock Action { get; set; } = null; - - /// - /// The column to set the breakpoint on - /// - [Parameter(Position = 2, ParameterSetName = "Line")] - [ValidateRange(1, int.MaxValue)] - public int Column - { - get - { - return _column ?? 0; - } - set - { - _column = value; - } - } - private int? _column = null; - - - /// - /// the command(s) to set the breakpoint on - /// - [Alias("C")] - [Parameter(ParameterSetName = "Command", Mandatory = true)] - [ValidateNotNull] - public string[] Command { get; set; } = null; - - /// - /// the line to set the breakpoint on - /// - [Parameter(Position = 1, ParameterSetName = "Line", Mandatory = true)] - [ValidateNotNull] - public int[] Line { get; set; } = null; - - /// - /// the script to set the breakpoint on - /// - [Parameter(ParameterSetName = "Command", Position = 0)] - [Parameter(ParameterSetName = "Line", Mandatory = true, Position = 0)] - [Parameter(ParameterSetName = "Variable", Position = 0)] - [ValidateNotNull] - public string[] Script { get; set; } = null; - - /// - /// the variables to set the breakpoint(s) on - /// - [Alias("V")] - [Parameter(ParameterSetName = "Variable", Mandatory = true)] - [ValidateNotNull] - public string[] Variable { get; set; } = null; - /// - /// - /// - [Parameter(ParameterSetName = "Variable")] - public VariableAccessMode Mode { get; set; } = VariableAccessMode.Write; - - #endregion parameters - - /// - /// verifies that debugging is supported + /// Verifies that debugging is supported. /// protected override void BeginProcessing() { - // // Check whether we are executing on a remote session and if so // whether the RemoteScript debug option is selected. - // if (this.Context.InternalHost.ExternalHost is System.Management.Automation.Remoting.ServerRemoteHost && ((this.Context.CurrentRunspace == null) || (this.Context.CurrentRunspace.Debugger == null) || ((this.Context.CurrentRunspace.Debugger.DebugMode & DebugModes.RemoteScript) != DebugModes.RemoteScript) && @@ -128,59 +56,17 @@ protected override void BeginProcessing() } /// - /// set a new breakpoint + /// Set a new breakpoint. /// protected override void ProcessRecord() { - // // If there is a script, resolve its path - // - Collection scripts = new Collection(); - - if (Script != null) - { - foreach (string script in Script) - { - Collection scriptPaths = SessionState.Path.GetResolvedPSPathFromPSPath(script); - - for (int i = 0; i < scriptPaths.Count; i++) - { - string providerPath = scriptPaths[i].ProviderPath; - - if (!File.Exists(providerPath)) - { - WriteError( - new ErrorRecord( - new ArgumentException(StringUtil.Format(Debugger.FileDoesNotExist, providerPath)), - "SetPSBreakpoint:FileDoesNotExist", - ErrorCategory.InvalidArgument, - null)); - - continue; - } - - string extension = Path.GetExtension(providerPath); - - if (!extension.Equals(".ps1", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".psm1", StringComparison.OrdinalIgnoreCase)) - { - WriteError( - new ErrorRecord( - new ArgumentException(StringUtil.Format(Debugger.WrongExtension, providerPath)), - "SetPSBreakpoint:WrongExtension", - ErrorCategory.InvalidArgument, - null)); - continue; - } - - scripts.Add(Path.GetFullPath(providerPath)); - } - } - } + Collection scripts = ResolveScriptPaths(); // // If it is a command breakpoint... // - if (ParameterSetName.Equals("Command", StringComparison.OrdinalIgnoreCase)) + if (ParameterSetName.Equals(CommandParameterSetName, StringComparison.OrdinalIgnoreCase)) { for (int i = 0; i < Command.Length; i++) { @@ -202,7 +88,7 @@ protected override void ProcessRecord() // // If it is a variable breakpoint... // - else if (ParameterSetName.Equals("Variable", StringComparison.OrdinalIgnoreCase)) + else if (ParameterSetName.Equals(VariableParameterSetName, StringComparison.OrdinalIgnoreCase)) { for (int i = 0; i < Variable.Length; i++) { @@ -226,7 +112,7 @@ protected override void ProcessRecord() // else { - Debug.Assert(ParameterSetName.Equals("Line", StringComparison.OrdinalIgnoreCase)); + Debug.Assert(ParameterSetName.Equals(LineParameterSetName, StringComparison.OrdinalIgnoreCase)); for (int i = 0; i < Line.Length; i++) { @@ -244,7 +130,7 @@ protected override void ProcessRecord() foreach (string path in scripts) { - if (_column != null) + if (Column != 0) { WriteObject( Context.Debugger.NewStatementBreakpoint(path, Line[i], Column, Action)); @@ -259,4 +145,4 @@ protected override void ProcessRecord() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetAliasCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetAliasCommand.cs index ce54fa27ce0f..0ceb6a5b1c97 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetAliasCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetAliasCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -9,9 +8,8 @@ namespace Microsoft.PowerShell.Commands { /// - /// The implementation of the "set-alias" cmdlet + /// The implementation of the "set-alias" cmdlet. /// - /// [Cmdlet(VerbsCommon.Set, "Alias", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113390")] [OutputType(typeof(AliasInfo))] public class SetAliasCommand : WriteAliasCommandBase @@ -21,7 +19,6 @@ public class SetAliasCommand : WriteAliasCommandBase /// /// The main processing loop of the command. /// - /// protected override void ProcessRecord() { // Create the alias info @@ -48,7 +45,7 @@ protected override void ProcessRecord() try { - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { result = SessionState.Internal.SetAliasItem(aliasToSet, Force, MyInvocation.CommandOrigin); } @@ -73,8 +70,7 @@ protected override void ProcessRecord() WriteObject(result); } } - } // ProcessRecord + } #endregion Command code - } // class SetAliasCommand -}//Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs index 11e6b12d4edd..a03adbe97ffe 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs @@ -1,6 +1,6 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma warning disable 1634, 1691 using System; @@ -8,12 +8,13 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Runtime.InteropServices; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// implementation for the set-date command + /// Implementation for the set-date command. /// [Cmdlet(VerbsCommon.Set, "Date", DefaultParameterSetName = "Date", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113393")] [OutputType(typeof(DateTime))] @@ -22,22 +23,20 @@ public sealed class SetDateCommand : PSCmdlet #region parameters /// - /// Allows user to override the date/time object that will be processed + /// Allows user to override the date/time object that will be processed. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "Date", ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public DateTime Date { get; set; } - /// - /// Allows a use to specify a timespan with which to apply to the current time + /// Allows a use to specify a timespan with which to apply to the current time. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "Adjust", ValueFromPipelineByPropertyName = true)] [AllowNull] public TimeSpan Adjust { get; set; } - /// - /// This option determines the default output format used to display the object set-date emits + /// This option determines the default output format used to display the object set-date emits. /// [Parameter] public DisplayHintType DisplayHint { get; set; } = DisplayHintType.DateTime; @@ -47,7 +46,7 @@ public sealed class SetDateCommand : PSCmdlet #region methods /// - /// set the date + /// Set the date. /// [ArchitectureSensitive] protected override void ProcessRecord() @@ -102,13 +101,13 @@ protected override void ProcessRecord() #endif } - //output DateTime object wrapped in an PSObject with DisplayHint attached + // output DateTime object wrapped in an PSObject with DisplayHint attached PSObject outputObj = new PSObject(dateToUse); PSNoteProperty note = new PSNoteProperty("DisplayHint", DisplayHint); outputObj.Properties.Add(note); WriteObject(outputObj); - } // EndProcessing + } #endregion @@ -117,7 +116,7 @@ protected override void ProcessRecord() internal static class NativeMethods { [StructLayout(LayoutKind.Sequential)] - public class SystemTime + public struct SystemTime { public UInt16 Year; public UInt16 Month; @@ -130,11 +129,9 @@ public class SystemTime } [DllImport(PinvokeDllNames.SetLocalTimeDllName, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetLocalTime(ref SystemTime systime); - } // NativeMethods - + } #endregion - } // SetDateCommand -} // namespace Microsoft.PowerShell.Commands - - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommand.cs index e048249152e9..3681de8c4a7c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommand.cs @@ -1,22 +1,20 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Management.Automation; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +using Microsoft.PowerShell.Commands.ShowCommandExtension; namespace Microsoft.PowerShell.Commands { - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Globalization; - using System.Management.Automation; - using System.Reflection; - using System.Runtime.InteropServices; - using System.Text; - using System.Threading; - using Microsoft.PowerShell.Commands.ShowCommandExtension; - /// /// Show-Command displays a GUI for a cmdlet, or for all cmdlets if no specific cmdlet is specified. /// @@ -25,7 +23,7 @@ public class ShowCommandCommand : PSCmdlet, IDisposable { #region Private Fields /// - /// Set to true when ProcessRecord is reached, since it will always open a window + /// Set to true when ProcessRecord is reached, since it will always open a window. /// private bool _hasOpenedWindow; @@ -45,7 +43,7 @@ public class ShowCommandCommand : PSCmdlet, IDisposable private List _commands; /// - /// List of modules that have been loaded indexed by module name + /// List of modules that have been loaded indexed by module name. /// private Dictionary _importedModules; @@ -60,13 +58,13 @@ public class ShowCommandCommand : PSCmdlet, IDisposable private SwitchParameter _noCommonParameter; /// - /// Object used for ShowCommand with a command name that holds the view model created for the command + /// Object used for ShowCommand with a command name that holds the view model created for the command. /// private object _commandViewModelObj; #endregion /// - /// Finalizes an instance of the ShowCommandCommand class + /// Finalizes an instance of the ShowCommandCommand class. /// ~ShowCommandCommand() { @@ -96,37 +94,39 @@ public class ShowCommandCommand : PSCmdlet, IDisposable public double Width { get; set; } /// - /// Gets or sets a value indicating Common Parameters should not be displayed + /// Gets or sets a value indicating Common Parameters should not be displayed. /// [Parameter] public SwitchParameter NoCommonParameter { get { return _noCommonParameter; } + set { _noCommonParameter = value; } } /// - /// Gets or sets a value indicating errors should not cause a message window to be displayed + /// Gets or sets a value indicating errors should not cause a message window to be displayed. /// [Parameter] public SwitchParameter ErrorPopup { get; set; } /// - /// Gets or sets a value indicating the command should be sent to the pipeline as a string instead of run + /// Gets or sets a value indicating the command should be sent to the pipeline as a string instead of run. /// [Parameter] public SwitchParameter PassThru { get { return _passThrough; } + set { _passThrough = value; } - } // PassThru + } #endregion #region Public and Protected Methods /// /// Executes a PowerShell script, writing the output objects to the pipeline. /// - /// Script to execute + /// Script to execute. public void RunScript(string script) { if (_showCommandProxy == null || string.IsNullOrEmpty(script)) @@ -164,7 +164,7 @@ public void RunScript(string script) } /// - /// Dispose method in IDisposable + /// Dispose method in IDisposable. /// public void Dispose() { @@ -182,7 +182,7 @@ protected override void BeginProcessing() if (_showCommandProxy.ScreenHeight < this.Height) { ErrorRecord error = new ErrorRecord( - new NotSupportedException(String.Format(CultureInfo.CurrentUICulture, FormatAndOut_out_gridview.PropertyValidate, "Height", _showCommandProxy.ScreenHeight)), + new NotSupportedException(string.Format(CultureInfo.CurrentUICulture, FormatAndOut_out_gridview.PropertyValidate, "Height", _showCommandProxy.ScreenHeight)), "PARAMETER_DATA_ERROR", ErrorCategory.InvalidData, null); @@ -192,7 +192,7 @@ protected override void BeginProcessing() if (_showCommandProxy.ScreenWidth < this.Width) { ErrorRecord error = new ErrorRecord( - new NotSupportedException(String.Format(CultureInfo.CurrentUICulture, FormatAndOut_out_gridview.PropertyValidate, "Width", _showCommandProxy.ScreenWidth)), + new NotSupportedException(string.Format(CultureInfo.CurrentUICulture, FormatAndOut_out_gridview.PropertyValidate, "Width", _showCommandProxy.ScreenWidth)), "PARAMETER_DATA_ERROR", ErrorCategory.InvalidData, null); @@ -216,7 +216,7 @@ protected override void ProcessRecord() } /// - /// Optionally displays errors in a message + /// Optionally displays errors in a message. /// protected override void EndProcessing() { @@ -271,7 +271,7 @@ protected override void StopProcessing() /// Runs the script in a new PowerShell instance and hooks up error stream to potentially display error popup. /// This method has the inconvenience of not showing to the console user the script being executed. /// - /// script to be run + /// Script to be run. private void RunScriptSilentlyAndWithErrorHookup(string script) { // errors are not created here, because there is a field for it used in the final pop up @@ -289,12 +289,12 @@ private void RunScriptSilentlyAndWithErrorHookup(string script) } /// - /// Issues an error when this.commandName was not found + /// Issues an error when this.commandName was not found. /// private void IssueErrorForNoCommand() { InvalidOperationException errorException = new InvalidOperationException( - String.Format( + string.Format( CultureInfo.CurrentUICulture, FormatAndOut_out_gridview.CommandNotFound, Name)); @@ -302,12 +302,12 @@ private void IssueErrorForNoCommand() } /// - /// Issues an error when there is more than one command matching this.commandName + /// Issues an error when there is more than one command matching this.commandName. /// private void IssueErrorForMoreThanOneCommand() { InvalidOperationException errorException = new InvalidOperationException( - String.Format( + string.Format( CultureInfo.CurrentUICulture, FormatAndOut_out_gridview.MoreThanOneCommand, Name, @@ -316,10 +316,10 @@ private void IssueErrorForMoreThanOneCommand() } /// - /// Called from CommandProcessRecord to run the command that will get the CommandInfo and list of modules + /// Called from CommandProcessRecord to run the command that will get the CommandInfo and list of modules. /// - /// command to be retrieved - /// list of loaded modules + /// Command to be retrieved. + /// List of loaded modules. private void GetCommandInfoAndModules(out CommandInfo command, out Dictionary modules) { command = null; @@ -367,7 +367,7 @@ private void GetCommandInfoAndModules(out CommandInfo command, out Dictionary /// ProcessRecord when a command name is specified. /// - /// true if there was no exception processing this record + /// True if there was no exception processing this record. private bool CanProcessRecordForOneCommand() { CommandInfo commandInfo; @@ -391,7 +391,7 @@ private bool CanProcessRecordForOneCommand() /// /// ProcessRecord when a command name is not specified. /// - /// true if there was no exception processing this record + /// True if there was no exception processing this record. private bool CanProcessRecordForAllCommands() { Collection rawCommands = this.InvokeCommand.InvokeScript(_showCommandProxy.GetShowAllModulesCommand()); @@ -413,7 +413,7 @@ private bool CanProcessRecordForAllCommands() } /// - /// Waits untill the window has been closed answering HelpNeeded events + /// Waits until the window has been closed answering HelpNeeded events. /// private void WaitForWindowClosedOrHelpNeeded() { @@ -455,29 +455,29 @@ private void WaitForWindowClosedOrHelpNeeded() } /// - /// Writes the output of a script being run into the pipeline + /// Writes the output of a script being run into the pipeline. /// - /// output collection - /// output event + /// Output collection. + /// Output event. private void Output_DataAdded(object sender, DataAddedEventArgs e) { this.WriteObject(((PSDataCollection)sender)[e.Index]); } /// - /// Writes the errors of a script being run into the pipeline + /// Writes the errors of a script being run into the pipeline. /// - /// error collection - /// error event + /// Error collection. + /// Error event. private void Error_DataAdded(object sender, DataAddedEventArgs e) { this.WriteError(((PSDataCollection)sender)[e.Index]); } /// - /// Implements IDisposable logic + /// Implements IDisposable logic. /// - /// true if being called from Dispose + /// True if being called from Dispose. private void Dispose(bool isDisposing) { if (isDisposing) @@ -492,21 +492,21 @@ private void Dispose(bool isDisposing) #endregion /// - /// Wraps interop code for console input buffer + /// Wraps interop code for console input buffer. /// internal static class ConsoleInputWithNativeMethods { /// - /// Constant used in calls to GetStdHandle + /// Constant used in calls to GetStdHandle. /// internal const int STD_INPUT_HANDLE = -10; /// - /// Adds a string to the console input buffer + /// Adds a string to the console input buffer. /// - /// string to add to console input buffer - /// true to add Enter after the string - /// true if it was successful in adding all characters to console input buffer + /// String to add to console input buffer. + /// True to add Enter after the string. + /// True if it was successful in adding all characters to console input buffer. internal static bool AddToConsoleInputBuffer(string str, bool newLine) { IntPtr handle = ConsoleInputWithNativeMethods.GetStdHandle(ConsoleInputWithNativeMethods.STD_INPUT_HANDLE); @@ -554,21 +554,21 @@ internal static bool AddToConsoleInputBuffer(string str, bool newLine) } /// - /// Gets the console handle + /// Gets the console handle. /// - /// which console handle to get - /// the console handle + /// Which console handle to get. + /// The console handle. [DllImport("kernel32.dll", SetLastError = true)] internal static extern IntPtr GetStdHandle(int nStdHandle); /// - /// Writes to the console input buffer + /// Writes to the console input buffer. /// - /// console handle - /// inputs to be written - /// number of inputs to be written - /// returned number of inputs actually written - /// 0 if the function fails + /// Console handle. + /// Inputs to be written. + /// Number of inputs to be written. + /// Returned number of inputs actually written. + /// 0 if the function fails. [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool WriteConsoleInput( @@ -578,31 +578,31 @@ internal static bool AddToConsoleInputBuffer(string str, bool newLine) out uint lpNumberOfEventsWritten); /// - /// A record to be added to the console buffer + /// A record to be added to the console buffer. /// internal struct INPUT_RECORD { /// - /// The proper event type for a KeyEvent KEY_EVENT_RECORD + /// The proper event type for a KeyEvent KEY_EVENT_RECORD. /// internal const int KEY_EVENT = 0x0001; /// - /// input buffer event type + /// Input buffer event type. /// internal ushort EventType; /// - /// The actual event. The original structure is a union of many others, but this is the largest of them - /// And we don't need other kinds of events + /// The actual event. The original structure is a union of many others, but this is the largest of them. + /// And we don't need other kinds of events. /// internal KEY_EVENT_RECORD KeyEvent; /// /// Sets the necessary fields of for a KeyDown event for the /// - /// input record to be set - /// character to set the record with + /// Input record to be set. + /// Character to set the record with. internal static void SetInputRecord(ref INPUT_RECORD inputRecord, char character) { inputRecord.EventType = INPUT_RECORD.KEY_EVENT; @@ -612,38 +612,38 @@ internal static void SetInputRecord(ref INPUT_RECORD inputRecord, char character } /// - /// Type of INPUT_RECORD which is a key + /// Type of INPUT_RECORD which is a key. /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct KEY_EVENT_RECORD { /// - /// true for key down and false for key up, but only needed if wVirtualKeyCode is used + /// True for key down and false for key up, but only needed if wVirtualKeyCode is used. /// internal bool bKeyDown; /// - /// repeat count + /// Repeat count. /// internal ushort wRepeatCount; /// - /// virtual key code + /// Virtual key code. /// internal ushort wVirtualKeyCode; /// - /// virtual key scan code + /// Virtual key scan code. /// internal ushort wVirtualScanCode; /// - /// character in input. If this is specified, wVirtualKeyCode, and others don't need to be + /// Character in input. If this is specified, wVirtualKeyCode, and others don't need to be. /// internal char UnicodeChar; /// - /// State of keys like Shift and control + /// State of keys like Shift and control. /// internal uint dwControlKeyState; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandCommandInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandCommandInfo.cs index c6e6ae0457ad..7b6bb0674c7b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandCommandInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandCommandInfo.cs @@ -1,31 +1,27 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands.ShowCommandExtension { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Management.Automation; - /// - /// Implements a facade around CommandInfo and its deserialized counterpart + /// Implements a facade around CommandInfo and its deserialized counterpart. /// public class ShowCommandCommandInfo { /// - /// Creates an instance of the ShowCommandCommandInfo class based on a CommandInfo object + /// Creates an instance of the ShowCommandCommandInfo class based on a CommandInfo object. /// - /// /// /// The object to wrap. /// public ShowCommandCommandInfo(CommandInfo other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -66,15 +62,14 @@ public ShowCommandCommandInfo(CommandInfo other) } /// - /// Creates an instance of the ShowCommandCommandInfo class based on a PSObject object + /// Creates an instance of the ShowCommandCommandInfo class based on a PSObject object. /// - /// /// /// The object to wrap. /// public ShowCommandCommandInfo(PSObject other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -105,9 +100,8 @@ public ShowCommandCommandInfo(PSObject other) } /// - /// Builds a strongly typed IEnumerable{object} out of an IEnumerable + /// Builds a strongly typed IEnumerable{object} out of an IEnumerable. /// - /// /// /// The object to enumerate. /// @@ -149,4 +143,4 @@ internal static IEnumerable GetObjectEnumerable(System.Collections.IEnum /// public ICollection ParameterSets { get; private set; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandModuleInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandModuleInfo.cs index 384c4c8bc6f9..9c3f97d5165d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandModuleInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandModuleInfo.cs @@ -1,29 +1,25 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands.ShowCommandExtension { - using System; - using System.Management.Automation; - /// - /// Implements a facade around PSModuleInfo and its deserialized counterpart + /// Implements a facade around PSModuleInfo and its deserialized counterpart. /// public class ShowCommandModuleInfo { /// - /// Creates an instance of the ShowCommandModuleInfo class based on a CommandInfo object + /// Creates an instance of the ShowCommandModuleInfo class based on a CommandInfo object. /// - /// /// /// The object to wrap. /// public ShowCommandModuleInfo(PSModuleInfo other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -32,15 +28,14 @@ public ShowCommandModuleInfo(PSModuleInfo other) } /// - /// Creates an instance of the ShowCommandModuleInfo class based on a PSObject object + /// Creates an instance of the ShowCommandModuleInfo class based on a PSObject object. /// - /// /// /// The object to wrap. /// public ShowCommandModuleInfo(PSObject other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -49,8 +44,8 @@ public ShowCommandModuleInfo(PSObject other) } /// - /// Gets the name of this module + /// Gets the name of this module. /// public string Name { get; private set; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterInfo.cs index 95ce809a7e07..a7fb2664a119 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterInfo.cs @@ -1,32 +1,27 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands.ShowCommandExtension { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Management.Automation; - - /// - /// Implements a facade around ShowCommandParameterInfo and its deserialized counterpart + /// Implements a facade around ShowCommandParameterInfo and its deserialized counterpart. /// public class ShowCommandParameterInfo { /// - /// Creates an instance of the ShowCommandParameterInfo class based on a CommandParameterInfo object + /// Creates an instance of the ShowCommandParameterInfo class based on a CommandParameterInfo object. /// - /// /// /// The object to wrap. /// public ShowCommandParameterInfo(CommandParameterInfo other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -46,15 +41,14 @@ public ShowCommandParameterInfo(CommandParameterInfo other) } /// - /// Creates an instance of the ShowCommandParameterInfo class based on a PSObject object + /// Creates an instance of the ShowCommandParameterInfo class based on a PSObject object. /// - /// /// /// The object to wrap. /// public ShowCommandParameterInfo(PSObject other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -92,7 +86,7 @@ public ShowCommandParameterInfo(PSObject other) public ShowCommandParameterType ParameterType { get; private set; } /// - /// The possible values of this parameter + /// The possible values of this parameter. /// public IList ValidParamSetValues { get; private set; } @@ -107,4 +101,4 @@ public ShowCommandParameterInfo(PSObject other) /// public int Position { get; private set; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterSetInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterSetInfo.cs index 0a1933e44273..e9d149bfca53 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterSetInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterSetInfo.cs @@ -1,32 +1,27 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands.ShowCommandExtension { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Management.Automation; - - /// - /// Implements a facade around CommandParameterSetInfo and its deserialized counterpart + /// Implements a facade around CommandParameterSetInfo and its deserialized counterpart. /// public class ShowCommandParameterSetInfo { /// - /// Creates an instance of the ShowCommandParameterSetInfo class based on a CommandParameterSetInfo object + /// Creates an instance of the ShowCommandParameterSetInfo class based on a CommandParameterSetInfo object. /// - /// /// /// The object to wrap. /// public ShowCommandParameterSetInfo(CommandParameterSetInfo other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -37,15 +32,14 @@ public ShowCommandParameterSetInfo(CommandParameterSetInfo other) } /// - /// Creates an instance of the ShowCommandParameterSetInfo class based on a PSObject object + /// Creates an instance of the ShowCommandParameterSetInfo class based on a PSObject object. /// - /// /// /// The object to wrap. /// public ShowCommandParameterSetInfo(PSObject other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -57,7 +51,7 @@ public ShowCommandParameterSetInfo(PSObject other) } /// - /// Gets the name of the parameter set + /// Gets the name of the parameter set. /// public string Name { get; private set; } @@ -71,4 +65,4 @@ public ShowCommandParameterSetInfo(PSObject other) /// public ICollection Parameters { get; private set; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterType.cs index 9760a7046882..3bde6cdf858e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandParameterType.cs @@ -1,31 +1,26 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands.ShowCommandExtension { - using System; - using System.Collections; - using System.Management.Automation; - - /// - /// Implements a facade around ShowCommandParameterInfo and its deserialized counterpart + /// Implements a facade around ShowCommandParameterInfo and its deserialized counterpart. /// public class ShowCommandParameterType { /// - /// Creates an instance of the ShowCommandParameterType class based on a Type object + /// Creates an instance of the ShowCommandParameterType class based on a Type object. /// - /// /// /// The object to wrap. /// public ShowCommandParameterType(Type other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -47,15 +42,14 @@ public ShowCommandParameterType(Type other) } /// - /// Creates an instance of the ShowCommandParameterType class based on a Type object + /// Creates an instance of the ShowCommandParameterType class based on a Type object. /// - /// /// /// The object to wrap. /// public ShowCommandParameterType(PSObject other) { - if (null == other) + if (other == null) { throw new ArgumentNullException("other"); } @@ -78,82 +72,82 @@ public ShowCommandParameterType(PSObject other) } /// - /// The full name of the outermost type + /// The full name of the outermost type. /// public string FullName { get; private set; } /// - /// Whether or not this type is an enum + /// Whether or not this type is an enum. /// public bool IsEnum { get; private set; } /// - /// Whether or not this type is an dictionary + /// Whether or not this type is an dictionary. /// public bool ImplementsDictionary { get; private set; } /// - /// Whether or not this enum has a flag attribute + /// Whether or not this enum has a flag attribute. /// public bool HasFlagAttribute { get; private set; } /// - /// Whether or not this type is an array type + /// Whether or not this type is an array type. /// public bool IsArray { get; private set; } /// - /// Gets the inner type, if this corresponds to an array type + /// Gets the inner type, if this corresponds to an array type. /// public ShowCommandParameterType ElementType { get; private set; } /// - /// Whether or not this type is a string + /// Whether or not this type is a string. /// public bool IsString { get { - return String.Equals(this.FullName, "System.String", StringComparison.OrdinalIgnoreCase); + return string.Equals(this.FullName, "System.String", StringComparison.OrdinalIgnoreCase); } } /// - /// Whether or not this type is an script block + /// Whether or not this type is an script block. /// public bool IsScriptBlock { get { - return String.Equals(this.FullName, "System.Management.Automation.ScriptBlock", StringComparison.OrdinalIgnoreCase); + return string.Equals(this.FullName, "System.Management.Automation.ScriptBlock", StringComparison.OrdinalIgnoreCase); } } /// - /// Whether or not this type is a bool + /// Whether or not this type is a bool. /// public bool IsBoolean { get { - return String.Equals(this.FullName, "System.Management.Automation.ScriptBlock", StringComparison.OrdinalIgnoreCase); + return string.Equals(this.FullName, "System.Management.Automation.ScriptBlock", StringComparison.OrdinalIgnoreCase); } } /// - /// Whether or not this type is a switch parameter + /// Whether or not this type is a switch parameter. /// public bool IsSwitch { get { - return String.Equals(this.FullName, "System.Management.Automation.SwitchParameter", StringComparison.OrdinalIgnoreCase); + return string.Equals(this.FullName, "System.Management.Automation.SwitchParameter", StringComparison.OrdinalIgnoreCase); } } /// - /// If this is an enum value, return the list of potential values + /// If this is an enum value, return the list of potential values. /// public ArrayList EnumValues { get; private set; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs index fcda24ca44f9..e41c58bc2f16 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs @@ -1,22 +1,20 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Management.Automation; +using System.Management.Automation.Internal; +using System.Threading; + +using Microsoft.PowerShell.Commands.ShowCommandExtension; namespace Microsoft.PowerShell.Commands { - using System; - using System.Collections.Generic; - using System.Management.Automation; - using System.Management.Automation.Internal; - using System.Threading; - using System.Collections.ObjectModel; - using Microsoft.PowerShell.Commands.ShowCommandExtension; - /// /// Help show-command create WPF object and invoke WPF windows with the - /// Microsoft.PowerShell.Commands.ShowCommandInternal.ShowCommandHelperhelp type defined in Microsoft.PowerShell.GraphicalHost.dll + /// Microsoft.PowerShell.Commands.ShowCommandInternal.ShowCommandHelperhelp type defined in Microsoft.PowerShell.GraphicalHost.dll. /// internal class ShowCommandProxy { @@ -127,7 +125,6 @@ internal AutoResetEvent WindowLoaded } } - internal string CommandNeedingHelp { get @@ -149,7 +146,6 @@ internal void DisplayHelp(Collection helpResults) _graphicalHostReflectionWrapper.CallMethod("DisplayHelp", helpResults); } - internal string GetImportModuleCommand(string module) { return (string)_graphicalHostReflectionWrapper.CallStaticMethod("GetImportModuleCommand", module, false, true); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowMarkdownCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowMarkdownCommand.cs new file mode 100644 index 000000000000..beb351971317 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowMarkdownCommand.cs @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; + +using Microsoft.PowerShell.MarkdownRender; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// Show the VT100EncodedString or Html property of on console or show. + /// VT100EncodedString will be displayed on console. + /// Html will be displayed in default browser. + /// + [Cmdlet( + VerbsCommon.Show, "Markdown", + DefaultParameterSetName = "Path", + HelpUri = "https://go.microsoft.com/fwlink/?linkid=2006266")] + [OutputType(typeof(string))] + public class ShowMarkdownCommand : PSCmdlet + { + /// + /// Gets or sets InputObject of type Microsoft.PowerShell.MarkdownRender.MarkdownInfo to display. + /// + [ValidateNotNullOrEmpty] + [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = "InputObject")] + public PSObject InputObject { get; set; } + + /// + /// Gets or sets path to markdown file(s) to display. + /// + [ValidateNotNullOrEmpty] + [Parameter(Position = 0, Mandatory = true, + ValueFromPipelineByPropertyName = true, ParameterSetName = "Path")] + public string[] Path { get; set; } + + /// + /// Gets or sets the literal path parameter to markdown files(s) to display. + /// + [Parameter(ParameterSetName = "LiteralPath", + Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] + [Alias("PSPath", "LP")] + public string[] LiteralPath + { + get { return Path; } + + set { Path = value; } + } + + /// + /// Gets or sets the switch to view Html in default browser. + /// + [Parameter] + public SwitchParameter UseBrowser { get; set; } + + private System.Management.Automation.PowerShell _powerShell; + + /// + /// Override BeginProcessing. + /// + protected override void BeginProcessing() + { + _powerShell = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); + } + + /// + /// Override ProcessRecord. + /// + protected override void ProcessRecord() + { + switch (ParameterSetName) + { + case "InputObject": + if (InputObject.BaseObject is MarkdownInfo markdownInfo) + { + ProcessMarkdownInfo(markdownInfo); + } + else + { + ConvertFromMarkdown("InputObject", InputObject.BaseObject); + } + + break; + + case "Path": + case "LiteralPath": + ConvertFromMarkdown(ParameterSetName, Path); + break; + + default: + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ConvertMarkdownStrings.InvalidParameterSet, ParameterSetName)); + } + } + + /// + /// Process markdown as path. + /// + /// Name of parameter to pass to `ConvertFrom-Markdown`. + /// Value of parameter. + private void ConvertFromMarkdown(string parameter, object input) + { + _powerShell.AddCommand("Microsoft.PowerShell.Utility\\ConvertFrom-Markdown").AddParameter(parameter, input); + if (!UseBrowser) + { + _powerShell.AddParameter("AsVT100EncodedString"); + } + + Collection output = _powerShell.Invoke(); + + if (_powerShell.HadErrors) + { + foreach (ErrorRecord errorRecord in _powerShell.Streams.Error) + { + WriteError(errorRecord); + } + } + + foreach (MarkdownInfo result in output) + { + ProcessMarkdownInfo(result); + } + } + + /// + /// Process markdown as input objects. + /// + /// Markdown object to process. + private void ProcessMarkdownInfo(MarkdownInfo markdownInfo) + { + if (UseBrowser) + { + var html = markdownInfo.Html; + + if (!string.IsNullOrEmpty(html)) + { + string tmpFilePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString() + ".html"); + + try + { + using (var writer = new StreamWriter(new FileStream(tmpFilePath, FileMode.Create, FileAccess.Write, FileShare.Write))) + { + writer.Write(html); + } + } + catch (Exception e) + { + var errorRecord = new ErrorRecord( + e, + "ErrorWritingTempFile", + ErrorCategory.WriteError, + tmpFilePath); + + WriteError(errorRecord); + return; + } + + if (InternalTestHooks.ShowMarkdownOutputBypass) + { + WriteObject(html); + return; + } + + try + { + ProcessStartInfo startInfo = new ProcessStartInfo(); + startInfo.FileName = tmpFilePath; + startInfo.UseShellExecute = true; + Process.Start(startInfo); + } + catch (Exception e) + { + var errorRecord = new ErrorRecord( + e, + "ErrorLaunchingDefaultApplication", + ErrorCategory.InvalidOperation, + targetObject: null); + + WriteError(errorRecord); + return; + } + } + else + { + string errorMessage = StringUtil.Format(ConvertMarkdownStrings.MarkdownInfoInvalid, "Html"); + var errorRecord = new ErrorRecord( + new InvalidDataException(errorMessage), + "HtmlIsNullOrEmpty", + ErrorCategory.InvalidData, + html); + + WriteError(errorRecord); + } + } + else + { + var vt100String = markdownInfo.VT100EncodedString; + + if (!string.IsNullOrEmpty(vt100String)) + { + WriteObject(vt100String); + } + else + { + string errorMessage = StringUtil.Format(ConvertMarkdownStrings.MarkdownInfoInvalid, "VT100EncodedString"); + var errorRecord = new ErrorRecord( + new InvalidDataException(errorMessage), + "VT100EncodedStringIsNullOrEmpty", + ErrorCategory.InvalidData, + vt100String); + + WriteError(errorRecord); + } + } + } + + /// + /// Override EndProcessing. + /// + protected override void EndProcessing() + { + if (_powerShell != null) + { + _powerShell.Dispose(); + } + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/sort-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Sort-Object.cs similarity index 84% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/sort-object.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/Sort-Object.cs index b3288396a306..6225c6e471d0 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/sort-object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Sort-Object.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Collections.Generic; using System.Management.Automation; @@ -8,50 +7,59 @@ namespace Microsoft.PowerShell.Commands { /// - /// /// [Cmdlet("Sort", "Object", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113403", - DefaultParameterSetName="Default", + DefaultParameterSetName = "Default", RemotingCapability = RemotingCapability.None)] public sealed class SortObjectCommand : OrderObjectBase { #region Command Line Switches + + /// + /// Gets or sets a value indicating whether a stable sort is required. + /// + /// + /// + /// Items that are duplicates according to the sort algorithm will appear + /// in the same relative order in a stable sort. + /// + [Parameter(ParameterSetName = "Default")] + public SwitchParameter Stable { get; set; } + /// - /// This param specifies if sort order is ascending. + /// Gets or sets a value indicating whether the sort order is descending. /// [Parameter] public SwitchParameter Descending { get { return DescendingOrder; } + set { DescendingOrder = value; } } + /// - /// This param specifies if only unique objects are filtered. + /// Gets or sets a value indicating whether the sort filters out any duplicate objects. /// /// [Parameter] - public SwitchParameter Unique - { - get { return _unique; } - set { _unique = value; } - } - private bool _unique; + public SwitchParameter Unique { get; set; } + #endregion /// - /// This param specifies you only want the top N items returned. + /// Gets or sets the number of items to return in a Top N sort. /// - [Parameter(ParameterSetName="Default")] - [ValidateRange(1,int.MaxValue)] + [Parameter(ParameterSetName = "Top", Mandatory = true)] + [ValidateRange(1, int.MaxValue)] public int Top { get; set; } = 0; /// - /// This param specifies you only want the bottom N items returned. + /// Gets or sets the number of items to return in a Bottom N sort. /// - [Parameter(ParameterSetName="Bottom", Mandatory=true)] - [ValidateRange(1,int.MaxValue)] + [Parameter(ParameterSetName = "Bottom", Mandatory = true)] + [ValidateRange(1, int.MaxValue)] public int Bottom { get; set; } = 0; /// @@ -86,7 +94,7 @@ private int MoveUniqueEntriesToFront(List sortedData, Orde } /// - /// Sort unsorted OrderByPropertyEntry data using a full sort + /// Sort unsorted OrderByPropertyEntry data using a full sort. /// private int FullSort(List dataToSort, OrderByPropertyComparer comparer) { @@ -98,7 +106,7 @@ private int FullSort(List dataToSort, OrderByPropertyCompa // versions of PowerShell). dataToSort.Sort(comparer); - if (_unique) + if (Unique) { // Move unique entries to the front of the list (this is significantly faster // than removing them) @@ -109,7 +117,7 @@ private int FullSort(List dataToSort, OrderByPropertyCompa } /// - /// Sort unsorted OrderByPropertyEntry data using an indexed min-/max-heap sort + /// Sort unsorted OrderByPropertyEntry data using an indexed min-/max-heap sort. /// private int Heapify(List dataToSort, OrderByPropertyComparer orderByPropertyComparer) { @@ -118,7 +126,8 @@ private int Heapify(List dataToSort, OrderByPropertyCompar // Identify how many items will be in the heap and the current number of items int heapCount = 0; - int heapCapacity = Top > 0 ? Top : Bottom; + int heapCapacity = Stable ? int.MaxValue + : Top > 0 ? Top : Bottom; // Identify the comparator (the value all comparisons will be made against based on whether we're // doing a Top N or Bottom N sort) @@ -134,7 +143,7 @@ private int Heapify(List dataToSort, OrderByPropertyCompar int comparator = Top > 0 ? -1 : 1; // For unique sorts, use a sorted set to avoid adding unique items to the heap - SortedSet uniqueSet = _unique ? new SortedSet(orderByPropertyComparer) : null; + SortedSet uniqueSet = Unique ? new SortedSet(orderByPropertyComparer) : null; // Tracking the index is necessary so that unsortable items can be output at the end, in the order // in which they were received. @@ -148,7 +157,7 @@ private int Heapify(List dataToSort, OrderByPropertyCompar } // If we're doing a unique sort and the entry is not unique, discard the duplicate entry - if (_unique && !uniqueSet.Add(dataToSort[dataIndex])) + if (Unique && !uniqueSet.Add(dataToSort[dataIndex])) { discardedDuplicates++; if (dataIndex != dataToSort.Count - discardedDuplicates) @@ -158,6 +167,7 @@ private int Heapify(List dataToSort, OrderByPropertyCompar dataToSort[dataIndex] = dataToSort[dataToSort.Count - discardedDuplicates]; dataIndex--; } + continue; } @@ -180,6 +190,7 @@ private int Heapify(List dataToSort, OrderByPropertyCompar childIndex = parentIndex; } + heapCount++; // If the heap size is too large, remove the root and rearrange the heap @@ -225,7 +236,6 @@ private int Heapify(List dataToSort, OrderByPropertyCompar } /// - /// /// protected override void EndProcessing() { @@ -242,13 +252,14 @@ protected override void EndProcessing() // Track the number of items that will be output from the data once it is sorted int sortedItemCount = dataToProcess.Count; - // If -Top & -Bottom were not used, or if -Top or -Bottom would return all objects, invoke - // an in-place full sort - if ((Top == 0 && Bottom == 0) || Top >= dataToProcess.Count || Bottom >= dataToProcess.Count) + // If -Stable, -Top & -Bottom were not used, invoke an in-place full sort + if (!Stable && Top == 0 && Bottom == 0) { sortedItemCount = FullSort(dataToProcess, comparer); } - // Otherwise, use an indexed min-/max-heap to perform an in-place sort of all objects + // Otherwise, use an indexed min-/max-heap to perform an in-place heap sort (heap + // sorts are inheritantly stable, meaning they will preserve the respective order + // of duplicate objects as they are sorted on the heap) else { sortedItemCount = Heapify(dataToProcess, comparer); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index fa12ccaa5987..cd71a988bed3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -1,10 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; using System.Threading; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -19,7 +19,7 @@ public sealed class StartSleepCommand : PSCmdlet, IDisposable #region IDisposable /// - /// Dispose method of IDisposable interface. + /// Dispose method of IDisposable interface. /// public void Dispose() { @@ -30,27 +30,25 @@ public void Dispose() _waitHandle.Dispose(); _waitHandle = null; } + _disposed = true; } } #endregion - - #region parameters /// - /// Allows sleep time to be specified in seconds + /// Allows sleep time to be specified in seconds. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "Seconds", ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] - [ValidateRangeAttribute(0, int.MaxValue / 1000)] - public int Seconds { get; set; } - + [ValidateRangeAttribute(0.0, (double)(int.MaxValue / 1000))] + public double Seconds { get; set; } /// - /// Allows sleep time to be specified in milliseconds + /// Allows sleep time to be specified in milliseconds. /// [Parameter(Mandatory = true, ParameterSetName = "Milliseconds", ValueFromPipelineByPropertyName = true)] [ValidateRangeAttribute(0, int.MaxValue)] @@ -61,19 +59,18 @@ public void Dispose() #region methods - //Wait handle which is used by thread to sleep. + // Wait handle which is used by thread to sleep. private ManualResetEvent _waitHandle; - //object used for synchronizes pipeline thread and stop thread - //access to waitHandle + // object used for synchronizes pipeline thread and stop thread + // access to waitHandle private object _syncObject = new object(); - //this is set to true by stopProcessing + // this is set to true by stopProcessing private bool _stopping = false; /// - /// This method causes calling thread to sleep for - /// specified milliseconds + /// This method causes calling thread to sleep for specified milliseconds. /// private void Sleep(int milliSecondsToSleep) { @@ -84,6 +81,7 @@ private void Sleep(int milliSecondsToSleep) _waitHandle = new ManualResetEvent(false); } } + if (_waitHandle != null) { _waitHandle.WaitOne(milliSecondsToSleep, true); @@ -91,7 +89,7 @@ private void Sleep(int milliSecondsToSleep) } /// - /// + /// ProcessRecord method. /// protected override void ProcessRecord() { @@ -100,7 +98,7 @@ protected override void ProcessRecord() switch (ParameterSetName) { case "Seconds": - sleepTime = Seconds * 1000; + sleepTime = (int)(Seconds * 1000); break; case "Milliseconds": @@ -113,14 +111,12 @@ protected override void ProcessRecord() } Sleep(sleepTime); - } // EndProcessing + } /// - /// stopprocessing override + /// StopProcessing override. /// - protected override - void - StopProcessing() + protected override void StopProcessing() { lock (_syncObject) { @@ -133,6 +129,5 @@ protected override } #endregion - } // StartSleepCommand -} // namespace Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/tee-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tee-Object.cs similarity index 86% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/tee-object.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tee-Object.cs index b5520bbad740..ec861aa1e35c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/tee-object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tee-Object.cs @@ -1,52 +1,58 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Microsoft.PowerShell.Commands.Internal.Format; namespace Microsoft.PowerShell.Commands { /// - /// Class for Tee-object implementation + /// Class for Tee-object implementation. /// [Cmdlet("Tee", "Object", DefaultParameterSetName = "File", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113417")] public sealed class TeeObjectCommand : PSCmdlet, IDisposable { /// - /// object to process + /// Object to process. /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { get { return _inputObject; } + set { _inputObject = value; } } + private PSObject _inputObject; /// - /// FilePath parameter + /// FilePath parameter. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "File")] + [Alias("Path")] public string FilePath { get { return _fileName; } + set { _fileName = value; } } + private string _fileName; /// - /// Literal FilePath parameter + /// Literal FilePath parameter. /// [Parameter(Mandatory = true, ParameterSetName = "LiteralFile")] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { get { return _fileName; } + set { _fileName = value; @@ -54,40 +60,43 @@ public string LiteralPath } /// - /// Append switch + /// Append switch. /// [Parameter(ParameterSetName = "File")] public SwitchParameter Append { get { return _append; } + set { _append = value; } } + private bool _append; /// - /// Variable parameter + /// Variable parameter. /// [Parameter(Mandatory = true, ParameterSetName = "Variable")] public string Variable { get { return _variable; } + set { _variable = value; } } + private string _variable; /// - /// /// protected override void BeginProcessing() { _commandWrapper = new CommandWrapper(); - if (String.Equals(ParameterSetName, "File", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ParameterSetName, "File", StringComparison.OrdinalIgnoreCase)) { _commandWrapper.Initialize(Context, "out-file", typeof(OutFileCommand)); _commandWrapper.AddNamedParameter("filepath", _fileName); _commandWrapper.AddNamedParameter("append", _append); } - else if (String.Equals(ParameterSetName, "LiteralFile", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(ParameterSetName, "LiteralFile", StringComparison.OrdinalIgnoreCase)) { _commandWrapper.Initialize(Context, "out-file", typeof(OutFileCommand)); _commandWrapper.AddNamedParameter("LiteralPath", _fileName); @@ -103,7 +112,6 @@ protected override void BeginProcessing() } } /// - /// /// protected override void ProcessRecord() { @@ -112,7 +120,6 @@ protected override void ProcessRecord() } /// - /// /// protected override void EndProcessing() { @@ -133,7 +140,7 @@ private void Dispose(bool isDisposing) } /// - /// Dispose method in IDisposable + /// Dispose method in IDisposable. /// public void Dispose() { @@ -142,7 +149,7 @@ public void Dispose() } /// - /// Finalizer + /// Finalizer. /// ~TeeObjectCommand() { @@ -154,4 +161,3 @@ public void Dispose() #endregion private } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs new file mode 100644 index 000000000000..23f0cc7c37f9 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Management.Automation; +using System.Management.Automation.Internal; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NJsonSchema; + +namespace Microsoft.PowerShell.Commands +{ + /// + /// This class implements Test-Json command. + /// + [Cmdlet(VerbsDiagnostic.Test, "Json", HelpUri = "")] + public class TestJsonCommand : PSCmdlet + { + /// + /// An JSON to be validated. + /// + [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] + public string Json { get; set; } + + /// + /// A schema to validate the JSON against. + /// This is optional parameter. + /// If the parameter is absent the cmdlet only attempts to parse the JSON string. + /// If the parameter present the cmdlet attempts to parse the JSON string and + /// then validates the JSON against the schema. Before testing the JSON string, + /// the cmdlet parses the schema doing implicitly check the schema too. + /// + [Parameter(Position = 1)] + [ValidateNotNullOrEmpty()] + public string Schema { get; set; } + + private JsonSchema _jschema; + + /// + /// Prepare an JSON schema. + /// + protected override void BeginProcessing() + { + if (Schema != null) + { + try + { + _jschema = JsonSchema.FromJsonAsync(Schema).Result; + } + catch (Exception exc) + { + Exception exception = new Exception(TestJsonCmdletStrings.InvalidJsonSchema, exc); + ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, null)); + } + } + } + + /// + /// Validate an JSON. + /// + protected override void ProcessRecord() + { + JObject parsedJson = null; + bool result = true; + + try + { + parsedJson = JObject.Parse(Json); + + if (_jschema != null) + { + var errorMessages = _jschema.Validate(parsedJson); + if (errorMessages != null && errorMessages.Count != 0) + { + result = false; + + Exception exception = new Exception(TestJsonCmdletStrings.InvalidJsonAgainstSchema); + + foreach (var message in errorMessages) + { + ErrorRecord errorRecord = new ErrorRecord(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); + errorRecord.ErrorDetails = new ErrorDetails(message.ToString()); + WriteError(errorRecord); + } + } + } + } + catch (Exception exc) + { + result = false; + + Exception exception = new Exception(TestJsonCmdletStrings.InvalidJson, exc); + WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, Json)); + } + + WriteObject(result); + } + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TimeExpressionCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TimeExpressionCommand.cs index 7cbab7653beb..c1a8433d02c1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TimeExpressionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TimeExpressionCommand.cs @@ -1,13 +1,12 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; using System.Management.Automation.Internal; - #endregion namespace Microsoft.PowerShell.Commands @@ -23,14 +22,13 @@ public sealed class MeasureCommandCommand : PSCmdlet #region parameters /// - /// This parameter specifies the current pipeline object + /// This parameter specifies the current pipeline object. /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { set; get; } = AutomationNull.Value; - /// - /// The script block to apply + /// The script block to apply. /// [Parameter(Position = 0, Mandatory = true)] public ScriptBlock Expression { set; get; } @@ -45,19 +43,16 @@ public sealed class MeasureCommandCommand : PSCmdlet #region methods - /// - /// Output the timer + /// Output the timer. /// protected override void EndProcessing() { WriteObject(_stopWatch.Elapsed); - } // EndProcessing - + } /// - /// Execute the script block passing in the current pipeline object as - /// it's only parameter. + /// Execute the script block passing in the current pipeline object as it's only parameter. /// protected override void ProcessRecord() { @@ -68,15 +63,13 @@ protected override void ProcessRecord() useLocalScope: false, errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe, dollarUnder: InputObject, // $_ - input: new object[0], // $input + input: Array.Empty(), // $input scriptThis: AutomationNull.Value, outputPipe: new Pipe { NullPipe = true }, invocationInfo: null); _stopWatch.Stop(); } - #endregion } -} // namespace Microsoft.PowerShell.Commands - +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs index 5578654c42c1..0f1ff4af3715 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs @@ -1,7 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #if !UNIX -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ #region Using directives @@ -10,6 +10,7 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Management.Automation; using System.Management.Automation.Internal; @@ -23,7 +24,7 @@ namespace Microsoft.PowerShell.Commands public sealed class UnblockFileCommand : PSCmdlet { /// - /// The path of the file to unblock + /// The path of the file to unblock. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "ByPath")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] @@ -33,6 +34,7 @@ public string[] Path { return _paths; } + set { _paths = value; @@ -40,10 +42,10 @@ public string[] Path } /// - /// The literal path of the file to unblock + /// The literal path of the file to unblock. /// [Parameter(Mandatory = true, ParameterSetName = "ByLiteralPath", ValueFromPipelineByPropertyName = true)] - [Alias("PSPath")] + [Alias("PSPath", "LP")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] LiteralPath { @@ -51,6 +53,7 @@ public string[] LiteralPath { return _paths; } + set { _paths = value; @@ -67,7 +70,7 @@ protected override void ProcessRecord() List pathsToProcess = new List(); ProviderInfo provider = null; - if (String.Equals(this.ParameterSetName, "ByLiteralPath", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(this.ParameterSetName, "ByLiteralPath", StringComparison.OrdinalIgnoreCase)) { foreach (string path in _paths) { @@ -119,18 +122,9 @@ protected override void ProcessRecord() { AlternateDataStreamUtilities.DeleteFileStream(path, "Zone.Identifier"); } - catch (Win32Exception accessException) + catch (Exception e) { - // NativeErrorCode=2 - File not found. - // If the block stream not found the 'path' was not blocked and we successfully return. - if (accessException.NativeErrorCode != 2) - { - WriteError(new ErrorRecord(accessException, "RemoveItemUnauthorizedAccessError", ErrorCategory.PermissionDenied, path)); - } - else - { - WriteVerbose(StringUtil.Format(UtilityCommonStrings.NoZoneIdentifierFileStream, path)); - } + WriteError(new ErrorRecord(e, "RemoveItemUnableToAccessFile", ErrorCategory.ResourceUnavailable, path)); } } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnregisterEventCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnregisterEventCommand.cs index 8ab72b1cd400..23adc57cdeef 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnregisterEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnregisterEventCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -16,7 +15,7 @@ public class UnregisterEventCommand : PSCmdlet #region parameters /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "BySource")] public string SourceIdentifier @@ -25,6 +24,7 @@ public string SourceIdentifier { return _sourceIdentifier; } + set { _sourceIdentifier = value; @@ -35,17 +35,17 @@ public string SourceIdentifier } } } + private string _sourceIdentifier = null; /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = "ById")] public int SubscriptionId { get; set; } = -1; /// - /// Flag that determines if we should include subscriptions used to support - /// other subscriptions + /// Flag that determines if we should include subscriptions used to support other subscriptions. /// [Parameter()] public SwitchParameter Force { get; set; } @@ -56,7 +56,7 @@ public string SourceIdentifier private bool _foundMatch = false; /// - /// Unsubscribe from the event + /// Unsubscribe from the event. /// protected override void ProcessRecord() { @@ -80,7 +80,7 @@ protected override void ProcessRecord() _foundMatch = true; if (ShouldProcess( - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, EventingStrings.EventSubscription, subscriber.SourceIdentifier), @@ -99,7 +99,7 @@ protected override void ProcessRecord() { ErrorRecord errorRecord = new ErrorRecord( new ArgumentException( - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, EventingStrings.EventSubscriptionNotFound, _sourceIdentifier)), "INVALID_SOURCE_IDENTIFIER", @@ -113,7 +113,7 @@ protected override void ProcessRecord() { ErrorRecord errorRecord = new ErrorRecord( new ArgumentException( - String.Format( + string.Format( System.Globalization.CultureInfo.CurrentCulture, EventingStrings.EventSubscriptionNotFound, SubscriptionId)), "INVALID_SUBSCRIPTION_IDENTIFIER", @@ -124,4 +124,4 @@ protected override void ProcessRecord() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-Data.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-Data.cs index 36a90b93c837..a0b093cfb904 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-Data.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-Data.cs @@ -1,39 +1,37 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; using System.Collections.ObjectModel; - +using System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// This is the base class for update-typedata and update-formatdata + /// This is the base class for update-typedata and update-formatdata. /// public class UpdateData : PSCmdlet { /// - /// File parameter set name + /// File parameter set name. /// protected const string FileParameterSet = "FileSet"; /// - /// Files to append to the existing set + /// Files to append to the existing set. /// [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = FileParameterSet)] [Alias("PSPath", "Path")] [ValidateNotNull] - public string[] AppendPath { set; get; } = Utils.EmptyArray(); + public string[] AppendPath { set; get; } = Array.Empty(); /// - /// Files to prepend to the existing set + /// Files to prepend to the existing set. /// [Parameter(ParameterSetName = FileParameterSet)] [ValidateNotNull] - public string[] PrependPath { set; get; } = Utils.EmptyArray(); + public string[] PrependPath { set; get; } = Array.Empty(); private static void ReportWrongExtension(string file, string errorId, PSCmdlet cmdlet) { @@ -56,7 +54,6 @@ private static void ReportWrongProviderType(string providerId, string errorId, P } /// - /// /// /// /// @@ -78,11 +75,13 @@ internal static Collection Glob(string[] files, string errorId, PSCmdlet cmdlet.WriteError(new ErrorRecord(e, errorId, ErrorCategory.InvalidOperation, file)); continue; } + if (!provider.NameEquals(cmdlet.Context.ProviderNames.FileSystem)) { ReportWrongProviderType(provider.FullName, errorId, cmdlet); continue; } + foreach (string providerPath in providerPaths) { if (!providerPath.EndsWith(".ps1xml", StringComparison.OrdinalIgnoreCase)) @@ -90,6 +89,7 @@ internal static Collection Glob(string[] files, string errorId, PSCmdlet ReportWrongExtension(providerPath, "WrongExtension", cmdlet); continue; } + retValue.Add(providerPath); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/update-list.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-List.cs similarity index 90% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/update-list.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-List.cs index afff8f3b8d5f..9ba6c8980203 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/update-list.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-List.cs @@ -1,11 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; -using System.Management.Automation; using System.Diagnostics.CodeAnalysis; +using System.Management.Automation; namespace Microsoft.PowerShell.Commands { @@ -13,7 +12,6 @@ namespace Microsoft.PowerShell.Commands /// This cmdlet updates the property of incoming objects and passes them to the /// pipeline. This cmdlet also returns a .NET object with properties that /// defines the update action on a list. - /// /// This cmdlet is most helpful when the cmdlet author wants the user to do /// update action on object list that are not directly exposed through /// cmdlet parameter. One wants to update a property value which is a list @@ -25,7 +23,7 @@ public class UpdateListCommand : PSCmdlet { /// /// The following is the definition of the input parameter "Add". - /// Objects to be add to the list + /// Objects to add to the list. /// [Parameter(ParameterSetName = "AddRemoveSet")] [ValidateNotNullOrEmpty()] @@ -34,7 +32,7 @@ public class UpdateListCommand : PSCmdlet /// /// The following is the definition of the input parameter "Remove". - /// Objects to be removed from the list + /// Objects to be removed from the list. /// [Parameter(ParameterSetName = "AddRemoveSet")] [ValidateNotNullOrEmpty()] @@ -52,22 +50,20 @@ public class UpdateListCommand : PSCmdlet /// /// The following is the definition of the input parameter "InputObject". - /// List of InputObjects where the updates needs to applied to the - /// specific property + /// List of InputObjects where the updates needs to applied to the specific property. /// - //[Parameter(ValueFromPipeline = true, ParameterSetName = "AddRemoveSet")] - //[Parameter(ValueFromPipeline = true, ParameterSetName = "ReplaceSet")] + // [Parameter(ValueFromPipeline = true, ParameterSetName = "AddRemoveSet")] + // [Parameter(ValueFromPipeline = true, ParameterSetName = "ReplaceSet")] [Parameter(ValueFromPipeline = true)] [ValidateNotNullOrEmpty()] public PSObject InputObject { get; set; } /// /// The following is the definition of the input parameter "Property". - /// Defines which property of the input object should be updated with Add and - /// Remove actions + /// Defines which property of the input object should be updated with Add and Remove actions. /// - //[Parameter(Position = 0, ParameterSetName = "AddRemoveSet")] - //[Parameter(Position = 0, ParameterSetName = "ReplaceSet")] + // [Parameter(Position = 0, ParameterSetName = "AddRemoveSet")] + // [Parameter(Position = 0, ParameterSetName = "ReplaceSet")] [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] public string Property { get; set; } @@ -113,7 +109,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -139,14 +134,17 @@ private Hashtable CreateHashtable() { hash.Add("Add", Add); } + if (Remove != null) { hash.Add("Remove", Remove); } + if (Replace != null) { hash.Add("Replace", Replace); } + return hash; } @@ -160,6 +158,7 @@ private PSListModifier CreatePSListModifier() listModifier.Add.Add(obj); } } + if (Remove != null) { foreach (object obj in Remove) @@ -167,6 +166,7 @@ private PSListModifier CreatePSListModifier() listModifier.Remove.Add(obj); } } + if (Replace != null) { foreach (object obj in Replace) @@ -174,6 +174,7 @@ private PSListModifier CreatePSListModifier() listModifier.Replace.Add(obj); } } + return listModifier; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs index b81a6501dedb..ee5f40856c4a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Update-TypeData.cs @@ -1,25 +1,25 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; -using System.Reflection; -using System.Management.Automation; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Management.Automation; using System.Management.Automation.Runspaces; -using Dbg = System.Management.Automation.Diagnostics; +using System.Reflection; +using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Commands { /// /// This class implements update-typeData command. /// - [Cmdlet(VerbsData.Update, "TypeData", SupportsShouldProcess = true, DefaultParameterSetName = FileParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113421")] + [Cmdlet(VerbsData.Update, "TypeData", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low, + DefaultParameterSetName = FileParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113421")] public class UpdateTypeDataCommand : UpdateData { #region dynamic type set @@ -37,7 +37,7 @@ private static bool HasBeenSpecified(object obj) private PSMemberTypes _memberType; private bool _isMemberTypeSet = false; /// - /// The member type of to be added + /// The member type of to be added. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNullOrEmpty] @@ -54,18 +54,20 @@ public PSMemberTypes MemberType _memberType = value; _isMemberTypeSet = true; } + get { return _memberType; } } private string _memberName; /// - /// The name of the new member + /// The name of the new member. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNullOrEmpty] public string MemberName { set { _memberName = value; } + get { return _memberName; } } @@ -78,6 +80,7 @@ public string MemberName public object Value { set { _value1 = value; } + get { return _value1; } } @@ -91,59 +94,62 @@ public object Value public object SecondValue { set { _value2 = value; } + get { return _value2; } } private Type _typeConverter; /// - /// The type converter to be added + /// The type converter to be added. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNull] public Type TypeConverter { set { _typeConverter = value; } + get { return _typeConverter; } } private Type _typeAdapter; /// - /// The type adapter to be added + /// The type adapter to be added. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNull] public Type TypeAdapter { set { _typeAdapter = value; } + get { return _typeAdapter; } } /// - /// SerializationMethod + /// SerializationMethod. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNullOrEmpty] public string SerializationMethod { set { _serializationMethod = value; } + get { return _serializationMethod; } } - /// - /// TargetTypeForDeserialization + /// TargetTypeForDeserialization. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNull] public Type TargetTypeForDeserialization { set { _targetTypeForDeserialization = value; } + get { return _targetTypeForDeserialization; } } - /// - /// SerializationDepth + /// SerializationDepth. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNull] @@ -151,48 +157,48 @@ public Type TargetTypeForDeserialization public int SerializationDepth { set { _serializationDepth = value; } + get { return _serializationDepth; } } - /// - /// DefaultDisplayProperty + /// DefaultDisplayProperty. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNullOrEmpty] public string DefaultDisplayProperty { set { _defaultDisplayProperty = value; } + get { return _defaultDisplayProperty; } } - /// - /// InheritPropertySerializationSet + /// InheritPropertySerializationSet. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNull] - public Nullable InheritPropertySerializationSet + public bool? InheritPropertySerializationSet { set { _inheritPropertySerializationSet = value; } + get { return _inheritPropertySerializationSet; } } - /// - /// StringSerializationSource + /// StringSerializationSource. /// [Parameter(ParameterSetName = DynamicTypeSet)] [ValidateNotNullOrEmpty] public string StringSerializationSource { set { _stringSerializationSource = value; } + get { return _stringSerializationSource; } } - /// - /// DefaultDisplayPropertySet + /// DefaultDisplayPropertySet. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")] [Parameter(ParameterSetName = DynamicTypeSet)] @@ -200,11 +206,12 @@ public string StringSerializationSource public string[] DefaultDisplayPropertySet { set { _defaultDisplayPropertySet = value; } + get { return _defaultDisplayPropertySet; } } /// - /// DefaultKeyPropertySet + /// DefaultKeyPropertySet. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")] [Parameter(ParameterSetName = DynamicTypeSet)] @@ -212,12 +219,12 @@ public string[] DefaultDisplayPropertySet public string[] DefaultKeyPropertySet { set { _defaultKeyPropertySet = value; } + get { return _defaultKeyPropertySet; } } - /// - /// PropertySerializationSet + /// PropertySerializationSet. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")] [Parameter(ParameterSetName = DynamicTypeSet)] @@ -225,6 +232,7 @@ public string[] DefaultKeyPropertySet public string[] PropertySerializationSet { set { _propertySerializationSet = value; } + get { return _propertySerializationSet; } } @@ -233,7 +241,7 @@ public string[] PropertySerializationSet private Type _targetTypeForDeserialization; private int _serializationDepth = int.MinValue; private string _defaultDisplayProperty; - private Nullable _inheritPropertySerializationSet; + private bool? _inheritPropertySerializationSet; // These members are represented as AliasProperty in types.ps1xml private string _stringSerializationSource; @@ -245,7 +253,7 @@ public string[] PropertySerializationSet private string _typeName; /// - /// The type name we want to update on + /// The type name we want to update on. /// [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = DynamicTypeSet)] [ArgumentToTypeNameTransformationAttribute()] @@ -253,18 +261,20 @@ public string[] PropertySerializationSet public string TypeName { set { _typeName = value; } + get { return _typeName; } } private bool _force = false; /// - /// True if we should overwrite a possibly existing member + /// True if we should overwrite a possibly existing member. /// [Parameter(ParameterSetName = DynamicTypeSet)] [Parameter(ParameterSetName = TypeDataSet)] public SwitchParameter Force { set { _force = value; } + get { return _force; } } @@ -274,20 +284,21 @@ public SwitchParameter Force private TypeData[] _typeData; /// - /// The TypeData instances + /// The TypeData instances. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")] [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = TypeDataSet)] public TypeData[] TypeData { set { _typeData = value; } + get { return _typeData; } } #endregion strong type data set /// - /// This method verify if the Type Table is shared and cannot be updated + /// This method verify if the Type Table is shared and cannot be updated. /// protected override void BeginProcessing() { @@ -299,7 +310,7 @@ protected override void BeginProcessing() } /// - /// This method implements the ProcessRecord method for update-typeData command + /// This method implements the ProcessRecord method for update-typeData command. /// protected override void ProcessRecord() { @@ -318,7 +329,7 @@ protected override void ProcessRecord() } /// - /// This method implements the EndProcessing method for update-typeData command + /// This method implements the EndProcessing method for update-typeData command. /// protected override void EndProcessing() { @@ -339,6 +350,7 @@ private void ProcessStrongTypeData() { continue; } + TypeData type = item.Copy(); // Set property IsOverride to be true if -Force parameter is specified @@ -389,14 +401,15 @@ private void ProcessStrongTypeData() #region dynamic type processing /// - /// Process the dynamic type update + /// Process the dynamic type update. /// private void ProcessDynamicType() { - if (String.IsNullOrWhiteSpace(_typeName)) + if (string.IsNullOrWhiteSpace(_typeName)) { ThrowTerminatingError(NewError("TargetTypeNameEmpty", UpdateDataStrings.TargetTypeNameEmpty, _typeName)); } + TypeData type = new TypeData(_typeName) { IsOverride = _force }; GetMembers(type.Members); @@ -405,6 +418,7 @@ private void ProcessDynamicType() { type.TypeConverter = _typeConverter; } + if (_typeAdapter != null) { type.TypeAdapter = _typeAdapter; @@ -414,36 +428,44 @@ private void ProcessDynamicType() { type.SerializationMethod = _serializationMethod; } + if (_targetTypeForDeserialization != null) { type.TargetTypeForDeserialization = _targetTypeForDeserialization; } + if (_serializationDepth != int.MinValue) { type.SerializationDepth = (uint)_serializationDepth; } + if (_defaultDisplayProperty != null) { type.DefaultDisplayProperty = _defaultDisplayProperty; } + if (_inheritPropertySerializationSet != null) { type.InheritPropertySerializationSet = _inheritPropertySerializationSet.Value; } + if (_stringSerializationSource != null) { type.StringSerializationSource = _stringSerializationSource; } + if (_defaultDisplayPropertySet != null) { PropertySetData defaultDisplayPropertySet = new PropertySetData(_defaultDisplayPropertySet); type.DefaultDisplayPropertySet = defaultDisplayPropertySet; } + if (_defaultKeyPropertySet != null) { PropertySetData defaultKeyPropertySet = new PropertySetData(_defaultKeyPropertySet); type.DefaultKeyPropertySet = defaultKeyPropertySet; } + if (_propertySerializationSet != null) { PropertySetData propertySerializationSet = new PropertySetData(_propertySerializationSet); @@ -498,7 +520,7 @@ private void ProcessDynamicType() } /// - /// Get the members for the TypeData + /// Get the members for the TypeData. /// /// private void GetMembers(Dictionary members) @@ -511,6 +533,7 @@ private void GetMembers(Dictionary members) { ThrowTerminatingError(NewError("MemberTypeIsMissing", UpdateDataStrings.MemberTypeIsMissing, null)); } + return; } @@ -553,7 +576,7 @@ private T GetParameterType(object sourceValue) private void EnsureMemberNameHasBeenSpecified() { - if (String.IsNullOrEmpty(_memberName)) + if (string.IsNullOrEmpty(_memberName)) { ThrowTerminatingError(NewError("MemberNameShouldBeSpecified", UpdateDataStrings.ShouldBeSpecified, null, "MemberName", _memberType)); } @@ -571,10 +594,11 @@ private void EnsureValue1NotNullOrEmpty() { if (_value1 is string) { - if (String.IsNullOrEmpty((string)_value1)) + if (string.IsNullOrEmpty((string)_value1)) { ThrowTerminatingError(NewError("ValueShouldBeSpecified", UpdateDataStrings.ShouldNotBeNull, null, "Value", _memberType)); } + return; } @@ -601,10 +625,10 @@ private void EnsureValue1AndValue2AreNotBothNull() } /// - /// Check if the TypeData instance contains no members + /// Check if the TypeData instance contains no members. /// /// - /// false if empty, true if not + /// False if empty, true if not. private bool EnsureTypeDataIsNotEmpty(TypeData typeData) { if (typeData.Members.Count == 0 && typeData.StandardMembers.Count == 0 @@ -616,6 +640,7 @@ private bool EnsureTypeDataIsNotEmpty(TypeData typeData) this.WriteError(NewError("TypeDataEmpty", UpdateDataStrings.TypeDataEmpty, null, typeData.TypeName)); return false; } + return true; } @@ -641,6 +666,7 @@ private AliasPropertyData GetAliasProperty() alias = new AliasPropertyData(_memberName, referencedName, type); return alias; } + alias = new AliasPropertyData(_memberName, referencedName); return alias; } @@ -712,7 +738,7 @@ private CodeMethodData GetCodeMethod() } /// - /// Generate error record + /// Generate error record. /// /// /// @@ -842,6 +868,7 @@ private void ProcessTypeFiles() RuntimeException rte = new RuntimeException(s); this.WriteError(new ErrorRecord(rte, "TypesXmlUpdateException", ErrorCategory.InvalidOperation, null)); } + errors = new ConcurrentBag(); } } @@ -858,11 +885,12 @@ private void ProcessTypeFiles() /// /// This class implements update-typeData command. /// - [Cmdlet(VerbsData.Update, "FormatData", SupportsShouldProcess = true, DefaultParameterSetName = FileParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113420")] + [Cmdlet(VerbsData.Update, "FormatData", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low, + DefaultParameterSetName = FileParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113420")] public class UpdateFormatDataCommand : UpdateData { /// - /// This method verify if the Format database manager is shared and cannot be updated + /// This method verify if the Format database manager is shared and cannot be updated. /// protected override void BeginProcessing() { @@ -874,7 +902,7 @@ protected override void BeginProcessing() } /// - /// This method implements the ProcessRecord method for update-FormatData command + /// This method implements the ProcessRecord method for update-FormatData command. /// protected override void ProcessRecord() { @@ -948,6 +976,7 @@ protected override void ProcessRecord() } } + var originalFormats = Context.InitialSessionState.Formats; try { // Always rebuild the format information @@ -985,14 +1014,17 @@ protected override void ProcessRecord() if (entries.Count > 0) { Context.FormatDBManager.UpdateDataBase(entries, this.Context.AuthorizationManager, this.Context.EngineHostInterface, false); - FormatAndTypeDataHelper.ThrowExceptionOnError( "ErrorsUpdatingFormats", + FormatAndTypeDataHelper.ThrowExceptionOnError("ErrorsUpdatingFormats", null, entries, - RunspaceConfigurationCategory.Formats); - } + FormatAndTypeDataHelper.Category.Formats); + } } catch (RuntimeException e) { + // revert Formats if there is a failure + Context.InitialSessionState.Formats.Clear(); + Context.InitialSessionState.Formats.Add(originalFormats); this.WriteError(new ErrorRecord(e, "FormatXmlUpdateException", ErrorCategory.InvalidOperation, null)); } } @@ -1004,7 +1036,7 @@ protected override void ProcessRecord() } /// - /// Remove-TypeData cmdlet + /// Remove-TypeData cmdlet. /// [Cmdlet(VerbsCommon.Remove, "TypeData", SupportsShouldProcess = true, DefaultParameterSetName = RemoveTypeDataSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=217038")] @@ -1015,8 +1047,9 @@ public class RemoveTypeDataCommand : PSCmdlet private const string RemoveTypeDataSet = "RemoveTypeDataSet"; private string _typeName; + /// - /// The target type to remove + /// The target type to remove. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = RemoveTypeSet)] [ArgumentToTypeNameTransformationAttribute()] @@ -1024,12 +1057,14 @@ public class RemoveTypeDataCommand : PSCmdlet public string TypeName { get { return _typeName; } + set { _typeName = value; } } private string[] _typeFiles; + /// - /// The type xml file to remove from the cache + /// The type xml file to remove from the cache. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")] [Parameter(Mandatory = true, ParameterSetName = RemoveFileSet)] @@ -1037,17 +1072,20 @@ public string TypeName public string[] Path { get { return _typeFiles; } + set { _typeFiles = value; } } private TypeData _typeData; + /// - /// The TypeData to remove + /// The TypeData to remove. /// [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = RemoveTypeDataSet)] public TypeData TypeData { get { return _typeData; } + set { _typeData = value; } } @@ -1065,7 +1103,7 @@ private static void ConstructFileToIndexMap(string fileName, int index, Dictiona } /// - /// This method implements the ProcessRecord method for Remove-TypeData command + /// This method implements the ProcessRecord method for Remove-TypeData command. /// protected override void ProcessRecord() { @@ -1161,14 +1199,15 @@ protected override void ProcessRecord() } else { - if (String.IsNullOrWhiteSpace(_typeName)) + if (string.IsNullOrWhiteSpace(_typeName)) { ThrowTerminatingError(NewError("TargetTypeNameEmpty", UpdateDataStrings.TargetTypeNameEmpty, _typeName)); } + typeNameToRemove = _typeName; } - Dbg.Assert(!String.IsNullOrEmpty(typeNameToRemove), "TypeNameToRemove should be not null and not empty at this point"); + Dbg.Assert(!string.IsNullOrEmpty(typeNameToRemove), "TypeNameToRemove should be not null and not empty at this point"); TypeData type = new TypeData(typeNameToRemove); string removeTypeFormattedTarget = string.Format(CultureInfo.InvariantCulture, removeTypeTarget, typeNameToRemove); @@ -1208,7 +1247,7 @@ protected override void ProcessRecord() } /// - /// This method implements the EndProcessing method for Remove-TypeData command + /// This method implements the EndProcessing method for Remove-TypeData command. /// protected override void EndProcessing() { @@ -1228,7 +1267,7 @@ private ErrorRecord NewError(string errorId, string template, object targetObjec } /// - /// Get-TypeData cmdlet + /// Get-TypeData cmdlet. /// [Cmdlet(VerbsCommon.Get, "TypeData", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=217033")] [OutputType(typeof(System.Management.Automation.PSObject))] @@ -1237,8 +1276,7 @@ public class GetTypeDataCommand : PSCmdlet private WildcardPattern[] _filter; /// - /// Get Formatting information only for the specified - /// typename + /// Get Formatting information only for the specified typename. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [ValidateNotNullOrEmpty] @@ -1257,7 +1295,7 @@ private void ValidateTypeName() var exception = new InvalidOperationException(UpdateDataStrings.TargetTypeNameEmpty); foreach (string typeName in TypeName) { - if (String.IsNullOrWhiteSpace(typeName)) + if (string.IsNullOrWhiteSpace(typeName)) { WriteError( new ErrorRecord( @@ -1275,6 +1313,7 @@ private void ValidateTypeName() { typeNameInUse = type.FullName; } + typeNames.Add(typeNameInUse); } @@ -1287,8 +1326,7 @@ private void ValidateTypeName() } /// - /// Takes out the content from the database and writes them - /// out + /// Takes out the content from the database and writes it out. /// protected override void ProcessRecord() { @@ -1321,7 +1359,7 @@ protected override void ProcessRecord() /// To make it easier to specify a TypeName, we add an ArgumentTransformationAttribute here. /// * string: return the string /// * Type: return the Type.ToString() - /// * instance: return instance.GetType().ToString() + /// * instance: return instance.GetType().ToString() . /// internal sealed class ArgumentToTypeNameTransformationAttribute : ArgumentTransformationAttribute { @@ -1356,4 +1394,3 @@ public override object Transform(EngineIntrinsics engineIntrinsics, object input } } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs index c5988b3a4500..6e167f61825a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs @@ -1,21 +1,19 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Text; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; - [module: SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope = "type", Target = "Microsoft.PowerShell.Commands.ByteCollection")] namespace Microsoft.PowerShell.Commands { /// - /// Don't use! The API is obsolete! + /// Don't use! The API is obsolete!. /// [Obsolete("This class is included in this SDK for completeness only. The members of this class cannot be used directly, nor should this class be used to derive other classes.", true)] public enum TextEncodingType @@ -62,8 +60,9 @@ public enum TextEncodingType } /// - /// Utility class to contain resources for the Microsoft.PowerShell.Utility module + /// Utility class to contain resources for the Microsoft.PowerShell.Utility module. /// + [Obsolete("This class is obsolete", true)] public static class UtilityResources { /// @@ -101,12 +100,30 @@ public class ByteCollection /// The Offset address to be used while displaying the bytes in the collection. /// Underlying bytes stored in the collection. /// Indicates the path of the file whose contents are wrapped in the ByteCollection. - public ByteCollection(UInt32 offset, Byte[] value, string path) + [Obsolete("The constructor is deprecated.", true)] + public ByteCollection(UInt32 offset, byte[] value, string path) { - this.Offset = offset; - _initialOffSet = offset; - this.Bytes = value; - this.Path = path; + Offset64 = offset; + Bytes = value; + Path = path; + } + + /// + /// Initializes a new instance of ByteCollection. + /// + /// The Offset address to be used while displaying the bytes in the collection. + /// Underlying bytes stored in the collection. + /// Indicates the path of the file whose contents are wrapped in the ByteCollection. + public ByteCollection(UInt64 offset, byte[] value, string path) + { + if (value == null) + { + throw PSTraceSource.NewArgumentNullException("value"); + } + + Offset64 = offset; + Bytes = value; + Path = path; } /// @@ -114,36 +131,78 @@ public ByteCollection(UInt32 offset, Byte[] value, string path) /// /// The Offset address to be used while displaying the bytes in the collection. /// Underlying bytes stored in the collection. - public ByteCollection(UInt32 offset, Byte[] value) + [Obsolete("The constructor is deprecated.", true)] + public ByteCollection(UInt32 offset, byte[] value) { - this.Offset = offset; - _initialOffSet = offset; - this.Bytes = value; + if (value == null) + { + throw PSTraceSource.NewArgumentNullException("value"); + } + + Offset64 = offset; + Bytes = value; } /// /// ByteCollection constructor. /// + /// The Offset address to be used while displaying the bytes in the collection. /// Underlying bytes stored in the collection. - public ByteCollection(Byte[] value) + public ByteCollection(UInt64 offset, byte[] value) { - this.Bytes = value; + if (value == null) + { + throw PSTraceSource.NewArgumentNullException("value"); + } + + Offset64 = offset; + Bytes = value; } /// - /// The Offset address to be used while displaying the bytes in the collection. + /// ByteCollection constructor. /// - public UInt32 Offset { get; private set; } - private UInt32 _initialOffSet = 0; + /// Underlying bytes stored in the collection. + public ByteCollection(byte[] value) + { + if (value == null) + { + throw PSTraceSource.NewArgumentNullException("value"); + } + + Bytes = value; + } + + /// + /// Gets the Offset address to be used while displaying the bytes in the collection. + /// + [Obsolete("The property is deprecated, please use Offset64 instead.", true)] + public UInt32 Offset + { + get + { + return (UInt32)Offset64; + } + + private set + { + Offset64 = value; + } + } + + /// + /// Gets the Offset address to be used while displaying the bytes in the collection. + /// + public UInt64 Offset64 { get; private set; } /// - /// Underlying bytes stored in the collection. + /// Gets underlying bytes stored in the collection. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public Byte[] Bytes { get; private set; } + public byte[] Bytes { get; private set; } /// - /// Indicates the path of the file whose contents are wrapped in the ByteCollection. + /// Gets the path of the file whose contents are wrapped in the ByteCollection. /// public string Path { get; private set; } @@ -153,20 +212,28 @@ public ByteCollection(Byte[] value) /// public override string ToString() { - StringBuilder result = new StringBuilder(); - StringBuilder nextLine = new StringBuilder(); - StringBuilder asciiEnd = new StringBuilder(); + const int BytesPerLine = 16; + const string LineFormat = "{0:X20} "; + + // '20 + 3' comes from format "{0:X20} ". + // '20' comes from '[Uint64]::MaxValue.ToString().Length'. + StringBuilder nextLine = new StringBuilder(20 + 3 + (BytesPerLine * 3)); + StringBuilder asciiEnd = new StringBuilder(BytesPerLine); + + // '+1' comes from 'result.Append(nextLine.ToString() + " " + asciiEnd.ToString());' below. + StringBuilder result = new StringBuilder(nextLine.Capacity + asciiEnd.Capacity + 1); if (Bytes.Length > 0) { - UInt32 charCounter = 0; + Int64 charCounter = 0; // ToString() in invoked thrice by the F&O for the same content. // Hence making sure that Offset is not getting incremented thrice for the same bytes being displayed. - Offset = _initialOffSet; + var currentOffset = Offset64; + + nextLine.AppendFormat(CultureInfo.InvariantCulture, LineFormat, currentOffset); - nextLine.AppendFormat("{0:X2} ", CultureInfo.InvariantCulture.TextInfo.ToUpper(Convert.ToString(Offset, 16)).PadLeft(8, '0')); - foreach (Byte currentByte in Bytes) + foreach (byte currentByte in Bytes) { // Display each byte, in 2-digit hexadecimal, and add that to the left-hand side. nextLine.AppendFormat("{0:X2} ", currentByte); @@ -181,43 +248,44 @@ public override string ToString() { asciiEnd.Append('.'); } + charCounter++; // If we've hit the end of a line, combine the right half with the // left half, and start a new line. - if ((charCounter % 16) == 0) + if ((charCounter % BytesPerLine) == 0) { - result.Append(nextLine.ToString() + " " + asciiEnd.ToString()); + result.Append(nextLine).Append(' ').Append(asciiEnd); nextLine.Clear(); asciiEnd.Clear(); - Offset += 0x10; - nextLine.AppendFormat("{0:X2} ", CultureInfo.InvariantCulture.TextInfo.ToUpper(Convert.ToString(Offset, 16)).PadLeft(8, '0')); + currentOffset += BytesPerLine; + nextLine.AppendFormat(CultureInfo.InvariantCulture, LineFormat, currentOffset); // Adding a newline to support long inputs strings flowing through InputObject parameterset. if ((charCounter <= Bytes.Length) && string.IsNullOrEmpty(this.Path)) { - result.Append("\r\n"); + result.AppendLine(); } } } // At the end of the file, we might not have had the chance to output - // the end of the line yet. Only do this if we didn't exit on the 16-byte + // the end of the line yet. Only do this if we didn't exit on the 16-byte // boundary, though. if ((charCounter % 16) != 0) { while ((charCounter % 16) != 0) { - nextLine.Append(" "); + nextLine.Append(' ', 3); asciiEnd.Append(' '); charCounter++; } - result.Append(nextLine.ToString() + " " + asciiEnd.ToString()); + + result.Append(nextLine).Append(' ').Append(asciiEnd); } } return result.ToString(); } } -} // namespace Microsoft.PowerShell.Commands - +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs index e596e0cb64a8..08dd6c311be7 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -13,9 +12,7 @@ namespace Microsoft.PowerShell.Commands { /// /// Base class for all variable commands. - /// - /// Because -Scope is defined in VariableCommandBase, all derived commands - /// must implement -Scope. + /// Because -Scope is defined in VariableCommandBase, all derived commands must implement -Scope. /// public abstract class VariableCommandBase : PSCmdlet @@ -32,9 +29,8 @@ public abstract class VariableCommandBase : PSCmdlet #endregion parameters /// - /// The Include parameter for all the variable commands + /// The Include parameter for all the variable commands. /// - /// protected string[] IncludeFilters { get @@ -46,17 +42,18 @@ protected string[] IncludeFilters { if (value == null) { - value = new string[0]; + value = Array.Empty(); } + _include = value; } } - private string[] _include = new string[0]; + + private string[] _include = Array.Empty(); /// - /// The Exclude parameter for all the variable commands + /// The Exclude parameter for all the variable commands. /// - /// protected string[] ExcludeFilters { get @@ -68,13 +65,14 @@ protected string[] ExcludeFilters { if (value == null) { - value = new string[0]; + value = Array.Empty(); } + _exclude = value; } } - private string[] _exclude = new string[0]; + private string[] _exclude = Array.Empty(); #region helpers @@ -82,37 +80,30 @@ protected string[] ExcludeFilters /// Gets the matching variable for the specified name, using the /// Include, Exclude, and Scope parameters defined in the base class. /// - /// /// /// The name or pattern of the variables to retrieve. /// - /// /// - /// The scope to do the lookup in. If null or empty the normal scoping - /// rules apply. + /// The scope to do the lookup in. If null or empty the normal scoping rules apply. /// - /// /// /// True is returned if a variable exists of the given name but was filtered /// out via globbing, include, or exclude. /// - /// /// /// If true, don't report errors when trying to access private variables. /// - /// /// /// A collection of the variables matching the name, include, and exclude /// pattern in the specified scope. /// - /// internal List GetMatchingVariables(string name, string lookupScope, out bool wasFiltered, bool quiet) { wasFiltered = false; List result = new List(); - if (String.IsNullOrEmpty(name)) + if (string.IsNullOrEmpty(name)) { name = "*"; } @@ -166,7 +157,7 @@ internal List GetMatchingVariables(string name, string lookupScope, // view. IDictionary variableTable = null; - if (String.IsNullOrEmpty(lookupScope)) + if (string.IsNullOrEmpty(lookupScope)) { variableTable = SessionState.Internal.GetVariableTable(); } @@ -223,6 +214,7 @@ internal List GetMatchingVariables(string name, string lookupScope, } } } + result.Add(entry.Value); } else @@ -238,13 +230,13 @@ internal List GetMatchingVariables(string name, string lookupScope, } } } + return result; } #endregion helpers } - /// /// Implements get-variable command. /// @@ -255,7 +247,7 @@ public class GetVariableCommand : VariableCommandBase #region parameters /// - /// Name of the PSVariable + /// Name of the PSVariable. /// [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty()] @@ -272,12 +264,12 @@ public string[] Name { value = new string[] { "*" }; } + _name = value; } } - private string[] _name = new string[] { "*" }; - + private string[] _name = new string[] { "*" }; /// /// Output only the value(s) of the requested variable(s). @@ -289,18 +281,18 @@ public SwitchParameter ValueOnly { return _valueOnly; } + set { _valueOnly = value; } } - private bool _valueOnly; + private bool _valueOnly; /// - /// The Include parameter for all the variable commands + /// The Include parameter for all the variable commands. /// - /// [Parameter] public string[] Include { @@ -316,9 +308,8 @@ public string[] Include } /// - /// The Exclude parameter for all the variable commands + /// The Exclude parameter for all the variable commands. /// - /// [Parameter] public string[] Exclude { @@ -384,37 +375,36 @@ protected override void ProcessRecord() } /// - /// Class implementing new-variable command + /// Class implementing new-variable command. /// - [Cmdlet(VerbsCommon.New, "Variable", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113361")] + [Cmdlet(VerbsCommon.New, "Variable", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low, + HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113361")] public sealed class NewVariableCommand : VariableCommandBase { #region parameters /// - /// Name of the PSVariable + /// Name of the PSVariable. /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true, Mandatory = true)] public string Name { get; set; } /// - /// Value of the PSVariable + /// Value of the PSVariable. /// [Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public object Value { get; set; } /// - /// Description of the variable + /// Description of the variable. /// [Parameter] public string Description { get; set; } - /// /// The options for the variable to specify if the variable should /// be ReadOnly, Constant, and/or Private. /// - /// [Parameter] public ScopedItemOptions Option { get; set; } = ScopedItemOptions.None; @@ -434,6 +424,7 @@ public SessionStateEntryVisibility Visibility _visibility = value; } } + private SessionStateEntryVisibility? _visibility; /// @@ -452,6 +443,7 @@ public SwitchParameter Force _force = value; } } + private bool _force; /// @@ -464,11 +456,13 @@ public SwitchParameter PassThru { return _passThru; } + set { _passThru = value; } } + private bool _passThru; #endregion parameters @@ -478,7 +472,6 @@ public SwitchParameter PassThru /// take the place of the Value parameter if none was specified on the /// command line. /// - /// protected override void ProcessRecord() { // If Force is not specified, see if the variable already exists @@ -488,7 +481,7 @@ protected override void ProcessRecord() if (!Force) { PSVariable varFound = null; - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { varFound = SessionState.PSVariable.GetAtScope(Name, "local"); @@ -540,7 +533,7 @@ protected override void ProcessRecord() try { - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { SessionState.Internal.NewVariable(newVariable, Force); } @@ -571,12 +564,11 @@ protected override void ProcessRecord() WriteObject(newVariable); } } - } // ProcessRecord - } // NewVariableCommand - + } + } /// - /// This class implements set-variable command + /// This class implements set-variable command. /// [Cmdlet(VerbsCommon.Set, "Variable", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113401")] [OutputType(typeof(PSVariable))] @@ -585,21 +577,20 @@ public sealed class SetVariableCommand : VariableCommandBase #region parameters /// - /// Name of the PSVariable(s) to set + /// Name of the PSVariable(s) to set. /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true, Mandatory = true)] public string[] Name { get; set; } /// - /// Value of the PSVariable + /// Value of the PSVariable. /// [Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public object Value { get; set; } = AutomationNull.Value; /// - /// The Include parameter for all the variable commands + /// The Include parameter for all the variable commands. /// - /// [Parameter] public string[] Include { @@ -615,9 +606,8 @@ public string[] Include } /// - /// The Exclude parameter for all the variable commands + /// The Exclude parameter for all the variable commands. /// - /// [Parameter] public string[] Exclude { @@ -633,17 +623,15 @@ public string[] Exclude } /// - /// Description of the variable + /// Description of the variable. /// [Parameter] public string Description { get; set; } - /// /// The options for the variable to specify if the variable should /// be ReadOnly, Constant, and/or Private. /// - /// [Parameter] public ScopedItemOptions Option { @@ -651,12 +639,14 @@ public ScopedItemOptions Option { return (ScopedItemOptions)_options; } + set { _options = value; } } - private Nullable _options; + + private ScopedItemOptions? _options; /// /// Force the operation to make the best attempt at setting the variable. @@ -674,6 +664,7 @@ public SwitchParameter Force _force = value; } } + private bool _force; /// @@ -692,8 +683,8 @@ public SessionStateEntryVisibility Visibility _visibility = value; } } - private SessionStateEntryVisibility? _visibility; + private SessionStateEntryVisibility? _visibility; /// /// The variable object should be passed down the pipeline. @@ -705,11 +696,13 @@ public SwitchParameter PassThru { return _passThru; } + set { _passThru = value; } } + private bool _passThru; private bool _nameIsFormalParameter; @@ -717,8 +710,7 @@ public SwitchParameter PassThru #endregion parameters /// - /// Checks to see if the name and value parameters were - /// bound as formal parameters. + /// Checks to see if the name and value parameters were bound as formal parameters. /// protected override void BeginProcessing() { @@ -742,7 +734,6 @@ protected override void BeginProcessing() /// If name is not a formal parameter, then set /// the variable each time ProcessRecord is called. /// - /// protected override void ProcessRecord() { if (_nameIsFormalParameter && _valueIsFormalParameter) @@ -758,6 +749,7 @@ protected override void ProcessRecord() { _valueList = new ArrayList(); } + _valueList.Add(Value); } } @@ -766,6 +758,7 @@ protected override void ProcessRecord() SetVariable(Name, Value); } } + private ArrayList _valueList; /// @@ -808,15 +801,12 @@ protected override void EndProcessing() /// /// Sets the variables of the given names to the specified value. /// - /// /// /// The name(s) of the variables to set. /// - /// /// /// The value to set the variable to. /// - /// private void SetVariable(string[] varNames, object varValue) { CommandOrigin origin = MyInvocation.CommandOrigin; @@ -829,7 +819,7 @@ private void SetVariable(string[] varNames, object varValue) bool wasFiltered = false; - if (!String.IsNullOrEmpty(Scope)) + if (!string.IsNullOrEmpty(Scope)) { // We really only need to find matches if the scope was specified. // If the scope wasn't specified then we need to create the @@ -862,8 +852,8 @@ private void SetVariable(string[] varNames, object varValue) { ScopedItemOptions newOptions = ScopedItemOptions.None; - if (!String.IsNullOrEmpty(Scope) && - String.Equals("private", Scope, StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(Scope) && + string.Equals("private", Scope, StringComparison.OrdinalIgnoreCase)) { newOptions = ScopedItemOptions.Private; } @@ -887,8 +877,9 @@ private void SetVariable(string[] varNames, object varValue) if (Description == null) { - Description = String.Empty; + Description = string.Empty; } + varToSet.Description = Description; // If visibility was specified, set it on the variable @@ -905,7 +896,7 @@ private void SetVariable(string[] varNames, object varValue) { object result = null; - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { result = SessionState.Internal.SetVariable(varToSet, Force, origin); @@ -974,8 +965,17 @@ private void SetVariable(string[] varNames, object varValue) if (varValue != AutomationNull.Value) { matchingVariable.Value = varValue; - } + if (Context.LanguageMode == PSLanguageMode.ConstrainedLanguage) + { + // In 'ConstrainedLanguage' we want to monitor untrusted values assigned to 'Global:' variables + // and 'Script:' variables, because they may be set from 'ConstrainedLanguage' environment and + // referenced within trusted script block, and thus result in security issues. + // Here we are setting the value of an existing variable and don't know what scope this variable + // is from, so we mark the value as untrusted, regardless of the scope. + ExecutionContext.MarkObjectAsUntrusted(matchingVariable.Value); + } + } if (Description != null) { @@ -1027,11 +1027,11 @@ private void SetVariable(string[] varNames, object varValue) } } } - } // ProcessRecord - } // SetVariableCommand + } + } /// - /// The Remove-Variable cmdlet implementation + /// The Remove-Variable cmdlet implementation. /// [Cmdlet(VerbsCommon.Remove, "Variable", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113380")] public sealed class RemoveVariableCommand : VariableCommandBase @@ -1039,15 +1039,14 @@ public sealed class RemoveVariableCommand : VariableCommandBase #region parameters /// - /// Name of the PSVariable(s) to set + /// Name of the PSVariable(s) to set. /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true, Mandatory = true)] public string[] Name { get; set; } /// - /// The Include parameter for all the variable commands + /// The Include parameter for all the variable commands. /// - /// [Parameter] public string[] Include { @@ -1063,9 +1062,8 @@ public string[] Include } /// - /// The Exclude parameter for all the variable commands + /// The Exclude parameter for all the variable commands. /// - /// [Parameter] public string[] Exclude { @@ -1081,9 +1079,8 @@ public string[] Exclude } /// - /// If true, the variable is removed even if it is ReadOnly + /// If true, the variable is removed even if it is ReadOnly. /// - /// [Parameter] public SwitchParameter Force { @@ -1091,19 +1088,20 @@ public SwitchParameter Force { return _force; } + set { _force = value; } } + private bool _force; #endregion parameters /// - /// Removes the matching variables from the specified scope + /// Removes the matching variables from the specified scope. /// - /// protected override void ProcessRecord() { // Removal of variables only happens in the local scope if the @@ -1114,7 +1112,6 @@ protected override void ProcessRecord() Scope = "local"; } - foreach (string varName in Name) { // First look for existing variables to set. @@ -1155,7 +1152,7 @@ protected override void ProcessRecord() { try { - if (String.IsNullOrEmpty(Scope)) + if (string.IsNullOrEmpty(Scope)) { SessionState.Internal.RemoveVariable(matchingVariable, _force); } @@ -1181,11 +1178,11 @@ protected override void ProcessRecord() } } } - } // ProcessRecord - } // RemoveVariableCommand + } + } /// - /// This class implements set-variable command + /// This class implements set-variable command. /// [Cmdlet(VerbsCommon.Clear, "Variable", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113285")] [OutputType(typeof(PSVariable))] @@ -1194,15 +1191,14 @@ public sealed class ClearVariableCommand : VariableCommandBase #region parameters /// - /// Name of the PSVariable(s) to set + /// Name of the PSVariable(s) to set. /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true, Mandatory = true)] public string[] Name { get; set; } /// - /// The Include parameter for all the variable commands + /// The Include parameter for all the variable commands. /// - /// [Parameter] public string[] Include { @@ -1218,9 +1214,8 @@ public string[] Include } /// - /// The Exclude parameter for all the variable commands + /// The Exclude parameter for all the variable commands. /// - /// [Parameter] public string[] Exclude { @@ -1251,6 +1246,7 @@ public SwitchParameter Force _force = value; } } + private bool _force; /// @@ -1263,19 +1259,20 @@ public SwitchParameter PassThru { return _passThru; } + set { _passThru = value; } } + private bool _passThru; #endregion parameters /// - /// The implementation of the Clear-Variable command + /// The implementation of the Clear-Variable command. /// - /// protected override void ProcessRecord() { foreach (string varName in Name) @@ -1359,17 +1356,15 @@ protected override void ProcessRecord() } } } - } // ProcessRecord + } /// /// Clears the value of the variable using the PSVariable instance if the scope /// was specified or using standard variable lookup if the scope was not specified. /// - /// /// /// The variable that matched the name parameter(s). /// - /// private PSVariable ClearValue(PSVariable matchingVariable) { PSVariable result = matchingVariable; @@ -1382,8 +1377,8 @@ private PSVariable ClearValue(PSVariable matchingVariable) SessionState.PSVariable.Set(matchingVariable.Name, null); result = SessionState.PSVariable.Get(matchingVariable.Name); } + return result; } - } // ClearVariableCommand + } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WaitEventCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WaitEventCommand.cs index a66bda09d81a..5ce7f331425f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WaitEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WaitEventCommand.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; @@ -18,7 +17,7 @@ public class WaitEventCommand : PSCmdlet #region parameters /// - /// An identifier for this event subscription + /// An identifier for this event subscription. /// [Parameter(Position = 0, ValueFromPipelineByPropertyName = true)] public string SourceIdentifier @@ -27,12 +26,14 @@ public string SourceIdentifier { return _sourceIdentifier; } + set { _sourceIdentifier = value; _matchPattern = WildcardPattern.Get(value, WildcardOptions.IgnoreCase); } } + private string _sourceIdentifier = null; /// @@ -48,22 +49,24 @@ public int Timeout { return _timeoutInSeconds; } + set { _timeoutInSeconds = value; } } + private int _timeoutInSeconds = -1; // -1: infinite, this default is to wait for as long as it takes. #endregion parameters private AutoResetEvent _eventArrived = new AutoResetEvent(false); private PSEventArgs _receivedEvent = null; - private Object _receivedEventLock = new Object(); + private object _receivedEventLock = new Object(); private WildcardPattern _matchPattern; /// - /// Wait for the event to arrive + /// Wait for the event to arrive. /// protected override void ProcessRecord() { @@ -102,7 +105,7 @@ protected override void ProcessRecord() } /// - /// Handle Control-C + /// Handle Control-C. /// protected override void StopProcessing() { @@ -123,7 +126,6 @@ private void ReceivedEvents_PSEventReceived(Object sender, PSEventArgs e) } } - // Go through all the received events. If one matches the subscription identifier, // break. private void ScanEventQueue() @@ -158,4 +160,4 @@ private void NotifyEvent(PSEventArgs e) } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs index 22709a2bc999..664c3d69d465 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs @@ -1,33 +1,68 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Management.Automation; using System.Net; -using System.IO; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net.Http; namespace Microsoft.PowerShell.Commands { /// - /// Response object for html content without DOM parsing + /// Response object for html content without DOM parsing. /// - public partial class BasicHtmlWebResponseObject : WebResponseObject + public class BasicHtmlWebResponseObject : WebResponseObject { + #region Private Fields + + private static Regex s_attribNameValueRegex; + private static Regex s_attribsRegex; + private static Regex s_imageRegex; + private static Regex s_inputFieldRegex; + private static Regex s_linkRegex; + private static Regex s_tagRegex; + + #endregion Private Fields + + #region Constructors + + /// + /// Constructor for BasicHtmlWebResponseObject. + /// + /// + public BasicHtmlWebResponseObject(HttpResponseMessage response) + : this(response, null) + { } + + /// + /// Constructor for HtmlWebResponseObject with memory stream. + /// + /// + /// + public BasicHtmlWebResponseObject(HttpResponseMessage response, Stream contentStream) + : base(response, contentStream) + { + EnsureHtmlParser(); + InitializeContent(); + InitializeRawContent(response); + } + + #endregion Constructors + #region Properties /// - /// gets or protected sets the Content property + /// Gets the Content property. /// public new string Content { get; private set; } /// - /// Gets the Encoding that was used to decode the Content + /// Gets the Encoding that was used to decode the Content. /// /// /// The Encoding used to decode the Content; otherwise, a null reference if the content is not text. @@ -37,7 +72,7 @@ public partial class BasicHtmlWebResponseObject : WebResponseObject private WebCmdletElementCollection _inputFields; /// - /// gets the Fields property + /// Gets the Fields property. /// public WebCmdletElementCollection InputFields { @@ -64,7 +99,7 @@ public WebCmdletElementCollection InputFields private WebCmdletElementCollection _links; /// - /// gets the Links property + /// Gets the Links property. /// public WebCmdletElementCollection Links { @@ -91,7 +126,7 @@ public WebCmdletElementCollection Links private WebCmdletElementCollection _images; /// - /// gets the Images property + /// Gets the Images property. /// public WebCmdletElementCollection Images { @@ -117,18 +152,45 @@ public WebCmdletElementCollection Images #endregion Properties - #region Private Fields + #region Methods - private static Regex s_tagRegex; - private static Regex s_attribsRegex; - private static Regex s_attribNameValueRegex; - private static Regex s_inputFieldRegex; - private static Regex s_linkRegex; - private static Regex s_imageRegex; + /// + /// Reads the response content from the web response. + /// + protected void InitializeContent() + { + string contentType = ContentHelper.GetContentType(BaseResponse); + if (ContentHelper.IsText(contentType)) + { + Encoding encoding = null; + // fill the Content buffer + string characterSet = WebResponseHelper.GetCharacterSet(BaseResponse); - #endregion Private Fields + if (string.IsNullOrEmpty(characterSet) && ContentHelper.IsJson(contentType)) + { + characterSet = Encoding.UTF8.HeaderName; + } - #region Methods + this.Content = StreamHelper.DecodeStream(RawContentStream, characterSet, out encoding); + this.Encoding = encoding; + } + else + { + this.Content = string.Empty; + } + } + + private PSObject CreateHtmlObject(string html, string tagName) + { + PSObject elementObject = new PSObject(); + + elementObject.Properties.Add(new PSNoteProperty("outerHTML", html)); + elementObject.Properties.Add(new PSNoteProperty("tagName", tagName)); + + ParseAttributes(html, elementObject); + + return elementObject; + } private void EnsureHtmlParser() { @@ -164,21 +226,16 @@ private void EnsureHtmlParser() if (s_imageRegex == null) { - s_imageRegex = new Regex(@"]*>", + s_imageRegex = new Regex(@"]*>", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled); } } - private PSObject CreateHtmlObject(string html, string tagName) + private void InitializeRawContent(HttpResponseMessage baseResponse) { - PSObject elementObject = new PSObject(); - - elementObject.Properties.Add(new PSNoteProperty("outerHTML", html)); - elementObject.Properties.Add(new PSNoteProperty("tagName", tagName)); - - ParseAttributes(html, elementObject); - - return elementObject; + StringBuilder raw = ContentHelper.GetRawContentHeader(baseResponse); + raw.Append(Content); + this.RawContent = raw.ToString(); } private void ParseAttributes(string outerHtml, PSObject elementObject) @@ -223,70 +280,6 @@ private void ParseAttributes(string outerHtml, PSObject elementObject) } } - /// - /// Reads the response content from the web response. - /// - protected void InitializeContent() - { - string contentType = ContentHelper.GetContentType(BaseResponse); - if (ContentHelper.IsText(contentType)) - { - Encoding encoding = null; - // fill the Content buffer - string characterSet = WebResponseHelper.GetCharacterSet(BaseResponse); - this.Content = StreamHelper.DecodeStream(RawContentStream, characterSet, out encoding); - this.Encoding = encoding; - } - else - { - this.Content = string.Empty; - } - } - - #endregion Methods - } - - // TODO: Merge Partials - - // - /// Response object for html content without DOM parsing - /// - public partial class BasicHtmlWebResponseObject : WebResponseObject - { - #region Constructors - - /// - /// Constructor for BasicHtmlWebResponseObject - /// - /// - public BasicHtmlWebResponseObject(HttpResponseMessage response) - : this(response, null) - { } - - /// - /// Constructor for HtmlWebResponseObject with memory stream - /// - /// - /// - public BasicHtmlWebResponseObject(HttpResponseMessage response, Stream contentStream) - : base(response, contentStream) - { - EnsureHtmlParser(); - InitializeContent(); - InitializeRawContent(response); - } - - #endregion Constructors - - #region Methods - - private void InitializeRawContent(HttpResponseMessage baseResponse) - { - StringBuilder raw = ContentHelper.GetRawContentHeader(baseResponse); - raw.Append(Content); - this.RawContent = raw.ToString(); - } - #endregion Methods } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs index 8bc5546b181c..98d5a73d328a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs @@ -1,47 +1,51 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; -using System.Text; -using Microsoft.Win32; using System.Linq; +using System.Management.Automation; using System.Net.Http; using System.Net.Http.Headers; +using System.Text; + +using Microsoft.Win32; namespace Microsoft.PowerShell.Commands { - internal static partial class ContentHelper + internal static class ContentHelper { #region Constants - // used to split contentType arguments - private static readonly char[] s_contentTypeParamSeparator = { ';' }; - // default codepage encoding for web content. See RFC 2616. private const string _defaultCodePage = "ISO-8859-1"; #endregion Constants + #region Fields + + // used to split contentType arguments + private static readonly char[] s_contentTypeParamSeparator = { ';' }; + + #endregion Fields + #region Internal Methods - internal static bool IsText(string contentType) + internal static string GetContentType(HttpResponseMessage response) { - contentType = GetContentTypeSignature(contentType); - return CheckIsText(contentType); + // ContentType may not exist in response header. Return null if not. + return response.Content.Headers.ContentType?.MediaType; } - internal static bool IsXml(string contentType) + internal static Encoding GetDefaultEncoding() { - contentType = GetContentTypeSignature(contentType); - return CheckIsXml(contentType); + return GetEncodingOrDefault((string)null); } - internal static bool IsJson(string contentType) + internal static Encoding GetEncoding(HttpResponseMessage response) { - contentType = GetContentTypeSignature(contentType); - return CheckIsJson(contentType); + // ContentType may not exist in response header. + string charSet = response.Content.Headers.ContentType?.CharSet; + return GetEncodingOrDefault(charSet); } internal static Encoding GetEncodingOrDefault(string characterSet) @@ -63,27 +67,93 @@ internal static Encoding GetEncodingOrDefault(string characterSet) return encoding; } - internal static Encoding GetDefaultEncoding() + internal static StringBuilder GetRawContentHeader(HttpResponseMessage response) { - return GetEncodingOrDefault((string)null); + StringBuilder raw = new StringBuilder(); + + string protocol = WebResponseHelper.GetProtocol(response); + if (!string.IsNullOrEmpty(protocol)) + { + int statusCode = WebResponseHelper.GetStatusCode(response); + string statusDescription = WebResponseHelper.GetStatusDescription(response); + raw.AppendFormat("{0} {1} {2}", protocol, statusCode, statusDescription); + raw.AppendLine(); + } + + HttpHeaders[] headerCollections = + { + response.Headers, + response.Content == null ? null : response.Content.Headers + }; + + foreach (var headerCollection in headerCollections) + { + if (headerCollection == null) + { + continue; + } + + foreach (var header in headerCollection) + { + // Headers may have multiple entries with different values + foreach (var headerValue in header.Value) + { + raw.Append(header.Key); + raw.Append(": "); + raw.Append(headerValue); + raw.AppendLine(); + } + } + } + + raw.AppendLine(); + return raw; + } + + internal static bool IsJson(string contentType) + { + contentType = GetContentTypeSignature(contentType); + return CheckIsJson(contentType); + } + + internal static bool IsText(string contentType) + { + contentType = GetContentTypeSignature(contentType); + return CheckIsText(contentType); + } + + internal static bool IsXml(string contentType) + { + contentType = GetContentTypeSignature(contentType); + return CheckIsXml(contentType); } #endregion Internal Methods #region Private Helper Methods - private static string GetContentTypeSignature(string contentType) + private static bool CheckIsJson(string contentType) { - if (String.IsNullOrEmpty(contentType)) - return null; + if (string.IsNullOrEmpty(contentType)) + return false; - string sig = contentType.Split(s_contentTypeParamSeparator, 2)[0].ToUpperInvariant(); - return (sig); + // the correct type for JSON content, as specified in RFC 4627 + bool isJson = contentType.Equals("application/json", StringComparison.OrdinalIgnoreCase); + + // add in these other "javascript" related types that + // sometimes get sent down as the mime type for JSON content + isJson |= contentType.Equals("text/json", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("application/x-javascript", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("text/x-javascript", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("application/javascript", StringComparison.OrdinalIgnoreCase) + || contentType.Equals("text/javascript", StringComparison.OrdinalIgnoreCase); + + return (isJson); } private static bool CheckIsText(string contentType) { - if (String.IsNullOrEmpty(contentType)) + if (string.IsNullOrEmpty(contentType)) return false; // any text, xml or json types are text @@ -120,7 +190,7 @@ private static bool CheckIsText(string contentType) private static bool CheckIsXml(string contentType) { - if (String.IsNullOrEmpty(contentType)) + if (string.IsNullOrEmpty(contentType)) return false; // RFC 3023: Media types with the suffix "+xml" are XML @@ -132,85 +202,15 @@ private static bool CheckIsXml(string contentType) return (isXml); } - private static bool CheckIsJson(string contentType) - { - if (String.IsNullOrEmpty(contentType)) - return false; - - // the correct type for JSON content, as specified in RFC 4627 - bool isJson = contentType.Equals("application/json", StringComparison.OrdinalIgnoreCase); - - // add in these other "javascript" related types that - // sometimes get sent down as the mime type for JSON content - isJson |= contentType.Equals("text/json", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("application/x-javascript", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("text/x-javascript", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("application/javascript", StringComparison.OrdinalIgnoreCase) - || contentType.Equals("text/javascript", StringComparison.OrdinalIgnoreCase); - - return (isJson); - } - - #endregion Internal Helper Methods - } - - // TODO: merge Partials - - internal static partial class ContentHelper - { - internal static Encoding GetEncoding(HttpResponseMessage response) + private static string GetContentTypeSignature(string contentType) { - // ContentType may not exist in response header. - string charSet = response.Content.Headers.ContentType?.CharSet; - return GetEncodingOrDefault(charSet); - } + if (string.IsNullOrEmpty(contentType)) + return null; - internal static string GetContentType(HttpResponseMessage response) - { - // ContentType may not exist in response header. Return null if not. - return response.Content.Headers.ContentType?.MediaType; + string sig = contentType.Split(s_contentTypeParamSeparator, 2)[0].ToUpperInvariant(); + return (sig); } - internal static StringBuilder GetRawContentHeader(HttpResponseMessage response) - { - StringBuilder raw = new StringBuilder(); - - string protocol = WebResponseHelper.GetProtocol(response); - if (!string.IsNullOrEmpty(protocol)) - { - int statusCode = WebResponseHelper.GetStatusCode(response); - string statusDescription = WebResponseHelper.GetStatusDescription(response); - raw.AppendFormat("{0} {1} {2}", protocol, statusCode, statusDescription); - raw.AppendLine(); - } - - HttpHeaders[] headerCollections = - { - response.Headers, - response.Content == null ? null : response.Content.Headers - }; - - foreach (var headerCollection in headerCollections) - { - if (headerCollection == null) - { - continue; - } - foreach (var header in headerCollection) - { - // Headers may have multiple entries with different values - foreach (var headerValue in header.Value) - { - raw.Append(header.Key); - raw.Append(": "); - raw.Append(headerValue); - raw.AppendLine(); - } - } - } - - raw.AppendLine(); - return raw; - } + #endregion Private Helper Methods } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs index 7c6a149cc7f7..13a2aa4ee40d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; using System.IO; +using System.Management.Automation; +using System.Net.Http; +using System.Text; using System.Xml; + using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using System.Net.Http; -using System.Text; namespace Microsoft.PowerShell.Commands { @@ -18,42 +18,45 @@ public partial class InvokeRestMethodCommand #region Parameters /// - /// gets or sets the parameter Method + /// Gets or sets the parameter Method. /// [Parameter(ParameterSetName = "StandardMethod")] [Parameter(ParameterSetName = "StandardMethodNoProxy")] public override WebRequestMethod Method { get { return base.Method; } + set { base.Method = value; } } /// - /// gets or sets the parameter CustomMethod + /// Gets or sets the parameter CustomMethod. /// - [Parameter(Mandatory=true,ParameterSetName = "CustomMethod")] - [Parameter(Mandatory=true,ParameterSetName = "CustomMethodNoProxy")] + [Parameter(Mandatory = true, ParameterSetName = "CustomMethod")] + [Parameter(Mandatory = true, ParameterSetName = "CustomMethodNoProxy")] [Alias("CM")] [ValidateNotNullOrEmpty] public override string CustomMethod { get { return base.CustomMethod; } + set { base.CustomMethod = value; } } /// - /// enable automatic following of rel links + /// Enable automatic following of rel links. /// [Parameter] [Alias("FL")] public SwitchParameter FollowRelLink { get { return base._followRelLink; } + set { base._followRelLink = value; } } /// - /// gets or sets the maximum number of rel links to follow + /// Gets or sets the maximum number of rel links to follow. /// [Parameter] [Alias("ML")] @@ -61,6 +64,7 @@ public SwitchParameter FollowRelLink public int MaximumFollowRelLink { get { return base._maximumFollowRelLink; } + set { base._maximumFollowRelLink = value; } } @@ -88,8 +92,8 @@ private bool TryProcessFeedStream(BufferingStreamReader responseStream) int readCount = 0; while ((readCount < 10) && reader.Read()) { - if (String.Equals("rss", reader.Name, StringComparison.OrdinalIgnoreCase) || - String.Equals("feed", reader.Name, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("rss", reader.Name, StringComparison.OrdinalIgnoreCase) || + string.Equals("feed", reader.Name, StringComparison.OrdinalIgnoreCase)) { isRssOrFeed = true; break; @@ -140,7 +144,7 @@ private XmlReaderSettings GetSecureXmlReaderSettings() xrs.CheckCharacters = false; xrs.CloseInput = false; - //The XML data needs to be in conformance to the rules for a well-formed XML 1.0 document. + // The XML data needs to be in conformance to the rules for a well-formed XML 1.0 document. xrs.IgnoreProcessingInstructions = true; xrs.MaxCharactersFromEntities = 1024; xrs.DtdProcessing = DtdProcessing.Ignore; @@ -167,7 +171,8 @@ private bool TryConvertToXml(string xml, out object doc, ref Exception exRef) exRef = ex; doc = null; } - return (null != doc); + + return (doc != null); } private bool TryConvertToJson(string json, out object obj, ref Exception exRef) @@ -178,9 +183,9 @@ private bool TryConvertToJson(string json, out object obj, ref Exception exRef) ErrorRecord error; obj = JsonObject.ConvertFromJson(json, out error); - if (null == obj) + if (obj == null) { - // This ensures that a null returned by ConvertFromJson() is the actual JSON null literal. + // This ensures that a null returned by ConvertFromJson() is the actual JSON null literal. // if not, the ArgumentException will be caught. JToken.Parse(json); } @@ -211,30 +216,31 @@ private bool TryConvertToJson(string json, out object obj, ref Exception exRef) exRef = new ArgumentException(msg, ex); obj = null; } + return converted; } #endregion /// - /// enum for rest return type. + /// Enum for rest return type. /// public enum RestReturnType { /// /// Return type not defined in response, - /// best effort detect + /// best effort detect. /// Detect, /// - /// Json return type + /// Json return type. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] Json, /// - /// Xml return type + /// Xml return type. /// Xml, } @@ -277,11 +283,13 @@ public override long Length { get { return _length; } } + private long _length; public override long Position { get { return _streamBuffer.Position; } + set { _streamBuffer.Position = value; } } @@ -366,7 +374,7 @@ public partial class InvokeRestMethodCommand : WebRequestPSCmdlet /// internal override void ProcessResponse(HttpResponseMessage response) { - if (null == response) { throw new ArgumentNullException("response"); } + if (response == null) { throw new ArgumentNullException("response"); } using (BufferingStreamReader responseStream = new BufferingStreamReader(StreamHelper.GetResponseStream(response))) { @@ -393,16 +401,31 @@ internal override void ProcessResponse(HttpResponseMessage response) StreamHelper.TryGetEncoding(charSet, out encoding); } + if (string.IsNullOrEmpty(charSet) && returnType == RestReturnType.Json) + { + encoding = Encoding.UTF8; + } + object obj = null; Exception ex = null; string str = StreamHelper.DecodeStream(responseStream, ref encoding); + + string encodingVerboseName; + try + { + encodingVerboseName = string.IsNullOrEmpty(encoding.HeaderName) ? encoding.EncodingName : encoding.HeaderName; + } + catch (NotSupportedException) + { + encodingVerboseName = encoding.EncodingName; + } // NOTE: Tests use this verbose output to verify the encoding. WriteVerbose(string.Format ( System.Globalization.CultureInfo.InvariantCulture, "Content encoding: {0}", - string.IsNullOrEmpty(encoding.HeaderName) ? encoding.EncodingName : encoding.HeaderName) + encodingVerboseName) ); bool convertSuccess = false; @@ -431,7 +454,7 @@ internal override void ProcessResponse(HttpResponseMessage response) StreamHelper.SaveStreamToFile(responseStream, QualifiedOutFile, this); } - if (!String.IsNullOrEmpty(ResponseHeadersVariable)) + if (!string.IsNullOrEmpty(ResponseHeadersVariable)) { PSVariableIntrinsics vi = SessionState.PSVariable; vi.Set(ResponseHeadersVariable, WebResponseHelper.GetHeadersDictionary(response)); @@ -445,7 +468,7 @@ internal override void ProcessResponse(HttpResponseMessage response) private RestReturnType CheckReturnType(HttpResponseMessage response) { - if (null == response) { throw new ArgumentNullException("response"); } + if (response == null) { throw new ArgumentNullException("response"); } RestReturnType rt = RestReturnType.Detect; string contentType = ContentHelper.GetContentType(response); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index 2b2dc46a6c30..6cdb5ecfbe65 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -1,32 +1,33 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections; +using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; +using System.Linq; using System.Management.Automation; using System.Net; -using System.IO; -using System.Text; -using System.Collections; -using System.Globalization; +using System.Net.Http; +using System.Net.Http.Headers; using System.Security; using System.Security.Authentication; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using Microsoft.Win32; -using System.Net.Http; -using System.Net.Http.Headers; +using System.Text; +using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; using System.Xml; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Linq; + +using Microsoft.Win32; namespace Microsoft.PowerShell.Commands { /// - /// The valid values for the -Authentication parameter for Invoke-RestMethod and Invoke-WebRequest + /// The valid values for the -Authentication parameter for Invoke-RestMethod and Invoke-WebRequest. /// public enum WebAuthenticationType { @@ -36,17 +37,17 @@ public enum WebAuthenticationType None, /// - /// RFC-7617 Basic Authentication. Requires -Credential + /// RFC-7617 Basic Authentication. Requires -Credential. /// Basic, /// - /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token + /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token. /// Bearer, /// - /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token + /// RFC-6750 OAuth 2.0 Bearer Authentication. Requires -Token. /// OAuth, } @@ -54,13 +55,13 @@ public enum WebAuthenticationType // WebSslProtocol is used because not all SslProtocols are supported by HttpClientHandler. // Also SslProtocols.Default is not the "default" for HttpClientHandler as SslProtocols.Ssl3 is not supported. /// - /// The valid values for the -SslProtocol parameter for Invoke-RestMethod and Invoke-WebRequest + /// The valid values for the -SslProtocol parameter for Invoke-RestMethod and Invoke-WebRequest. /// [Flags] public enum WebSslProtocol { /// - /// No SSL protocol will be set and the system defaults will be used. + /// No SSL protocol will be set and the system defaults will be used. /// Default = 0, @@ -70,12 +71,12 @@ public enum WebSslProtocol Tls = SslProtocols.Tls, /// - /// Specifies the TLS 1.1 security protocol. The TLS protocol is defined in IETF RFC 4346. + /// Specifies the TLS 1.1 security protocol. The TLS protocol is defined in IETF RFC 4346. /// Tls11 = SslProtocols.Tls11, /// - /// Specifies the TLS 1.2 security protocol. The TLS protocol is defined in IETF RFC 5246 + /// Specifies the TLS 1.2 security protocol. The TLS protocol is defined in IETF RFC 5246. /// Tls12 = SslProtocols.Tls12 } @@ -96,7 +97,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet public virtual SwitchParameter UseBasicParsing { get; set; } = true; /// - /// gets or sets the Uri property + /// Gets or sets the Uri property. /// [Parameter(Position = 0, Mandatory = true)] [ValidateNotNullOrEmpty] @@ -106,13 +107,13 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet #region Session /// - /// gets or sets the Session property + /// Gets or sets the Session property. /// [Parameter] public virtual WebRequestSession WebSession { get; set; } /// - /// gets or sets the SessionVariable property + /// Gets or sets the SessionVariable property. /// [Parameter] [Alias("SV")] @@ -123,7 +124,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet #region Authorization and Credentials /// - /// Gets or sets the AllowUnencryptedAuthentication property + /// Gets or sets the AllowUnencryptedAuthentication property. /// [Parameter] public virtual SwitchParameter AllowUnencryptedAuthentication { get; set; } @@ -132,47 +133,47 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet /// Gets or sets the Authentication property used to determin the Authentication method for the web session. /// Authentication does not work with UseDefaultCredentials. /// Authentication over unencrypted sessions requires AllowUnencryptedAuthentication. - /// Basic: Requires Credential - /// OAuth/Bearer: Requires Token + /// Basic: Requires Credential. + /// OAuth/Bearer: Requires Token. /// [Parameter] public virtual WebAuthenticationType Authentication { get; set; } = WebAuthenticationType.None; /// - /// gets or sets the Credential property + /// Gets or sets the Credential property. /// [Parameter] [Credential] public virtual PSCredential Credential { get; set; } /// - /// gets or sets the UseDefaultCredentials property + /// Gets or sets the UseDefaultCredentials property. /// [Parameter] public virtual SwitchParameter UseDefaultCredentials { get; set; } /// - /// gets or sets the CertificateThumbprint property + /// Gets or sets the CertificateThumbprint property. /// [Parameter] [ValidateNotNullOrEmpty] public virtual string CertificateThumbprint { get; set; } /// - /// gets or sets the Certificate property + /// Gets or sets the Certificate property. /// [Parameter] [ValidateNotNull] public virtual X509Certificate Certificate { get; set; } /// - /// gets or sets the SkipCertificateCheck property + /// Gets or sets the SkipCertificateCheck property. /// [Parameter] public virtual SwitchParameter SkipCertificateCheck { get; set; } /// - /// Gets or sets the TLS/SSL protocol used by the Web Cmdlet + /// Gets or sets the TLS/SSL protocol used by the Web Cmdlet. /// [Parameter] public virtual WebSslProtocol SslProtocol { get; set; } = WebSslProtocol.Default; @@ -188,26 +189,26 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet #region Headers /// - /// gets or sets the UserAgent property + /// Gets or sets the UserAgent property. /// [Parameter] public virtual string UserAgent { get; set; } /// - /// gets or sets the DisableKeepAlive property + /// Gets or sets the DisableKeepAlive property. /// [Parameter] public virtual SwitchParameter DisableKeepAlive { get; set; } /// - /// gets or sets the TimeOut property + /// Gets or sets the TimeOut property. /// [Parameter] [ValidateRange(0, Int32.MaxValue)] public virtual int TimeoutSec { get; set; } /// - /// gets or sets the Headers property + /// Gets or sets the Headers property. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] [Parameter] @@ -218,45 +219,65 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet #region Redirect /// - /// gets or sets the RedirectMax property + /// Gets or sets the RedirectMax property. /// [Parameter] [ValidateRange(0, Int32.MaxValue)] public virtual int MaximumRedirection { get { return _maximumRedirection; } + set { _maximumRedirection = value; } } + private int _maximumRedirection = -1; + /// + /// Gets or sets the MaximumRetryCount property, which determines the number of retries of a failed web request. + /// + [Parameter] + [ValidateRange(0, Int32.MaxValue)] + public virtual int MaximumRetryCount { get; set; } = 0; + + /// + /// Gets or sets the RetryIntervalSec property, which determines the number seconds between retries. + /// + [Parameter] + [ValidateRange(1, Int32.MaxValue)] + public virtual int RetryIntervalSec { get; set; } = 5; + #endregion #region Method /// - /// gets or sets the Method property + /// Gets or sets the Method property. /// [Parameter(ParameterSetName = "StandardMethod")] [Parameter(ParameterSetName = "StandardMethodNoProxy")] public virtual WebRequestMethod Method { get { return _method; } + set { _method = value; } } + private WebRequestMethod _method = WebRequestMethod.Default; /// - /// gets or sets the CustomMethod property + /// Gets or sets the CustomMethod property. /// - [Parameter(Mandatory=true,ParameterSetName = "CustomMethod")] - [Parameter(Mandatory=true,ParameterSetName = "CustomMethodNoProxy")] + [Parameter(Mandatory = true, ParameterSetName = "CustomMethod")] + [Parameter(Mandatory = true, ParameterSetName = "CustomMethodNoProxy")] [Alias("CM")] [ValidateNotNullOrEmpty] public virtual string CustomMethod { get { return _customMethod; } + set { _customMethod = value; } } + private string _customMethod; #endregion @@ -264,10 +285,10 @@ public virtual string CustomMethod #region NoProxy /// - /// gets or sets the NoProxy property + /// Gets or sets the NoProxy property. /// - [Parameter(Mandatory=true,ParameterSetName = "CustomMethodNoProxy")] - [Parameter(Mandatory=true,ParameterSetName = "StandardMethodNoProxy")] + [Parameter(Mandatory = true, ParameterSetName = "CustomMethodNoProxy")] + [Parameter(Mandatory = true, ParameterSetName = "StandardMethodNoProxy")] public virtual SwitchParameter NoProxy { get; set; } #endregion @@ -275,14 +296,14 @@ public virtual string CustomMethod #region Proxy /// - /// gets or sets the Proxy property + /// Gets or sets the Proxy property. /// [Parameter(ParameterSetName = "StandardMethod")] [Parameter(ParameterSetName = "CustomMethod")] public virtual Uri Proxy { get; set; } /// - /// gets or sets the ProxyCredential property + /// Gets or sets the ProxyCredential property. /// [Parameter(ParameterSetName = "StandardMethod")] [Parameter(ParameterSetName = "CustomMethod")] @@ -290,7 +311,7 @@ public virtual string CustomMethod public virtual PSCredential ProxyCredential { get; set; } /// - /// gets or sets the ProxyUseDefaultCredentials property + /// Gets or sets the ProxyUseDefaultCredentials property. /// [Parameter(ParameterSetName = "StandardMethod")] [Parameter(ParameterSetName = "CustomMethod")] @@ -301,33 +322,40 @@ public virtual string CustomMethod #region Input /// - /// gets or sets the Body property + /// Gets or sets the Body property. /// [Parameter(ValueFromPipeline = true)] public virtual object Body { get; set; } /// - /// gets or sets the ContentType property + /// Dictionary for use with RFC-7578 multipart/form-data submissions. + /// Keys are form fields and their respective values are form values. + /// A value may be a collection of form values or single form value. + /// + [Parameter] + public virtual IDictionary Form { get; set; } + + /// + /// Gets or sets the ContentType property. /// [Parameter] public virtual string ContentType { get; set; } /// - /// gets or sets the TransferEncoding property + /// Gets or sets the TransferEncoding property. /// [Parameter] [ValidateSet("chunked", "compress", "deflate", "gzip", "identity", IgnoreCase = true)] public virtual string TransferEncoding { get; set; } /// - /// gets or sets the InFile property + /// Gets or sets the InFile property. /// [Parameter] public virtual string InFile { get; set; } /// - /// keep the original file path after the resolved provider path is - /// assigned to InFile + /// Keep the original file path after the resolved provider path is assigned to InFile. /// private string _originalFilePath; @@ -336,17 +364,23 @@ public virtual string CustomMethod #region Output /// - /// gets or sets the OutFile property + /// Gets or sets the OutFile property. /// [Parameter] public virtual string OutFile { get; set; } /// - /// gets or sets the PassThrough property + /// Gets or sets the PassThrough property. /// [Parameter] public virtual SwitchParameter PassThru { get; set; } + /// + /// Resumes downloading a partial or incomplete file. OutFile is required. + /// + [Parameter] + public virtual SwitchParameter Resume { get; set; } + #endregion #endregion Virtual Properties @@ -356,7 +390,7 @@ public virtual string CustomMethod internal virtual void ValidateParameters() { // sessions - if ((null != WebSession) && (null != SessionVariable)) + if ((WebSession != null) && (SessionVariable != null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.SessionConflict, "WebCmdletSessionConflictException"); @@ -370,31 +404,36 @@ internal virtual void ValidateParameters() "WebCmdletAuthenticationConflictException"); ThrowTerminatingError(error); } - if ((Authentication != WebAuthenticationType.None) && (null != Token) && (null != Credential)) + + if ((Authentication != WebAuthenticationType.None) && (Token != null) && (Credential != null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationTokenConflict, "WebCmdletAuthenticationTokenConflictException"); ThrowTerminatingError(error); } - if ((Authentication == WebAuthenticationType.Basic) && (null == Credential)) + + if ((Authentication == WebAuthenticationType.Basic) && (Credential == null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationCredentialNotSupplied, "WebCmdletAuthenticationCredentialNotSuppliedException"); ThrowTerminatingError(error); } - if ((Authentication == WebAuthenticationType.OAuth || Authentication == WebAuthenticationType.Bearer) && (null == Token)) + + if ((Authentication == WebAuthenticationType.OAuth || Authentication == WebAuthenticationType.Bearer) && (Token == null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.AuthenticationTokenNotSupplied, "WebCmdletAuthenticationTokenNotSuppliedException"); ThrowTerminatingError(error); } + if (!AllowUnencryptedAuthentication && (Authentication != WebAuthenticationType.None) && (Uri.Scheme != "https")) { ErrorRecord error = GetValidationError(WebCmdletStrings.AllowUnencryptedAuthenticationRequired, "WebCmdletAllowUnencryptedAuthenticationRequiredException"); ThrowTerminatingError(error); } - if (!AllowUnencryptedAuthentication && (null != Credential || UseDefaultCredentials) && (Uri.Scheme != "https")) + + if (!AllowUnencryptedAuthentication && (Credential != null || UseDefaultCredentials) && (Uri.Scheme != "https")) { ErrorRecord error = GetValidationError(WebCmdletStrings.AllowUnencryptedAuthenticationRequired, "WebCmdletAllowUnencryptedAuthenticationRequiredException"); @@ -402,7 +441,7 @@ internal virtual void ValidateParameters() } // credentials - if (UseDefaultCredentials && (null != Credential)) + if (UseDefaultCredentials && (Credential != null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.CredentialConflict, "WebCmdletCredentialConflictException"); @@ -410,13 +449,13 @@ internal virtual void ValidateParameters() } // Proxy server - if (ProxyUseDefaultCredentials && (null != ProxyCredential)) + if (ProxyUseDefaultCredentials && (ProxyCredential != null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.ProxyCredentialConflict, "WebCmdletProxyCredentialConflictException"); ThrowTerminatingError(error); } - else if ((null == Proxy) && ((null != ProxyCredential) || ProxyUseDefaultCredentials)) + else if ((Proxy == null) && ((ProxyCredential != null) || ProxyUseDefaultCredentials)) { ErrorRecord error = GetValidationError(WebCmdletStrings.ProxyUriNotSupplied, "WebCmdletProxyUriNotSuppliedException"); @@ -424,13 +463,27 @@ internal virtual void ValidateParameters() } // request body content - if ((null != Body) && (null != InFile)) + if ((Body != null) && (InFile != null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.BodyConflict, "WebCmdletBodyConflictException"); ThrowTerminatingError(error); } + if ((Body != null) && (Form != null)) + { + ErrorRecord error = GetValidationError(WebCmdletStrings.BodyFormConflict, + "WebCmdletBodyFormConflictException"); + ThrowTerminatingError(error); + } + + if ((InFile != null) && (Form != null)) + { + ErrorRecord error = GetValidationError(WebCmdletStrings.FormInFileConflict, + "WebCmdletFormInFileConflictException"); + ThrowTerminatingError(error); + } + // validate InFile path if (InFile != null) { @@ -465,6 +518,7 @@ internal virtual void ValidateParameters() errorRecord = GetValidationError(WebCmdletStrings.DirectoryPathSpecified, "WebCmdletInFileNotFilePathException", InFile); } + _originalFilePath = InFile; InFile = providerPaths[0]; } @@ -493,7 +547,15 @@ internal virtual void ValidateParameters() if (PassThru && (OutFile == null)) { ErrorRecord error = GetValidationError(WebCmdletStrings.OutFileMissing, - "WebCmdletOutFileMissingException"); + "WebCmdletOutFileMissingException", nameof(PassThru)); + ThrowTerminatingError(error); + } + + // Resume requires OutFile. + if (Resume.IsPresent && OutFile == null) + { + ErrorRecord error = GetValidationError(WebCmdletStrings.OutFileMissing, + "WebCmdletOutFileMissingException", nameof(Resume)); ThrowTerminatingError(error); } } @@ -501,12 +563,12 @@ internal virtual void ValidateParameters() internal virtual void PrepareSession() { // make sure we have a valid WebRequestSession object to work with - if (null == WebSession) + if (WebSession == null) { WebSession = new WebRequestSession(); } - if (null != SessionVariable) + if (SessionVariable != null) { // save the session back to the PS environment if requested PSVariableIntrinsics vi = SessionState.PSVariable; @@ -516,7 +578,7 @@ internal virtual void PrepareSession() // // handle credentials // - if (null != Credential && Authentication == WebAuthenticationType.None) + if (Credential != null && Authentication == WebAuthenticationType.None) { // get the relevant NetworkCredential NetworkCredential netCred = Credential.GetNetworkCredential(); @@ -525,7 +587,7 @@ internal virtual void PrepareSession() // supplying a credential overrides the UseDefaultCredentials setting WebSession.UseDefaultCredentials = false; } - else if ((null != Credential || null!= Token) && Authentication != WebAuthenticationType.None) + else if ((Credential != null || null != Token) && Authentication != WebAuthenticationType.None) { ProcessAuthentication(); } @@ -534,8 +596,7 @@ internal virtual void PrepareSession() WebSession.UseDefaultCredentials = true; } - - if (null != CertificateThumbprint) + if (CertificateThumbprint != null) { X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); @@ -546,6 +607,7 @@ internal virtual void PrepareSession() CryptographicException ex = new CryptographicException(WebCmdletStrings.ThumbprintNotFound); throw ex; } + foreach (X509Certificate2 tbCert in tbCollection) { X509Certificate certificate = (X509Certificate)tbCert; @@ -553,7 +615,7 @@ internal virtual void PrepareSession() } } - if (null != Certificate) + if (Certificate != null) { WebSession.AddCertificate(Certificate); } @@ -561,17 +623,17 @@ internal virtual void PrepareSession() // // handle the user agent // - if (null != UserAgent) + if (UserAgent != null) { // store the UserAgent string WebSession.UserAgent = UserAgent; } - if (null != Proxy) + if (Proxy != null) { WebProxy webProxy = new WebProxy(Proxy); webProxy.BypassProxyOnLocal = false; - if (null != ProxyCredential) + if (ProxyCredential != null) { webProxy.Credentials = ProxyCredential.GetNetworkCredential(); } @@ -581,6 +643,7 @@ internal virtual void PrepareSession() // UseDefaultCredentials will overwrite the supplied credentials. webProxy.UseDefaultCredentials = true; } + WebSession.Proxy = webProxy; } @@ -590,7 +653,7 @@ internal virtual void PrepareSession() } // store the other supplied headers - if (null != Headers) + if (Headers != null) { foreach (string key in Headers.Keys) { @@ -598,6 +661,14 @@ internal virtual void PrepareSession() WebSession.Headers[key] = Headers[key].ToString(); } } + + if (MaximumRetryCount > 0) + { + WebSession.MaximumRetryCount = MaximumRetryCount; + + // only set retry interval if retry count is set. + WebSession.RetryIntervalInSeconds = RetryIntervalSec; + } } #endregion Virtual Methods @@ -619,10 +690,17 @@ internal bool ShouldWriteToPipeline get { return (!ShouldSaveToOutFile || PassThru); } } + /// + /// Determines whether writing to a file should Resume and append rather than overwrite. + /// + internal bool ShouldResume + { + get { return (Resume.IsPresent && _resumeSuccess); } + } + #endregion Helper Properties #region Helper Methods - private Uri PrepareUri(Uri uri) { uri = CheckProtocol(uri); @@ -631,7 +709,7 @@ private Uri PrepareUri(Uri uri) // preprocess Body if content is a dictionary and method is GET (set as query) IDictionary bodyAsDictionary; LanguagePrimitives.TryConvertTo(Body, out bodyAsDictionary); - if ((null != bodyAsDictionary) + if ((bodyAsDictionary != null) && ((IsStandardMethodSet() && (Method == WebRequestMethod.Default || Method == WebRequestMethod.Get)) || (IsCustomMethodSet() && CustomMethod.ToUpperInvariant() == "GET"))) { @@ -644,6 +722,7 @@ private Uri PrepareUri(Uri uri) { uriBuilder.Query = FormatDictionary(bodyAsDictionary); } + uri = uriBuilder.Uri; // set body to null to prevent later FillRequestStream Body = null; @@ -654,12 +733,13 @@ private Uri PrepareUri(Uri uri) private Uri CheckProtocol(Uri uri) { - if (null == uri) { throw new ArgumentNullException("uri"); } + if (uri == null) { throw new ArgumentNullException("uri"); } if (!uri.IsAbsoluteUri) { uri = new Uri("http://" + uri.OriginalString); } + return (uri); } @@ -686,14 +766,15 @@ private string FormatDictionary(IDictionary content) // URLEncode the key and value string encodedKey = WebUtility.UrlEncode(key); - string encodedValue = String.Empty; - if (null != value) + string encodedValue = string.Empty; + if (value != null) { encodedValue = WebUtility.UrlEncode(value.ToString()); } bodyBuilder.AppendFormat("{0}={1}", encodedKey, encodedValue); } + return bodyBuilder.ToString(); } @@ -724,19 +805,20 @@ private bool IsCustomMethodSet() private string GetBasicAuthorizationHeader() { - string unencoded = String.Format("{0}:{1}", Credential.UserName, Credential.GetNetworkCredential().Password); - Byte[] bytes = Encoding.UTF8.GetBytes(unencoded); - return String.Format("Basic {0}", Convert.ToBase64String(bytes)); + var password = new NetworkCredential(null, Credential.Password).Password; + string unencoded = string.Format("{0}:{1}", Credential.UserName, password); + byte[] bytes = Encoding.UTF8.GetBytes(unencoded); + return string.Format("Basic {0}", Convert.ToBase64String(bytes)); } private string GetBearerAuthorizationHeader() { - return String.Format("Bearer {0}", new NetworkCredential(String.Empty, Token).Password); + return string.Format("Bearer {0}", new NetworkCredential(string.Empty, Token).Password); } private void ProcessAuthentication() { - if(Authentication == WebAuthenticationType.Basic) + if (Authentication == WebAuthenticationType.Basic) { WebSession.Headers["Authorization"] = GetBasicAuthorizationHeader(); } @@ -746,7 +828,7 @@ private void ProcessAuthentication() } else { - Diagnostics.Assert(false, String.Format("Unrecognized Authentication value: {0}", Authentication)); + Diagnostics.Assert(false, string.Format("Unrecognized Authentication value: {0}", Authentication)); } } @@ -756,22 +838,22 @@ private void ProcessAuthentication() // TODO: Merge Partials /// - /// Exception class for webcmdlets to enable returning HTTP error response + /// Exception class for webcmdlets to enable returning HTTP error response. /// public sealed class HttpResponseException : HttpRequestException { /// - /// Constructor for HttpResponseException + /// Constructor for HttpResponseException. /// - /// Message for the exception - /// Response from the HTTP server - public HttpResponseException (string message, HttpResponseMessage response) : base(message) + /// Message for the exception. + /// Response from the HTTP server. + public HttpResponseException(string message, HttpResponseMessage response) : base(message) { Response = response; } /// - /// HTTP error response + /// HTTP error response. /// public HttpResponseMessage Response { get; private set; } } @@ -781,9 +863,8 @@ public HttpResponseException (string message, HttpResponseMessage response) : ba /// public abstract partial class WebRequestPSCmdlet : PSCmdlet { - /// - /// gets or sets the PreserveAuthorizationOnRedirect property + /// Gets or sets the PreserveAuthorizationOnRedirect property. /// /// /// This property overrides compatibility with web requests on Windows. @@ -798,7 +879,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet public virtual SwitchParameter PreserveAuthorizationOnRedirect { get; set; } /// - /// gets or sets the SkipHeaderValidation property + /// Gets or sets the SkipHeaderValidation property. /// /// /// This property adds headers to the request's header collection without validation. @@ -809,39 +890,48 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet #region Abstract Methods /// - /// Read the supplied WebResponse object and push the - /// resulting output into the pipeline. + /// Read the supplied WebResponse object and push the resulting output into the pipeline. /// - /// Instance of a WebResponse object to be processed + /// Instance of a WebResponse object to be processed. internal abstract void ProcessResponse(HttpResponseMessage response); #endregion Abstract Methods /// - /// Cancellation token source + /// Cancellation token source. /// private CancellationTokenSource _cancelToken = null; /// - /// Parse Rel Links + /// Parse Rel Links. /// internal bool _parseRelLink = false; /// - /// Automatically follow Rel Links + /// Automatically follow Rel Links. /// internal bool _followRelLink = false; /// - /// Automatically follow Rel Links + /// Automatically follow Rel Links. /// internal Dictionary _relationLink = null; /// - /// Maximum number of Rel Links to follow + /// Maximum number of Rel Links to follow. /// internal int _maximumFollowRelLink = Int32.MaxValue; + /// + /// The remote endpoint returned a 206 status code indicating successful resume. + /// + private bool _resumeSuccess = false; + + /// + /// The current size of the local file being resumed. + /// + private long _resumeFileSize = 0; + private HttpMethod GetHttpMethod(WebRequestMethod method) { switch (Method) @@ -897,7 +987,7 @@ internal virtual HttpClient GetHttpClient(bool handleRedirect) handler.Proxy = WebSession.Proxy; } - if (null != WebSession.Certificates) + if (WebSession.Certificates != null) { handler.ClientCertificates.AddRange(WebSession.Certificates); } @@ -927,7 +1017,6 @@ internal virtual HttpClient GetHttpClient(bool handleRedirect) handler.SslProtocols = (SslProtocols)SslProtocol; - HttpClient httpClient = new HttpClient(handler); // check timeout setting (in seconds instead of milliseconds as in HttpWebRequest) @@ -944,7 +1033,7 @@ internal virtual HttpClient GetHttpClient(bool handleRedirect) return httpClient; } - internal virtual HttpRequestMessage GetRequest(Uri uri, bool stripAuthorization) + internal virtual HttpRequestMessage GetRequest(Uri uri) { Uri requestUri = PrepareUri(uri); HttpMethod httpMethod = null; @@ -965,6 +1054,7 @@ internal virtual HttpRequestMessage GetRequest(Uri uri, bool stripAuthorization) // set the method if the parameter was provided httpMethod = new HttpMethod(CustomMethod.ToString().ToUpperInvariant()); } + break; } @@ -983,14 +1073,6 @@ internal virtual HttpRequestMessage GetRequest(Uri uri, bool stripAuthorization) } else { - if (stripAuthorization - && - String.Equals(entry.Key, HttpKnownHeaderNames.Authorization.ToString(), StringComparison.OrdinalIgnoreCase) - ) - { - continue; - } - if (SkipHeaderValidation) { request.Headers.TryAddWithoutValidation(entry.Key, entry.Value); @@ -1025,7 +1107,6 @@ internal virtual HttpRequestMessage GetRequest(Uri uri, bool stripAuthorization) { request.Headers.Add(HttpKnownHeaderNames.UserAgent, WebSession.UserAgent); } - } // Set 'Keep-Alive' to false. This means set the Connection to 'Close'. @@ -1045,23 +1126,34 @@ internal virtual HttpRequestMessage GetRequest(Uri uri, bool stripAuthorization) } } - // Some web sites (e.g. Twitter) will return exception on POST when Expect100 is sent - // Default behavior is continue to send body content anyway after a short period - // Here it send the two part as a whole. - request.Headers.ExpectContinue = false; + // If the file to resume downloading exists, create the Range request header using the file size. + // If not, create a Range to request the entire file. + if (Resume.IsPresent) + { + var fileInfo = new FileInfo(QualifiedOutFile); + if (fileInfo.Exists) + { + request.Headers.Range = new RangeHeaderValue(fileInfo.Length, null); + _resumeFileSize = fileInfo.Length; + } + else + { + request.Headers.Range = new RangeHeaderValue(0, null); + } + } return (request); } internal virtual void FillRequestStream(HttpRequestMessage request) { - if (null == request) { throw new ArgumentNullException("request"); } + if (request == null) { throw new ArgumentNullException("request"); } // set the content type if (ContentType != null) { WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType] = ContentType; - //request + // request } // ContentType == null else if (Method == WebRequestMethod.Post || (IsCustomMethodSet() && CustomMethod.ToUpperInvariant() == "POST")) @@ -1075,8 +1167,22 @@ internal virtual void FillRequestStream(HttpRequestMessage request) } } + if (Form != null) + { + // Content headers will be set by MultipartFormDataContent which will throw unless we clear them first + WebSession.ContentHeaders.Clear(); + + var formData = new MultipartFormDataContent(); + foreach (DictionaryEntry formEntry in Form) + { + // AddMultipartContent will handle PSObject unwrapping, Object type determination and enumerateing top level IEnumerables. + AddMultipartContent(fieldName: formEntry.Key, fieldValue: formEntry.Value, formData: formData, enumerate: true); + } + + SetRequestContent(request, formData); + } // coerce body into a usable form - if (Body != null) + else if (Body != null) { object content = Body; @@ -1087,29 +1193,24 @@ internal virtual void FillRequestStream(HttpRequestMessage request) content = psBody.BaseObject; } - if (content is FormObject) + if (content is FormObject form) { - FormObject form = content as FormObject; SetRequestContent(request, form.Fields); } - else if (content is IDictionary && request.Method != HttpMethod.Get) + else if (content is IDictionary dictionary && request.Method != HttpMethod.Get) { - IDictionary dictionary = content as IDictionary; SetRequestContent(request, dictionary); } - else if (content is XmlNode) + else if (content is XmlNode xmlNode) { - XmlNode xmlNode = content as XmlNode; SetRequestContent(request, xmlNode); } - else if (content is Stream) + else if (content is Stream stream) { - Stream stream = content as Stream; SetRequestContent(request, stream); } - else if (content is byte[]) + else if (content is byte[] bytes) { - byte[] bytes = content as byte[]; SetRequestContent(request, bytes); } else if (content is MultipartFormDataContent multipartFormDataContent) @@ -1119,7 +1220,8 @@ internal virtual void FillRequestStream(HttpRequestMessage request) } else { - SetRequestContent(request, + SetRequestContent( + request, (string)LanguagePrimitives.ConvertTo(content, typeof(string), CultureInfo.InvariantCulture)); } } @@ -1128,7 +1230,7 @@ internal virtual void FillRequestStream(HttpRequestMessage request) try { // open the input file - SetRequestContent(request, new FileStream(InFile, FileMode.Open)); + SetRequestContent(request, new FileStream(InFile, FileMode.Open, FileAccess.Read, FileShare.Read)); } catch (UnauthorizedAccessException) { @@ -1139,19 +1241,38 @@ internal virtual void FillRequestStream(HttpRequestMessage request) } // Add the content headers - if (request.Content != null) + if (request.Content == null) + { + request.Content = new StringContent(string.Empty); + request.Content.Headers.Clear(); + } + + foreach (var entry in WebSession.ContentHeaders) { - foreach (var entry in WebSession.ContentHeaders) + if (SkipHeaderValidation) { - request.Content.Headers.Add(entry.Key, entry.Value); + request.Content.Headers.TryAddWithoutValidation(entry.Key, entry.Value); + } + else + { + try + { + request.Content.Headers.Add(entry.Key, entry.Value); + } + catch (FormatException ex) + { + var outerEx = new ValidationMetadataException(WebCmdletStrings.ContentTypeException, ex); + ErrorRecord er = new ErrorRecord(outerEx, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); + ThrowTerminatingError(er); + } } } } // Returns true if the status code is one of the supported redirection codes. - static bool IsRedirectCode(HttpStatusCode code) + private static bool IsRedirectCode(HttpStatusCode code) { - int intCode = (int) code; + int intCode = (int)code; return ( (intCode >= 300 && intCode < 304) @@ -1162,7 +1283,7 @@ static bool IsRedirectCode(HttpStatusCode code) // Returns true if the status code is a redirection code and the action requires switching from POST to GET on redirection. // NOTE: Some of these status codes map to the same underlying value but spelling them out for completeness. - static bool IsRedirectToGet(HttpStatusCode code) + private static bool IsRedirectToGet(HttpStatusCode code) { return ( @@ -1174,50 +1295,137 @@ static bool IsRedirectToGet(HttpStatusCode code) || code == HttpStatusCode.RedirectMethod || - code == HttpStatusCode.TemporaryRedirect + code == HttpStatusCode.SeeOther || - code == HttpStatusCode.RedirectKeepVerb + code == HttpStatusCode.Ambiguous || - code == HttpStatusCode.SeeOther + code == HttpStatusCode.MultipleChoices ); } - internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool stripAuthorization) + private bool ShouldRetry(HttpStatusCode code) + { + int intCode = (int)code; + + if (((intCode == 304) || (intCode >= 400 && intCode <= 599)) && WebSession.MaximumRetryCount > 0) + { + return true; + } + + return false; + } + + internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool keepAuthorization) { if (client == null) { throw new ArgumentNullException("client"); } + if (request == null) { throw new ArgumentNullException("request"); } - _cancelToken = new CancellationTokenSource(); - HttpResponseMessage response = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult(); + // Add 1 to account for the first request. + int totalRequests = WebSession.MaximumRetryCount + 1; + HttpRequestMessage req = request; + HttpResponseMessage response = null; - if (stripAuthorization && IsRedirectCode(response.StatusCode)) + do { - _cancelToken.Cancel(); - _cancelToken = null; + // Track the current URI being used by various requests and re-requests. + var currentUri = req.RequestUri; + + _cancelToken = new CancellationTokenSource(); + response = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult(); - // if explicit count was provided, reduce it for this redirection. - if (WebSession.MaximumRedirection > 0) + if (keepAuthorization && IsRedirectCode(response.StatusCode) && response.Headers.Location != null) { - WebSession.MaximumRedirection--; + _cancelToken.Cancel(); + _cancelToken = null; + + // if explicit count was provided, reduce it for this redirection. + if (WebSession.MaximumRedirection > 0) + { + WebSession.MaximumRedirection--; + } + // For selected redirects that used POST, GET must be used with the + // redirected Location. + // Since GET is the default; POST only occurs when -Method POST is used. + if (Method == WebRequestMethod.Post && IsRedirectToGet(response.StatusCode)) + { + // See https://msdn.microsoft.com/library/system.net.httpstatuscode(v=vs.110).aspx + Method = WebRequestMethod.Get; + } + + currentUri = new Uri(request.RequestUri, response.Headers.Location); + // Continue to handle redirection + using (client = GetHttpClient(handleRedirect: true)) + using (HttpRequestMessage redirectRequest = GetRequest(currentUri)) + { + response = GetResponse(client, redirectRequest, keepAuthorization); + } } - // For selected redirects that used POST, GET must be used with the - // redirected Location. - // Since GET is the default; POST only occurs when -Method POST is used. - if (Method == WebRequestMethod.Post && IsRedirectToGet(response.StatusCode)) + + // Request again without the Range header because the server indicated the range was not satisfiable. + // This happens when the local file is larger than the remote file. + // If the size of the remote file is the same as the local file, there is nothing to resume. + if (Resume.IsPresent && + response.StatusCode == HttpStatusCode.RequestedRangeNotSatisfiable && + (response.Content.Headers.ContentRange.HasLength && + response.Content.Headers.ContentRange.Length != _resumeFileSize)) { - // See https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx - Method = WebRequestMethod.Get; + _cancelToken.Cancel(); + + WriteVerbose(WebCmdletStrings.WebMethodResumeFailedVerboseMsg); + + // Disable the Resume switch so the subsequent calls to GetResponse() and FillRequestStream() + // are treated as a standard -OutFile request. This also disables appending local file. + Resume = new SwitchParameter(false); + + using (HttpRequestMessage requestWithoutRange = GetRequest(currentUri)) + { + FillRequestStream(requestWithoutRange); + long requestContentLength = 0; + if (requestWithoutRange.Content != null) + { + requestContentLength = requestWithoutRange.Content.Headers.ContentLength.Value; + } + + string reqVerboseMsg = string.Format( + CultureInfo.CurrentCulture, + WebCmdletStrings.WebMethodInvocationVerboseMsg, + requestWithoutRange.Method, + requestWithoutRange.RequestUri, + requestContentLength); + WriteVerbose(reqVerboseMsg); + + return GetResponse(client, requestWithoutRange, keepAuthorization); + } } - // recreate the HttpClient with redirection enabled since the first call suppressed redirection - using (client = GetHttpClient(false)) - using (HttpRequestMessage redirectRequest = GetRequest(response.Headers.Location, stripAuthorization:true)) + _resumeSuccess = response.StatusCode == HttpStatusCode.PartialContent; + + // When MaximumRetryCount is not specified, the totalRequests == 1. + if (totalRequests > 1 && ShouldRetry(response.StatusCode)) { - FillRequestStream(redirectRequest); + string retryMessage = string.Format( + CultureInfo.CurrentCulture, + WebCmdletStrings.RetryVerboseMsg, + RetryIntervalSec, + response.StatusCode); + + WriteVerbose(retryMessage); + _cancelToken = new CancellationTokenSource(); - response = client.SendAsync(redirectRequest, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult(); + Task.Delay(WebSession.RetryIntervalInSeconds * 1000, _cancelToken.Token).GetAwaiter().GetResult(); + _cancelToken.Cancel(); + _cancelToken = null; + + req.Dispose(); + req = GetRequest(currentUri); + FillRequestStream(req); } + + totalRequests--; } + while (totalRequests > 0 && !response.IsSuccessStatusCode); + return response; } @@ -1231,7 +1439,7 @@ internal virtual void UpdateSession(HttpResponseMessage response) #region Overrides /// - /// the main execution method for cmdlets derived from WebRequestPSCmdlet. + /// The main execution method for cmdlets derived from WebRequestPSCmdlet. /// protected override void ProcessRecord() { @@ -1243,15 +1451,15 @@ protected override void ProcessRecord() // if the request contains an authorization header and PreserveAuthorizationOnRedirect is not set, // it needs to be stripped on the first redirect. - bool stripAuthorization = null != WebSession + bool keepAuthorization = WebSession != null && - null != WebSession.Headers + WebSession.Headers != null && - !PreserveAuthorizationOnRedirect.IsPresent + PreserveAuthorizationOnRedirect.IsPresent && WebSession.Headers.ContainsKey(HttpKnownHeaderNames.Authorization.ToString()); - using (HttpClient client = GetHttpClient(stripAuthorization)) + using (HttpClient client = GetHttpClient(keepAuthorization)) { int followedRelLink = 0; Uri uri = Uri; @@ -1265,7 +1473,7 @@ protected override void ProcessRecord() WriteVerbose(linkVerboseMsg); } - using (HttpRequestMessage request = GetRequest(uri, stripAuthorization:false)) + using (HttpRequestMessage request = GetRequest(uri)) { FillRequestStream(request); try @@ -1274,14 +1482,14 @@ protected override void ProcessRecord() if (request.Content != null) requestContentLength = request.Content.Headers.ContentLength.Value; - string reqVerboseMsg = String.Format(CultureInfo.CurrentCulture, + string reqVerboseMsg = string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.WebMethodInvocationVerboseMsg, request.Method, request.RequestUri, requestContentLength); WriteVerbose(reqVerboseMsg); - HttpResponseMessage response = GetResponse(client, request, stripAuthorization); + HttpResponseMessage response = GetResponse(client, request, keepAuthorization); string contentType = ContentHelper.GetContentType(response); string respVerboseMsg = string.Format(CultureInfo.CurrentCulture, @@ -1290,19 +1498,34 @@ protected override void ProcessRecord() contentType); WriteVerbose(respVerboseMsg); - if (!response.IsSuccessStatusCode) + bool _isSuccess = response.IsSuccessStatusCode; + + // Check if the Resume range was not satisfiable because the file already completed downloading. + // This happens when the local file is the same size as the remote file. + if (Resume.IsPresent && + response.StatusCode == HttpStatusCode.RequestedRangeNotSatisfiable && + response.Content.Headers.ContentRange.HasLength && + response.Content.Headers.ContentRange.Length == _resumeFileSize) + { + _isSuccess = true; + WriteVerbose(string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.OutFileWritingSkipped, OutFile)); + // Disable writing to the OutFile. + OutFile = null; + } + + if (!_isSuccess) { - string message = String.Format(CultureInfo.CurrentCulture, WebCmdletStrings.ResponseStatusCodeFailure, + string message = string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.ResponseStatusCodeFailure, (int)response.StatusCode, response.ReasonPhrase); HttpResponseException httpEx = new HttpResponseException(message, response); ErrorRecord er = new ErrorRecord(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); - string detailMsg = ""; + string detailMsg = string.Empty; StreamReader reader = null; try { reader = new StreamReader(StreamHelper.GetResponseStream(response)); // remove HTML tags making it easier to read - detailMsg = System.Text.RegularExpressions.Regex.Replace(reader.ReadToEnd(), "<[^>]*>",""); + detailMsg = System.Text.RegularExpressions.Regex.Replace(reader.ReadToEnd(), "<[^>]*>", string.Empty); } catch (Exception) { @@ -1315,10 +1538,12 @@ protected override void ProcessRecord() reader.Dispose(); } } - if (!String.IsNullOrEmpty(detailMsg)) + + if (!string.IsNullOrEmpty(detailMsg)) { er.ErrorDetails = new ErrorDetails(detailMsg); } + ThrowTerminatingError(er); } @@ -1326,6 +1551,7 @@ protected override void ProcessRecord() { ParseLinkHeader(response, uri); } + ProcessResponse(response); UpdateSession(response); @@ -1352,6 +1578,7 @@ protected override void ProcessRecord() { er.ErrorDetails = new ErrorDetails(ex.InnerException.Message); } + ThrowTerminatingError(er); } @@ -1361,6 +1588,7 @@ protected override void ProcessRecord() { return; } + uri = new Uri(_relationLink["next"]); followedRelLink++; } @@ -1382,7 +1610,7 @@ protected override void ProcessRecord() } /// - /// Implementing ^C, after start the BeginGetResponse + /// Implementing ^C, after start the BeginGetResponse. /// protected override void StopProcessing() { @@ -1399,14 +1627,14 @@ protected override void StopProcessing() /// /// Sets the ContentLength property of the request and writes the specified content to the request's RequestStream. /// - /// The WebRequest who's content is to be set + /// The WebRequest who's content is to be set. /// A byte array containing the content data. - /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property + /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property. /// /// Because this function sets the request's ContentLength property and writes content data into the requests's stream, /// it should be called one time maximum on a given request. /// - internal long SetRequestContent(HttpRequestMessage request, Byte[] content) + internal long SetRequestContent(HttpRequestMessage request, byte[] content) { if (request == null) throw new ArgumentNullException("request"); @@ -1422,9 +1650,9 @@ internal long SetRequestContent(HttpRequestMessage request, Byte[] content) /// /// Sets the ContentLength property of the request and writes the specified content to the request's RequestStream. /// - /// The WebRequest who's content is to be set + /// The WebRequest who's content is to be set. /// A String object containing the content data. - /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property + /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property. /// /// Because this function sets the request's ContentLength property and writes content data into the requests's stream, /// it should be called one time maximum on a given request. @@ -1443,22 +1671,35 @@ internal long SetRequestContent(HttpRequestMessage request, string content) // If Content-Type contains the encoding format (as CharSet), use this encoding format // to encode the Body of the WebRequest sent to the server. Default Encoding format // would be used if Charset is not supplied in the Content-Type property. - var mediaTypeHeaderValue = new MediaTypeHeaderValue(ContentType); - if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) + try { - try + var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(ContentType); + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) { encoding = Encoding.GetEncoding(mediaTypeHeaderValue.CharSet); } - catch (ArgumentException ex) + } + catch (FormatException ex) + { + if (!SkipHeaderValidation) + { + var outerEx = new ValidationMetadataException(WebCmdletStrings.ContentTypeException, ex); + ErrorRecord er = new ErrorRecord(outerEx, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); + ThrowTerminatingError(er); + } + } + catch (ArgumentException ex) + { + if (!SkipHeaderValidation) { - ErrorRecord er = new ErrorRecord(ex, "WebCmdletEncodingException", ErrorCategory.InvalidArgument, ContentType); + var outerEx = new ValidationMetadataException(WebCmdletStrings.ContentTypeException, ex); + ErrorRecord er = new ErrorRecord(outerEx, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); ThrowTerminatingError(er); } } } - Byte[] bytes = StreamHelper.EncodeToBytes(content, encoding); + byte[] bytes = StreamHelper.EncodeToBytes(content, encoding); var byteArrayContent = new ByteArrayContent(bytes); request.Content = byteArrayContent; @@ -1473,7 +1714,7 @@ internal long SetRequestContent(HttpRequestMessage request, XmlNode xmlNode) if (xmlNode == null) return 0; - Byte[] bytes = null; + byte[] bytes = null; XmlDocument doc = xmlNode as XmlDocument; if (doc != null && (doc.FirstChild as XmlDeclaration) != null) { @@ -1495,9 +1736,9 @@ internal long SetRequestContent(HttpRequestMessage request, XmlNode xmlNode) /// /// Sets the ContentLength property of the request and writes the specified content to the request's RequestStream. /// - /// The WebRequest who's content is to be set + /// The WebRequest who's content is to be set. /// A Stream object containing the content data. - /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property + /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property. /// /// Because this function sets the request's ContentLength property and writes content data into the requests's stream, /// it should be called one time maximum on a given request. @@ -1518,9 +1759,9 @@ internal long SetRequestContent(HttpRequestMessage request, Stream contentStream /// /// Sets the ContentLength property of the request and writes the specified content to the request's RequestStream. /// - /// The WebRequest who's content is to be set + /// The WebRequest who's content is to be set. /// A MultipartFormDataContent object containing multipart/form-data content. - /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property + /// The number of bytes written to the requests RequestStream (and the new value of the request's ContentLength property. /// /// Because this function sets the request's ContentLength property and writes content data into the requests's stream, /// it should be called one time maximum on a given request. @@ -1531,6 +1772,7 @@ internal long SetRequestContent(HttpRequestMessage request, MultipartFormDataCon { throw new ArgumentNullException("request"); } + if (multipartContent == null) { throw new ArgumentNullException("multipartContent"); @@ -1550,14 +1792,14 @@ internal long SetRequestContent(HttpRequestMessage request, IDictionary content) string body = FormatDictionary(content); return (SetRequestContent(request, body)); - } internal void ParseLinkHeader(HttpResponseMessage response, System.Uri requestUri) { if (_relationLink == null) { - _relationLink = new Dictionary(); + // Must ignore the case of relation links. See RFC 8288 (https://tools.ietf.org/html/rfc8288) + _relationLink = new Dictionary(StringComparer.OrdinalIgnoreCase); } else { @@ -1566,7 +1808,7 @@ internal void ParseLinkHeader(HttpResponseMessage response, System.Uri requestUr // we only support the URL in angle brackets and `rel`, other attributes are ignored // user can still parse it themselves via the Headers property - string pattern = "<(?.*?)>;\\srel=\"(?.*?)\""; + string pattern = "<(?.*?)>;\\s*rel=\"(?.*?)\""; IEnumerable links; if (response.Headers.TryGetValues("Link", out links)) { @@ -1579,7 +1821,7 @@ internal void ParseLinkHeader(HttpResponseMessage response, System.Uri requestUr { string url = match.Groups["url"].Value; string rel = match.Groups["rel"].Value; - if (url != String.Empty && rel != String.Empty && !_relationLink.ContainsKey(rel)) + if (url != string.Empty && rel != string.Empty && !_relationLink.ContainsKey(rel)) { Uri absoluteUri = new Uri(requestUri, url); _relationLink.Add(rel, absoluteUri.AbsoluteUri.ToString()); @@ -1590,6 +1832,110 @@ internal void ParseLinkHeader(HttpResponseMessage response, System.Uri requestUr } } + /// + /// Adds content to a . Object type detection is used to determine if the value is String, File, or Collection. + /// + /// The Field Name to use. + /// The Field Value to use. + /// The > to update. + /// If true, collection types in will be enumerated. If false, collections will be treated as single value. + private void AddMultipartContent(object fieldName, object fieldValue, MultipartFormDataContent formData, bool enumerate) + { + if (formData == null) + { + throw new ArgumentNullException("formDate"); + } + + // It is possible that the dictionary keys or values are PSObject wrapped depending on how the dictionary is defined and assigned. + // Before processing the field name and value we need to ensure we are working with the base objects and not the PSObject wrappers. + + // Unwrap fieldName PSObjects + if (fieldName is PSObject namePSObject) + { + fieldName = namePSObject.BaseObject; + } + + // Unwrap fieldValue PSObjects + if (fieldValue is PSObject valuePSObject) + { + fieldValue = valuePSObject.BaseObject; + } + + // Treat a single FileInfo as a FileContent + if (fieldValue is FileInfo file) + { + formData.Add(GetMultipartFileContent(fieldName: fieldName, file: file)); + return; + } + + // Treat Strings and other single values as a StringContent. + // If enumeration is false, also treat IEnumerables as StringContents. + // String implements IEnumerable so the explicit check is required. + if (enumerate == false || fieldValue is string || !(fieldValue is IEnumerable)) + { + formData.Add(GetMultipartStringContent(fieldName: fieldName, fieldValue: fieldValue)); + return; + } + + // Treat the value as a collection and enumerate it if enumeration is true + if (enumerate == true && fieldValue is IEnumerable items) + { + foreach (var item in items) + { + // Recruse, but do not enumerate the next level. IEnumerables will be treated as single values. + AddMultipartContent(fieldName: fieldName, fieldValue: item, formData: formData, enumerate: false); + } + } + } + + /// + /// Gets a from the supplied field name and field value. Uses to convert the objects to strings. + /// + /// The Field Name to use for the + /// The Field Value to use for the + private StringContent GetMultipartStringContent(Object fieldName, object fieldValue) + { + var contentDisposition = new ContentDispositionHeaderValue("form-data"); + // .NET does not enclose field names in quotes, however, modern browsers and curl do. + contentDisposition.Name = "\"" + LanguagePrimitives.ConvertTo(fieldName) + "\""; + + var result = new StringContent(LanguagePrimitives.ConvertTo(fieldValue)); + result.Headers.ContentDisposition = contentDisposition; + + return result; + } + + /// + /// Gets a from the supplied field name and . Uses to convert the fieldname to a string. + /// + /// The Field Name to use for the + /// The to use for the + private StreamContent GetMultipartStreamContent(Object fieldName, Stream stream) + { + var contentDisposition = new ContentDispositionHeaderValue("form-data"); + // .NET does not enclose field names in quotes, however, modern browsers and curl do. + contentDisposition.Name = "\"" + LanguagePrimitives.ConvertTo(fieldName) + "\""; + + var result = new StreamContent(stream); + result.Headers.ContentDisposition = contentDisposition; + result.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); + + return result; + } + + /// + /// Gets a from the supplied field name and file. Calls to create the and then sets the file name. + /// + /// The Field Name to use for the + /// The file to use for the + private StreamContent GetMultipartFileContent(Object fieldName, FileInfo file) + { + var result = GetMultipartStreamContent(fieldName: fieldName, stream: new FileStream(file.FullName, FileMode.Open)); + // .NET does not enclose field names in quotes, however, modern browsers and curl do. + result.Headers.ContentDisposition.FileName = "\"" + file.Name + "\""; + + return result; + } #endregion Helper Methods } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs index ee29d80e6f2b..39ac6bdf20e6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs @@ -1,31 +1,30 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Text; using System.Net.Http; -using System.Collections.Generic; +using System.Text; namespace Microsoft.PowerShell.Commands { /// - /// WebResponseObject + /// WebResponseObject. /// public partial class WebResponseObject { #region Properties /// - /// gets or protected sets the Content property + /// Gets or protected sets the Content property. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public byte[] Content { get; protected set; } /// - /// gets the StatusCode property + /// Gets the StatusCode property. /// public int StatusCode { @@ -33,7 +32,7 @@ public int StatusCode } /// - /// gets the StatusDescription property + /// Gets the StatusDescription property. /// public string StatusDescription { @@ -42,7 +41,7 @@ public string StatusDescription private MemoryStream _rawContentStream; /// - /// gets the RawContentStream property + /// Gets the RawContentStream property. /// public MemoryStream RawContentStream { @@ -50,15 +49,15 @@ public MemoryStream RawContentStream } /// - /// gets the RawContentLength property + /// Gets the RawContentLength property. /// public long RawContentLength { - get { return (null == RawContentStream ? -1 : RawContentStream.Length); } + get { return (RawContentStream == null ? -1 : RawContentStream.Length); } } /// - /// gets or protected sets the RawContent property + /// Gets or protected sets the RawContent property. /// public string RawContent { get; protected set; } @@ -76,7 +75,7 @@ private void InitializeContent() private bool IsPrintable(char c) { - return (Char.IsLetterOrDigit(c) || Char.IsPunctuation(c) || Char.IsSeparator(c) || Char.IsSymbol(c) || Char.IsWhiteSpace(c)); + return (char.IsLetterOrDigit(c) || char.IsPunctuation(c) || char.IsSeparator(c) || char.IsSymbol(c) || char.IsWhiteSpace(c)); } /// @@ -103,25 +102,25 @@ public sealed override string ToString() // TODO: Merge Partials /// - /// WebResponseObject + /// WebResponseObject. /// public partial class WebResponseObject { #region Properties /// - /// gets or sets the BaseResponse property + /// Gets or sets the BaseResponse property. /// public HttpResponseMessage BaseResponse { get; set; } /// - /// gets the Headers property + /// Gets the Headers property. /// public Dictionary> Headers { get { - if(_headers == null) + if (_headers == null) { _headers = WebResponseHelper.GetHeadersDictionary(BaseResponse); } @@ -133,7 +132,7 @@ public partial class WebResponseObject private Dictionary> _headers = null; /// - /// gets the RelationLink property + /// Gets the RelationLink property. /// public Dictionary RelationLink { get; internal set; } @@ -142,7 +141,7 @@ public partial class WebResponseObject #region Constructors /// - /// Constructor for WebResponseObject + /// Constructor for WebResponseObject. /// /// public WebResponseObject(HttpResponseMessage response) @@ -150,7 +149,7 @@ public WebResponseObject(HttpResponseMessage response) { } /// - /// Constructor for WebResponseObject with contentStream + /// Constructor for WebResponseObject with contentStream. /// /// /// @@ -180,12 +179,12 @@ private void InitializeRawContent(HttpResponseMessage baseResponse) private void SetResponse(HttpResponseMessage response, Stream contentStream) { - if (null == response) { throw new ArgumentNullException("response"); } + if (response == null) { throw new ArgumentNullException("response"); } BaseResponse = response; MemoryStream ms = contentStream as MemoryStream; - if (null != ms) + if (ms != null) { _rawContentStream = ms; } @@ -202,13 +201,13 @@ private void SetResponse(HttpResponseMessage response, Stream contentStream) { contentLength = StreamHelper.DefaultReadBuffer; } + int initialCapacity = (int)Math.Min(contentLength, StreamHelper.DefaultReadBuffer); _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, null); } // set the position of the content stream to the beginning _rawContentStream.Position = 0; } - #endregion } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertFromJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertFromJsonCommand.cs index 3718b0937c2b..3556c1ac39cd 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertFromJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertFromJsonCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -10,8 +9,8 @@ namespace Microsoft.PowerShell.Commands { /// - /// The ConvertFrom-Json command - /// This command convert a Json string representation to a JsonObject + /// The ConvertFrom-Json command. + /// This command converts a Json string representation to a JsonObject. /// [Cmdlet(VerbsData.ConvertFrom, "Json", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=217031", RemotingCapability = RemotingCapability.None)] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] @@ -37,12 +36,19 @@ public class ConvertFromJsonCommand : Cmdlet [Parameter()] public SwitchParameter AsHashtable { get; set; } + /// + /// Gets or sets the maximum depth the JSON input is allowed to have. By default, it is 1024. + /// + [Parameter()] + [ValidateRange(ValidateRangeKind.Positive)] + public int Depth { get; set; } = 1024; + #endregion parameters #region overrides /// - /// Buffers InputObjet contents available in the pipeline. + /// Buffers InputObjet contents available in the pipeline. /// protected override void ProcessRecord() { @@ -96,12 +102,12 @@ protected override void EndProcessing() /// /// ConvertFromJsonHelper is a helper method to convert to Json input to .Net Type. /// - /// Input String. + /// Input string. /// True if successfully converted, else returns false. private bool ConvertFromJsonHelper(string input) { ErrorRecord error = null; - object result = JsonObject.ConvertFromJson(input, AsHashtable.IsPresent, out error); + object result = JsonObject.ConvertFromJson(input, AsHashtable.IsPresent, Depth, out error); if (error != null) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs index b5ccb1442448..2de53f3beee5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs @@ -1,37 +1,25 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Diagnostics.CodeAnalysis; using System.Collections.Generic; using System.Management.Automation; -using System.Collections; -using System.Reflection; -using System.Text; -using System.Globalization; -using Dbg = System.Management.Automation; using System.Management.Automation.Internal; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; +using System.Threading; -// FxCop suppressions for resource strings: -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "WebCmdletStrings.resources", MessageId = "json")] -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "WebCmdletStrings.resources", MessageId = "Json")] +using Newtonsoft.Json; namespace Microsoft.PowerShell.Commands { /// - /// The ConvertTo-Json command - /// This command convert an object to a Json string representation + /// The ConvertTo-Json command. + /// This command converts an object to a Json string representation. /// [Cmdlet(VerbsData.ConvertTo, "Json", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=217032", RemotingCapability = RemotingCapability.None)] - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] public class ConvertToJsonCommand : PSCmdlet { - #region parameters /// - /// gets or sets the InputObject property + /// Gets or sets the InputObject property. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] [AllowNull] @@ -39,16 +27,21 @@ public class ConvertToJsonCommand : PSCmdlet private int _depth = 2; private const int maxDepthAllowed = 100; + private readonly CancellationTokenSource _cancellationSource = new CancellationTokenSource(); /// - /// gets or sets the Depth property + /// Gets or sets the Depth property. /// [Parameter] [ValidateRange(1, int.MaxValue)] - public int Depth { get { return _depth; } set { _depth = value; } } + public int Depth + { + get { return _depth; } + set { _depth = value; } + } /// - /// gets or sets the Compress property. + /// Gets or sets the Compress property. /// If the Compress property is set to be true, the Json string will /// be output in the compressed way. Otherwise, the Json string will /// be output with indentations. @@ -57,20 +50,33 @@ public class ConvertToJsonCommand : PSCmdlet public SwitchParameter Compress { get; set; } /// - /// gets or sets the EnumsAsStrings property. + /// Gets or sets the EnumsAsStrings property. /// If the EnumsAsStrings property is set to true, enum values will /// be converted to their string equivalent. Otherwise, enum values /// will be converted to their numeric equivalent. /// - [Parameter()] + [Parameter] public SwitchParameter EnumsAsStrings { get; set; } - #endregion parameters + /// + /// Gets or sets the AsArray property. + /// If the AsArray property is set to be true, the result JSON string will + /// be returned with surrounding '[', ']' chars. Otherwise, + /// the array symbols will occur only if there is more than one input object. + /// + [Parameter] + public SwitchParameter AsArray { get; set; } - #region overrides + /// + /// Specifies how strings are escaped when writing JSON text. + /// If the EscapeHandling property is set to EscapeHtml, the result JSON string will + /// be returned with HTML (<, >, &, ', ") and control characters (e.g. newline) are escaped. + /// + [Parameter] + public StringEscapeHandling EscapeHandling { get; set; } = StringEscapeHandling.Default; /// - /// Prerequisite checks + /// Prerequisite checks. /// protected override void BeginProcessing() { @@ -88,7 +94,7 @@ protected override void BeginProcessing() private List _inputObjects = new List(); /// - /// Caching the input objects for the convertto-json command + /// Caching the input objects for the command. /// protected override void ProcessRecord() { @@ -99,590 +105,38 @@ protected override void ProcessRecord() } /// - /// Do the conversion to json and write output + /// Do the conversion to json and write output. /// protected override void EndProcessing() { if (_inputObjects.Count > 0) { - object objectToProcess = (_inputObjects.Count > 1) ? (_inputObjects.ToArray() as object) : (_inputObjects[0]); - // Pre-process the object so that it serializes the same, except that properties whose - // values cannot be evaluated are treated as having the value null. - object preprocessedObject = ProcessValue(objectToProcess, 0); - JsonSerializerSettings jsonSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None, MaxDepth = 1024 }; - if (EnumsAsStrings) - { - jsonSettings.Converters.Add(new StringEnumConverter()); - } - if (!Compress) - { - jsonSettings.Formatting = Formatting.Indented; - } - string output = JsonConvert.SerializeObject(preprocessedObject, jsonSettings); - WriteObject(output); - } - } - - #endregion overrides - - #region convertOutputToPrettierFormat - - /// - /// Convert the Json string to a more readable format - /// - /// - /// - private string ConvertToPrettyJsonString(string json) - { - if (!json.StartsWith("{", StringComparison.OrdinalIgnoreCase) && !json.StartsWith("[", StringComparison.OrdinalIgnoreCase)) - { - return json; - } - - StringBuilder retStr = new StringBuilder(); - if (json.StartsWith("{", StringComparison.OrdinalIgnoreCase)) - { - retStr.Append('{'); - ConvertDictionary(json, 1, retStr, "", 0); - } - else if (json.StartsWith("[", StringComparison.OrdinalIgnoreCase)) - { - retStr.Append('['); - ConvertList(json, 1, retStr, "", 0); - } - - return retStr.ToString(); - } - - /// - /// Convert a Json List, which starts with '['. - /// - /// - /// - /// - /// - /// - /// - private int ConvertList(string json, int index, StringBuilder result, string padString, int numberOfSpaces) - { - result.Append("\r\n"); - StringBuilder newPadString = new StringBuilder(); - newPadString.Append(padString); - AddSpaces(numberOfSpaces, newPadString); - AddIndentations(1, newPadString); - - bool headChar = true; - - for (int i = index; i < json.Length; i++) - { - switch (json[i]) - { - case '{': - result.Append(newPadString.ToString()); - result.Append(json[i]); - i = ConvertDictionary(json, i + 1, result, newPadString.ToString(), 0); - headChar = false; - break; - case '[': - result.Append(newPadString.ToString()); - result.Append(json[i]); - i = ConvertList(json, i + 1, result, newPadString.ToString(), 0); - headChar = false; - break; - case ']': - result.Append("\r\n"); - result.Append(padString); - AddSpaces(numberOfSpaces, result); - result.Append(json[i]); - return i; - case '"': - if (headChar) - { - result.Append(newPadString.ToString()); - } - result.Append(json[i]); - i = ConvertQuotedString(json, i + 1, result); - headChar = false; - break; - case ',': - result.Append(json[i]); - result.Append("\r\n"); - headChar = true; - break; - default: - if (headChar) - { - result.Append(newPadString.ToString()); - } - result.Append(json[i]); - headChar = false; - break; - } - } - - Dbg.Diagnostics.Assert(false, "ConvertDictionary should return when encounter '}'"); - ThrowTerminatingError(NewError()); - return -1; - } - - /// - /// Convert the quoted string. - /// - /// - /// - /// - /// - private int ConvertQuotedString(string json, int index, StringBuilder result) - { - for (int i = index; i < json.Length; i++) - { - result.Append(json[i]); - if (json[i] == '"') - { - // Ensure that the quote is not escaped by iteratively searching backwards for the backslash. - // Examples: - // "a \" b" --> here second quote is escaped - // "c:\\" --> here second quote is not escaped - // - var j = i; - var escaped = false; - while (j > 0 && json[--j] == '\\') - { - escaped = !escaped; - } - - if (!escaped) - { - return i; - } - } - } - - Dbg.Diagnostics.Assert(false, "ConvertDictionary should return when encounter '}'"); - ThrowTerminatingError(NewError()); - return -1; - } - - /// - /// Convert a Json dictionary, which starts with '{'. - /// - /// - /// - /// - /// - /// - /// - private int ConvertDictionary(string json, int index, StringBuilder result, string padString, int numberOfSpaces) - { - result.Append("\r\n"); - StringBuilder newPadString = new StringBuilder(); - newPadString.Append(padString); - AddSpaces(numberOfSpaces, newPadString); - AddIndentations(1, newPadString); - - bool headChar = true; - bool beforeQuote = true; - int newSpaceCount = 0; - const int spaceCountAfterQuoteMark = 1; - - for (int i = index; i < json.Length; i++) - { - switch (json[i]) - { - case '{': - result.Append(json[i]); - i = ConvertDictionary(json, i + 1, result, newPadString.ToString(), newSpaceCount); - headChar = false; - break; - case '[': - result.Append(json[i]); - i = ConvertList(json, i + 1, result, newPadString.ToString(), newSpaceCount); - headChar = false; - break; - case '}': - result.Append("\r\n"); - result.Append(padString); - AddSpaces(numberOfSpaces, result); - result.Append(json[i]); - return i; - case '"': - if (headChar) - { - result.Append(newPadString.ToString()); - } - result.Append(json[i]); - int end = ConvertQuotedString(json, i + 1, result); - if (beforeQuote) - { - newSpaceCount = 0; - } - i = end; - headChar = false; - break; - case ':': - result.Append(json[i]); - AddSpaces(spaceCountAfterQuoteMark, result); - headChar = false; - beforeQuote = false; - break; - case ',': - result.Append(json[i]); - result.Append("\r\n"); - headChar = true; - beforeQuote = true; - newSpaceCount = 0; - break; - default: - if (headChar) - { - result.Append(newPadString.ToString()); - } - result.Append(json[i]); - if (beforeQuote) - { - newSpaceCount += 1; - } - headChar = false; - break; - } - } - - Dbg.Diagnostics.Assert(false, "ConvertDictionary should return when encounter '}'"); - ThrowTerminatingError(NewError()); - return -1; - } - - /// - /// Add tabs to result - /// - /// - /// - private void AddIndentations(int numberOfTabsToReturn, StringBuilder result) - { - int realNumber = numberOfTabsToReturn * 2; - for (int i = 0; i < realNumber; i++) - { - result.Append(' '); - } - } - - /// - /// Add spaces to result - /// - /// - /// - private void AddSpaces(int numberOfSpacesToReturn, StringBuilder result) - { - for (int i = 0; i < numberOfSpacesToReturn; i++) - { - result.Append(' '); - } - } - - private ErrorRecord NewError() - { - ErrorRecord errorRecord = new ErrorRecord( - new InvalidOperationException(WebCmdletStrings.JsonStringInBadFormat), - "JsonStringInBadFormat", - ErrorCategory.InvalidOperation, - InputObject); - return errorRecord; - } - - #endregion convertOutputToPrettierFormat - - /// - /// Return an alternate representation of the specified object that serializes the same JSON, except - /// that properties that cannot be evaluated are treated as having the value null. - /// - /// Primitive types are returned verbatim. Aggregate types are processed recursively. - /// - /// The object to be processed - /// The current depth into the object graph - /// An object suitable for serializing to JSON - private object ProcessValue(object obj, int depth) - { - PSObject pso = obj as PSObject; - - if (pso != null) - obj = pso.BaseObject; - - Object rv = obj; - bool isPurePSObj = false; - bool isCustomObj = false; - - if (obj == null - || DBNull.Value.Equals(obj) - || obj is string - || obj is char - || obj is bool - || obj is DateTime - || obj is DateTimeOffset - || obj is Guid - || obj is Uri - || obj is double - || obj is float - || obj is decimal) - { - rv = obj; - } - else if (obj is Newtonsoft.Json.Linq.JObject jObject) - { - rv = jObject.ToObject>(); - } - else - { - TypeInfo t = obj.GetType().GetTypeInfo(); - - if (t.IsPrimitive) - { - rv = obj; - } - else if (t.IsEnum) - { - // Win8:378368 Enums based on System.Int64 or System.UInt64 are not JSON-serializable - // because JavaScript does not support the necessary precision. - Type enumUnderlyingType = Enum.GetUnderlyingType(obj.GetType()); - if (enumUnderlyingType.Equals(typeof(Int64)) || enumUnderlyingType.Equals(typeof(UInt64))) - { - rv = obj.ToString(); - } - else - { - rv = obj; - } - } - else - { - if (depth > Depth) - { - if (pso != null && pso.immediateBaseObjectIsEmpty) - { - // The obj is a pure PSObject, we convert the original PSObject to a string, - // instead of its base object in this case - rv = LanguagePrimitives.ConvertTo(pso, typeof(string), - CultureInfo.InvariantCulture); - isPurePSObj = true; - } - else - { - rv = LanguagePrimitives.ConvertTo(obj, typeof(String), - CultureInfo.InvariantCulture); - } - } - else - { - IDictionary dict = obj as IDictionary; - if (dict != null) - { - rv = ProcessDictionary(dict, depth); - } - else - { - IEnumerable enumerable = obj as IEnumerable; - if (enumerable != null) - { - rv = ProcessEnumerable(enumerable, depth); - } - else - { - rv = ProcessCustomObject(obj, depth); - isCustomObj = true; - } - } - } - } - } - - rv = AddPsProperties(pso, rv, depth, isPurePSObj, isCustomObj); - - return rv; - } - - /// - /// Add to a base object any properties that might have been added to an object (via PSObject) through the Add-Member cmdlet. - /// - /// The containing PSObject, or null if the base object was not contained in a PSObject - /// The base object that might have been decorated with additional properties - /// The current depth into the object graph - /// the processed object is a pure PSObject - /// the processed object is a custom object - /// - /// The original base object if no additional properties had been added, - /// otherwise a dictionary containing the value of the original base object in the "value" key - /// as well as the names and values of an additional properties. - /// - private object AddPsProperties(object psobj, object obj, int depth, bool isPurePSObj, bool isCustomObj) - { - PSObject pso = psobj as PSObject; - - if (pso == null) - return obj; - - // when isPurePSObj is true, the obj is guaranteed to be a string converted by LanguagePrimitives - if (isPurePSObj) - return obj; - - bool wasDictionary = true; - IDictionary dict = obj as IDictionary; - - if (dict == null) - { - wasDictionary = false; - dict = new Dictionary(); - dict.Add("value", obj); - } - - AppendPsProperties(pso, dict, depth, isCustomObj); - - if (wasDictionary == false && dict.Count == 1) - return obj; - - return dict; - } - - /// - /// Append to a dictionary any properties that might have been added to an object (via PSObject) through the Add-Member cmdlet. - /// If the passed in object is a custom object (not a simple object, not a dictionary, not a list, get processed in ProcessCustomObject method), - /// we also take Adapted properties into account. Otherwise, we only consider the Extended properties. - /// When the object is a pure PSObject, it also gets processed in "ProcessCustomObject" before reaching this method, so we will - /// iterate both extended and adapted properties for it. Since it's a pure PSObject, there will be no adapted properties. - /// - /// The containing PSObject, or null if the base object was not contained in a PSObject - /// The dictionary to which any additional properties will be appended - /// The current depth into the object graph - /// The processed object is a custom object - private void AppendPsProperties(PSObject psobj, IDictionary receiver, int depth, bool isCustomObject) - { - // serialize only Extended and Adapted properties.. - PSMemberInfoCollection srcPropertiesToSearch = - new PSMemberInfoIntegratingCollection(psobj, - isCustomObject ? PSObject.GetPropertyCollection(PSMemberViewTypes.Extended | PSMemberViewTypes.Adapted) : - PSObject.GetPropertyCollection(PSMemberViewTypes.Extended)); - - foreach (PSPropertyInfo prop in srcPropertiesToSearch) - { - object value = null; - try - { - value = prop.Value; - } - catch (Exception) - { - } + object objectToProcess = (_inputObjects.Count > 1 || AsArray) ? (_inputObjects.ToArray() as object) : _inputObjects[0]; - if (!receiver.Contains(prop.Name)) - { - receiver[prop.Name] = ProcessValue(value, depth + 1); - } - } - } - - /// - /// Return an alternate representation of the specified dictionary that serializes the same JSON, except - /// that any contained properties that cannot be evaluated are treated as having the value null. - /// - /// - /// - /// - private object ProcessDictionary(IDictionary dict, int depth) - { - Dictionary result = new Dictionary(dict.Count); + var context = new JsonObject.ConvertToJsonContext( + Depth, + EnumsAsStrings.IsPresent, + Compress.IsPresent, + _cancellationSource.Token, + EscapeHandling, + targetCmdlet: this); - foreach (DictionaryEntry entry in dict) - { - string name = entry.Key as string; - if (name == null) + // null is returned only if the pipeline is stopping (e.g. ctrl+c is signaled). + // in that case, we shouldn't write the null to the output pipe. + string output = JsonObject.ConvertToJson(objectToProcess, in context); + if (output != null) { - // use the error string that matches the message from JavaScriptSerializer - var exception = - new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, - WebCmdletStrings.NonStringKeyInDictionary, - dict.GetType().FullName)); - ThrowTerminatingError(new ErrorRecord(exception, "NonStringKeyInDictionary", ErrorCategory.InvalidOperation, dict)); + WriteObject(output); } - - result.Add(name, ProcessValue(entry.Value, depth + 1)); } - - return result; } /// - /// Return an alternate representation of the specified collection that serializes the same JSON, except - /// that any contained properties that cannot be evaluated are treated as having the value null. + /// Process the Ctrl+C signal. /// - /// - /// - /// - private object ProcessEnumerable(IEnumerable enumerable, int depth) + protected override void StopProcessing() { - List result = new List(); - - foreach (object o in enumerable) - { - result.Add(ProcessValue(o, depth + 1)); - } - - return result; - } - - /// - /// Return an alternate representation of the specified aggregate object that serializes the same JSON, except - /// that any contained properties that cannot be evaluated are treated as having the value null. - /// - /// The result is a dictionary in which all public fields and public gettable properties of the original object - /// are represented. If any exception occurs while retrieving the value of a field or property, that entity - /// is included in the output dictionary with a value of null. - /// - /// - /// - /// - private object ProcessCustomObject(object o, int depth) - { - Dictionary result = new Dictionary(); - Type t = o.GetType(); - - foreach (FieldInfo info in t.GetFields(BindingFlags.Public | BindingFlags.Instance)) - { - if (!info.IsDefined(typeof(T), true)) - { - object value; - try - { - value = info.GetValue(o); - } - catch (Exception) - { - value = null; - } - - result.Add(info.Name, ProcessValue(value, depth + 1)); - } - } - - foreach (PropertyInfo info2 in t.GetProperties(BindingFlags.Public | BindingFlags.Instance)) - { - if (!info2.IsDefined(typeof(T), true)) - { - MethodInfo getMethod = info2.GetGetMethod(); - if ((getMethod != null) && (getMethod.GetParameters().Length <= 0)) - { - object value; - try - { - value = getMethod.Invoke(o, new object[0]); - } - catch (Exception) - { - value = null; - } - - result.Add(info2.Name, ProcessValue(value, depth + 1)); - } - } - } - return result; + _cancellationSource.Cancel(); } } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs index 944df03eb4ef..1de3a7c14e5b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs index f7d0c831845e..0a5441faef5a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.IO; using System.Management.Automation; using System.Net.Http; -using System.IO; namespace Microsoft.PowerShell.Commands { /// - /// The Invoke-RestMethod command + /// The Invoke-WebRequest command. /// This command makes an HTTP or HTTPS request to a web server and returns the results. /// [Cmdlet(VerbsLifecycle.Invoke, "WebRequest", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=217035", DefaultParameterSetName = "StandardMethod")] @@ -19,7 +18,7 @@ public class InvokeWebRequestCommand : WebRequestPSCmdlet #region Virtual Method Overrides /// - /// Default constructor for InvokeWebRequestCommand + /// Default constructor for InvokeWebRequestCommand. /// public InvokeWebRequestCommand() : base() { @@ -32,7 +31,7 @@ public InvokeWebRequestCommand() : base() /// internal override void ProcessResponse(HttpResponseMessage response) { - if (null == response) { throw new ArgumentNullException("response"); } + if (response == null) { throw new ArgumentNullException("response"); } Stream responseStream = StreamHelper.GetResponseStream(response); if (ShouldWriteToPipeline) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs index 256db1888f51..c338be5ac9f5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Net; @@ -25,6 +24,7 @@ internal WebProxy(Uri address) public ICredentials Credentials { get { return _credentials; } + set { _credentials = value; } } @@ -39,6 +39,7 @@ internal bool UseDefaultCredentials { return _credentials == CredentialCache.DefaultCredentials; } + set { _credentials = value ? CredentialCache.DefaultCredentials : null; @@ -58,7 +59,6 @@ public Uri GetProxy(Uri destination) } return _proxyAddress; - } public bool IsBypassed(Uri host) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs index 0949b3431760..b61977d87e9e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs @@ -1,11 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; -using System.Net.Http; using System.Globalization; +using System.Net.Http; namespace Microsoft.PowerShell.Commands { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs index 2623da9ea323..bc8502ccc163 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs @@ -1,10 +1,9 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. -using System.Net.Http; using System.IO; using System.Management.Automation; +using System.Net.Http; namespace Microsoft.PowerShell.Commands { @@ -16,12 +15,12 @@ internal static WebResponseObject GetResponseObject(HttpResponseMessage response if (WebResponseHelper.IsText(response)) { output = new BasicHtmlWebResponseObject(response, responseStream); - } else { output = new WebResponseObject(response, responseStream); } + return (output); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObject.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObject.cs index fcb17ce1753c..aadaf616d389 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObject.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObject.cs @@ -1,38 +1,37 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Collections.Generic; namespace Microsoft.PowerShell.Commands { /// - /// FormObject used in HtmlWebResponseObject + /// FormObject used in HtmlWebResponseObject. /// public class FormObject { /// - /// gets or private sets the Id property + /// Gets or private sets the Id property. /// public string Id { get; private set; } /// - /// gets or private sets the Method property + /// Gets or private sets the Method property. /// public string Method { get; private set; } /// - /// gets or private sets the Action property + /// Gets or private sets the Action property. /// public string Action { get; private set; } /// - /// gets or private sets the Fields property + /// Gets or private sets the Fields property. /// public Dictionary Fields { get; private set; } /// - /// constructor for FormObject + /// Constructor for FormObject. /// /// /// @@ -48,7 +47,7 @@ public FormObject(string id, string method, string action) internal void AddField(string key, string value) { string test; - if (null != key && !Fields.TryGetValue(key, out test)) + if (key != null && !Fields.TryGetValue(key, out test)) { Fields[key] = value; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObjectCollection.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObjectCollection.cs index 23e9129caf2a..53c603841363 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObjectCollection.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/FormObjectCollection.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.ObjectModel; @@ -8,12 +7,12 @@ namespace Microsoft.PowerShell.Commands { /// - /// FormObjectCollection used in HtmlWebResponseObject + /// FormObjectCollection used in HtmlWebResponseObject. /// public class FormObjectCollection : Collection { /// - /// Gets the FormObject from the key + /// Gets the FormObject from the key. /// /// /// @@ -30,6 +29,7 @@ public class FormObjectCollection : Collection break; } } + return (form); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs index f06514ab4afa..b72c348ffd99 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs @@ -1,69 +1,170 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections; using System.Collections.Generic; -using System.Globalization; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Management.Automation; +using System.Reflection; using System.Text.RegularExpressions; +using System.Threading; + using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; -using System.Collections; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Management.Automation.Internal; -using System.Reflection; namespace Microsoft.PowerShell.Commands { /// - /// JsonObject class + /// JsonObject class. /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Preferring Json over JSON")] public static class JsonObject { - private const int maxDepthAllowed = 100; + #region HelperTypes + + /// + /// Context for convert-to-json operation. + /// + public readonly struct ConvertToJsonContext + { + /// + /// Gets the maximum depth for walking the object graph. + /// + public readonly int MaxDepth; + + /// + /// Gets the cancellation token. + /// + public readonly CancellationToken CancellationToken; + + /// + /// Gets the StringEscapeHandling setting. + /// + public readonly StringEscapeHandling StringEscapeHandling; + + /// + /// Gets the EnumsAsStrings setting. + /// + public readonly bool EnumsAsStrings; + + /// + /// Gets the CompressOutput setting. + /// + public readonly bool CompressOutput; + + /// + /// Gets the target cmdlet that is doing the convert-to-json operation. + /// + public readonly PSCmdlet Cmdlet; + + /// + /// Initializes a new instance of the struct. + /// + /// The maximum depth to visit the object. + /// Indicates whether to use enum names for the JSON conversion. + /// Indicates whether to get the compressed output. + public ConvertToJsonContext(int maxDepth, bool enumsAsStrings, bool compressOutput) + : this(maxDepth, enumsAsStrings, compressOutput, CancellationToken.None, StringEscapeHandling.Default, targetCmdlet: null) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The maximum depth to visit the object. + /// Indicates whether to use enum names for the JSON conversion. + /// Indicates whether to get the compressed output. + /// Specifies the cancellation token for cancelling the operation. + /// Specifies how strings are escaped when writing JSON text. + /// Specifies the cmdlet that is calling this method. + public ConvertToJsonContext( + int maxDepth, + bool enumsAsStrings, + bool compressOutput, + CancellationToken cancellationToken, + StringEscapeHandling stringEscapeHandling, + PSCmdlet targetCmdlet) + { + this.MaxDepth = maxDepth; + this.CancellationToken = cancellationToken; + this.StringEscapeHandling = stringEscapeHandling; + this.EnumsAsStrings = enumsAsStrings; + this.CompressOutput = compressOutput; + this.Cmdlet = targetCmdlet; + } + } + + private class DuplicateMemberHashSet : HashSet + { + public DuplicateMemberHashSet(int capacity) + : base(capacity, StringComparer.OrdinalIgnoreCase) + { + } + } + + #endregion HelperTypes + + #region ConvertFromJson /// /// Convert a Json string back to an object of type PSObject. /// - /// - /// + /// The json text to convert. + /// An error record if the conversion failed. /// A PSObject. - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Preferring Json over JSON")] public static object ConvertFromJson(string input, out ErrorRecord error) { - return ConvertFromJson(input, false, out error); + return ConvertFromJson(input, returnHashtable: false, out error); + } + + /// + /// Convert a Json string back to an object of type or + /// depending on parameter . + /// + /// The json text to convert. + /// True if the result should be returned as a + /// instead of a + /// An error record if the conversion failed. + /// A or a + /// if the parameter is true. + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Preferring Json over JSON")] + public static object ConvertFromJson(string input, bool returnHashtable, out ErrorRecord error) + { + return ConvertFromJson(input, returnHashtable, maxDepth: 1024, out error); } /// - /// Convert a Json string back to an object of type PSObject or Hashtable depending on parameter . + /// Convert a JSON string back to an object of type or + /// depending on parameter . /// - /// - /// - /// - /// A PSObject or a Hashtable if the parameter is true. - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] - public static object ConvertFromJson(string input, bool returnHashTable, out ErrorRecord error) + /// The JSON text to convert. + /// True if the result should be returned as a + /// instead of a . + /// The max depth allowed when deserializing the json input. Set to null for no maximum. + /// An error record if the conversion failed. + /// A or a + /// if the parameter is true. + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Preferring Json over JSON")] + public static object ConvertFromJson(string input, bool returnHashtable, int? maxDepth, out ErrorRecord error) { if (input == null) { - throw new ArgumentNullException("input"); + throw new ArgumentNullException(nameof(input)); } error = null; - object obj = null; try { // JsonConvert.DeserializeObject does not throw an exception when an invalid Json array is passed. - // This issue is being tracked by https://github.com/JamesNK/Newtonsoft.Json/issues/1321. + // This issue is being tracked by https://github.com/JamesNK/Newtonsoft.Json/issues/1930. // To work around this, we need to identify when input is a Json array, and then try to parse it via JArray.Parse(). // If input starts with '[' (ignoring white spaces). - if ((Regex.Match(input, @"^\s*\[")).Success) + if (Regex.Match(input, @"^\s*\[").Success) { // JArray.Parse() will throw a JsonException if the array is invalid. // This will be caught by the catch block below, and then throw an @@ -74,58 +175,50 @@ public static object ConvertFromJson(string input, bool returnHashTable, out Err // we just continue the deserialization. } - obj = JsonConvert.DeserializeObject(input, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None, MaxDepth = 1024 }); + var obj = JsonConvert.DeserializeObject( + input, + new JsonSerializerSettings + { + // This TypeNameHandling setting is required to be secure. + TypeNameHandling = TypeNameHandling.None, + MetadataPropertyHandling = MetadataPropertyHandling.Ignore, + MaxDepth = maxDepth + }); - // JObject is a IDictionary - var dictionary = obj as JObject; - if (dictionary != null) + switch (obj) { - if (returnHashTable) - { - obj = PopulateHashTableFromJDictionary(dictionary, out error); - } - else - { - obj = PopulateFromJDictionary(dictionary, out error); - } - } - else - { - // JArray is a collection - var list = obj as JArray; - if (list != null) - { - if (returnHashTable) - { - obj = PopulateHashTableFromJArray(list, out error); - } - else - { - obj = PopulateFromJArray(list, out error); - } - } + case JObject dictionary: + // JObject is a IDictionary + return returnHashtable + ? PopulateHashTableFromJDictionary(dictionary, out error) + : PopulateFromJDictionary(dictionary, new DuplicateMemberHashSet(dictionary.Count), out error); + case JArray list: + return returnHashtable + ? PopulateHashTableFromJArray(list, out error) + : PopulateFromJArray(list, out error); + default: + return obj; } } catch (JsonException je) { var msg = string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.JsonDeserializationFailed, je.Message); + // the same as JavaScriptSerializer does throw new ArgumentException(msg, je); } - return obj; } // This function is a clone of PopulateFromDictionary using JObject as an input. - private static PSObject PopulateFromJDictionary(JObject entries, out ErrorRecord error) + private static PSObject PopulateFromJDictionary(JObject entries, DuplicateMemberHashSet memberHashTracker, out ErrorRecord error) { error = null; - PSObject result = new PSObject(); + var result = new PSObject(entries.Count); foreach (var entry in entries) { if (string.IsNullOrEmpty(entry.Key)) { - string errorMsg = string.Format(CultureInfo.InvariantCulture, - WebCmdletStrings.EmptyKeyInJsonString); + var errorMsg = string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.EmptyKeyInJsonString); error = new ErrorRecord( new InvalidOperationException(errorMsg), "EmptyKeyInJsonString", @@ -136,10 +229,10 @@ private static PSObject PopulateFromJDictionary(JObject entries, out ErrorRecord // Case sensitive duplicates should normally not occur since JsonConvert.DeserializeObject // does not throw when encountering duplicates and just uses the last entry. - if (result.Properties.Any(psPropertyInfo => psPropertyInfo.Name.Equals(entry.Key, StringComparison.InvariantCulture))) + if (memberHashTracker.TryGetValue(entry.Key, out var maybePropertyName) + && string.Compare(entry.Key, maybePropertyName, StringComparison.CurrentCulture) == 0) { - string errorMsg = string.Format(CultureInfo.InvariantCulture, - WebCmdletStrings.DuplicateKeysInJsonString, entry.Key); + var errorMsg = string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.DuplicateKeysInJsonString, entry.Key); error = new ErrorRecord( new InvalidOperationException(errorMsg), "DuplicateKeysInJsonString", @@ -150,11 +243,9 @@ private static PSObject PopulateFromJDictionary(JObject entries, out ErrorRecord // Compare case insensitive to tell the user to use the -AsHashTable option instead. // This is because PSObject cannot have keys with different casing. - PSPropertyInfo property = result.Properties[entry.Key]; - if (property != null) + if (memberHashTracker.TryGetValue(entry.Key, out var propertyName)) { - string errorMsg = string.Format(CultureInfo.InvariantCulture, - WebCmdletStrings.KeysWithDifferentCasingInJsonString, property.Name, entry.Key); + var errorMsg = string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.KeysWithDifferentCasingInJsonString, propertyName, entry.Key); error = new ErrorRecord( new InvalidOperationException(errorMsg), "KeysWithDifferentCasingInJsonString", @@ -164,36 +255,41 @@ private static PSObject PopulateFromJDictionary(JObject entries, out ErrorRecord } // Array - else if (entry.Value is JArray) + switch (entry.Value) { - JArray list = entry.Value as JArray; - ICollection listResult = PopulateFromJArray(list, out error); - if (error != null) - { - return null; - } - result.Properties.Add(new PSNoteProperty(entry.Key, listResult)); - } + case JArray list: + { + var listResult = PopulateFromJArray(list, out error); + if (error != null) + { + return null; + } - // Dictionary - else if (entry.Value is JObject) - { - JObject dic = entry.Value as JObject; - PSObject dicResult = PopulateFromJDictionary(dic, out error); - if (error != null) - { - return null; - } - result.Properties.Add(new PSNoteProperty(entry.Key, dicResult)); - } + result.Properties.Add(new PSNoteProperty(entry.Key, listResult)); + break; + } + case JObject dic: + { + // Dictionary + var dicResult = PopulateFromJDictionary(dic, new DuplicateMemberHashSet(dic.Count), out error); + if (error != null) + { + return null; + } - // Value - else // (entry.Value is JValue) - { - JValue theValue = entry.Value as JValue; - result.Properties.Add(new PSNoteProperty(entry.Key, theValue.Value)); + result.Properties.Add(new PSNoteProperty(entry.Key, dicResult)); + break; + } + case JValue value: + { + result.Properties.Add(new PSNoteProperty(entry.Key, value.Value)); + break; + } } + + memberHashTracker.Add(entry.Key); } + return result; } @@ -201,56 +297,60 @@ private static PSObject PopulateFromJDictionary(JObject entries, out ErrorRecord private static ICollection PopulateFromJArray(JArray list, out ErrorRecord error) { error = null; - List result = new List(); + var result = new object[list.Count]; - foreach (var element in list) + for (var index = 0; index < list.Count; index++) { - // Array - if (element is JArray) + var element = list[index]; + switch (element) { - JArray subList = element as JArray; - ICollection listResult = PopulateFromJArray(subList, out error); - if (error != null) - { - return null; - } - result.Add(listResult); - } + case JArray subList: + { + // Array + var listResult = PopulateFromJArray(subList, out error); + if (error != null) + { + return null; + } - // Dictionary - else if (element is JObject) - { - JObject dic = element as JObject; - PSObject dicResult = PopulateFromJDictionary(dic, out error); - if (error != null) - { - return null; - } - result.Add(dicResult); - } + result[index] = listResult; + break; + } + case JObject dic: + { + // Dictionary + var dicResult = PopulateFromJDictionary(dic, new DuplicateMemberHashSet(dic.Count), out error); + if (error != null) + { + return null; + } - // Value - else // (element is JValue) - { - result.Add(((JValue)element).Value); + result[index] = dicResult; + break; + } + case JValue value: + { + result[index] = value.Value; + break; + } } } - return result.ToArray(); + + return result; } // This function is a clone of PopulateFromDictionary using JObject as an input. private static Hashtable PopulateHashTableFromJDictionary(JObject entries, out ErrorRecord error) { error = null; - Hashtable result = new Hashtable(); + Hashtable result = new Hashtable(entries.Count); foreach (var entry in entries) { // Case sensitive duplicates should normally not occur since JsonConvert.DeserializeObject // does not throw when encountering duplicates and just uses the last entry. if (result.ContainsKey(entry.Key)) { - string errorMsg = string.Format(CultureInfo.InvariantCulture, - WebCmdletStrings.DuplicateKeysInJsonString, entry.Key); + string errorMsg = string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.DuplicateKeysInJsonString, entry.Key); error = new ErrorRecord( new InvalidOperationException(errorMsg), "DuplicateKeysInJsonString", @@ -259,79 +359,438 @@ private static Hashtable PopulateHashTableFromJDictionary(JObject entries, out E return null; } - // Array - else if (entry.Value is JArray) + switch (entry.Value) + { + case JArray list: + { + // Array + var listResult = PopulateHashTableFromJArray(list, out error); + if (error != null) + { + return null; + } + + result.Add(entry.Key, listResult); + break; + } + case JObject dic: + { + // Dictionary + var dicResult = PopulateHashTableFromJDictionary(dic, out error); + if (error != null) + { + return null; + } + + result.Add(entry.Key, dicResult); + break; + } + case JValue value: + { + result.Add(entry.Key, value.Value); + break; + } + } + } + + return result; + } + + // This function is a clone of PopulateFromList using JArray as input. + private static ICollection PopulateHashTableFromJArray(JArray list, out ErrorRecord error) + { + error = null; + var result = new object[list.Count]; + + for (var index = 0; index < list.Count; index++) + { + var element = list[index]; + + switch (element) + { + case JArray array: + { + // Array + var listResult = PopulateHashTableFromJArray(array, out error); + if (error != null) + { + return null; + } + + result[index] = listResult; + break; + } + case JObject dic: + { + // Dictionary + var dicResult = PopulateHashTableFromJDictionary(dic, out error); + if (error != null) + { + return null; + } + + result[index] = dicResult; + break; + } + case JValue value: + { + result[index] = value.Value; + break; + } + } + } + + return result; + } + + #endregion ConvertFromJson + + #region ConvertToJson + + /// + /// Convert an object to JSON string. + /// + public static string ConvertToJson(object objectToProcess, in ConvertToJsonContext context) + { + try + { + // Pre-process the object so that it serializes the same, except that properties whose + // values cannot be evaluated are treated as having the value null. + object preprocessedObject = ProcessValue(objectToProcess, currentDepth: 0, in context); + var jsonSettings = new JsonSerializerSettings { - JArray list = entry.Value as JArray; - ICollection listResult = PopulateHashTableFromJArray(list, out error); - if (error != null) + // This TypeNameHandling setting is required to be secure. + TypeNameHandling = TypeNameHandling.None, + MaxDepth = 1024, + StringEscapeHandling = context.StringEscapeHandling + }; + + if (context.EnumsAsStrings) + { + jsonSettings.Converters.Add(new StringEnumConverter()); + } + + if (!context.CompressOutput) + { + jsonSettings.Formatting = Formatting.Indented; + } + + return JsonConvert.SerializeObject(preprocessedObject, jsonSettings); + } + catch (OperationCanceledException) + { + return null; + } + } + + /// + /// Return an alternate representation of the specified object that serializes the same JSON, except + /// that properties that cannot be evaluated are treated as having the value null. + /// Primitive types are returned verbatim. Aggregate types are processed recursively. + /// + /// The object to be processed. + /// The current depth into the object graph. + /// The context to use for the convert-to-json operation. + /// An object suitable for serializing to JSON. + private static object ProcessValue(object obj, int currentDepth, in ConvertToJsonContext context) + { + context.CancellationToken.ThrowIfCancellationRequested(); + + PSObject pso = obj as PSObject; + + if (pso != null) + { + obj = pso.BaseObject; + } + + object rv = obj; + bool isPurePSObj = false; + bool isCustomObj = false; + + if (obj == null + || DBNull.Value.Equals(obj) + || obj is string + || obj is char + || obj is bool + || obj is DateTime + || obj is DateTimeOffset + || obj is Guid + || obj is Uri + || obj is double + || obj is float + || obj is decimal) + { + rv = obj; + } + else if (obj is Newtonsoft.Json.Linq.JObject jObject) + { + rv = jObject.ToObject>(); + } + else + { + Type t = obj.GetType(); + + if (t.IsPrimitive) + { + rv = obj; + } + else if (t.IsEnum) + { + // Win8:378368 Enums based on System.Int64 or System.UInt64 are not JSON-serializable + // because JavaScript does not support the necessary precision. + Type enumUnderlyingType = Enum.GetUnderlyingType(obj.GetType()); + if (enumUnderlyingType.Equals(typeof(Int64)) || enumUnderlyingType.Equals(typeof(UInt64))) + { + rv = obj.ToString(); + } + else { - return null; + rv = obj; } - result.Add(entry.Key, listResult); } - - // Dictionary - else if (entry.Value is JObject) + else { - JObject dic = entry.Value as JObject; - Hashtable dicResult = PopulateHashTableFromJDictionary(dic, out error); - if (error != null) + if (currentDepth > context.MaxDepth) + { + if (pso != null && pso.ImmediateBaseObjectIsEmpty) + { + // The obj is a pure PSObject, we convert the original PSObject to a string, + // instead of its base object in this case + rv = LanguagePrimitives.ConvertTo(pso, typeof(string), + CultureInfo.InvariantCulture); + isPurePSObj = true; + } + else + { + rv = LanguagePrimitives.ConvertTo(obj, typeof(String), + CultureInfo.InvariantCulture); + } + } + else { - return null; + IDictionary dict = obj as IDictionary; + if (dict != null) + { + rv = ProcessDictionary(dict, currentDepth, in context); + } + else + { + IEnumerable enumerable = obj as IEnumerable; + if (enumerable != null) + { + rv = ProcessEnumerable(enumerable, currentDepth, in context); + } + else + { + rv = ProcessCustomObject(obj, currentDepth, in context); + isCustomObj = true; + } + } } - result.Add(entry.Key, dicResult); + } + } + + rv = AddPsProperties(pso, rv, currentDepth, isPurePSObj, isCustomObj, in context); + + return rv; + } + + /// + /// Add to a base object any properties that might have been added to an object (via PSObject) through the Add-Member cmdlet. + /// + /// The containing PSObject, or null if the base object was not contained in a PSObject. + /// The base object that might have been decorated with additional properties. + /// The current depth into the object graph. + /// The processed object is a pure PSObject. + /// The processed object is a custom object. + /// The context for the operation. + /// + /// The original base object if no additional properties had been added, + /// otherwise a dictionary containing the value of the original base object in the "value" key + /// as well as the names and values of an additional properties. + /// + private static object AddPsProperties(object psObj, object obj, int depth, bool isPurePSObj, bool isCustomObj, in ConvertToJsonContext context) + { + PSObject pso = psObj as PSObject; + + if (pso == null) + { + return obj; + } + + // when isPurePSObj is true, the obj is guaranteed to be a string converted by LanguagePrimitives + if (isPurePSObj) + { + return obj; + } + + bool wasDictionary = true; + IDictionary dict = obj as IDictionary; + + if (dict == null) + { + wasDictionary = false; + dict = new Dictionary(); + dict.Add("value", obj); + } + + AppendPsProperties(pso, dict, depth, isCustomObj, in context); + + if (wasDictionary == false && dict.Count == 1) + { + return obj; + } + + return dict; + } + + /// + /// Append to a dictionary any properties that might have been added to an object (via PSObject) through the Add-Member cmdlet. + /// If the passed in object is a custom object (not a simple object, not a dictionary, not a list, get processed in ProcessCustomObject method), + /// we also take Adapted properties into account. Otherwise, we only consider the Extended properties. + /// When the object is a pure PSObject, it also gets processed in "ProcessCustomObject" before reaching this method, so we will + /// iterate both extended and adapted properties for it. Since it's a pure PSObject, there will be no adapted properties. + /// + /// The containing PSObject, or null if the base object was not contained in a PSObject. + /// The dictionary to which any additional properties will be appended. + /// The current depth into the object graph. + /// The processed object is a custom object. + /// The context for the operation. + private static void AppendPsProperties(PSObject psObj, IDictionary receiver, int depth, bool isCustomObject, in ConvertToJsonContext context) + { + // serialize only Extended and Adapted properties.. + PSMemberInfoCollection srcPropertiesToSearch = + new PSMemberInfoIntegratingCollection(psObj, + isCustomObject ? PSObject.GetPropertyCollection(PSMemberViewTypes.Extended | PSMemberViewTypes.Adapted) : + PSObject.GetPropertyCollection(PSMemberViewTypes.Extended)); + + foreach (PSPropertyInfo prop in srcPropertiesToSearch) + { + object value = null; + try + { + value = prop.Value; + } + catch (Exception) + { } - // Value - else // (entry.Value is JValue) + if (!receiver.Contains(prop.Name)) { - JValue theValue = entry.Value as JValue; - result.Add(entry.Key, theValue.Value); + receiver[prop.Name] = ProcessValue(value, depth + 1, in context); } } - return result; } - // This function is a clone of PopulateFromList using JArray as input. - private static ICollection PopulateHashTableFromJArray(JArray list, out ErrorRecord error) + /// + /// Return an alternate representation of the specified dictionary that serializes the same JSON, except + /// that any contained properties that cannot be evaluated are treated as having the value null. + /// + private static object ProcessDictionary(IDictionary dict, int depth, in ConvertToJsonContext context) { - error = null; - List result = new List(); + Dictionary result = new Dictionary(dict.Count); - foreach (var element in list) + foreach (DictionaryEntry entry in dict) { - // Array - if (element is JArray) + string name = entry.Key as string; + if (name == null) { - JArray subList = element as JArray; - ICollection listResult = PopulateHashTableFromJArray(subList, out error); - if (error != null) + // use the error string that matches the message from JavaScriptSerializer + string errorMsg = string.Format( + CultureInfo.CurrentCulture, + WebCmdletStrings.NonStringKeyInDictionary, + dict.GetType().FullName); + + var exception = new InvalidOperationException(errorMsg); + if (context.Cmdlet != null) + { + var errorRecord = new ErrorRecord(exception, "NonStringKeyInDictionary", ErrorCategory.InvalidOperation, dict); + context.Cmdlet.ThrowTerminatingError(errorRecord); + } + else { - return null; + throw exception; } - result.Add(listResult); } - // Dictionary - else if (element is JObject) + result.Add(name, ProcessValue(entry.Value, depth + 1, in context)); + } + + return result; + } + + /// + /// Return an alternate representation of the specified collection that serializes the same JSON, except + /// that any contained properties that cannot be evaluated are treated as having the value null. + /// + private static object ProcessEnumerable(IEnumerable enumerable, int depth, in ConvertToJsonContext context) + { + List result = new List(); + + foreach (object o in enumerable) + { + result.Add(ProcessValue(o, depth + 1, in context)); + } + + return result; + } + + /// + /// Return an alternate representation of the specified aggregate object that serializes the same JSON, except + /// that any contained properties that cannot be evaluated are treated as having the value null. + /// + /// The result is a dictionary in which all public fields and public gettable properties of the original object + /// are represented. If any exception occurs while retrieving the value of a field or property, that entity + /// is included in the output dictionary with a value of null. + /// + private static object ProcessCustomObject(object o, int depth, in ConvertToJsonContext context) + { + Dictionary result = new Dictionary(); + Type t = o.GetType(); + + foreach (FieldInfo info in t.GetFields(BindingFlags.Public | BindingFlags.Instance)) + { + if (!info.IsDefined(typeof(T), true)) { - JObject dic = element as JObject; - Hashtable dicResult = PopulateHashTableFromJDictionary(dic, out error); - if (error != null) + object value; + try + { + value = info.GetValue(o); + } + catch (Exception) { - return null; + value = null; } - result.Add(dicResult); + + result.Add(info.Name, ProcessValue(value, depth + 1, in context)); } + } - // Value - else // (element is JValue) + foreach (PropertyInfo info2 in t.GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (!info2.IsDefined(typeof(T), true)) { - result.Add(((JValue)element).Value); + MethodInfo getMethod = info2.GetGetMethod(); + if ((getMethod != null) && (getMethod.GetParameters().Length <= 0)) + { + object value; + try + { + value = getMethod.Invoke(o, Array.Empty()); + } + catch (Exception) + { + value = null; + } + + result.Add(info2.Name, ProcessValue(value, depth + 1, in context)); + } } } - return result.ToArray(); + + return result; } + + #endregion ConvertToJson } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/PSUserAgent.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/PSUserAgent.cs index 7fd144c3e344..be3b79ecfc5e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/PSUserAgent.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/PSUserAgent.cs @@ -1,21 +1,19 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Globalization; using System.Management.Automation; using System.Runtime.InteropServices; -using System.Globalization; using System.Text.RegularExpressions; namespace Microsoft.PowerShell.Commands { /// - /// Construct the Useragent string + /// Construct the Useragent string. /// public static class PSUserAgent { - private static string s_windowsUserAgent; internal static string UserAgent @@ -31,7 +29,7 @@ internal static string UserAgent } /// - /// Useragent string for InternetExplorer (9.0) + /// Useragent string for InternetExplorer (9.0). /// public static string InternetExplorer { @@ -46,7 +44,7 @@ public static string InternetExplorer } /// - /// Useragent string for Firefox (4.0) + /// Useragent string for Firefox (4.0). /// public static string FireFox { @@ -61,7 +59,7 @@ public static string FireFox } /// - /// Useragent string for Chrome (7.0) + /// Useragent string for Chrome (7.0). /// public static string Chrome { @@ -76,7 +74,7 @@ public static string Chrome } /// - /// Useragent string for Opera (9.0) + /// Useragent string for Opera (9.0). /// public static string Opera { @@ -91,7 +89,7 @@ public static string Opera } /// - /// Useragent string for Safari (5.0) + /// Useragent string for Safari (5.0). /// public static string Safari { @@ -130,7 +128,8 @@ internal static string PlatformName if (Platform.IsWindows) { // only generate the windows user agent once - if(s_windowsUserAgent == null){ + if (s_windowsUserAgent == null) + { // find the version in the windows operating system description Regex pattern = new Regex(@"\d+(\.\d+)+"); string versionText = pattern.Match(OS).Value; @@ -152,7 +151,7 @@ internal static string PlatformName { // unknown/unsupported platform Diagnostics.Assert(false, "Unable to determine Operating System Platform"); - return String.Empty; + return string.Empty; } } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 7664652cb6c7..f0ea77d50d13 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -1,15 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; -using System.Text.RegularExpressions; using System.IO; using System.IO.Compression; using System.Management.Automation; using System.Management.Automation.Internal; using System.Net.Http; +using System.Text; +using System.Text.RegularExpressions; namespace Microsoft.PowerShell.Commands { @@ -31,11 +30,10 @@ internal class WebResponseContentMemoryStream : MemoryStream #region Constructors /// - /// /// /// /// - /// Owner cmdlet if any + /// Owner cmdlet if any. internal WebResponseContentMemoryStream(Stream stream, int initialCapacity, Cmdlet cmdlet) : base(initialCapacity) { @@ -45,7 +43,6 @@ internal WebResponseContentMemoryStream(Stream stream, int initialCapacity, Cmdl #endregion /// - /// /// public override bool CanRead { @@ -56,7 +53,6 @@ public override bool CanRead } /// - /// /// public override bool CanSeek { @@ -67,7 +63,6 @@ public override bool CanSeek } /// - /// /// public override bool CanTimeout { @@ -78,7 +73,6 @@ public override bool CanTimeout } /// - /// /// public override bool CanWrite { @@ -89,7 +83,6 @@ public override bool CanWrite } /// - /// /// public override long Length { @@ -101,7 +94,6 @@ public override long Length } /// - /// /// /// /// @@ -114,7 +106,6 @@ public override System.Threading.Tasks.Task CopyToAsync(Stream destination, int } /// - /// /// /// /// @@ -127,7 +118,6 @@ public override int Read(byte[] buffer, int offset, int count) } /// - /// /// /// /// @@ -141,7 +131,6 @@ public override System.Threading.Tasks.Task ReadAsync(byte[] buffer, int of } /// - /// /// /// public override int ReadByte() @@ -151,7 +140,6 @@ public override int ReadByte() } /// - /// /// /// public override void SetLength(long value) @@ -161,7 +149,6 @@ public override void SetLength(long value) } /// - /// /// /// public override byte[] ToArray() @@ -171,7 +158,6 @@ public override byte[] ToArray() } /// - /// /// /// /// @@ -183,7 +169,6 @@ public override void Write(byte[] buffer, int offset, int count) } /// - /// /// /// /// @@ -197,7 +182,6 @@ public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset } /// - /// /// /// public override void WriteByte(byte value) @@ -207,7 +191,6 @@ public override void WriteByte(byte value) } /// - /// /// /// public override void WriteTo(Stream stream) @@ -217,7 +200,6 @@ public override void WriteTo(Stream stream) } /// - /// /// protected override void Dispose(bool disposing) { @@ -225,11 +207,11 @@ protected override void Dispose(bool disposing) } /// - /// /// private void Initialize() { if (_isInitialized) { return; } + _isInitialized = true; try { @@ -238,7 +220,7 @@ private void Initialize() ProgressRecord record = new ProgressRecord(StreamHelper.ActivityId, WebCmdletStrings.ReadResponseProgressActivity, "statusDescriptionPlaceholder"); for (int read = 1; 0 < read; totalLength += read) { - if (null != _ownerCmdlet) + if (_ownerCmdlet != null) { record.StatusDescription = StringUtil.Format(WebCmdletStrings.ReadResponseProgressStatus, totalLength); _ownerCmdlet.WriteProgress(record); @@ -316,7 +298,6 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet) } } while (read != 0); - if (cmdlet != null) { ProgressRecord record = new ProgressRecord(ActivityId, @@ -344,9 +325,20 @@ internal static void WriteToStream(byte[] input, Stream output) /// internal static void SaveStreamToFile(Stream stream, string filePath, PSCmdlet cmdlet) { - using (FileStream output = File.Create(filePath)) + // If the web cmdlet should resume, append the file instead of overwriting. + if (cmdlet is WebRequestPSCmdlet webCmdlet && webCmdlet.ShouldResume) + { + using (FileStream output = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.Read)) + { + WriteToStream(stream, output, cmdlet); + } + } + else { - WriteToStream(stream, output, cmdlet); + using (FileStream output = File.Create(filePath)) + { + WriteToStream(stream, output, cmdlet); + } } } @@ -405,6 +397,7 @@ internal static string DecodeStream(Stream stream, string characterSet, out Enco { encoding = null; } + return DecodeStream(stream, ref encoding); } @@ -420,47 +413,54 @@ internal static bool TryGetEncoding(string characterSet, out Encoding encoding) { encoding = null; } + return result; } - static readonly Regex s_metaexp = new Regex(@"<]*charset\s*=\s*[""'\n]?(?[A-Za-z].[^\s""'\n<>]*)[\s""'\n>]"); + private static readonly Regex s_metaexp = new Regex( + @"<]*charset\s*=\s*[""'\n]?(?[A-Za-z].[^\s""'\n<>]*)[\s""'\n>]", + RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase + ); internal static string DecodeStream(Stream stream, ref Encoding encoding) { bool isDefaultEncoding = false; - if (null == encoding) + if (encoding == null) { // Use the default encoding if one wasn't provided encoding = ContentHelper.GetDefaultEncoding(); isDefaultEncoding = true; } - string content = StreamToString (stream, encoding); - if (isDefaultEncoding) do + string content = StreamToString(stream, encoding); + if (isDefaultEncoding) { - // check for a charset attribute on the meta element to override the default. - Match match = s_metaexp.Match(content); - if (match.Success) + do { - Encoding localEncoding = null; - string characterSet = match.Groups["charset"].Value; - - if (TryGetEncoding(characterSet, out localEncoding)) + // check for a charset attribute on the meta element to override the default. + Match match = s_metaexp.Match(content); + if (match.Success) { - stream.Seek(0, SeekOrigin.Begin); - content = StreamToString(stream, localEncoding); - // report the encoding used. - encoding = localEncoding; + Encoding localEncoding = null; + string characterSet = match.Groups["charset"].Value; + + if (TryGetEncoding(characterSet, out localEncoding)) + { + stream.Seek(0, SeekOrigin.Begin); + content = StreamToString(stream, localEncoding); + // report the encoding used. + encoding = localEncoding; + } } - } - } while (false); + } while (false); + } return content; } - internal static Byte[] EncodeToBytes(String str, Encoding encoding) + internal static byte[] EncodeToBytes(String str, Encoding encoding) { - if (null == encoding) + if (encoding == null) { // just use the default encoding if one wasn't provided encoding = ContentHelper.GetDefaultEncoding(); @@ -469,7 +469,7 @@ internal static Byte[] EncodeToBytes(String str, Encoding encoding) return encoding.GetBytes(str); } - internal static Byte[] EncodeToBytes(String str) + internal static byte[] EncodeToBytes(String str) { return EncodeToBytes(str, null); } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebCmdletElementCollection.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebCmdletElementCollection.cs index 83044fabc9cf..340baf18550a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebCmdletElementCollection.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebCmdletElementCollection.cs @@ -1,15 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Management.Automation; -using System.Collections.Generic; namespace Microsoft.PowerShell.Commands { /// - /// WebCmdletElementCollection for elements in html web responses + /// WebCmdletElementCollection for elements in html web responses. /// public class WebCmdletElementCollection : ReadOnlyCollection { @@ -19,10 +18,10 @@ internal WebCmdletElementCollection(IList list) } /// - /// Finds the element with name or id + /// Finds the element with name or id. /// /// - /// + /// Found element as PSObject. public PSObject Find(string nameOrId) { // try Id first @@ -32,20 +31,20 @@ public PSObject Find(string nameOrId) } /// - /// Finds the element by id + /// Finds the element by id. /// /// - /// + /// Found element as PSObject. public PSObject FindById(string id) { return Find(id, true); } /// - /// Finds the element by name + /// Finds the element by name. /// /// - /// + /// Found element as PSObject. public PSObject FindByName(string name) { return Find(name, false); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestMethod.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestMethod.cs index 11afdf24b190..1ed35bd95459 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestMethod.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestMethod.cs @@ -1,61 +1,60 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. namespace Microsoft.PowerShell.Commands { /// - /// enums for web request method. + /// Enums for web request method. /// public enum WebRequestMethod { /// - /// Default method + /// Default method. /// Default, /// - /// GET method + /// GET method. /// Get, /// - /// HEAD method + /// HEAD method. /// Head, /// - /// POST method + /// POST method. /// Post, /// - /// PUT method + /// PUT method. /// Put, /// - /// DELETE method + /// DELETE method. /// Delete, /// - /// TRACE method + /// TRACE method. /// Trace, /// - /// OPTIONS method + /// OPTIONS method. /// Options, /// - /// MERGE method + /// MERGE method. /// Merge, /// - /// PATCH method + /// PATCH method. /// Patch, } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs index b55639acd778..384c72a5219e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs @@ -1,10 +1,9 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Net; using System.Collections.Generic; +using System.Net; using System.Security.Cryptography.X509Certificates; namespace Microsoft.PowerShell.Commands @@ -15,35 +14,35 @@ namespace Microsoft.PowerShell.Commands public class WebRequestSession { /// - /// gets or sets the Header property + /// Gets or sets the Header property. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public Dictionary Headers { get; set; } /// - /// gets or sets the content Headers when using HttpClient + /// Gets or sets the content Headers when using HttpClient. /// internal Dictionary ContentHeaders { get; set; } /// - /// gets or sets the Cookies property + /// Gets or sets the Cookies property. /// public CookieContainer Cookies { get; set; } #region Credentials /// - /// gets or sets the UseDefaultCredentials property + /// Gets or sets the UseDefaultCredentials property. /// public bool UseDefaultCredentials { get; set; } /// - /// gets or sets the Credentials property + /// Gets or sets the Credentials property. /// public ICredentials Credentials { get; set; } /// - /// gets or sets the Certificates property + /// Gets or sets the Certificates property. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public X509CertificateCollection Certificates { get; set; } @@ -51,20 +50,30 @@ public class WebRequestSession #endregion /// - /// gets or sets the UserAgent property + /// Gets or sets the UserAgent property. /// public string UserAgent { get; set; } /// - /// gets or sets the Proxy property + /// Gets or sets the Proxy property. /// public IWebProxy Proxy { get; set; } /// - /// gets or sets the RedirectMax property + /// Gets or sets the RedirectMax property. /// public int MaximumRedirection { get; set; } + /// + /// Gets or sets the count of retries for request failures. + /// + public int MaximumRetryCount { get; set; } + + /// + /// Gets or sets the interval in seconds between retries. + /// + public int RetryIntervalInSeconds { get; set; } + /// /// Construct a new instance of a WebRequestSession object. /// @@ -95,10 +104,11 @@ public WebRequestSession() /// The certificate to be added. internal void AddCertificate(X509Certificate certificate) { - if (null == Certificates) + if (Certificates == null) { Certificates = new X509CertificateCollection(); } + Certificates.Add(certificate); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs index 2ac76d2c63a9..376f30f516a4 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; @@ -8,56 +7,38 @@ namespace Microsoft.PowerShell.Commands { #region WriteOutputCommand /// - /// This class implements Write-output command - /// + /// This class implements Write-Output command. /// [Cmdlet(VerbsCommunications.Write, "Output", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113427", RemotingCapability = RemotingCapability.None)] public sealed class WriteOutputCommand : PSCmdlet { - private PSObject[] _inputObjects = null; - /// - /// Holds the list of objects to be Written + /// Holds the list of objects to be written. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromRemainingArguments = true)] [AllowNull] [AllowEmptyCollection] - public PSObject[] InputObject - { - get { return _inputObjects; } - set { _inputObjects = value; } - } + public PSObject InputObject { get; set; } /// - /// Prevents Write-Output from unravelling collections passed to the InputObject - /// parameter. + /// Prevents Write-Output from unravelling collections passed to the InputObject parameter. /// - [Parameter()] - public SwitchParameter NoEnumerate - { - get; - set; - } + [Parameter] + public SwitchParameter NoEnumerate { get; set; } /// - /// This method implements the ProcessRecord method for Write-output command + /// This method implements the ProcessRecord method for Write-output command. /// protected override void ProcessRecord() { - if (null == _inputObjects) + if (InputObject == null) { - WriteObject(_inputObjects); + WriteObject(InputObject); return; } - bool enumerate = true; - if (NoEnumerate.IsPresent) - { - enumerate = false; - } - - WriteObject(_inputObjects, enumerate); - }//processrecord - }//WriteOutputCommand + WriteObject(InputObject, !NoEnumerate.IsPresent); + } + } #endregion } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/write.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write.cs similarity index 79% rename from src/Microsoft.PowerShell.Commands.Utility/commands/utility/write.cs rename to src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write.cs index f1b1bcd51a7f..b0f60972b091 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/write.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write.cs @@ -1,19 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; using System.Management.Automation.Internal; using System.Runtime.Serialization; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.PowerShell.Commands { #region WriteDebugCommand /// - /// This class implements Write-Debug command - /// + /// This class implements Write-Debug command. /// [Cmdlet(VerbsCommunications.Write, "Debug", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113424", RemotingCapability = RemotingCapability.None)] public sealed class WriteDebugCommand : PSCmdlet @@ -26,9 +23,8 @@ public sealed class WriteDebugCommand : PSCmdlet [Alias("Msg")] public string Message { get; set; } = null; - /// - /// This method implements the ProcessRecord method for Write-Debug command + /// This method implements the ProcessRecord method for Write-Debug command. /// protected override void ProcessRecord() { @@ -56,14 +52,13 @@ protected override void ProcessRecord() { WriteDebug(Message); } - }//processrecord - }//WriteDebugCommand + } + } #endregion WriteDebugCommand #region WriteVerboseCommand /// - /// This class implements Write-Verbose command - /// + /// This class implements Write-Verbose command. /// [Cmdlet(VerbsCommunications.Write, "Verbose", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113429", RemotingCapability = RemotingCapability.None)] public sealed class WriteVerboseCommand : PSCmdlet @@ -76,9 +71,8 @@ public sealed class WriteVerboseCommand : PSCmdlet [Alias("Msg")] public string Message { get; set; } = null; - /// - /// This method implements the ProcessRecord method for Write-verbose command + /// This method implements the ProcessRecord method for Write-verbose command. /// protected override void ProcessRecord() { @@ -106,14 +100,13 @@ protected override void ProcessRecord() { WriteVerbose(Message); } - }//processrecord - }//WriteVerboseCommand + } + } #endregion WriteVerboseCommand #region WriteWarningCommand /// - /// This class implements Write-Warning command - /// + /// This class implements Write-Warning command. /// [Cmdlet(VerbsCommunications.Write, "Warning", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113430", RemotingCapability = RemotingCapability.None)] public sealed class WriteWarningCommand : PSCmdlet @@ -126,9 +119,8 @@ public sealed class WriteWarningCommand : PSCmdlet [Alias("Msg")] public string Message { get; set; } = null; - /// - /// This method implements the ProcessRecord method for Write-Warning command + /// This method implements the ProcessRecord method for Write-Warning command. /// protected override void ProcessRecord() { @@ -156,14 +148,13 @@ protected override void ProcessRecord() { WriteWarning(Message); } - }//processrecord - }//WriteWarningCommand + } + } #endregion WriteWarningCommand #region WriteInformationCommand /// - /// This class implements Write-Information command - /// + /// This class implements Write-Information command. /// [Cmdlet(VerbsCommunications.Write, "Information", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=525909", RemotingCapability = RemotingCapability.None)] public sealed class WriteInformationCommand : PSCmdlet @@ -172,18 +163,18 @@ public sealed class WriteInformationCommand : PSCmdlet /// Object to be sent to the Information stream. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] - [Alias("Msg")] - public Object MessageData { get; set; } + [Alias("Msg", "Message")] + [AllowNull] + public object MessageData { get; set; } /// - /// Any tags to be associated with this information + /// Any tags to be associated with this information. /// [Parameter(Position = 1)] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] Tags { get; set; } /// - /// This method implements the processing of the Write-Information command + /// This method implements the processing of the Write-Information command. /// protected override void BeginProcessing() { @@ -203,36 +194,32 @@ protected override void BeginProcessing() } /// - /// This method implements the ProcessRecord method for Write-Information command + /// This method implements the ProcessRecord method for Write-Information command. /// protected override void ProcessRecord() { WriteInformation(MessageData, Tags); } - - }//WriteInformationCommand + } #endregion WriteInformationCommand - #region WriteOrThrowErrorCommand /// - /// This class implements the Write-Error command + /// This class implements the Write-Error command. /// public class WriteOrThrowErrorCommand : PSCmdlet { /// - /// ErrorRecord.Exception -- if not specified, ErrorRecord.Exception is - /// System.Exception. + /// ErrorRecord.Exception -- if not specified, ErrorRecord.Exception is System.Exception. /// [Parameter(ParameterSetName = "WithException", Mandatory = true)] public Exception Exception { get; set; } = null; /// - /// If Exception is specified, this is ErrorRecord.ErrorDetails.Message. - /// Otherwise, the Exception is System.Exception, and this is - /// Exception.Message. + /// If Exception is specified, this is ErrorRecord.ErrorDetails.Message; + /// otherwise, the Exception is System.Exception, and this is Exception.Message. /// [Parameter(Position = 0, ParameterSetName = "NoException", Mandatory = true, ValueFromPipeline = true)] [Parameter(ParameterSetName = "WithException")] @@ -242,39 +229,38 @@ public class WriteOrThrowErrorCommand : PSCmdlet public string Message { get; set; } = null; /// - /// If Exception is specified, this is ErrorRecord.ErrorDetails.Message. - /// Otherwise, the Exception is System.Exception, and this is - /// Exception.Message. + /// If Exception is specified, this is ErrorRecord.ErrorDetails.Message; + /// otherwise, the Exception is System.Exception, and this is Exception.Message. /// [Parameter(ParameterSetName = "ErrorRecord", Mandatory = true)] public ErrorRecord ErrorRecord { get; set; } = null; /// - /// ErrorRecord.CategoryInfo.Category + /// ErrorRecord.CategoryInfo.Category. /// [Parameter(ParameterSetName = "NoException")] [Parameter(ParameterSetName = "WithException")] public ErrorCategory Category { get; set; } = ErrorCategory.NotSpecified; /// - /// ErrorRecord.ErrorId + /// ErrorRecord.ErrorId. /// [Parameter(ParameterSetName = "NoException")] [Parameter(ParameterSetName = "WithException")] - public string ErrorId { get; set; } = ""; + public string ErrorId { get; set; } = string.Empty; /// - /// ErrorRecord.TargetObject + /// ErrorRecord.TargetObject. /// [Parameter(ParameterSetName = "NoException")] [Parameter(ParameterSetName = "WithException")] public object TargetObject { get; set; } = null; /// - /// ErrorRecord.ErrorDetails.RecommendedAction + /// ErrorRecord.ErrorDetails.RecommendedAction. /// [Parameter] - public string RecommendedAction { get; set; } = ""; + public string RecommendedAction { get; set; } = string.Empty; /* 2005/01/25 removing throw-error /// @@ -284,33 +270,32 @@ public class WriteOrThrowErrorCommand : PSCmdlet */ /// - /// ErrorRecord.CategoryInfo.Activity + /// ErrorRecord.CategoryInfo.Activity. /// [Parameter] [Alias("Activity")] - public string CategoryActivity { get; set; } = ""; + public string CategoryActivity { get; set; } = string.Empty; /// - /// ErrorRecord.CategoryInfo.Reason + /// ErrorRecord.CategoryInfo.Reason. /// [Parameter] [Alias("Reason")] - public string CategoryReason { get; set; } = ""; + public string CategoryReason { get; set; } = string.Empty; /// - /// ErrorRecord.CategoryInfo.TargetName + /// ErrorRecord.CategoryInfo.TargetName. /// [Parameter] [Alias("TargetName")] - public string CategoryTargetName { get; set; } = ""; + public string CategoryTargetName { get; set; } = string.Empty; /// - /// ErrorRecord.CategoryInfo.TargetType + /// ErrorRecord.CategoryInfo.TargetType. /// [Parameter] [Alias("TargetType")] - public string CategoryTargetType { get; set; } = ""; - + public string CategoryTargetType { get; set; } = string.Empty; /// /// Write an error to the output pipe, or throw a terminating error. @@ -318,7 +303,7 @@ public class WriteOrThrowErrorCommand : PSCmdlet protected override void ProcessRecord() { ErrorRecord errorRecord = this.ErrorRecord; - if (null != errorRecord) + if (errorRecord != null) { // copy constructor errorRecord = new ErrorRecord(errorRecord, null); @@ -327,15 +312,17 @@ protected override void ProcessRecord() { Exception e = this.Exception; string msg = Message; - if (null == e) + if (e == null) { e = new WriteErrorException(msg); } + string errid = ErrorId; - if (String.IsNullOrEmpty(errid)) + if (string.IsNullOrEmpty(errid)) { errid = e.GetType().FullName; } + errorRecord = new ErrorRecord( e, errid, @@ -343,29 +330,30 @@ protected override void ProcessRecord() TargetObject ); - if ((null != this.Exception && !String.IsNullOrEmpty(msg))) + if (this.Exception != null && !string.IsNullOrEmpty(msg)) { errorRecord.ErrorDetails = new ErrorDetails(msg); } } string recact = RecommendedAction; - if (!String.IsNullOrEmpty(recact)) + if (!string.IsNullOrEmpty(recact)) { - if (null == errorRecord.ErrorDetails) + if (errorRecord.ErrorDetails == null) { errorRecord.ErrorDetails = new ErrorDetails(errorRecord.ToString()); } + errorRecord.ErrorDetails.RecommendedAction = recact; } - if (!String.IsNullOrEmpty(CategoryActivity)) + if (!string.IsNullOrEmpty(CategoryActivity)) errorRecord.CategoryInfo.Activity = CategoryActivity; - if (!String.IsNullOrEmpty(CategoryReason)) + if (!string.IsNullOrEmpty(CategoryReason)) errorRecord.CategoryInfo.Reason = CategoryReason; - if (!String.IsNullOrEmpty(CategoryTargetName)) + if (!string.IsNullOrEmpty(CategoryTargetName)) errorRecord.CategoryInfo.TargetName = CategoryTargetName; - if (!String.IsNullOrEmpty(CategoryTargetType)) + if (!string.IsNullOrEmpty(CategoryTargetType)) errorRecord.CategoryInfo.TargetType = CategoryTargetType; /* 2005/01/25 removing throw-error @@ -380,11 +368,11 @@ protected override void ProcessRecord() // 2005/07/14-913791 "write-error output is confusing and misleading" // set InvocationInfo to the script not the command InvocationInfo myInvocation = GetVariableValue(SpecialVariables.MyInvocation) as InvocationInfo; - if (null != myInvocation) + if (myInvocation != null) { errorRecord.SetInvocationInfo(myInvocation); errorRecord.PreserveInvocationInfoOnce = true; - if (!String.IsNullOrEmpty(CategoryActivity)) + if (!string.IsNullOrEmpty(CategoryActivity)) errorRecord.CategoryInfo.Activity = CategoryActivity; else errorRecord.CategoryInfo.Activity = "Write-Error"; @@ -394,18 +382,18 @@ protected override void ProcessRecord() /* } */ - }//processrecord - }//WriteOrThrowErrorCommand + } + } /// - /// This class implements Write-Error command + /// This class implements Write-Error command. /// [Cmdlet(VerbsCommunications.Write, "Error", DefaultParameterSetName = "NoException", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113425", RemotingCapability = RemotingCapability.None)] public sealed class WriteErrorCommand : WriteOrThrowErrorCommand { /// - /// constructor + /// Constructor. /// public WriteErrorCommand() { @@ -414,13 +402,13 @@ public WriteErrorCommand() /* 2005/01/25 removing throw-error /// - /// This class implements Write-Error command + /// This class implements Write-Error command. /// [Cmdlet("Throw", "Error", DefaultParameterSetName = "NoException")] public sealed class ThrowErrorCommand : WriteOrThrowErrorCommand { /// - /// constructor + /// Constructor. /// public ThrowErrorCommand() { @@ -445,30 +433,30 @@ public class WriteErrorException : SystemException { #region ctor /// - /// Constructor for class WriteErrorException + /// Constructor for class WriteErrorException. /// - /// constructed object + /// Constructed object. public WriteErrorException() : base(StringUtil.Format(WriteErrorStrings.WriteErrorException)) { } /// - /// Constructor for class WriteErrorException + /// Constructor for class WriteErrorException. /// - /// - /// constructed object + /// + /// Constructed object. public WriteErrorException(string message) : base(message) { } /// - /// Constructor for class WriteErrorException + /// Constructor for class WriteErrorException. /// - /// - /// - /// constructed object + /// + /// + /// Constructed object. public WriteErrorException(string message, Exception innerException) : base(message, innerException) @@ -478,20 +466,17 @@ public WriteErrorException(string message) #region Serialization /// - /// Serialization constructor for class WriteErrorException + /// Serialization constructor for class WriteErrorException. /// - /// serialization information - /// streaming context - /// constructed object + /// Serialization information. + /// Streaming context. + /// Constructed object. protected WriteErrorException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endregion Serialization - } // WriteErrorException + } #endregion WriteErrorException -} //namespace - - - +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteAliasCommandBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteAliasCommandBase.cs index 9e195d3e30f5..130f88c2a8f3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteAliasCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteAliasCommandBase.cs @@ -1,56 +1,49 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands { /// - /// The base class for the SetAliasCommand and NewAliasCommand + /// The base class for the SetAliasCommand and NewAliasCommand. /// - /// public class WriteAliasCommandBase : PSCmdlet { #region Parameters /// - /// The Name parameter for the command + /// The Name parameter for the command. /// - /// [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string Name { get; set; } /// - /// The Value parameter for the command + /// The Value parameter for the command. /// - /// [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)] public string Value { get; set; } /// /// The description for the alias. /// - /// [Parameter] - public string Description { get; set; } = String.Empty; + public string Description { get; set; } = string.Empty; /// /// The Option parameter allows the alias to be set to /// ReadOnly (for existing aliases) and/or Constant (only /// for new aliases). /// - /// [Parameter] public ScopedItemOptions Option { get; set; } = ScopedItemOptions.None; /// - /// If set to true, the alias that is set is passed to the - /// pipeline. + /// If set to true, the alias that is set is passed to the pipeline. /// - /// [Parameter] public SwitchParameter PassThru { @@ -64,22 +57,19 @@ public SwitchParameter PassThru _passThru = value; } } + private bool _passThru; /// - /// The scope parameter for the command determines - /// which scope the alias is set in. + /// The scope parameter for the command determines which scope the alias is set in. /// - /// [Parameter] public string Scope { get; set; } - /// /// If set to true and an existing alias of the same name exists /// and is ReadOnly, the alias will be overwritten. /// - /// [Parameter] public SwitchParameter Force { @@ -93,9 +83,8 @@ public SwitchParameter Force _force = value; } } + private bool _force; #endregion Parameters - - } // class WriteAliasCommandBase -}//Microsoft.PowerShell.Commands - + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteConsoleCmdlet.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteConsoleCmdlet.cs index c53dc13623de..6cbd3a00c861 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteConsoleCmdlet.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteConsoleCmdlet.cs @@ -1,45 +1,29 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; using System.Collections; +using System.Management.Automation; using System.Text; namespace Microsoft.PowerShell.Commands { /// - /// - /// Class comment - /// + /// WriteHost cmdlet. /// - [Cmdlet(VerbsCommunications.Write, "Host", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113426", RemotingCapability = RemotingCapability.None)] public sealed class WriteHostCommand : ConsoleColorCmdlet { - // - // Parameters - // - - - /// - /// /// Object to be output. - /// /// - [Parameter(Position = 0, ValueFromRemainingArguments = true, ValueFromPipeline = true)] + [Alias("Msg", "Message")] public object Object { get; set; } = null; - /// - /// /// False to add a newline to the end of the output string, true if not. - /// /// - [Parameter] public SwitchParameter NoNewline { @@ -47,29 +31,23 @@ public SwitchParameter NoNewline { return _notAppendNewline; } + set { _notAppendNewline = value; } } - - /// - /// - /// The separator to print between objects - /// + /// Gets and sets the separator to print between objects. /// /// - [Parameter] public object Separator { get; set; } = " "; - // // Cmdlet Overrides // - private string ProcessObject(object o) { if (o != null) @@ -118,16 +96,12 @@ private string ProcessObject(object o) return null; } - - /// - /// - /// Outputs the object to the host console, with optional newline - /// + /// Outputs the object to the host console, with optional newline. /// protected override void ProcessRecord() { - string result = ProcessObject(Object) ?? ""; + string result = ProcessObject(Object) ?? string.Empty; HostInformationMessage informationMessage = new HostInformationMessage(); informationMessage.Message = result; @@ -145,9 +119,8 @@ protected override void ProcessRecord() } this.WriteInformation(informationMessage, new string[] { "PSHOST" }); - this.Host.UI.TranscribeResult(result); } - private Boolean _notAppendNewline = false; + private bool _notAppendNewline = false; } -} // namespace Microsoft.PowerShell.Commands \ No newline at end of file +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteProgressCmdlet.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteProgressCmdlet.cs index d9936e142294..eb76bdc525e1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteProgressCmdlet.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WriteProgressCmdlet.cs @@ -1,33 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; using Dbg = System.Management.Automation.Diagnostics; - - namespace Microsoft.PowerShell.Commands { /// - /// - /// Implements the write-progress cmdlet - /// + /// Implements the write-progress cmdlet. /// - [Cmdlet(VerbsCommunications.Write, "Progress", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113428", RemotingCapability = RemotingCapability.None)] public sealed class WriteProgressCommand : PSCmdlet { /// - /// /// Describes the activity for which progress is being reported. - /// /// - /// - [Parameter( Position = 0, Mandatory = true, @@ -35,14 +24,9 @@ public sealed class WriteProgressCommand : PSCmdlet HelpMessageResourceId = "ActivityParameterHelpMessage")] public string Activity { get; set; } - /// - /// /// Describes the current state of the activity. - /// /// - /// - [Parameter( Position = 1, HelpMessageBaseName = HelpMessageBaseName, @@ -50,73 +34,43 @@ public sealed class WriteProgressCommand : PSCmdlet [ValidateNotNullOrEmpty] public string Status { get; set; } = WriteProgressResourceStrings.Processing; - /// - /// /// Uniquely identifies this activity for purposes of chaining subordinate activities. - /// /// - /// - [Parameter(Position = 2)] [ValidateRange(0, Int32.MaxValue)] public int Id { get; set; } = 0; - /// - /// - /// Percentage completion of the activity, or -1 if n/a - /// + /// Percentage completion of the activity, or -1 if n/a. /// - /// - [Parameter] [ValidateRange(-1, 100)] public int PercentComplete { get; set; } = -1; - /// - /// - /// Seconds remaining to complete the operation, or -1 if n/a - /// + /// Seconds remaining to complete the operation, or -1 if n/a. /// - /// - [Parameter] public int SecondsRemaining { get; set; } = -1; - /// - /// - /// Description of current operation in activity, empty if n/a - /// + /// Description of current operation in activity, empty if n/a. /// - /// - [Parameter] public string CurrentOperation { get; set; } - /// - /// /// Identifies the parent Id of this activity, or -1 if none. - /// /// - /// - [Parameter] [ValidateRange(-1, Int32.MaxValue)] public int ParentId { get; set; } = -1; - /// - /// /// Identifies whether the activity has completed (and the display for it should be removed), /// or if it is proceeding (and the display for it should be shown). - /// /// - /// - [Parameter] public SwitchParameter Completed { @@ -124,31 +78,22 @@ public SwitchParameter Completed { return _completed; } + set { _completed = value; } } - - /// - /// /// Identifies the source of the record. - /// /// - /// - [Parameter] public int SourceId { get; set; } - /// - /// /// Writes a ProgressRecord created from the parameters. - /// /// - protected override void ProcessRecord() @@ -163,11 +108,8 @@ protected override WriteProgress(SourceId, pr); } - private bool _completed; - private const string HelpMessageBaseName = "WriteProgressResourceStrings"; } } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs index 33845a3f23eb..73b0652101f6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs @@ -1,12 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Management.Automation; @@ -19,7 +17,7 @@ namespace Microsoft.PowerShell.Commands { /// - /// implementation for the Export-Clixml command + /// Implementation for the Export-Clixml command. /// [Cmdlet(VerbsData.Export, "Clixml", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113297")] public sealed class ExportClixmlCommand : PSCmdlet, IDisposable @@ -30,39 +28,41 @@ public sealed class ExportClixmlCommand : PSCmdlet, IDisposable // implementation will need to be modified. /// - /// Depth of serialization + /// Depth of serialization. /// [Parameter] [ValidateRange(1, int.MaxValue)] public int Depth { get; set; } = 0; /// - /// mandatory file name to write to + /// Mandatory file name to write to. /// [Parameter(Mandatory = true, Position = 0, ParameterSetName = "ByPath")] public string Path { get; set; } /// - /// mandatory file name to write to + /// Mandatory file name to write to. /// [Parameter(Mandatory = true, ParameterSetName = "ByLiteralPath")] - [Alias("PSPath")] + [Alias("PSPath", "LP")] public string LiteralPath { get { return Path; } + set { Path = value; _isLiteralPath = true; } } + private bool _isLiteralPath = false; /// - /// Input object to be exported + /// Input object to be exported. /// [Parameter(ValueFromPipeline = true, Mandatory = true)] [AllowNull] @@ -78,11 +78,13 @@ public SwitchParameter Force { return _force; } + set { _force = value; } } + private bool _force; /// @@ -96,30 +98,21 @@ public SwitchParameter NoClobber { return _noclobber; } + set { _noclobber = value; } } + private bool _noclobber; /// - /// Encoding optional flag + /// Encoding optional flag. /// - /// [Parameter] [ArgumentToEncodingTransformationAttribute()] - [ArgumentCompletions( - EncodingConversion.Ascii, - EncodingConversion.BigEndianUnicode, - EncodingConversion.OEM, - EncodingConversion.Unicode, - EncodingConversion.Utf7, - EncodingConversion.Utf8, - EncodingConversion.Utf8Bom, - EncodingConversion.Utf8NoBom, - EncodingConversion.Utf32 - )] + [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); @@ -128,7 +121,7 @@ public SwitchParameter NoClobber #region Overrides /// - /// BeginProcessing override + /// BeginProcessing override. /// protected override void @@ -137,15 +130,13 @@ protected override CreateFileStream(); } - /// - /// /// protected override void ProcessRecord() { - if (null != _serializer) + if (_serializer != null) { _serializer.Serialize(InputObject); _xw.Flush(); @@ -153,7 +144,6 @@ protected override } /// - /// /// protected override void @@ -164,11 +154,11 @@ protected override _serializer.Done(); _serializer = null; } + CleanUp(); } /// - /// /// protected override void StopProcessing() { @@ -181,22 +171,22 @@ protected override void StopProcessing() #region file /// - /// handle to file stream + /// Handle to file stream. /// private FileStream _fs; /// - /// stream writer used to write to file + /// Stream writer used to write to file. /// private XmlWriter _xw; /// - /// Serializer used for serialization + /// Serializer used for serialization. /// private Serializer _serializer; /// - /// FileInfo of file to clear read-only flag when operation is complete + /// FileInfo of file to clear read-only flag when operation is complete. /// private FileInfo _readOnlyFileInfo = null; @@ -249,6 +239,7 @@ private void CreateFileStream() _xw.Dispose(); _xw = null; } + _fs.Dispose(); _fs = null; } @@ -259,12 +250,12 @@ private void CreateFileStream() #region IDisposable Members /// - /// Set to true when object is disposed + /// Set to true when object is disposed. /// private bool _disposed; /// - /// public dispose method + /// Public dispose method. /// public void @@ -274,6 +265,7 @@ private void CreateFileStream() { CleanUp(); } + _disposed = true; } @@ -281,7 +273,7 @@ private void CreateFileStream() } /// - /// Implements Import-Clixml command + /// Implements Import-Clixml command. /// [Cmdlet(VerbsData.Import, "Clixml", SupportsPaging = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113340")] public sealed class ImportClixmlCommand : PSCmdlet, IDisposable @@ -289,31 +281,31 @@ public sealed class ImportClixmlCommand : PSCmdlet, IDisposable #region Command Line Parameters /// - /// mandatory file name to read from + /// Mandatory file name to read from. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")] - public String[] Path { get; set; } + public string[] Path { get; set; } /// - /// mandatory file name to read from + /// Mandatory file name to read from. /// [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")] - [Alias("PSPath")] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] LiteralPath + [Alias("PSPath", "LP")] + public string[] LiteralPath { get { return Path; } + set { Path = value; _isLiteralPath = true; } } - private bool _isLiteralPath = false; + private bool _isLiteralPath = false; #endregion Command Line Parameters @@ -322,7 +314,7 @@ public String[] LiteralPath private bool _disposed = false; /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { @@ -334,6 +326,7 @@ public void Dispose() _helper.Dispose(); _helper = null; } + _disposed = true; } } @@ -343,7 +336,7 @@ public void Dispose() private ImportXmlHelper _helper; /// - /// ProcessRecord overload + /// ProcessRecord overload. /// protected override void ProcessRecord() { @@ -358,7 +351,6 @@ protected override void ProcessRecord() } /// - /// /// protected override void StopProcessing() { @@ -367,34 +359,30 @@ protected override void StopProcessing() } } - /// - /// implementation for the convertto-xml command + /// Implementation for the convertto-xml command. /// [Cmdlet(VerbsData.ConvertTo, "Xml", SupportsShouldProcess = false, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135204", RemotingCapability = RemotingCapability.None)] - [OutputType(typeof(XmlDocument), typeof(String))] + [OutputType(typeof(XmlDocument), typeof(string))] public sealed class ConvertToXmlCommand : PSCmdlet, IDisposable { #region Command Line Parameters - /// - /// Depth of serialization + /// Depth of serialization. /// [Parameter(HelpMessage = "Specifies how many levels of contained objects should be included in the XML representation")] [ValidateRange(1, int.MaxValue)] public int Depth { get; set; } = 0; - /// - /// Input Object which is written to XML format + /// Input Object which is written to XML format. /// [Parameter(Position = 0, ValueFromPipeline = true, Mandatory = true)] [AllowNull] public PSObject InputObject { get; set; } - /// /// Property that sets NoTypeInformation parameter. /// @@ -405,11 +393,13 @@ public SwitchParameter NoTypeInformation { return _notypeinformation; } + set { _notypeinformation = value; } } + private bool _notypeinformation; /// @@ -422,11 +412,10 @@ public SwitchParameter NoTypeInformation #endregion Command Line Parameters - #region Overrides /// - /// BeginProcessing override + /// BeginProcessing override. /// protected override void BeginProcessing() { @@ -441,9 +430,8 @@ protected override void BeginProcessing() } } - /// - /// override ProcessRecord + /// Override ProcessRecord. /// protected override void ProcessRecord() { @@ -451,37 +439,35 @@ protected override void ProcessRecord() { CreateMemoryStream(); - if (null != _serializer) + if (_serializer != null) _serializer.SerializeAsStream(InputObject); - - if (null != _serializer) + if (_serializer != null) { _serializer.DoneAsStream(); _serializer = null; } - //Loading to the XML Document + // Loading to the XML Document _ms.Position = 0; StreamReader read = new StreamReader(_ms); string data = read.ReadToEnd(); WriteObject(data); - //Cleanup + // Cleanup CleanUp(); } else { - if (null != _serializer) + if (_serializer != null) _serializer.Serialize(InputObject); } } /// - /// /// protected override void EndProcessing() { - if (null != _serializer) + if (_serializer != null) { _serializer.Done(); _serializer = null; @@ -493,7 +479,7 @@ protected override void EndProcessing() } else { - //Loading to the XML Document + // Loading to the XML Document _ms.Position = 0; if (As.Equals("Document", StringComparison.OrdinalIgnoreCase)) { @@ -510,12 +496,12 @@ protected override void EndProcessing() } } - //Cleaning up + // Cleaning up CleanUp(); } /// - /// + /// StopProcessing. /// protected override void StopProcessing() { @@ -527,17 +513,17 @@ protected override void StopProcessing() #region memory /// - /// XmlText writer + /// XmlText writer. /// private XmlWriter _xw; /// - /// Serializer used for serialization + /// Serializer used for serialization. /// private CustomSerialization _serializer; /// - /// Memory Stream used for serialization + /// Memory Stream used for serialization. /// private MemoryStream _ms; @@ -587,7 +573,7 @@ private void CreateMemoryStream() } /// - ///Cleaning up the MemoryStream + ///Cleaning up the MemoryStream. /// private void CleanUp() { @@ -609,12 +595,12 @@ private void CleanUp() #region IDisposable Members /// - /// Set to true when object is disposed + /// Set to true when object is disposed. /// private bool _disposed; /// - /// public dispose method + /// Public dispose method. /// public void @@ -624,27 +610,27 @@ private void CleanUp() { CleanUp(); } + _disposed = true; } #endregion IDisposable Members } - /// - /// Helper class to import single XML file + /// Helper class to import single XML file. /// internal class ImportXmlHelper : IDisposable { #region constructor /// - /// XML file to import + /// XML file to import. /// private readonly string _path; /// - /// Reference to cmdlet which is using this helper class + /// Reference to cmdlet which is using this helper class. /// private readonly PSCmdlet _cmdlet; private bool _isLiteralPath; @@ -663,12 +649,12 @@ internal ImportXmlHelper(string fileName, PSCmdlet cmdlet, bool isLiteralPath) #region file /// - /// handle to file stream + /// Handle to file stream. /// internal FileStream _fs; /// - /// XmlReader used to read file + /// XmlReader used to read file. /// internal XmlReader _xr; @@ -710,12 +696,12 @@ private void CleanUp() #region IDisposable Members /// - /// Set to true when object is disposed + /// Set to true when object is disposed. /// private bool _disposed; /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { @@ -723,6 +709,7 @@ public void Dispose() { CleanUp(); } + _disposed = true; GC.SuppressFinalize(this); } @@ -742,7 +729,6 @@ internal void Import() _cmdlet.WriteObject(totalCount); } - ulong skip = _cmdlet.PagingParameters.Skip; ulong first = _cmdlet.PagingParameters.First; @@ -808,7 +794,7 @@ internal void Stop() _deserializer.Stop(); } } - } // ImportXmlHelper + } #region Select-Xml /// @@ -818,46 +804,42 @@ internal void Stop() [OutputType(typeof(SelectXmlInfo))] public class SelectXmlCommand : PSCmdlet { - # region parameters + #region parameters /// - /// Specifies the path which contains the xml files. The default is the current - /// user directory + /// Specifies the path which contains the xml files. The default is the current user directory. /// - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "Path")] [ValidateNotNullOrEmpty] - public String[] Path { get; set; } + public string[] Path { get; set; } /// - /// Specifies the literal path which contains the xml files. The default is the current - /// user directory + /// Specifies the literal path which contains the xml files. The default is the current user directory. /// - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "LiteralPath")] [ValidateNotNullOrEmpty] - [Alias("PSPath")] - public String[] LiteralPath + [Alias("PSPath", "LP")] + public string[] LiteralPath { get { return Path; } + set { Path = value; _isLiteralPath = true; } } + private bool _isLiteralPath = false; /// /// The following is the definition of the input parameter "XML". - /// Specifies the xml Node + /// Specifies the xml Node. /// [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, ParameterSetName = "Xml")] [ValidateNotNullOrEmpty] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode")] [Alias("Node")] public System.Xml.XmlNode[] Xml { get; set; } @@ -865,7 +847,6 @@ public String[] LiteralPath /// The following is the definition of the input parameter in string format. /// Specifies the string format of a fully qualified xml. /// - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = "Content")] [ValidateNotNullOrEmpty] @@ -881,17 +862,15 @@ public String[] LiteralPath public string XPath { get; set; } /// - /// The following definition used to specify the - /// NameSpace of xml. + /// The following definition used to specify the NameSpace of xml. /// [Parameter] [ValidateNotNullOrEmpty] - [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public Hashtable Namespace { get; set; } - # endregion parameters + #endregion parameters - # region private + #region private private void WriteResults(XmlNodeList foundXmlNodes, string filePath) { @@ -922,14 +901,15 @@ private void ProcessXmlNode(XmlNode xmlNode, string filePath) { xList = xmlNode.SelectNodes(XPath); } + this.WriteResults(xList, filePath); } private void ProcessXmlFile(string filePath) { - //Cannot use ImportXMLHelper because it will throw terminating error which will - //not be inline with Select-String - //So doing self processing of the file. + // Cannot use ImportXMLHelper because it will throw terminating error which will + // not be inline with Select-String + // So doing self processing of the file. try { XmlDocument xmlDocument = InternalDeserializer.LoadUnsafeXmlDocument( @@ -1018,7 +998,7 @@ private XmlNamespaceManager AddNameSpaceTable(string parametersetname, XmlDocume return xmlns; } - # endregion private + #endregion private #region override @@ -1038,7 +1018,7 @@ protected override void ProcessRecord() (ParameterSetName.Equals("Path", StringComparison.OrdinalIgnoreCase) || (ParameterSetName.Equals("LiteralPath", StringComparison.OrdinalIgnoreCase)))) { - //If any file not resolved, execution stops. this is to make consistent with select-string. + // If any file not resolved, execution stops. this is to make consistent with select-string. List fullresolvedPaths = new List(); foreach (string fpath in Path) { @@ -1053,16 +1033,18 @@ protected override void ProcessRecord() Collection resolvedPaths = GetResolvedProviderPathFromPSPath(fpath, out provider); if (!provider.NameEquals(this.Context.ProviderNames.FileSystem)) { - //Cannot open File error + // Cannot open File error string message = StringUtil.Format(UtilityCommonStrings.FileOpenError, provider.FullName); InvalidOperationException e = new InvalidOperationException(message); ErrorRecord er = new ErrorRecord(e, "ProcessingFile", ErrorCategory.InvalidOperation, fpath); WriteError(er); continue; } + fullresolvedPaths.AddRange(resolvedPaths); } } + foreach (string file in fullresolvedPaths) { ProcessXmlFile(file); @@ -1090,10 +1072,9 @@ protected override void ProcessRecord() { Dbg.Assert(false, "Unrecognized parameterset"); } - }//End ProcessRecord() - + } #endregion overrides - }//End Class + } /// /// The object returned by Select-Xml representing the result of a match. @@ -1108,9 +1089,8 @@ public sealed class SelectXmlInfo private const string SimpleFormat = "{0}"; /// - /// The XmlNode that matches search + /// The XmlNode that matches search. /// - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode")] public XmlNode Node { get; set; } /// @@ -1122,9 +1102,10 @@ public string Path { return _path; } + set { - if (String.IsNullOrEmpty(value)) + if (string.IsNullOrEmpty(value)) { _path = inputStream; } @@ -1134,10 +1115,11 @@ public string Path } } } + private string _path; /// - /// The pattern used to search + /// The pattern used to search. /// public string Pattern { get; set; } @@ -1152,7 +1134,7 @@ public override string ToString() } /// - /// Return String representation of the object + /// Return String representation of the object. /// /// /// @@ -1168,7 +1150,7 @@ private string ToString(string directory) /// internal string GetNodeText() { - string nodeText = String.Empty; + string nodeText = string.Empty; if (Node != null) { if (Node.Value != null) @@ -1180,6 +1162,7 @@ internal string GetNodeText() nodeText = Node.InnerXml.Trim(); } } + return nodeText; } @@ -1209,6 +1192,7 @@ private string RelativePath(string directory) } } } + return relPath; } @@ -1230,7 +1214,5 @@ private string FormatLine(string text, string displaypath) } } } - #endregion Select-Xml } - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/group-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/group-object.cs deleted file mode 100644 index 60d316aecb0a..000000000000 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/group-object.cs +++ /dev/null @@ -1,410 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Management.Automation; -using System.Management.Automation.Internal; -using System.Text; - -namespace Microsoft.PowerShell.Commands -{ - /// - /// PSTuple is a helper class used to create Tuple from an input array. - /// - internal static class PSTuple - { - /// - /// ArrayToTuple is a helper method used to create a tuple for the supplied input array. - /// - /// Input objects used to create a tuple. - /// Tuple object. - internal static object ArrayToTuple(object[] inputObjects) - { - Diagnostics.Assert(inputObjects != null, "inputObjects is null"); - Diagnostics.Assert(inputObjects.Length > 0, "inputObjects is empty"); - - return ArrayToTuple(inputObjects, 0); - } - - /// - /// ArrayToTuple is a helper method used to create a tuple for the supplied input array. - /// - /// Input objects used to create a tuple - /// Start index of the array from which the objects have to considered for the tuple creation. - /// Tuple object. - internal static object ArrayToTuple(object[] inputObjects, int startIndex) - { - Diagnostics.Assert(inputObjects != null, "inputObjects is null"); - Diagnostics.Assert(inputObjects.Length > 0, "inputObjects is empty"); - - switch (inputObjects.Length - startIndex) - { - case 0: - return null; - case 1: - return Tuple.Create(inputObjects[startIndex]); - case 2: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1]); - case 3: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2]); - case 4: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2], inputObjects[startIndex + 3]); - case 5: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2], inputObjects[startIndex + 3], inputObjects[startIndex + 4]); - case 6: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2], inputObjects[startIndex + 3], inputObjects[startIndex + 4], - inputObjects[startIndex + 5]); - case 7: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2], inputObjects[startIndex + 3], inputObjects[startIndex + 4], - inputObjects[startIndex + 5], inputObjects[startIndex + 6]); - case 8: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2], inputObjects[startIndex + 3], inputObjects[startIndex + 4], - inputObjects[startIndex + 5], inputObjects[startIndex + 6], inputObjects[startIndex + 7]); - default: - return Tuple.Create(inputObjects[startIndex], inputObjects[startIndex + 1], inputObjects[startIndex + 2], inputObjects[startIndex + 3], inputObjects[startIndex + 4], - inputObjects[startIndex + 5], inputObjects[startIndex + 6], ArrayToTuple(inputObjects, startIndex + 7)); - } - } - } - - /// - /// Emitted by Group-Object when the NoElement option is true - /// - public sealed class GroupInfoNoElement : GroupInfo - { - internal GroupInfoNoElement(OrderByPropertyEntry groupValue) - : base(groupValue) - { - } - - internal override void Add(PSObject groupValue) - { - Count++; - } - } - - /// - /// Emitted by Group-Object - /// - public class GroupInfo - { - internal GroupInfo(OrderByPropertyEntry groupValue) - { - Group = new Collection(); - this.Add(groupValue.inputObject); - GroupValue = groupValue; - Name = BuildName(groupValue.orderValues); - } - - internal virtual void Add(PSObject groupValue) - { - Group.Add(groupValue); - Count++; - } - - - - private static string BuildName(List propValues) - { - StringBuilder sb = new StringBuilder(); - foreach (ObjectCommandPropertyValue propValue in propValues) - { - if (propValue != null && propValue.PropertyValue != null) - { - var propertyValueItems = propValue.PropertyValue as ICollection; - if (propertyValueItems != null) - { - sb.Append("{"); - var length = sb.Length; - - foreach (object item in propertyValueItems) - { - sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}, ", item.ToString())); - } - - sb = sb.Length > length ? sb.Remove(sb.Length - 2, 2) : sb; - sb.Append("}, "); - } - else - { - sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}, ", propValue.PropertyValue.ToString())); - } - } - } - return sb.Length >= 2 ? sb.Remove(sb.Length - 2, 2).ToString() : string.Empty; - } - - - /// - /// - /// Values of the group - /// - /// - public ArrayList Values - { - get - { - ArrayList values = new ArrayList(); - foreach (ObjectCommandPropertyValue propValue in GroupValue.orderValues) - { - values.Add(propValue.PropertyValue); - } - return values; - } - } - - /// - /// - /// Number of objects in the group - /// - /// - public int Count { get; internal set; } - - /// - /// - /// The list of objects in this group - /// - /// - public Collection Group { get; } = null; - - /// - /// - /// The name of the group - /// - /// - public string Name { get; } = null; - - /// - /// - /// The OrderByPropertyEntry used to build this group object - /// - /// - internal OrderByPropertyEntry GroupValue { get; } = null; - } - - /// - /// - /// Group-Object implementation - /// - /// - [Cmdlet(VerbsData.Group, "Object", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113338", RemotingCapability = RemotingCapability.None)] - [OutputType(typeof(Hashtable), typeof(GroupInfo))] - public class GroupObjectCommand : ObjectBase - { - #region tracer - - /// - /// An instance of the PSTraceSource class used for trace output - /// - [TraceSourceAttribute( - "GroupObjectCommand", - "Class that has group base implementation")] - private static PSTraceSource s_tracer = - PSTraceSource.GetTracer("GroupObjectCommand", - "Class that has group base implementation"); - - #endregion tracer - - #region Command Line Switches - - /// - /// - /// Flatten the groups - /// - /// - /// - [Parameter] - public SwitchParameter NoElement - { - get { return _noElement; } - set { _noElement = value; } - } - private bool _noElement; - /// - /// the AsHashTable parameter - /// - /// - [Parameter(ParameterSetName = "HashTable")] - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "HashTable")] - [Alias("AHT")] - public SwitchParameter AsHashTable { get; set; } - - /// - /// - /// - /// - [Parameter(ParameterSetName = "HashTable")] - public SwitchParameter AsString { get; set; } - - private List _groups = new List(); - private OrderByProperty _orderByProperty = new OrderByProperty(); - private bool _hasProcessedFirstInputObject; - private Dictionary _tupleToGroupInfoMappingDictionary = new Dictionary(); - private OrderByPropertyComparer _orderByPropertyComparer = null; - - #endregion - - #region utils - - /// - /// Utility function called by Group-Object to create Groups. - /// - /// Input object that needs to be grouped. - /// true if we are not accumulating objects - /// List containing Groups. - /// Dictionary used to keep track of the groups with hash of the property values being the key. - /// The Comparer to be used while comparing to check if new group has to be created. - internal static void DoGrouping(OrderByPropertyEntry currentObjectEntry, bool noElement, List groups, Dictionary groupInfoDictionary, - OrderByPropertyComparer orderByPropertyComparer) - { - if (currentObjectEntry != null && currentObjectEntry.orderValues != null && currentObjectEntry.orderValues.Count > 0) - { - object currentTupleObject = PSTuple.ArrayToTuple(currentObjectEntry.orderValues.ToArray()); - - GroupInfo currentGroupInfo = null; - if (groupInfoDictionary.TryGetValue(currentTupleObject, out currentGroupInfo)) - { - if (currentGroupInfo != null) - { - //add this inputObject to an existing group - currentGroupInfo.Add(currentObjectEntry.inputObject); - } - } - else - { - bool isCurrentItemGrouped = false; - - for (int groupsIndex = 0; groupsIndex < groups.Count; groupsIndex++) - { - // Check if the current input object can be converted to one of the already known types - // by looking up in the type to GroupInfo mapping. - if (orderByPropertyComparer.Compare(groups[groupsIndex].GroupValue, currentObjectEntry) == 0) - { - groups[groupsIndex].Add(currentObjectEntry.inputObject); - isCurrentItemGrouped = true; - break; - } - } - - if (!isCurrentItemGrouped) - { - // create a new group - s_tracer.WriteLine("Create a new group: {0}", currentObjectEntry.orderValues); - GroupInfo newObjGrp = noElement ? new GroupInfoNoElement(currentObjectEntry) : new GroupInfo(currentObjectEntry); - groups.Add(newObjGrp); - - groupInfoDictionary.Add(currentTupleObject, newObjGrp); - } - } - } - } - private void WriteNonTerminatingError(Exception exception, string resourceIdAndErrorId, - ErrorCategory category) - { - Exception ex = new Exception(StringUtil.Format(resourceIdAndErrorId), exception); - WriteError(new ErrorRecord(ex, resourceIdAndErrorId, category, null)); - } - #endregion utils - - /// - /// Process every input object to group them. - /// - protected override void ProcessRecord() - { - if (InputObject != null && InputObject != AutomationNull.Value) - { - OrderByPropertyEntry currentEntry = null; - - if (!_hasProcessedFirstInputObject) - { - if (Property == null) - { - Property = OrderByProperty.GetDefaultKeyPropertySet(InputObject); - } - _orderByProperty.ProcessExpressionParameter(this, Property); - - currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo); - bool[] ascending = new bool[currentEntry.orderValues.Count]; - for (int index = 0; index < currentEntry.orderValues.Count; index++) - { - ascending[index] = true; - } - _orderByPropertyComparer = new OrderByPropertyComparer(ascending, _cultureInfo, CaseSensitive); - - _hasProcessedFirstInputObject = true; - } - else - { - currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo); - } - - DoGrouping(currentEntry, this.NoElement, _groups, _tupleToGroupInfoMappingDictionary, _orderByPropertyComparer); - } - } - - /// - /// - /// - protected override void EndProcessing() - { - s_tracer.WriteLine(_groups.Count); - if (_groups.Count > 0) - { - if (AsHashTable) - { - Hashtable _table = CollectionsUtil.CreateCaseInsensitiveHashtable(); - try - { - foreach (GroupInfo _grp in _groups) - { - if (AsString) - { - _table.Add(_grp.Name, _grp.Group); - } - else - { - if (_grp.Values.Count == 1) - { - _table.Add(_grp.Values[0], _grp.Group); - } - else - { - ArgumentException ex = new ArgumentException(UtilityCommonStrings.GroupObjectSingleProperty); - ErrorRecord er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidArgument, Property); - ThrowTerminatingError(er); - } - } - } - } - catch (ArgumentException e) - { - WriteNonTerminatingError(e, UtilityCommonStrings.InvalidOperation, ErrorCategory.InvalidArgument); - return; - } - WriteObject(_table); - } - else - { - if (AsString) - { - ArgumentException ex = new ArgumentException(UtilityCommonStrings.GroupObjectWithHashTable); - ErrorRecord er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidArgument, AsString); - ThrowTerminatingError(er); - } - else - { - WriteObject(_groups, true); - } - } - } - } - } -} - diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/GetTracerCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/GetTracerCommand.cs index 8b9103f2923d..6b93c25cb9db 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/GetTracerCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/GetTracerCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Linq; using System.Management.Automation; @@ -8,7 +7,7 @@ namespace Microsoft.PowerShell.Commands { /// - /// A cmdlet that gets the TraceSource instances that are instantiated in the process + /// A cmdlet that gets the TraceSource instances that are instantiated in the process. /// [Cmdlet(VerbsCommon.Get, "TraceSource", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113333")] [OutputType(typeof(PSTraceSource))] @@ -17,8 +16,7 @@ public class GetTraceSourceCommand : TraceCommandBase #region Parameters /// - /// Gets or sets the category parameter which determines - /// which trace switch to get. + /// Gets or sets the category parameter which determines which trace switch to get. /// /// [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -39,7 +37,8 @@ public string[] Name _names = value; } - } // TraceSource + } + private string[] _names = new string[] { "*" }; #endregion Parameters @@ -47,14 +46,14 @@ public string[] Name #region Cmdlet code /// - /// Gets the PSTraceSource for the specified category + /// Gets the PSTraceSource for the specified category. /// protected override void ProcessRecord() { var sources = GetMatchingTraceSource(_names, true); var result = sources.OrderBy(source => source.Name); WriteObject(result, true); - } // ProcessRecord + } #endregion Cmdlet code } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs index ae0af27e05b0..c95c9793be0f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs @@ -1,12 +1,11 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; -using System.Security.Permissions; using System.Management.Automation; using System.Management.Automation.Internal.Host; +using System.Security.Permissions; +using System.Text; namespace Microsoft.PowerShell.Commands { @@ -15,12 +14,10 @@ namespace Microsoft.PowerShell.Commands /// coming from a System.Management.Automation.TraceSwitch /// to be passed to the Msh host's RawUI methods. /// - /// /// /// This trace listener cannot be specified in the app.config file. /// It must be added through the add-tracelistener cmdlet. /// - /// internal class PSHostTraceListener : System.Diagnostics.TraceListener { @@ -30,7 +27,7 @@ internal class PSHostTraceListener /// Default constructor used if no. /// internal PSHostTraceListener(PSCmdlet cmdlet) - : base("") + : base(string.Empty) { if (cmdlet == null) { @@ -50,15 +47,11 @@ internal PSHostTraceListener(PSCmdlet cmdlet) } /// - /// Closes the TraceListenerDialog so that it no longer - /// receives trace output. + /// Closes the TraceListenerDialog so that it no longer receives trace output. /// - /// /// - /// true if the TraceListener is being disposed, false - /// otherwise. + /// True if the TraceListener is being disposed, false otherwise. /// - /// [SecurityPermission(SecurityAction.LinkDemand)] protected override void Dispose(bool disposing) { @@ -78,12 +71,11 @@ protected override void Dispose(bool disposing) #endregion TraceListener constructors and disposer /// - /// Sends the given output string to the host for processing + /// Sends the given output string to the host for processing. /// /// - /// The trace output to be written + /// The trace output to be written. /// - /// [SecurityPermission(SecurityAction.LinkDemand)] public override void Write(string output) { @@ -97,13 +89,14 @@ public override void Write(string output) // We don't want tracing to bring down the process. } } + private StringBuilder _cachedWrite = new StringBuilder(); /// - /// Sends the given output string to the host for processing + /// Sends the given output string to the host for processing. /// /// - /// The trace output to be written + /// The trace output to be written. /// [SecurityPermission(SecurityAction.LinkDemand)] public override void WriteLine(string output) @@ -111,6 +104,7 @@ public override void WriteLine(string output) try { _cachedWrite.Append(output); + _cachedWrite.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff ")); _ui.WriteDebugLine(_cachedWrite.ToString()); _cachedWrite.Remove(0, _cachedWrite.Length); @@ -126,5 +120,5 @@ public override void WriteLine(string output) /// The host interface to write the debug line to. /// private InternalHostUserInterface _ui; - } // class PSHostTraceListener -} // namespace System.Management.Automation + } +} diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/SetTracerCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/SetTracerCommand.cs index 49c4c51ffa37..1cbf6f565216 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/SetTracerCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/SetTracerCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Collections.ObjectModel; using System.Diagnostics; @@ -9,7 +8,7 @@ namespace Microsoft.PowerShell.Commands { /// - /// A cmdlet that sets the properties of the TraceSwitch instances that are instantiated in the process + /// A cmdlet that sets the properties of the TraceSwitch instances that are instantiated in the process. /// [Cmdlet(VerbsCommon.Set, "TraceSource", DefaultParameterSetName = "optionsSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113400")] [OutputType(typeof(PSTraceSource))] @@ -21,38 +20,36 @@ public class SetTraceSourceCommand : TraceListenerCommandBase /// The TraceSource parameter determines which TraceSource categories the /// operation will take place on. /// - /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] public string[] Name { get { return base.NameInternal; } + set { base.NameInternal = value; } } /// - /// The flags to be set on the TraceSource + /// The flags to be set on the TraceSource. /// - /// [Parameter(Position = 1, ValueFromPipelineByPropertyName = true, ParameterSetName = "optionsSet")] public PSTraceSourceOptions Option { get { return base.OptionsInternal; } + set { base.OptionsInternal = value; } - } // Flags - + } /// - /// The parameter which determines the options for output from the - /// trace listeners. + /// The parameter which determines the options for output from the trace listeners. /// - /// [Parameter(ParameterSetName = "optionsSet")] public TraceOptions ListenerOption { get { return base.ListenerOptionsInternal; } + set { base.ListenerOptionsInternal = value; @@ -60,56 +57,56 @@ public TraceOptions ListenerOption } /// - /// Adds the file trace listener using the specified file + /// Adds the file trace listener using the specified file. /// /// [Parameter(ParameterSetName = "optionsSet")] - [Alias("PSPath")] + [Alias("PSPath", "Path")] public string FilePath { get { return base.FileListener; } + set { base.FileListener = value; } - } // File + } /// - /// Force parameter to control read-only files + /// Force parameter to control read-only files. /// [Parameter(ParameterSetName = "optionsSet")] public SwitchParameter Force { get { return base.ForceWrite; } + set { base.ForceWrite = value; } } /// - /// If this parameter is specified the Debugger trace listener - /// will be added. + /// If this parameter is specified the Debugger trace listener will be added. /// /// [Parameter(ParameterSetName = "optionsSet")] public SwitchParameter Debugger { get { return base.DebuggerListener; } + set { base.DebuggerListener = value; } - } // Debugger + } /// - /// If this parameter is specified the Msh Host trace listener - /// will be added. + /// If this parameter is specified the Msh Host trace listener will be added. /// /// [Parameter(ParameterSetName = "optionsSet")] public SwitchParameter PSHost { get { return base.PSHostListener; } + set { base.PSHostListener = value; } - } // PSHost + } /// - /// If set, the specified listeners will be removed regardless - /// of their type. + /// If set, the specified listeners will be removed regardless of their type. /// - /// [Parameter(ParameterSetName = "removeAllListenersSet")] [ValidateNotNullOrEmpty] public string[] RemoveListener { get; set; } = new string[] { "*" }; @@ -117,7 +114,6 @@ public SwitchParameter PSHost /// /// If set, the specified file trace listeners will be removed. /// - /// [Parameter(ParameterSetName = "removeFileListenersSet")] [ValidateNotNullOrEmpty] public string[] RemoveFileListener { get; set; } = new string[] { "*" }; @@ -131,8 +127,10 @@ public SwitchParameter PSHost public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } - } // Passthru + } + private bool _passThru; #endregion Parameters @@ -140,7 +138,7 @@ public SwitchParameter PassThru #region Cmdlet code /// - /// Sets the TraceSource properties + /// Sets the TraceSource properties. /// protected override void ProcessRecord() { @@ -157,6 +155,7 @@ protected override void ProcessRecord() WriteObject(matchingSources, true); WriteObject(preconfiguredTraceSources, true); } + break; case "removeAllListenersSet": @@ -169,7 +168,7 @@ protected override void ProcessRecord() RemoveListenersByName(matchingSources, RemoveFileListener, true); break; } - } // ProcessRecord + } #endregion Cmdlet code } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceCommandBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceCommandBase.cs index 292a69db8923..87fa21d3b8e5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceCommandBase.cs @@ -1,39 +1,33 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Management.Automation; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Commands { /// - /// A base class for cmdlets that has helper methods for globbing - /// trace source instances + /// A base class for cmdlets that has helper methods for globbing trace source instances. /// public class TraceCommandBase : PSCmdlet { /// - /// Gets the matching PSTraceSource instances for the - /// specified patterns. + /// Gets the matching PSTraceSource instances for the specified patterns. /// - /// /// /// The patterns used to match the PSTraceSource name. /// - /// /// /// If true and the pattern does not contain wildcard patterns and no /// match is found, then WriteError will be called. /// - /// /// /// A collection of the matching PSTraceSource instances. /// - /// internal Collection GetMatchingTraceSource( string[] patternsToMatch, bool writeErrorIfMatchNotFound) @@ -43,27 +37,21 @@ public class TraceCommandBase : PSCmdlet } /// - /// Gets the matching PSTraceSource instances for the - /// specified patterns. + /// Gets the matching PSTraceSource instances for the specified patterns. /// - /// /// /// The patterns used to match the PSTraceSource name. /// - /// /// /// If true and the pattern does not contain wildcard patterns and no /// match is found, then WriteError will be called. /// - /// /// /// The patterns for which a match was not found. /// - /// /// /// A collection of the matching PSTraceSource instances. /// - /// internal Collection GetMatchingTraceSource( string[] patternsToMatch, bool writeErrorIfMatchNotFound, @@ -76,7 +64,7 @@ public class TraceCommandBase : PSCmdlet { bool matchFound = false; - if (String.IsNullOrEmpty(patternToMatch)) + if (string.IsNullOrEmpty(patternToMatch)) { notMatched.Add(patternToMatch); continue; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs index bffa86fcc933..3eec497c0c6d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.ObjectModel; @@ -10,6 +9,7 @@ using System.Management.Automation.Internal; using System.Management.Automation.Runspaces; using System.Threading; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Commands @@ -24,7 +24,7 @@ public class TraceCommandCommand : TraceListenerCommandBase, IDisposable #region Parameters /// - /// This parameter specifies the current pipeline object + /// This parameter specifies the current pipeline object. /// [Parameter(ValueFromPipeline = true)] public PSObject InputObject { set; get; } = AutomationNull.Value; @@ -33,27 +33,28 @@ public class TraceCommandCommand : TraceListenerCommandBase, IDisposable /// The TraceSource parameter determines which TraceSource categories the /// operation will take place on. /// - /// [Parameter(Position = 0, Mandatory = true)] public string[] Name { get { return base.NameInternal; } + set { base.NameInternal = value; } } /// - /// The flags to be set on the TraceSource + /// The flags to be set on the TraceSource. /// /// [Parameter(Position = 2)] public PSTraceSourceOptions Option { get { return base.OptionsInternal; } + set { base.OptionsInternal = value; } - } // Options + } /// /// The parameter for the expression that should be traced. @@ -71,21 +72,20 @@ public PSTraceSourceOptions Option /// /// When set, this parameter is the arguments to pass to the command specified by - /// the -Command parameter + /// the -Command parameter. /// [Parameter(ParameterSetName = "commandSet", ValueFromRemainingArguments = true)] [Alias("Args")] public object[] ArgumentList { get; set; } /// - /// The parameter which determines the options for output from the - /// trace listeners. + /// The parameter which determines the options for output from the trace listeners. /// - /// [Parameter] public TraceOptions ListenerOption { get { return base.ListenerOptionsInternal; } + set { base.ListenerOptionsInternal = value; @@ -93,51 +93,52 @@ public TraceOptions ListenerOption } /// - /// Adds the file trace listener using the specified file + /// Adds the file trace listener using the specified file. /// /// [Parameter] - [Alias("PSPath")] + [Alias("PSPath", "Path")] public string FilePath { get { return base.FileListener; } + set { base.FileListener = value; } - } // File + } /// - /// Force parameter to control read-only files + /// Force parameter to control read-only files. /// [Parameter] public SwitchParameter Force { get { return base.ForceWrite; } + set { base.ForceWrite = value; } } /// - /// If this parameter is specified the Debugger trace listener - /// will be added. + /// If this parameter is specified the Debugger trace listener will be added. /// /// [Parameter] public SwitchParameter Debugger { get { return base.DebuggerListener; } + set { base.DebuggerListener = value; } - } // Debugger + } /// - /// If this parameter is specified the Msh Host trace listener - /// will be added. + /// If this parameter is specified the Msh Host trace listener will be added. /// /// [Parameter] public SwitchParameter PSHost { get { return base.PSHostListener; } - set { base.PSHostListener = value; } - } // PSHost + set { base.PSHostListener = value; } + } #endregion Parameters @@ -153,7 +154,6 @@ protected override void BeginProcessing() Collection preconfiguredSources = null; _matchingSources = ConfigureTraceSource(base.NameInternal, false, out preconfiguredSources); - TurnOnTracing(_matchingSources, false); TurnOnTracing(preconfiguredSources, true); @@ -185,13 +185,13 @@ protected override void BeginProcessing() _pipeline.ExternalErrorOutput = new TracePipelineWriter(this, true, _matchingSources); _pipeline.ExternalSuccessOutput = new TracePipelineWriter(this, false, _matchingSources); } + ResetTracing(_matchingSources); } /// /// Executes the expression. - /// - /// Note, this was taken from apply-expression + /// Note, this was taken from apply-expression. /// protected override void ProcessRecord() { @@ -208,6 +208,7 @@ protected override void ProcessRecord() result = StepCommand(); break; } + ResetTracing(_matchingSources); if (result == null) @@ -215,13 +216,11 @@ protected override void ProcessRecord() return; } - if (!LanguagePrimitives.IsNull(result)) { WriteObject(result, true); } - } // ProcessRecord - + } /// /// Finishes running the command if specified and then sets the @@ -239,13 +238,13 @@ protected override void EndProcessing() WriteObject(results, true); } + this.Dispose(); } /// /// Ensures that the sub-pipeline we created gets stopped as well. /// - /// protected override void StopProcessing() { if (_pipeline != null) @@ -264,7 +263,7 @@ private object RunExpression() dollarUnder: InputObject, input: new object[] { InputObject }, scriptThis: AutomationNull.Value, - args: Utils.EmptyArray()); + args: Array.Empty()); } private object StepCommand() @@ -273,6 +272,7 @@ private object StepCommand() { _pipeline.Step(InputObject); } + return null; } @@ -311,9 +311,11 @@ public void Dispose() fileStream.Dispose(); } } + GC.SuppressFinalize(this); } - } // Dispose + } + private bool _disposed; #endregion IDisposable } @@ -323,7 +325,6 @@ public void Dispose() /// cmdlet. It gets attached to the sub-pipelines success or error pipeline and redirects /// all objects written to these pipelines to trace-command pipeline. /// - /// internal class TracePipelineWriter : PipelineWriter { internal TracePipelineWriter( @@ -347,8 +348,7 @@ internal class TracePipelineWriter : PipelineWriter } /// - /// Get the wait handle signaled when buffer space is available - /// in the underlying stream. + /// Get the wait handle signaled when buffer space is available in the underlying stream. /// public override WaitHandle WaitHandle { @@ -372,7 +372,7 @@ public override bool IsOpen } /// - /// Returns the number of objects in the underlying stream + /// Returns the number of objects in the underlying stream. /// public override int Count { @@ -380,7 +380,7 @@ public override int Count } /// - /// Get the capacity of the stream + /// Get the capacity of the stream. /// /// /// The capacity of the stream. @@ -396,7 +396,7 @@ public override int MaxCapacity } /// - /// Close the stream + /// Close the stream. /// /// /// Causes subsequent calls to IsOpen to return false and calls to @@ -404,7 +404,7 @@ public override int MaxCapacity /// All calls to Close() after the first call are silently ignored. /// /// - /// The stream is already disposed + /// The stream is already disposed. /// public override void Close() { @@ -420,23 +420,23 @@ public override void Close() /// but disposed streams may not. /// /// - /// The underlying stream is disposed + /// The underlying stream is disposed. /// public override void Flush() { } /// - /// Write a single object into the underlying stream + /// Write a single object into the underlying stream. /// - /// The object to add to the stream + /// The object to add to the stream. /// /// One, if the write was successful, otherwise; /// zero if the stream was closed before the object could be written, /// or if the object was AutomationNull.Value. /// /// - /// The underlying stream is closed + /// The underlying stream is closed. /// public override int Write(object obj) { @@ -461,9 +461,9 @@ public override int Write(object obj) } /// - /// Write objects to the underlying stream + /// Write objects to the underlying stream. /// - /// object or enumeration to read from + /// Object or enumeration to read from. /// /// If enumerateCollection is true, and /// is an enumeration according to LanguagePrimitives.GetEnumerable, @@ -471,9 +471,9 @@ public override int Write(object obj) /// written separately. Otherwise, /// will be written as a single object. /// - /// The number of objects written + /// The number of objects written. /// - /// The underlying stream is closed + /// The underlying stream is closed. /// /// /// contains AutomationNull.Value diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceListenerCommandBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceListenerCommandBase.cs index 34ddcc2e0070..31a6845c0ebc 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceListenerCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceListenerCommandBase.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -10,13 +9,14 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Security; + using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Commands { /// /// A base class for the trace cmdlets that allow you to specify - /// which trace listeners to add to a TraceSource + /// which trace listeners to add to a TraceSource. /// public class TraceListenerCommandBase : TraceCommandBase { @@ -26,23 +26,23 @@ public class TraceListenerCommandBase : TraceCommandBase /// The TraceSource parameter determines which TraceSource categories the /// operation will take place on. /// - /// - internal string[] NameInternal { get; set; } = new string[0]; - + internal string[] NameInternal { get; set; } = Array.Empty(); /// - /// The flags to be set on the TraceSource + /// The flags to be set on the TraceSource. /// /// internal PSTraceSourceOptions OptionsInternal { get { return _options; } + set { _options = value; optionsSpecified = true; } - } // Flags + } + private PSTraceSourceOptions _options = PSTraceSourceOptions.All; /// @@ -51,31 +51,31 @@ internal PSTraceSourceOptions OptionsInternal internal bool optionsSpecified; /// - /// The parameter which determines the options for output from the - /// trace listeners. + /// The parameter which determines the options for output from the trace listeners. /// - /// internal TraceOptions ListenerOptionsInternal { get { return _traceOptions; } + set { traceOptionsSpecified = true; _traceOptions = value; } } + private TraceOptions _traceOptions = TraceOptions.None; /// - /// True if the TraceOptions parameter was specified, or false otherwise + /// True if the TraceOptions parameter was specified, or false otherwise. /// internal bool traceOptionsSpecified; /// - /// Adds the file trace listener using the specified file + /// Adds the file trace listener using the specified file. /// /// - internal string FileListener { get; set; } // File + internal string FileListener { get; set; } /// /// Property that sets force parameter. This will clear the @@ -84,25 +84,25 @@ internal TraceOptions ListenerOptionsInternal /// /// Note that we do not attempt to reset the read-only attribute. /// - public bool ForceWrite { get; set; } // Force + public bool ForceWrite { get; set; } /// - /// If this parameter is specified the Debugger trace listener - /// will be added. + /// If this parameter is specified the Debugger trace listener will be added. /// /// - internal bool DebuggerListener { get; set; } // Debugger + internal bool DebuggerListener { get; set; } /// - /// If this parameter is specified the Msh Host trace listener - /// will be added. + /// If this parameter is specified the Msh Host trace listener will be added. /// /// internal SwitchParameter PSHostListener { get { return _host; } + set { _host = value; } - } // UseHost + } + private bool _host = false; #endregion Parameters @@ -136,7 +136,7 @@ internal SwitchParameter PSHostListener foreach (string notMatchedName in notMatched) { - if (String.IsNullOrEmpty(notMatchedName)) + if (string.IsNullOrEmpty(notMatchedName)) { continue; } @@ -149,7 +149,7 @@ internal SwitchParameter PSHostListener PSTraceSource newTraceSource = PSTraceSource.GetNewTraceSource( notMatchedName, - String.Empty, + string.Empty, true); preconfiguredSources.Add(newTraceSource); @@ -188,10 +188,8 @@ internal SwitchParameter PSHostListener #region AddTraceListeners /// - /// Adds the console, debugger, file, or host listener - /// if requested. + /// Adds the console, debugger, file, or host listener if requested. /// - /// internal void AddTraceListenersToSources(Collection matchingSources) { if (DebuggerListener) @@ -204,6 +202,7 @@ internal void AddTraceListenersToSources(Collection matchingSourc // Note, this is not meant to be localized. _defaultListener.Name = "Debug"; } + AddListenerToSources(matchingSources, _defaultListener); } @@ -217,6 +216,7 @@ internal void AddTraceListenersToSources(Collection matchingSourc // Note, this is not meant to be localized. _hostListener.Name = "Host"; } + AddListenerToSources(matchingSources, _hostListener); } @@ -271,6 +271,7 @@ internal void AddTraceListenersToSources(Collection matchingSourc FileListener, provider.FullName)); } + resolvedPaths.Add(path); } @@ -294,7 +295,7 @@ internal void AddTraceListenersToSources(Collection matchingSourc // Save some disk write time by checking whether file is readonly.. if ((fInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { - //Make sure the file is not read only + // Make sure the file is not read only fInfo.Attributes &= ~(FileAttributes.ReadOnly); } } @@ -370,14 +371,14 @@ internal void AddTraceListenersToSources(Collection matchingSourc } } } + private DefaultTraceListener _defaultListener; private PSHostTraceListener _hostListener; private Collection _fileListeners; /// - /// The file streams that were open by this command + /// The file streams that were open by this command. /// - /// internal Collection FileStreams { get; private set; } private static void AddListenerToSources(Collection matchingSources, TraceListener listener) @@ -394,9 +395,8 @@ private static void AddListenerToSources(Collection matchingSourc #region RemoveTraceListeners /// - /// Removes the tracelisteners from the specified trace sources + /// Removes the tracelisteners from the specified trace sources. /// - /// internal static void RemoveListenersByName( Collection matchingSources, string[] listenerNames, @@ -439,15 +439,14 @@ private static void AddListenerToSources(Collection matchingSourc } } } - } // RemoveAllTraceListenersFromSource - + } #endregion RemoveTraceListeners #region SetTraceListenerOptions /// - /// Sets the trace listener options based on the ListenerOptions parameter + /// Sets the trace listener options based on the ListenerOptions parameter. /// internal void SetTraceListenerOptions(Collection matchingSources) { @@ -469,9 +468,8 @@ internal void SetTraceListenerOptions(Collection matchingSources) #region SetFlags /// - /// Sets the flags for all the specified TraceSources + /// Sets the flags for all the specified TraceSources. /// - /// internal void SetFlags(Collection matchingSources) { foreach (PSTraceSource structuredSource in matchingSources) @@ -484,8 +482,7 @@ internal void SetFlags(Collection matchingSources) #region TurnOnTracing /// - /// Turns on tracing for the TraceSources, flags, and listeners defined by - /// the parameters + /// Turns on tracing for the TraceSources, flags, and listeners defined by the parameters. /// internal void TurnOnTracing(Collection matchingSources, bool preConfigured) { @@ -596,6 +593,7 @@ protected void ClearStoredState() listener.Dispose(); } } + _storedTraceSourceState.Clear(); } diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/AddTypeStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/AddTypeStrings.resx index 51762730bac6..ba570831de8a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/AddTypeStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/AddTypeStrings.resx @@ -117,8 +117,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - {0}({1}) : {2} + + The source code was already compiled and loaded. The generated type defines no public methods or properties. @@ -138,9 +138,6 @@ Cannot add type. Specify only the Language or CodeDomProvider parameters. - - Cannot add type. The '{0}' language requires Microsoft .NET Framework {1}. - Cannot add type. The assembly name {0} matches both {1} and {2}. @@ -162,12 +159,6 @@ Cannot add type. The OutputType parameter requires that the OutputAssembly parameter be specified. - - Cannot add type due to the following exception: {0}. Verify that Microsoft .NET Framework {1} is installed. On x64-based versions of Windows, you must also install the WOW64 feature. - - - Cannot add type. The '{0}' parameter and the '{1}' parameter cannot both be specified. - Cannot add type. Definition of new types is not supported in this language mode. diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/ConvertMarkdownStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/ConvertMarkdownStrings.resx new file mode 100644 index 000000000000..d37509d0f504 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/ConvertMarkdownStrings.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The type of the input object '{0}' is invalid. + + + The file is not found: '{0}'. + + + Only FileSystem Provider paths are supported. The file path is not supported: '{0}'. + + + The property {0} of the given object is null or empty. + + + Invalid parameter set name: {0}. + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx index 8d0ae2da593a..0eff0d6f84f2 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx @@ -127,6 +127,9 @@ Reviewed by TArcher on 2010-06-29. + + You must specify either the -UseQuotes or -QuoteFields parameters, but not both. + You must specify either the -IncludeTypeInformation or -NoTypeInformation parameters, but not both. @@ -136,4 +139,22 @@ One or more headers were not specified. Default names starting with "H" have been used in place of any missing headers. + + FileName is a mandatory parameter. + + + ReconcilePreexistingPropertyNames method should only get called when appending. + + + ReconcilePreexistingPropertyNames method should only get called when preexisting property names have been read successfully. + + + BuildPropertyNames method should be called only once per cmdlet instance. + + + Type hierarchy should not have null values. + + + EOF is reached. + diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx index cce49c375f94..63b4271c3826 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/NewObjectStrings.resx @@ -138,10 +138,13 @@ Creating instances of attribute and delegated Windows RT types is not supported. + + Cannot create instances of the ByRef-like type "{0}". ByRef-like types are not supported in PowerShell. + Cannot create type. Only core types are supported in this language mode. - {0} Please note that Single-Threaded Apartment is not supported in PowerShell Core. + {0} Please note that Single-Threaded Apartment is not supported in PowerShell. diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx new file mode 100644 index 000000000000..a5c8d5d24d92 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/TestJsonCmdletStrings.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cannot parse the JSON schema. + + + Cannot parse the JSON. + + + The JSON is not valid with the schema. + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx index 651d75d1a324..551f0d1fcb83 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx @@ -171,10 +171,7 @@ The file '{0}' could not be parsed as a PowerShell Data File. - - '{0}' is not supported in this system. - - - The file is not blocked: {0} + + Cannot construct a security descriptor from the given SDDL due to the following error: {0} diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx index a1304e38da44..397718a09bbe 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx @@ -138,6 +138,15 @@ The cmdlet cannot run because the following conflicting parameters are specified: Body and InFile. Specify either Body or Infile, then retry. + + The cmdlet cannot run because the following conflicting parameters are specified: Body and Form. Specify either Body or Form, then retry. + + + The cmdlet cannot run because the following conflicting parameters are specified: InFile and Form. Specify either InFile or Form, then retry. + + + The cmdlet cannot run because the -ContentType parameter is not a valid Content-Type header. Specify a valid Content-Type for -ContentType, then retry. To suppress header validation, supply the -SkipHeaderValidation parameter. + The cmdlet cannot run because the following conflicting parameters are specified: Credential and UseDefaultCredentials. Specify either Credential or UseDefaultCredentials, then retry. @@ -178,7 +187,10 @@ Path '{0}' is not a file system path. Please specify the path to a file in the file system. - The cmdlet cannot run because the following parameter is missing: OutFile. Provide a valid OutFile parameter value when using the PassThru parameter, then retry. + The cmdlet cannot run because the following parameter is missing: OutFile. Provide a valid OutFile parameter value when using the {0} parameter, then retry. + + + The file will not be re-downloaded because the remote file is the same size as the OutFile: {0} The cmdlet cannot run because the following conflicting parameters are specified: ProxyCredential and ProxyUseDefaultCredentials. Specify either ProxyCredential or ProxyUseDefaultCredentials, then retry. @@ -240,7 +252,13 @@ {0} {1} with {2}-byte payload + + The remote server indicated it could not resume downloading. The local file will be overwritten. + received {0}-byte response of content type {1} + + Retrying after interval of {0} seconds. Status code for previous attempt: {1} + diff --git a/src/Microsoft.PowerShell.Commands.Utility/singleshell/installer/MshUtilityMshSnapin.cs b/src/Microsoft.PowerShell.Commands.Utility/singleshell/installer/MshUtilityMshSnapin.cs index b26ef9a062ab..c86dad7e0540 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/singleshell/installer/MshUtilityMshSnapin.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/singleshell/installer/MshUtilityMshSnapin.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.ComponentModel; using System.Management.Automation; @@ -8,14 +7,11 @@ namespace Microsoft.PowerShell { /// - /// /// MshUtilityMshSnapin (or MshUtilityMshSnapinInstaller) is a class for facilitating registry /// of necessary information for monad utility mshsnapin. /// - /// This class will be built with monad utility dll - /// + /// This class will be built with monad utility dll. /// - /// [RunInstaller(true)] public sealed class PSUtilityPSSnapIn : PSSnapIn { diff --git a/src/Microsoft.PowerShell.ConsoleHost/AssemblyInfo.cs b/src/Microsoft.PowerShell.ConsoleHost/AssemblyInfo.cs index 5ccccbcb8e18..7a8ebd5fbd27 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/AssemblyInfo.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/AssemblyInfo.cs @@ -1,22 +1,7 @@ -using System.Reflection; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System.Runtime.CompilerServices; -#if !CORECLR -using System.Runtime.ConstrainedExecution; -#else -using System.Resources; -#endif [assembly: InternalsVisibleTo("powershell-tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] - -#if !CORECLR -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyInformationalVersionAttribute(@"10.0.10011.16384")] -[assembly: ReliabilityContractAttribute(Consistency.MayCorruptAppDomain, Cer.MayFail)] -[assembly: AssemblyTitle("Microsoft.PowerShell.ConsoleHost")] -[assembly: AssemblyDescription("Microsoft Windows PowerShell Console Host")] - -[assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5")] -[assembly: System.Reflection.AssemblyFileVersion("10.0.10011.16384")] -#endif - [assembly: System.Runtime.InteropServices.ComVisible(false)] diff --git a/src/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj b/src/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj index a7ec8d9ba3b5..156834ea6fce 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj +++ b/src/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj @@ -8,13 +8,16 @@ - $(DefineConstants);CORECLR + + + + @@ -23,16 +26,4 @@ - - portable - - - - $(DefineConstants);UNIX - - - - full - - diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/ComInterfaces.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/ComInterfaces.cs new file mode 100644 index 000000000000..1cf2749928d8 --- /dev/null +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/ComInterfaces.cs @@ -0,0 +1,244 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Microsoft.PowerShell +{ + internal static class ComInterfaces + { + [DllImport("kernel32.dll", SetLastError = false, EntryPoint = "GetStartupInfoW")] + internal static extern void GetStartupInfo(out StartUpInfo lpStartupInfo); + + /// + /// IntPtr is being used for the string fields to make the marshaller faster and + /// simpler. With IntPtr, all fields are blittable, and since we don't use the + /// string fields at all, nothing is lost. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct StartUpInfo + { + public readonly UInt32 cb; + private readonly IntPtr lpReserved; + public readonly IntPtr lpDesktop; + public readonly IntPtr lpTitle; + public readonly UInt32 dwX; + public readonly UInt32 dwY; + public readonly UInt32 dwXSize; + public readonly UInt32 dwYSize; + public readonly UInt32 dwXCountChars; + public readonly UInt32 dwYCountChars; + public readonly UInt32 dwFillAttribute; + public readonly UInt32 dwFlags; + public readonly UInt16 wShowWindow; + private readonly UInt16 cbReserved2; + private readonly IntPtr lpReserved2; + public readonly IntPtr hStdInput; + public readonly IntPtr hStdOutput; + public readonly IntPtr hStdError; + } + + [ComImport] + [Guid("00021401-0000-0000-C000-000000000046")] + [ClassInterface(ClassInterfaceType.None)] + internal class CShellLink { } + + [ComImport] + [Guid("000214F9-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IShellLinkW + { + void GetPath( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, + int cchMaxPath, + IntPtr pfd, + uint fFlags); + void GetIDList(out IntPtr ppidl); + void SetIDList(IntPtr pidl); + void GetDescription( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, + int cchMaxName); + void SetDescription( + [MarshalAs(UnmanagedType.LPWStr)] string pszName); + void GetWorkingDirectory( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, + int cchMaxPath + ); + void SetWorkingDirectory( + [MarshalAs(UnmanagedType.LPWStr)] string pszDir); + void GetArguments( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, + int cchMaxPath); + void SetArguments( + [MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + void GetHotKey(out short wHotKey); + void SetHotKey(short wHotKey); + void GetShowCmd(out uint iShowCmd); + void SetShowCmd(uint iShowCmd); + void GetIconLocation( + [Out(), MarshalAs(UnmanagedType.LPWStr)] out StringBuilder pszIconPath, + int cchIconPath, + out int iIcon); + void SetIconLocation( + [MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, + int iIcon); + void SetRelativePath( + [MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, + uint dwReserved); + void Resolve(IntPtr hwnd, uint fFlags); + void SetPath( + [MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } + + /// + /// A property store. + /// + [ComImport] + [Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IPropertyStore + { + /// + /// Gets the number of properties contained in the property store. + /// + /// + /// + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + HResult GetCount([Out] out uint propertyCount); + + /// + /// Get a property key located at a specific index. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + HResult GetAt([In] uint propertyIndex, out PropertyKey key); + + /// + /// Gets the value of a property from the store. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + HResult GetValue([In] ref PropertyKey key, [Out] PropVariant pv); + + /// + /// Sets the value of a property in the store. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), PreserveSig] + HResult SetValue([In] ref PropertyKey key, [In] PropVariant pv); + + /// + /// Commits the changes. + /// + /// + [PreserveSig] + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + HResult Commit(); + } + + [ComImport()] + [Guid("6332DEBF-87B5-4670-90C0-5E57B408A49E")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface ICustomDestinationList + { + void SetAppID( + [MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [PreserveSig] + HResult BeginList( + out uint cMaxSlots, + ref Guid riid, + [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + [PreserveSig] + HResult AppendCategory( + [MarshalAs(UnmanagedType.LPWStr)] string pszCategory, + [MarshalAs(UnmanagedType.Interface)] IObjectArray poa); + void AppendKnownCategory( + [MarshalAs(UnmanagedType.I4)] KnownDestinationCategory category); + [PreserveSig] + HResult AddUserTasks( + [MarshalAs(UnmanagedType.Interface)] IObjectArray poa); + void CommitList(); + void GetRemovedDestinations( + ref Guid riid, + [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + void DeleteList( + [MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + void AbortList(); + } + + internal enum KnownDestinationCategory + { + Frequent = 1, + Recent + } + + [ComImport()] + [Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IObjectArray + { + void GetCount(out uint cObjects); + void GetAt( + uint iIndex, + ref Guid riid, + [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + } + + [ComImport()] + [Guid("5632B1A4-E38A-400A-928A-D4CD63230295")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IObjectCollection + { + // IObjectArray + [PreserveSig] + void GetCount(out uint cObjects); + [PreserveSig] + void GetAt( + uint iIndex, + ref Guid riid, + [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + + // IObjectCollection + void AddObject( + [MarshalAs(UnmanagedType.Interface)] object pvObject); + void AddFromArray( + [MarshalAs(UnmanagedType.Interface)] IObjectArray poaSource); + void RemoveObject(uint uiIndex); + void Clear(); + } + + [ComImport] + [Guid("45e2b4ae-b1c3-11d0-b92f-00a0c90312e1"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IShellLinkDataListW + { + [PreserveSig] + Int32 AddDataBlock(IntPtr pDataBlock); + + [PreserveSig] + Int32 CopyDataBlock(UInt32 dwSig, out IntPtr ppDataBlock); + + [PreserveSig] + Int32 RemoveDataBlock(UInt32 dwSig); + + void GetFlags(out uint pdwFlags); + void SetFlags(uint dwFlags); + } + + [DllImport("ole32.Dll")] + internal static extern HResult CoCreateInstance(ref Guid clsid, + [MarshalAs(UnmanagedType.IUnknown)] object inner, + uint context, + ref Guid uuid, + [MarshalAs(UnmanagedType.IUnknown)] out object rReturnedComObject); + } +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/HResult.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/HResult.cs new file mode 100644 index 000000000000..13e6fb612d6a --- /dev/null +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/HResult.cs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.PowerShell +{ + /// + /// HRESULT Wrapper + /// + internal enum HResult + { + /// + /// S_OK + /// + Ok = 0x0000, + + /// + /// S_FALSE. + /// + False = 0x0001, + + /// + /// E_INVALIDARG. + /// + InvalidArguments = unchecked((int)0x80070057), + + /// + /// E_OUTOFMEMORY. + /// + OutOfMemory = unchecked((int)0x8007000E), + + /// + /// E_NOINTERFACE. + /// + NoInterface = unchecked((int)0x80004002), + + /// + /// E_FAIL. + /// + Fail = unchecked((int)0x80004005), + + /// + /// E_ELEMENTNOTFOUND. + /// + ElementNotFound = unchecked((int)0x80070490), + + /// + /// TYPE_E_ELEMENTNOTFOUND. + /// + TypeElementNotFound = unchecked((int)0x8002802B), + + /// + /// NO_OBJECT. + /// + NoObject = unchecked((int)0x800401E5), + + /// + /// Win32 Error code: ERROR_CANCELLED. + /// + Win32ErrorCanceled = 1223, + + /// + /// ERROR_CANCELLED. + /// + Canceled = unchecked((int)0x800704C7), + + /// + /// The requested resource is in use. + /// + ResourceInUse = unchecked((int)0x800700AA), + + /// + /// The requested resources is read-only. + /// + AccessDenied = unchecked((int)0x80030005) + } +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropVariant.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropVariant.cs new file mode 100644 index 000000000000..8beb35c637c1 --- /dev/null +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropVariant.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.PowerShell +{ + /// + /// Represents the OLE struct PROPVARIANT. + /// This class is intended for internal use only. + /// + /// + /// Originally sourced from https://blogs.msdn.com/adamroot/pages/interop-with-propvariants-in-net.aspx + /// and modified to add ability to set values + /// + [StructLayout(LayoutKind.Explicit)] + internal sealed class PropVariant : IDisposable + { + // This is actually a VarEnum value, but the VarEnum type requires 4 bytes instead of the expected 2. + [FieldOffset(0)] + ushort _valueType; + + [FieldOffset(8)] + IntPtr _ptr; + + /// + /// Set a string value. + /// + internal PropVariant(string value) + { + if (value == null) + { + throw new ArgumentException("PropVariantNullString", "value"); + } + +#pragma warning disable CS0618 // Type or member is obsolete (might get deprecated in future versions + _valueType = (ushort)VarEnum.VT_LPWSTR; +#pragma warning restore CS0618 // Type or member is obsolete (might get deprecated in future versions + _ptr = Marshal.StringToCoTaskMemUni(value); + } + + /// + /// Disposes the object, calls the clear function. + /// + public void Dispose() + { + PropVariantNativeMethods.PropVariantClear(this); + + GC.SuppressFinalize(this); + } + + /// + /// Finalizer. + /// + ~PropVariant() + { + Dispose(); + } + + private class PropVariantNativeMethods + { + [DllImport("Ole32.dll", PreserveSig = false)] + internal static extern void PropVariantClear([In, Out] PropVariant pvar); + } + } +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropertyKey.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropertyKey.cs new file mode 100644 index 000000000000..2040c905a525 --- /dev/null +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropertyKey.cs @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.PowerShell +{ + /// + /// Defines a unique key for a Shell Property. + /// + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct PropertyKey : IEquatable + { + #region Public Properties + /// + /// A unique GUID for the property. + /// + public Guid FormatId { get; } + + /// + /// Property identifier (PID) + /// + public Int32 PropertyId { get; } + + #endregion + + #region Public Construction + + /// + /// PropertyKey Constructor. + /// + /// A unique GUID for the property. + /// Property identifier (PID). + internal PropertyKey(Guid formatId, Int32 propertyId) + { + this.FormatId = formatId; + this.PropertyId = propertyId; + } + + #endregion + + #region IEquatable Members + + /// + /// Returns whether this object is equal to another. This is vital for performance of value types. + /// + /// The object to compare against. + /// Equality result. + public bool Equals(PropertyKey other) + { + return other.Equals((object)this); + } + + #endregion + + #region equality and hashing + + /// + /// Returns the hash code of the object. This is vital for performance of value types. + /// + /// + public override int GetHashCode() + { + return FormatId.GetHashCode() ^ PropertyId; + } + + /// + /// Returns whether this object is equal to another. This is vital for performance of value types. + /// + /// The object to compare against. + /// Equality result. + public override bool Equals(object obj) + { + if (obj == null) + return false; + + if (!(obj is PropertyKey)) + return false; + + PropertyKey other = (PropertyKey)obj; + return other.FormatId.Equals(FormatId) && (other.PropertyId == PropertyId); + } + + /// + /// Implements the == (equality) operator. + /// + /// First property key to compare. + /// Second property key to compare. + /// True if object a equals object b. false otherwise. + public static bool operator ==(PropertyKey propKey1, PropertyKey propKey2) + { + return propKey1.Equals(propKey2); + } + + /// + /// Implements the != (inequality) operator. + /// + /// First property key to compare. + /// Second property key to compare. + /// True if object a does not equal object b. false otherwise. + public static bool operator !=(PropertyKey propKey1, PropertyKey propKey2) + { + return !propKey1.Equals(propKey2); + } + + /// + /// Override ToString() to provide a user friendly string representation. + /// + /// String representing the property key. + public override string ToString() + { + return string.Format(System.Globalization.CultureInfo.InvariantCulture, + "PropertyKeyFormatString", + FormatId.ToString("B"), PropertyId); + } + + #endregion + } +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/TaskbarJumpList.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/TaskbarJumpList.cs new file mode 100644 index 000000000000..58f639d34283 --- /dev/null +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/TaskbarJumpList.cs @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Management.Automation; +using System.Reflection; +using System.Threading; + +using static Microsoft.PowerShell.ComInterfaces; + +namespace Microsoft.PowerShell +{ + internal static class TaskbarJumpList + { + // Creating a JumpList entry takes around 55ms when the PowerShell process is interactive and + // owns the current window (otherwise it does a fast exit anyway). Since there is no 'GET' like API, + // we always have to execute this call because we do not know if it has been created yet. + // The JumpList does persist as long as the filepath of the executable does not change but there + // could be disruptions to it like e.g. the bi-annual Windows update, we decided to + // not over-optimize this and always create the JumpList as a non-blocking background STA thread instead. + internal static void CreateRunAsAdministratorJumpList() + { + // The STA apartment state is not supported on NanoServer and Windows IoT. + // Plus, there is not need to create jump list in those environment anyways. + if (!Platform.IsWindowsDesktop) + { + return; + } + + // Some COM APIs are implicitly STA only, therefore the executing thread must run in STA. + var thread = new Thread(() => + { + try + { + TaskbarJumpList.CreateElevatedEntry(ConsoleHostStrings.RunAsAdministrator); + } + catch (Exception exception) + { + // Due to COM threading complexity there might still be sporadic failures but they can be + // ignored as creating the JumpList is not critical and persists after its first creation. + Debug.Fail($"Creating 'Run as Administrator' JumpList failed. {exception}"); + } + }); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + } + + private static void CreateElevatedEntry(string title) + { + // Check startupInfo first to know if the current shell is interactive and owns a window before proceeding + // This check is fast (less than 1ms) and allows for quick-exit + GetStartupInfo(out StartUpInfo startupInfo); + var STARTF_USESHOWWINDOW = 0x00000001; + var SW_HIDE = 0; + if (((startupInfo.dwFlags & STARTF_USESHOWWINDOW) == 1) && (startupInfo.wShowWindow != SW_HIDE)) + { + string cmdPath = Assembly.GetEntryAssembly().Location.Replace(".dll", ".exe"); + + // Check for maximum available slots in JumpList and start creating the custom Destination List + var CLSID_DestinationList = new Guid(@"77f10cf0-3db5-4966-b520-b7c54fd35ed6"); + const uint CLSCTX_INPROC_SERVER = 1; + var IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); + var hResult = CoCreateInstance(ref CLSID_DestinationList, null, CLSCTX_INPROC_SERVER, ref IID_IUnknown, out object pCustDestListobj); + if (hResult < 0) + { + Debug.Fail($"Creating ICustomDestinationList failed with HResult '{hResult}'."); + return; + } + + var pCustDestList = (ICustomDestinationList)pCustDestListobj; + hResult = pCustDestList.BeginList(out uint uMaxSlots, new Guid(@"92CA9DCD-5622-4BBA-A805-5E9F541BD8C9"), out object pRemovedItems); + if (hResult < 0) + { + Debug.Fail($"BeginList on ICustomDestinationList failed with HResult '{hResult}'."); + return; + } + + if (uMaxSlots >= 1) + { + // Create JumpListLink + var nativeShellLink = (IShellLinkW)new CShellLink(); + var nativePropertyStore = (IPropertyStore)nativeShellLink; + nativeShellLink.SetPath(cmdPath); + nativeShellLink.SetShowCmd(0); + var shellLinkDataList = (IShellLinkDataListW)nativeShellLink; + shellLinkDataList.GetFlags(out uint flags); + flags |= 0x00800000; // SLDF_ALLOW_LINK_TO_LINK + flags |= 0x00002000; // SLDF_RUNAS_USER + shellLinkDataList.SetFlags(flags); + var PKEY_TITLE = new PropertyKey(new Guid("{F29F85E0-4FF9-1068-AB91-08002B27B3D9}"), 2); + hResult = nativePropertyStore.SetValue(ref PKEY_TITLE, new PropVariant(title)); + if (hResult < 0) + { + pCustDestList.AbortList(); + Debug.Fail($"SetValue on IPropertyStore with title '{title}' failed with HResult '{hResult}'."); + return; + } + + hResult = nativePropertyStore.Commit(); + if (hResult < 0) + { + pCustDestList.AbortList(); + Debug.Fail($"Commit on IPropertyStore failed with HResult '{hResult}'."); + return; + } + + // Create collection and add JumpListLink + var CLSID_EnumerableObjectCollection = new Guid(@"2d3468c1-36a7-43b6-ac24-d3f02fd9607a"); + const uint CLSCTX_INPROC_HANDLER = 2; + const uint CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER; + var ComSvrInterface_GUID = new Guid(@"555E2D2B-EE00-47AA-AB2B-39F953F6B339"); + hResult = CoCreateInstance(ref CLSID_EnumerableObjectCollection, null, CLSCTX_INPROC, ref IID_IUnknown, out object instance); + if (hResult < 0) + { + pCustDestList.AbortList(); + Debug.Fail($"Creating IObjectCollection failed with HResult '{hResult}'."); + return; + } + + var pShortCutCollection = (IObjectCollection)instance; + pShortCutCollection.AddObject((IShellLinkW)nativePropertyStore); + + // Add collection to custom destination list and commit the result + hResult = pCustDestList.AddUserTasks((IObjectArray)pShortCutCollection); + if (hResult < 0) + { + pCustDestList.AbortList(); + Debug.Fail($"AddUserTasks on ICustomDestinationList failed with HResult '{hResult}'."); + return; + } + + pCustDestList.CommitList(); + } + } + } + } +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs index cbce5c675dc9..6335230d1f6e 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs @@ -1,22 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; -using System.Text.RegularExpressions; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; using System.Globalization; using System.IO; -using System.Collections.ObjectModel; using System.Management.Automation; -using System.Management.Automation.Runspaces; -using System.Management.Automation.Internal; -using System.Diagnostics; -using Dbg = System.Management.Automation.Diagnostics; +using System.Management.Automation.Configuration; using System.Management.Automation.Host; -using System.Collections.Generic; +using System.Management.Automation.Internal; +using System.Management.Automation.Language; +using System.Management.Automation.Runspaces; using System.Security; +using System.Text; + +using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell { @@ -27,7 +27,7 @@ namespace Microsoft.PowerShell internal class NullHostUserInterface : PSHostUserInterface { /// - /// RawUI + /// RawUI. /// public override PSHostRawUserInterface RawUI { @@ -35,7 +35,7 @@ public override PSHostRawUserInterface RawUI } /// - /// Prompt + /// Prompt. /// /// /// @@ -47,7 +47,7 @@ public override PSHostRawUserInterface RawUI } /// - /// PromptForChoice + /// PromptForChoice. /// /// /// @@ -60,7 +60,7 @@ public override int PromptForChoice(string caption, string message, Collection - /// PromptForCredential + /// PromptForCredential. /// /// /// @@ -73,7 +73,7 @@ public override PSCredential PromptForCredential(string caption, string message, } /// - /// PromptForCredential + /// PromptForCredential. /// /// /// @@ -88,7 +88,7 @@ public override PSCredential PromptForCredential(string caption, string message, } /// - /// ReadLine + /// ReadLine. /// /// public override string ReadLine() @@ -97,7 +97,7 @@ public override string ReadLine() } /// - /// ReadLineAsSecureString + /// ReadLineAsSecureString. /// /// public override SecureString ReadLineAsSecureString() @@ -106,14 +106,14 @@ public override SecureString ReadLineAsSecureString() } /// - /// Write + /// Write. /// /// public override void Write(string value) { } /// - /// Write + /// Write. /// /// /// @@ -122,14 +122,14 @@ public override void Write(ConsoleColor foregroundColor, ConsoleColor background { } /// - /// WriteDebugLine + /// WriteDebugLine. /// /// public override void WriteDebugLine(string message) { } /// - /// WriteErrorLine + /// WriteErrorLine. /// /// public override void WriteErrorLine(string value) @@ -138,14 +138,14 @@ public override void WriteErrorLine(string value) } /// - /// WriteLine + /// WriteLine. /// /// public override void WriteLine(string value) { } /// - /// WriteProgress + /// WriteProgress. /// /// /// @@ -153,14 +153,14 @@ public override void WriteProgress(long sourceId, ProgressRecord record) { } /// - /// WriteVerboseLine + /// WriteVerboseLine. /// /// public override void WriteVerboseLine(string message) { } /// - /// WriteWarningLine + /// WriteWarningLine. /// /// public override void WriteWarningLine(string message) @@ -169,38 +169,44 @@ public override void WriteWarningLine(string message) internal class CommandLineParameterParser { + private const int MaxPipePathLengthLinux = 108; + private const int MaxPipePathLengthMacOS = 104; + internal static string[] validParameters = { - "version", - "nologo", - "noexit", -#if STAMODE "sta", "mta", -#endif - "noprofile", - "noninteractive", + "command", + "configurationname", + "custompipename", + "encodedcommand", + "executionpolicy", + "file", + "help", "inputformat", + "login", + "noexit", + "nologo", + "noninteractive", + "noprofile", "outputformat", -#if !UNIX + "removeworkingdirectorytrailingcharacter", + "settingsfile", + "version", "windowstyle", -#endif - "encodedcommand", - "configurationname", - "file", - "executionpolicy", - "command", - "help" + "workingdirectory" }; internal CommandLineParameterParser(PSHostUserInterface hostUI, string bannerText, string helpText) { if (hostUI == null) { throw new PSArgumentNullException("hostUI"); } + _hostUI = hostUI; _bannerText = bannerText; _helpText = helpText; } + #region Internal properties internal bool AbortStartup { get @@ -339,6 +345,14 @@ internal bool ShowVersion } } + internal string CustomPipeName + { + get + { + return _customPipeName; + } + } + internal Serialization.DataFormat OutputFormat { get @@ -349,6 +363,16 @@ internal Serialization.DataFormat OutputFormat } } + internal bool OutputFormatSpecified + { + get + { + Dbg.Assert(_dirty, "Parse has not been called yet"); + + return _outputFormatSpecified; + } + } + internal Serialization.DataFormat InputFormat { get @@ -389,25 +413,235 @@ internal bool NonInteractive get { return _noInteractive; } } + internal string WorkingDirectory + { + get + { +#if !UNIX + if (_removeWorkingDirectoryTrailingCharacter && _workingDirectory.Length > 0) + { + return _workingDirectory.Remove(_workingDirectory.Length - 1); + } +#endif + return _workingDirectory; + } + } + +#if !UNIX + internal bool RemoveWorkingDirectoryTrailingCharacter + { + get { return _removeWorkingDirectoryTrailingCharacter; } + } +#endif + + #endregion Internal properties + + #region static methods + /// + /// Processes the -SettingFile Argument. + /// + /// + /// The command line parameters to be processed. + /// + /// + /// The index in args to the argument following '-SettingFile'. + /// + /// + /// Used to allow the helper to write errors to the console. If not supplied, no errors will be written. + /// + /// + /// Returns true if the argument was parsed successfully and false if not. + /// + private static bool TryParseSettingFileHelper(string[] args, int settingFileArgIndex, CommandLineParameterParser parser) + { + if (settingFileArgIndex >= args.Length) + { + if (parser != null) + { + parser.WriteCommandLineError( + CommandLineParameterParserStrings.MissingSettingsFileArgument); + } + + return false; + } + + string configFile = null; + try + { + configFile = NormalizeFilePath(args[settingFileArgIndex]); + } + catch (Exception ex) + { + if (parser != null) + { + string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidSettingsFileArgument, args[settingFileArgIndex], ex.Message); + parser.WriteCommandLineError(error); + } + + return false; + } + + if (!System.IO.File.Exists(configFile)) + { + if (parser != null) + { + string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.SettingsFileNotExists, configFile); + parser.WriteCommandLineError(error); + } + + return false; + } + + PowerShellConfig.Instance.SetSystemConfigFilePath(configFile); + return true; + } + + private static string GetConfigurationNameFromGroupPolicy() + { + // Current user policy takes precedence. + var consoleSessionSetting = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + + return (consoleSessionSetting?.EnableConsoleSessionConfiguration == true && !string.IsNullOrEmpty(consoleSessionSetting?.ConsoleSessionConfigurationName)) ? + consoleSessionSetting.ConsoleSessionConfigurationName : string.Empty; + } + + /// + /// Processes the command line parameters to ConsoleHost which must be parsed before the Host is created. + /// Success to indicate that the program should continue running. + /// + /// + /// The command line parameters to be processed. + /// + internal static void EarlyParse(string[] args) + { + if (args == null) + { + Dbg.Assert(args != null, "Argument 'args' to EarlyParseHelper should never be null"); + return; + } + + bool noexitSeen = false; + for (int i = 0; i < args.Length; ++i) + { + (string SwitchKey, bool ShouldBreak) switchKeyResults = GetSwitchKey(args, ref i, parser: null, ref noexitSeen); + if (switchKeyResults.ShouldBreak) + { + break; + } + + string switchKey = switchKeyResults.SwitchKey; + + if (MatchSwitch(switchKey, match: "settingsfile", smallestUnambiguousMatch: "settings")) + { + // parse setting file arg and don't write error as there is no host yet. + if (!TryParseSettingFileHelper(args, ++i, parser: null)) + { + break; + } + } + } + } + + /// + /// Gets the word in a switch from the current argument or parses a file. + /// For example -foo, /foo, or --foo would return 'foo'. + /// + /// + /// The command line parameters to be processed. + /// + /// + /// The index in args to the argument to process. + /// + /// + /// Used to parse files in the args. If not supplied, Files will not be parsed. + /// + /// + /// Used during parsing files. + /// + /// + /// Returns a Tuple: + /// The first value is a String called SwitchKey with the word in a switch from the current argument or null. + /// The second value is a bool called ShouldBreak, indicating if the parsing look should break. + /// + private static (string SwitchKey, bool ShouldBreak) GetSwitchKey(string[] args, ref int argIndex, CommandLineParameterParser parser, ref bool noexitSeen) + { + string switchKey = args[argIndex].Trim().ToLowerInvariant(); + if (string.IsNullOrEmpty(switchKey)) + { + return (SwitchKey: null, ShouldBreak: false); + } + + if (!CharExtensions.IsDash(switchKey[0]) && switchKey[0] != '/') + { + // then its a file + if (parser != null) + { + --argIndex; + parser.ParseFile(args, ref argIndex, noexitSeen); + } + + return (SwitchKey: null, ShouldBreak: true); + } + + // chop off the first character so that we're agnostic wrt specifying / or - + // in front of the switch name. + switchKey = switchKey.Substring(1); + + // chop off the second dash so we're agnostic wrt specifying - or -- + if (!string.IsNullOrEmpty(switchKey) && CharExtensions.IsDash(switchKey[0])) + { + switchKey = switchKey.Substring(1); + } + + return (SwitchKey: switchKey, ShouldBreak: false); + } + + private static string NormalizeFilePath(string path) + { + // Normalize slashes + path = path.Replace(StringLiterals.AlternatePathSeparator, + StringLiterals.DefaultPathSeparator); + + return Path.GetFullPath(path); + } + + private static bool MatchSwitch(string switchKey, string match, string smallestUnambiguousMatch) + { + Dbg.Assert(switchKey != null, "need a value"); + Dbg.Assert(!string.IsNullOrEmpty(match), "need a value"); + Dbg.Assert(match.Trim().ToLowerInvariant() == match, "match should be normalized to lowercase w/ no outside whitespace"); + Dbg.Assert(smallestUnambiguousMatch.Trim().ToLowerInvariant() == smallestUnambiguousMatch, "match should be normalized to lowercase w/ no outside whitespace"); + Dbg.Assert(match.Contains(smallestUnambiguousMatch), "sUM should be a substring of match"); + + return (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0 && + switchKey.Length >= smallestUnambiguousMatch.Length); + } + + #endregion + private void ShowHelp() { Dbg.Assert(_helpText != null, "_helpText should not be null"); - _hostUI.WriteLine(""); + _hostUI.WriteLine(string.Empty); _hostUI.Write(_helpText); - _hostUI.WriteLine(""); + if (_showExtendedHelp) + { + _hostUI.Write(ManagedEntranceStrings.ExtendedHelp); + } + + _hostUI.WriteLine(string.Empty); } private void DisplayBanner() { // If banner text is not supplied do nothing. - if (!String.IsNullOrEmpty(_bannerText)) + if (!string.IsNullOrEmpty(_bannerText)) { _hostUI.WriteLine(_bannerText); _hostUI.WriteLine(); } } -#if STAMODE internal bool StaMode { get @@ -418,25 +652,17 @@ internal bool StaMode } else { - // Nano doesn't support STA COM apartment, so on Nano powershell has to use MTA as the default. - // return false; - // Win8: 182409 PowerShell 3.0 should run in STA mode by default return true; } } } -#endif /// - /// /// Processes all the command line parameters to ConsoleHost. Returns the exit code to be used to terminate the process, or /// Success to indicate that the program should continue running. - /// /// /// - /// /// The command line parameters to be processed. - /// /// internal void Parse(string[] args) @@ -459,36 +685,6 @@ internal void Parse(string[] args) } } - private static string s_groupPolicyBase = @"Software\Policies\Microsoft\Windows\PowerShell"; - private static string s_consoleSessionConfigurationKey = "ConsoleSessionConfiguration"; - private static string s_enableConsoleSessionConfiguration = "EnableConsoleSessionConfiguration"; - private static string s_consoleSessionConfigurationName = "ConsoleSessionConfigurationName"; - private static string GetConfigurationNameFromGroupPolicy() - { - // Current user policy takes precedence. - var groupPolicySettings = Utils.GetGroupPolicySetting(s_groupPolicyBase, s_consoleSessionConfigurationKey, Utils.RegCurrentUserThenLocalMachine); - if (groupPolicySettings != null) - { - object keyValue; - if (groupPolicySettings.TryGetValue(s_enableConsoleSessionConfiguration, out keyValue)) - { - if (String.Equals(keyValue.ToString(), "1", StringComparison.OrdinalIgnoreCase)) - { - if (groupPolicySettings.TryGetValue(s_consoleSessionConfigurationName, out keyValue)) - { - string consoleSessionConfigurationName = keyValue.ToString(); - if (!string.IsNullOrEmpty(consoleSessionConfigurationName)) - { - return consoleSessionConfigurationName; - } - } - } - } - } - - return string.Empty; - } - private void ParseHelper(string[] args) { Dbg.Assert(args != null, "Argument 'args' to ParseHelper should never be null"); @@ -496,32 +692,13 @@ private void ParseHelper(string[] args) for (int i = 0; i < args.Length; ++i) { - // Invariant culture used because command-line parameters are not localized. - - string switchKey = args[i].Trim().ToLowerInvariant(); - if (String.IsNullOrEmpty(switchKey)) + (string SwitchKey, bool ShouldBreak) switchKeyResults = GetSwitchKey(args, ref i, this, ref noexitSeen); + if (switchKeyResults.ShouldBreak) { - continue; - } - - if (!SpecialCharacters.IsDash(switchKey[0]) && switchKey[0] != '/') - { - // then its a file - - --i; - ParseFile(args, ref i, noexitSeen); break; } - // chop off the first character so that we're agnostic wrt specifying / or - - // in front of the switch name. - switchKey = switchKey.Substring(1); - - // chop off the second dash so we're agnostic wrt specifying - or -- - if (!String.IsNullOrEmpty(switchKey) && SpecialCharacters.IsDash(switchKey[0])) - { - switchKey = switchKey.Substring(1); - } + string switchKey = switchKeyResults.SwitchKey; // If version is in the commandline, don't continue to look at any other parameters if (MatchSwitch(switchKey, "version", "v")) @@ -533,11 +710,18 @@ private void ParseHelper(string[] args) _noExit = false; break; } - else if (MatchSwitch(switchKey, "help", "h") || MatchSwitch(switchKey, "?", "?")) + + if (MatchSwitch(switchKey, "help", "h") || MatchSwitch(switchKey, "?", "?")) { _showHelp = true; + _showExtendedHelp = true; _abortStartup = true; } + else if (MatchSwitch(switchKey, "login", "l")) + { + // This handles -Login on Windows only, where it does nothing. + // On *nix, -Login is handled much earlier to improve startup performance. + } else if (MatchSwitch(switchKey, "noexit", "noe")) { _noExit = true; @@ -587,6 +771,33 @@ private void ParseHelper(string[] args) _configurationName = args[i]; } + else if (MatchSwitch(switchKey, "custompipename", "cus")) + { + ++i; + if (i >= args.Length) + { + WriteCommandLineError( + CommandLineParameterParserStrings.MissingCustomPipeNameArgument); + break; + } + + if (!Platform.IsWindows) + { + int maxNameLength = (Platform.IsLinux ? MaxPipePathLengthLinux : MaxPipePathLengthMacOS) - Path.GetTempPath().Length; + if (args[i].Length > maxNameLength) + { + WriteCommandLineError( + string.Format( + CommandLineParameterParserStrings.CustomPipeNameTooLong, + maxNameLength, + args[i], + args[i].Length)); + break; + } + } + + _customPipeName = args[i]; + } else if (MatchSwitch(switchKey, "command", "c")) { if (!ParseCommand(args, ref i, noexitSeen, false)) @@ -594,9 +805,13 @@ private void ParseHelper(string[] args) break; } } -#if !UNIX else if (MatchSwitch(switchKey, "windowstyle", "w")) { +#if UNIX + WriteCommandLineError( + CommandLineParameterParserStrings.WindowStyleArgumentNotImplemented); + break; +#else ++i; if (i >= args.Length) { @@ -617,8 +832,8 @@ private void ParseHelper(string[] args) string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidWindowStyleArgument, args[i], e.Message)); break; } - } #endif + } else if (MatchSwitch(switchKey, "file", "f")) { if (!ParseFile(args, ref i, noexitSeen)) @@ -669,7 +884,7 @@ private void ParseHelper(string[] args) { string arg = args[i]; - if (!string.IsNullOrEmpty(arg) && SpecialCharacters.IsDash(arg[0])) + if (!string.IsNullOrEmpty(arg) && CharExtensions.IsDash(arg[0])) { break; } @@ -678,8 +893,10 @@ private void ParseHelper(string[] args) ConsoleHost.DefaultInitialSessionState.ImportPSModule(new string[] { arg }); moduleCount++; } + ++i; } + if (moduleCount < 1) { _hostUI.WriteErrorLine("No modules specified for -module option"); @@ -689,6 +906,7 @@ private void ParseHelper(string[] args) else if (MatchSwitch(switchKey, "outputformat", "o") || MatchSwitch(switchKey, "of", "o")) { ParseFormat(args, ref i, ref _outFormat, CommandLineParameterParserStrings.MissingOutputFormatParameter); + _outputFormatSpecified = true; } else if (MatchSwitch(switchKey, "inputformat", "in") || MatchSwitch(switchKey, "if", "if")) { @@ -713,10 +931,23 @@ private void ParseHelper(string[] args) break; } } -#if STAMODE - // explicit setting of the ApartmentState Not supported on NanoServer + else if (MatchSwitch(switchKey, "settingsfile", "settings")) + { + // Parse setting file arg and write error + if (!TryParseSettingFileHelper(args, ++i, this)) + { + break; + } + } else if (MatchSwitch(switchKey, "sta", "s")) { + if (!Platform.IsWindowsDesktop) + { + WriteCommandLineError( + CommandLineParameterParserStrings.STANotImplemented); + break; + } + if (_staMode.HasValue) { // -sta and -mta are mutually exclusive. @@ -727,10 +958,15 @@ private void ParseHelper(string[] args) _staMode = true; } - // Win8: 182409 PowerShell 3.0 should run in STA mode by default..so, consequently adding the switch -mta. - // Not deleting -sta for backward compatability reasons else if (MatchSwitch(switchKey, "mta", "mta")) { + if (!Platform.IsWindowsDesktop) + { + WriteCommandLineError( + CommandLineParameterParserStrings.MTANotImplemented); + break; + } + if (_staMode.HasValue) { // -sta and -mta are mutually exclusive. @@ -741,6 +977,23 @@ private void ParseHelper(string[] args) _staMode = false; } + else if (MatchSwitch(switchKey, "workingdirectory", "wo") || MatchSwitch(switchKey, "wd", "wd")) + { + ++i; + if (i >= args.Length) + { + WriteCommandLineError( + CommandLineParameterParserStrings.MissingWorkingDirectoryArgument); + break; + } + + _workingDirectory = args[i]; + } +#if !UNIX + else if (MatchSwitch(switchKey, "removeworkingdirectorytrailingcharacter", "removeworkingdirectorytrailingcharacter")) + { + _removeWorkingDirectoryTrailingCharacter = true; + } #endif else { @@ -779,32 +1032,13 @@ private void WriteCommandLineError(string msg, bool showHelp = false, bool showB _exitCode = ConsoleHost.ExitCodeBadCommandLineParameter; } - private bool MatchSwitch(string switchKey, string match, string smallestUnambiguousMatch) - { - Dbg.Assert(switchKey != null, "need a value"); - Dbg.Assert(!String.IsNullOrEmpty(match), "need a value"); - Dbg.Assert(match.Trim().ToLowerInvariant() == match, "match should be normalized to lowercase w/ no outside whitespace"); - Dbg.Assert(smallestUnambiguousMatch.Trim().ToLowerInvariant() == smallestUnambiguousMatch, "match should be normalized to lowercase w/ no outside whitespace"); - Dbg.Assert(match.Contains(smallestUnambiguousMatch), "sUM should be a substring of match"); - - if (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0) - { - if (switchKey.Length >= smallestUnambiguousMatch.Length) - { - return true; - } - } - - return false; - } - private void ParseFormat(string[] args, ref int i, ref Serialization.DataFormat format, string resourceStr) { StringBuilder sb = new StringBuilder(); foreach (string s in Enum.GetNames(typeof(Serialization.DataFormat))) { sb.Append(s); - sb.Append(ConsoleHostUserInterface.Crlf); + sb.Append(Environment.NewLine); } ++i; @@ -872,6 +1106,7 @@ bool TryGetBoolValue(string arg, out bool boolValue) boolValue = false; return true; } + boolValue = false; return false; } @@ -910,10 +1145,7 @@ bool TryGetBoolValue(string arg, out bool boolValue) string exceptionMessage = null; try { - // Normalize slashes - _file = args[i].Replace(StringLiterals.AlternatePathSeparator, - StringLiterals.DefaultPathSeparator); - _file = Path.GetFullPath(_file); + _file = NormalizeFilePath(args[i]); } catch (Exception e) { @@ -932,7 +1164,7 @@ bool TryGetBoolValue(string arg, out bool boolValue) if (!System.IO.File.Exists(_file)) { - if (args[i].StartsWith("-") && args[i].Length > 1) + if (args[i].StartsWith('-') && args[i].Length > 1) { string param = args[i].Substring(1, args[i].Length - 1).ToLower(); StringBuilder possibleParameters = new StringBuilder(); @@ -944,6 +1176,7 @@ bool TryGetBoolValue(string arg, out bool boolValue) possibleParameters.Append(validParameter); } } + if (possibleParameters.Length > 0) { WriteCommandLineError( @@ -953,9 +1186,10 @@ bool TryGetBoolValue(string arg, out bool boolValue) return false; } } + WriteCommandLineError( string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.ArgumentFileDoesNotExist, args[i]), - showBanner: false); + showHelp: true); return false; } @@ -975,7 +1209,7 @@ bool TryGetBoolValue(string arg, out bool boolValue) _collectedArgs.Add(new CommandParameter(pendingParameter, arg)); pendingParameter = null; } - else if (!string.IsNullOrEmpty(arg) && SpecialCharacters.IsDash(arg[0])) + else if (!string.IsNullOrEmpty(arg) && CharExtensions.IsDash(arg[0]) && arg.Length > 1) { int offset = arg.IndexOf(':'); if (offset >= 0) @@ -990,11 +1224,11 @@ bool TryGetBoolValue(string arg, out bool boolValue) string argName = arg.Substring(0, offset); if (TryGetBoolValue(argValue, out bool boolValue)) { - _collectedArgs.Add(new CommandParameter(argName, boolValue)); + _collectedArgs.Add(new CommandParameter(argName, boolValue)); } else { - _collectedArgs.Add(new CommandParameter(argName, argValue)); + _collectedArgs.Add(new CommandParameter(argName, argValue)); } } } @@ -1007,9 +1241,11 @@ bool TryGetBoolValue(string arg, out bool boolValue) { _collectedArgs.Add(new CommandParameter(null, arg)); } + ++i; } } + return true; } @@ -1091,11 +1327,13 @@ private bool ParseCommand(string[] args, ref int i, bool noexitSeen, bool isEnco cmdLineCmdSB.Append(args[i] + " "); ++i; } + if (cmdLineCmdSB.Length > 0) { // remove the last blank cmdLineCmdSB.Remove(cmdLineCmdSB.Length - 1, 1); } + _commandLineCommand = cmdLineCmdSB.ToString(); } @@ -1164,21 +1402,15 @@ private bool CollectArgs(string[] args, ref int i) private string _configurationName; private PSHostUserInterface _hostUI; private bool _showHelp; + private bool _showExtendedHelp; private bool _showBanner = true; private bool _noInteractive; private string _bannerText; private string _helpText; private bool _abortStartup; private bool _skipUserInit; -#if STAMODE - // Win8: 182409 PowerShell 3.0 should run in STA mode by default - // -sta and -mta are mutually exclusive..so tracking them using nullable boolean - // if true, then sta is specified on the command line. - // if false, then mta is specified on the command line. - // if null, then none is specified on the command line..use default in this case - // default is sta. + private string _customPipeName; private bool? _staMode = null; -#endif private bool _noExit = true; private bool _explicitReadCommandsFromStdin; private bool _noPrompt; @@ -1187,10 +1419,16 @@ private bool CollectArgs(string[] args, ref int i) private uint _exitCode = ConsoleHost.ExitCodeSuccess; private bool _dirty; private Serialization.DataFormat _outFormat = Serialization.DataFormat.Text; + private bool _outputFormatSpecified = false; private Serialization.DataFormat _inFormat = Serialization.DataFormat.Text; private Collection _collectedArgs = new Collection(); private string _file; private string _executionPolicy; + private string _workingDirectory; + +#if !UNIX + private bool _removeWorkingDirectoryTrailingCharacter = false; +#endif } } // namespace diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs index 84ae968d209d..75697a5f44dc 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs @@ -1,8 +1,7 @@ -#if !UNIX -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#if !UNIX // Implementation notes: In the functions that take ConsoleHandle parameters, we only assert that the handle is valid and not // closed, as opposed to doing a check and throwing an exception. This is because the win32 APIs that those functions wrap will @@ -13,7 +12,6 @@ // could do is diddle with the console buffer. #pragma warning disable 1634, 1691 - using System; using System.Text; using System.Runtime.InteropServices; @@ -43,16 +41,14 @@ namespace Microsoft.PowerShell { /// - /// /// Class ConsoleControl is used to wrap the various win32 console APIs 1:1 (i.e. at a low level, without attempting to be a /// "true" object-oriented library. - /// /// internal static class ConsoleControl { #if !UNIX -#region structs + #region structs internal enum InputRecordEventTypes : ushort { @@ -165,7 +161,7 @@ internal struct SMALL_RECT public override string ToString() { - return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", Left, Top, Right, Bottom); + return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", Left, Top, Right, Bottom); } } @@ -196,14 +192,14 @@ internal struct CONSOLE_CURSOR_INFO public override string ToString() { - return String.Format(CultureInfo.InvariantCulture, "Size: {0}, Visible: {1}", Size, Visible); + return string.Format(CultureInfo.InvariantCulture, "Size: {0}, Visible: {1}", Size, Visible); } } [StructLayout(LayoutKind.Sequential)] internal struct FONTSIGNATURE { - //From public\sdk\inc\wingdi.h + // From public\sdk\inc\wingdi.h // fsUsb*: A 128-bit Unicode subset bitfield (USB) identifying up to 126 Unicode subranges internal DWORD fsUsb0; @@ -218,7 +214,7 @@ internal struct FONTSIGNATURE [StructLayout(LayoutKind.Sequential)] internal struct CHARSETINFO { - //From public\sdk\inc\wingdi.h + // From public\sdk\inc\wingdi.h internal uint ciCharset; // Character set value. internal uint ciACP; // ANSI code-page identifier. internal FONTSIGNATURE fs; @@ -227,7 +223,7 @@ internal struct CHARSETINFO [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct TEXTMETRIC { - //From public\sdk\inc\wingdi.h + // From public\sdk\inc\wingdi.h public int tmHeight; public int tmAscent; public int tmDescent; @@ -250,7 +246,7 @@ internal struct TEXTMETRIC public byte tmCharSet; } -#region SentInput Data Structures + #region SentInput Data Structures [StructLayout(LayoutKind.Sequential)] internal struct INPUT @@ -295,7 +291,7 @@ internal struct MouseInput /// /// A set of bit flags that specify various aspects of mouse motion and button clicks. - /// See (http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx) + /// See (https://msdn.microsoft.com/library/ms646273(VS.85).aspx) /// internal DWORD Flags; @@ -305,7 +301,7 @@ internal struct MouseInput internal DWORD Time; /// - /// An additional value associated with the mouse event. An application calls GetMessageExtraInfo to obtain this extra information + /// An additional value associated with the mouse event. An application calls GetMessageExtraInfo to obtain this extra information. /// internal IntPtr ExtraInfo; } @@ -366,33 +362,33 @@ internal struct HardwareInput internal enum VirtualKeyCode : ushort { /// - /// LEFT ARROW key + /// LEFT ARROW key. /// Left = 0x25, /// - /// ENTER key + /// ENTER key. /// Return = 0x0D, } /// - /// Specify the type of the input + /// Specify the type of the input. /// internal enum InputType : uint { /// - /// INPUT_MOUSE = 0x00 + /// INPUT_MOUSE = 0x00. /// Mouse = 0, /// - /// INPUT_KEYBOARD = 0x01 + /// INPUT_KEYBOARD = 0x01. /// Keyboard = 1, /// - /// INPUT_HARDWARE = 0x02 + /// INPUT_HARDWARE = 0x02. /// Hardware = 2, } @@ -421,11 +417,11 @@ internal enum KeyboardFlag : uint ScanCode = 0x0008 } -#endregion SentInput Data Structures + #endregion SentInput Data Structures -#endregion structs + #endregion structs -#region Window Visibility + #region Window Visibility [DllImport(PinvokeDllNames.GetConsoleWindowDllName)] internal static extern IntPtr GetConsoleWindow(); @@ -450,9 +446,10 @@ internal enum KeyboardFlag : uint /// Code to control the display properties of the a window... /// /// The window to show... - /// The command to do - /// true it it was successful + /// The command to do. + /// True it it was successful. [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow); internal static void SetConsoleMode(ProcessWindowStyle style) @@ -476,14 +473,12 @@ internal static void SetConsoleMode(ProcessWindowStyle style) } } #endif -#endregion + #endregion -#region Input break handler (Ctrl-C, Ctrl-Break) + #region Input break handler (Ctrl-C, Ctrl-Break) /// - /// - /// Types of control ConsoleBreakSignals received by break Win32Handler delegates - /// + /// Types of control ConsoleBreakSignals received by break Win32Handler delegates. /// internal enum ConsoleBreakSignal : uint @@ -509,7 +504,7 @@ internal enum ConsoleBreakSignal : uint internal delegate bool BreakHandler(ConsoleBreakSignal ConsoleBreakSignal); /// - /// Set the console's break handler + /// Set the console's break handler. /// /// /// @@ -531,7 +526,7 @@ internal static void AddBreakHandler(BreakHandler handlerDelegate) } /// - /// Set the console's break handler to null + /// Set the console's break handler to null. /// /// /// If Win32's SetConsoleCtrlHandler fails @@ -551,9 +546,9 @@ internal static void RemoveBreakHandler() } } -#endregion + #endregion -#region Win32Handles + #region Win32Handles private static readonly Lazy _keyboardInputHandle = new Lazy(() => { @@ -626,14 +621,12 @@ internal static ConsoleHandle GetActiveScreenBufferHandle() return _outputHandle.Value; } -#endregion + #endregion -#region Mode + #region Mode /// - /// - /// flags used by ConsoleControl.GetMode and ConsoleControl.SetMode - /// + /// Flags used by ConsoleControl.GetMode and ConsoleControl.SetMode. /// [Flags] internal enum ConsoleModes : uint @@ -658,9 +651,7 @@ internal enum ConsoleModes : uint } /// - /// - /// Returns a mask of ConsoleModes flags describing the current modality of the console - /// + /// Returns a mask of ConsoleModes flags describing the current modality of the console. /// /// /// If Win32's GetConsoleMode fails @@ -687,24 +678,16 @@ internal static ConsoleModes GetMode(ConsoleHandle consoleHandle) } /// - /// - /// Sets the current mode of the console device - /// + /// Sets the current mode of the console device. /// /// - /// /// Handle to the console device returned by GetInputHandle - /// /// /// - /// /// Mask of mode flags - /// /// /// - /// /// If Win32's SetConsoleMode fails - /// /// internal static void SetMode(ConsoleHandle consoleHandle, ConsoleModes mode) @@ -724,61 +707,57 @@ internal static void SetMode(ConsoleHandle consoleHandle, ConsoleModes mode) } } + #endregion -#endregion - -#region Input - - + #region Input /// - /// /// Reads input from the console device according to the mode in effect (see GetMode, SetMode) - /// /// /// - /// /// Handle to the console device returned by GetInputHandle - /// - /// - /// - /// Initial contents of the edit buffer, if any. charactersToRead should be at least as large as the length of this string. - /// + /// + /// Length of initial content of the edit buffer. Zero if no initial content exists. + /// Must be less than editBuffer length. + /// + /// + /// Edit buffer with optional initial content. + /// Caution! Last position in the edit buffer is for a null in native code. /// /// - /// /// Number of characters to read from the device. - /// + /// Must be less than editBuffer length. /// /// - /// - /// true to allow the user to terminate input by hitting the tab or shift-tab key, in addition to the enter key - /// + /// True to allow the user to terminate input by hitting the tab or shift-tab key, in addition to the enter key /// /// - /// - /// bit mask indicating the state of the control/shift keys at the point input was terminated. - /// + /// Bit mask indicating the state of the control/shift keys at the point input was terminated. + /// /// /// /// - /// /// If Win32's ReadConsole fails - /// /// - internal static string ReadConsole(ConsoleHandle consoleHandle, string initialContent, - int charactersToRead, bool endOnTab, out uint keyState) + internal static string ReadConsole( + ConsoleHandle consoleHandle, + int initialContentLength, + Span editBuffer, + int charactersToRead, + bool endOnTab, + out uint keyState) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); - Dbg.Assert(initialContent != null, "if no initial content is desired, pass String.Empty"); + Dbg.Assert(initialContentLength < editBuffer.Length, "initialContentLength must be less than editBuffer.Length"); + Dbg.Assert(charactersToRead < editBuffer.Length, "charactersToRead must be less than editBuffer.Length"); keyState = 0; CONSOLE_READCONSOLE_CONTROL control = new CONSOLE_READCONSOLE_CONTROL(); control.nLength = (ULONG)Marshal.SizeOf(control); - control.nInitialChars = (ULONG)initialContent.Length; + control.nInitialChars = (ULONG)initialContentLength; control.dwControlKeyState = 0; if (endOnTab) { @@ -787,27 +766,34 @@ internal static void SetMode(ConsoleHandle consoleHandle, ConsoleModes mode) control.dwCtrlWakeupMask = (1 << TAB); } - DWORD charsReadUnused = 0; - StringBuilder buffer = new StringBuilder(initialContent, charactersToRead); + DWORD charsReaded = 0; + bool result = NativeMethods.ReadConsole( consoleHandle.DangerousGetHandle(), - buffer, + editBuffer, (DWORD)charactersToRead, - out charsReadUnused, + out charsReaded, ref control); keyState = control.dwControlKeyState; if (result == false) { int err = Marshal.GetLastWin32Error(); - HostException e = CreateHostException(err, "ReadConsole", - ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleExceptionTemplate); + HostException e = CreateHostException( + err, + "ReadConsole", + ErrorCategory.ReadError, + ConsoleControlStrings.ReadConsoleExceptionTemplate); throw e; } - if (charsReadUnused > (uint)buffer.Length) - charsReadUnused = (uint)buffer.Length; - return buffer.ToString(0, (int)charsReadUnused); + + if (charsReaded > (uint)charactersToRead) + { + charsReaded = (uint)charactersToRead; + } + + return editBuffer.Slice(0, (int)charsReaded).ToString(); } /// @@ -815,19 +801,13 @@ internal static void SetMode(ConsoleHandle consoleHandle, ConsoleModes mode) /// Returns the number of records read in buffer. /// /// - /// /// handle for the console where input is read - /// /// /// - /// /// array where data read are stored - /// /// /// - /// /// actual number of input records read - /// /// /// /// If Win32's ReadConsoleInput fails @@ -853,26 +833,21 @@ internal static int ReadConsoleInput(ConsoleHandle consoleHandle, ref INPUT_RECO ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleInputExceptionTemplate); throw e; } + return (int)recordsRead; } /// - /// Wraps Win32 PeekConsoleInput + /// Wraps Win32 PeekConsoleInput. /// /// - /// /// handle for the console where input is peeked - /// /// /// - /// /// array where data read are stored - /// /// /// - /// /// actual number of input records peeked - /// /// /// /// If Win32's PeekConsoleInput fails @@ -908,17 +883,13 @@ internal static int PeekConsoleInput } /// - /// Wraps Win32 GetNumberOfConsoleInputEvents + /// Wraps Win32 GetNumberOfConsoleInputEvents. /// /// - /// /// handle for the console where the number of console input events is obtained - /// /// /// - /// /// number of console input events - /// /// /// /// If Win32's GetNumberOfConsoleInputEvents fails @@ -945,12 +916,10 @@ internal static int GetNumberOfConsoleInputEvents(ConsoleHandle consoleHandle) } /// - /// Wraps Win32 FlushConsoleInputBuffer + /// Wraps Win32 FlushConsoleInputBuffer. /// /// - /// /// handle for the console where the input buffer is flushed - /// /// /// /// If Win32's FlushConsoleInputBuffer fails @@ -974,23 +943,19 @@ internal static void FlushConsoleInputBuffer(ConsoleHandle consoleHandle) } } -#endregion Input + #endregion Input -#region Buffer + #region Buffer /// /// Wraps Win32 GetConsoleScreenBufferInfo - /// Returns Console Screen Buffer Info + /// Returns Console Screen Buffer Info. /// /// - /// /// Handle for the console where the screen buffer info is obtained - /// /// /// - /// /// info about the screen buffer. See the definition of CONSOLE_SCREEN_BUFFER_INFO - /// /// /// /// If Win32's GetConsoleScreenBufferInfo fails @@ -1016,7 +981,7 @@ internal static CONSOLE_SCREEN_BUFFER_INFO GetConsoleScreenBufferInfo(ConsoleHan } /// - /// set the output buffer's size + /// Set the output buffer's size. /// /// /// @@ -1068,6 +1033,7 @@ internal static bool IsConsoleColor(ConsoleColor c) case ConsoleColor.Yellow: return true; } + return false; } @@ -1093,19 +1059,13 @@ internal static WORD ColorToWORD(ConsoleColor foreground, ConsoleColor backgroun /// is constrained. /// /// - /// /// handle for the console where output is written - /// /// /// - /// /// location on screen buffer where writing starts - /// /// /// - /// /// 2D array of cells. Caller needs to ensure that the array is 2D. - /// /// /// /// If Win32's GetConsoleScreenBufferInfo fails @@ -1126,6 +1086,7 @@ internal static void WriteConsoleOutput(ConsoleHandle consoleHandle, Coordinates { throw PSTraceSource.NewArgumentNullException("contents"); } + uint codePage; if (IsCJKOutputCodePage(out codePage)) { @@ -1150,11 +1111,11 @@ internal static void WriteConsoleOutput(ConsoleHandle consoleHandle, Coordinates screenRegion.Bottom - screenRegion.Top; #if DEBUG - //Check contents in contentsRegion + // Check contents in contentsRegion CheckWriteConsoleOutputContents(contents, contentsRegion); #endif - //Identify edges and areas of identical contiguous edges in contentsRegion + // Identify edges and areas of identical contiguous edges in contentsRegion List sameEdgeAreas = new List(); int firstLeftTrailingRow = -1, firstRightLeadingRow = -1; BuildEdgeTypeInfo(contentsRegion, contents, @@ -1211,11 +1172,13 @@ internal static void WriteConsoleOutput(ConsoleHandle consoleHandle, Coordinates { firstLeftTrailingRow = r; } + if (firstRightLeadingRow == -1 && ((range.Type & BufferCellArrayRowType.RightLeading) != 0)) { firstRightLeadingRow = r; } - for (;;) + + while (true) { r++; if (r > contentsRegion.Bottom) @@ -1224,6 +1187,7 @@ internal static void WriteConsoleOutput(ConsoleHandle consoleHandle, Coordinates sameEdgeAreas.Add(range); return; } + edgeType = GetEdgeType(contents[r, contentsRegion.Left], contents[r, contentsRegion.Right]); if (edgeType != range.Type) { @@ -1242,10 +1206,12 @@ private static BufferCellArrayRowType GetEdgeType(BufferCell left, BufferCell ri { edgeType |= BufferCellArrayRowType.LeftTrailing; } + if (right.BufferCellType == BufferCellType.Leading) { edgeType |= BufferCellArrayRowType.RightLeading; } + return edgeType; } @@ -1264,11 +1230,11 @@ private enum BufferCellArrayRowType : uint } /// - /// Check the existing screen columns left and right of areas to be written + /// Check the existing screen columns left and right of areas to be written. /// /// /// - /// must be within the screen buffer + /// Must be within the screen buffer. /// /// /// @@ -1316,7 +1282,7 @@ private enum BufferCellArrayRowType : uint } } } - //Check right edge + // Check right edge if (origin.X + (contentsRegion.Right - contentsRegion.Left) + 1 >= bufferInfo.BufferSize.X) { if (firstRightLeadingRow >= 0) @@ -1344,7 +1310,6 @@ private enum BufferCellArrayRowType : uint } } - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called in CHK builds")] private static void CheckWriteConsoleOutputContents(BufferCell[,] contents, Rectangle contentsRegion) { @@ -1369,6 +1334,7 @@ private static void CheckWriteConsoleOutputContents(BufferCell[,] contents, Rect { break; } + if (contents[r, c].Character != 0 || contents[r, c].BufferCellType != BufferCellType.Trailing) { // for a 2 cell character, either there is no trailing BufferCell or @@ -1449,6 +1415,7 @@ private static void WriteConsoleOutputCJK(ConsoleHandle consoleHandle, Coordinat bufferSize.X--; writeRegion.Right--; } + CHAR_INFO[] characterBuffer = new CHAR_INFO[bufferSize.Y * bufferSize.X]; // copy characterBuffer to contents; @@ -1508,6 +1475,7 @@ private static void WriteConsoleOutputCJK(ConsoleHandle consoleHandle, Coordinat // We don't output anything for this cell if Raster font is in use, or if the last cell is not a leading byte characterBufferIndex--; } + lastCharIsLeading = false; } } @@ -1545,6 +1513,7 @@ private static void WriteConsoleOutputCJK(ConsoleHandle consoleHandle, Coordinat bufferCoord, ref writeRegion); } + if (result == false) { // When WriteConsoleOutput fails, half bufferLimit @@ -1555,6 +1524,7 @@ private static void WriteConsoleOutputCJK(ConsoleHandle consoleHandle, Coordinat ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleOutputExceptionTemplate); throw e; } + bufferLimit /= 2; if (cols == colsRemaining) { @@ -1595,6 +1565,7 @@ private static void WriteConsoleOutputPlain(ConsoleHandle consoleHandle, Coordin tracer.WriteLine("contents passed in has 0 rows and columns"); return; } + int bufferLimit = 2 * 1024; // Limit is 8K bytes as each CHAR_INFO takes 4 bytes COORD bufferCoord; @@ -1681,6 +1652,7 @@ private static void WriteConsoleOutputPlain(ConsoleHandle consoleHandle, Coordin ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleOutputExceptionTemplate); throw e; } + bufferLimit /= 2; if (cols == colsRemaining) { @@ -1717,25 +1689,17 @@ private static void WriteConsoleOutputPlain(ConsoleHandle consoleHandle, Coordin /// is constrained. /// /// - /// /// handle for the console where output is read - /// /// /// - /// /// location on screen buffer where reading begins - /// /// /// - /// /// indicates the area in where the data read /// is stored. - /// /// /// - /// /// this is ref because the bounds and size of the array are needed. - /// /// /// /// If there is not enough memory to complete calls to Win32's ReadConsoleOutput @@ -1785,6 +1749,7 @@ internal static void ReadConsoleOutput { cellArray = new BufferCell[cellArrayRegion.Bottom + 1, 2]; } + checkOrigin = new Coordinates(origin.X + (contentsRegion.Right - contentsRegion.Left), origin.Y); ReadConsoleOutputCJK(consoleHandle, codePage, checkOrigin, @@ -1804,10 +1769,10 @@ internal static void ReadConsoleOutput } } -#region ReadConsoleOutput CJK + #region ReadConsoleOutput CJK /// /// If an edge cell read is a blank, it is potentially part of a double width character. Hence, - /// at least one of the left and right edges should be checked + /// at least one of the left and right edges should be checked. /// /// /// @@ -1822,6 +1787,7 @@ private static bool ShouldCheck(int edge, BufferCell[,] contents, Rectangle cont return true; } } + return false; } @@ -1859,6 +1825,7 @@ private static bool ReadConsoleOutputCJKSmall { return false; } + int characterBufferIndex = 0; for (int r = contentsRegion.Top; r <= contentsRegion.Bottom; r++) @@ -1912,11 +1879,12 @@ private static bool ReadConsoleOutputCJKSmall } } } + return true; } /// - /// Can handle reading CJK characters, but the left and right edges are not checked + /// Can handle reading CJK characters, but the left and right edges are not checked. /// /// /// @@ -2036,6 +2004,7 @@ internal static void ReadConsoleOutputCJK } } } + colsRemaining -= bufferSize.X; readRegion.Left += bufferSize.X; if (colsRemaining > 0 && (bufferSize.Y == 1) && @@ -2044,6 +2013,7 @@ internal static void ReadConsoleOutputCJK colsRemaining++; readRegion.Left--; } + bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); } // column iteration @@ -2051,7 +2021,6 @@ internal static void ReadConsoleOutputCJK readRegion.Top += bufferSize.Y; } // row iteration - // The following nested loop set the value of the empty cells in contents: // character to ' ' // foreground color to console's foreground color @@ -2088,15 +2057,16 @@ out background { break; } + contents[rowIndex, colIndex] = new BufferCell( ' ', foreground, background, BufferCellType.Complete); colIndex++; } + rowIndex++; } } -#endregion ReadConsoleOutput CJK - + #endregion ReadConsoleOutput CJK private static void ReadConsoleOutputPlain ( @@ -2223,6 +2193,7 @@ private static void ReadConsoleOutputPlain contents[r, c].BackgroundColor = bgColor; } } + colsRemaining -= bufferSize.X; readRegion.Left += bufferSize.X; bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); @@ -2268,38 +2239,31 @@ out background { break; } + contents[rowIndex, colIndex].Character = ' '; contents[rowIndex, colIndex].ForegroundColor = foreground; contents[rowIndex, colIndex].BackgroundColor = background; colIndex++; } + rowIndex++; } } - /// - /// Wraps Win32 FillConsoleOutputCharacter + /// Wraps Win32 FillConsoleOutputCharacter. /// /// - /// /// handle for the console where output is filled - /// /// /// - /// /// character to fill the console output - /// /// /// - /// /// number of times to write character - /// /// /// - /// /// location on screen buffer where writing starts - /// /// /// /// If Win32's FillConsoleOutputCharacter fails @@ -2341,27 +2305,19 @@ Coordinates origin } /// - /// Wraps Win32 FillConsoleOutputAttribute + /// Wraps Win32 FillConsoleOutputAttribute. /// /// - /// /// handle for the console where output is filled - /// /// /// - /// /// attribute to fill the console output - /// /// /// - /// /// number of times to write attribute - /// /// /// - /// /// location on screen buffer where writing starts - /// /// /// /// If Win32's FillConsoleOutputAttribute fails @@ -2402,32 +2358,22 @@ Coordinates origin } /// - /// Wrap Win32 ScrollConsoleScreenBuffer + /// Wrap Win32 ScrollConsoleScreenBuffer. /// /// - /// /// handle for the console where screen buffer is scrolled - /// /// /// - /// /// area to be scrolled - /// /// /// - /// /// area to be updated after scrolling - /// /// /// - /// /// location to which the top left corner of scrollRectangle move - /// /// /// - /// /// character and attribute to fill the area vacated by the scroll - /// /// /// /// If Win32's ScrollConsoleScreenBuffer fails @@ -2462,29 +2408,23 @@ internal static void ScrollConsoleScreenBuffer } } -#endregion Buffer + #endregion Buffer -#region Window + #region Window /// - /// Wraps Win32 SetConsoleWindowInfo + /// Wraps Win32 SetConsoleWindowInfo. /// /// - /// /// handle for the console where window info is set - /// /// /// - /// /// If this parameter is TRUE, the coordinates specify the new upper-left and /// lower-right corners of the window. If it is false, the coordinates are offsets /// to the current window-corner coordinates - /// /// /// - /// /// specify the size and position of the console screen buffer's window - /// /// /// /// If Win32's SetConsoleWindowInfo fails @@ -2508,17 +2448,13 @@ internal static void SetConsoleWindowInfo(ConsoleHandle consoleHandle, bool abso } /// - /// Wraps Win32 GetLargestConsoleWindowSize + /// Wraps Win32 GetLargestConsoleWindowSize. /// /// - /// /// handle for the console for which the largest window size is obtained - /// /// /// - /// /// the largest window size - /// /// /// /// If Win32's GetLargestConsoleWindowSize fails @@ -2543,16 +2479,12 @@ internal static Size GetLargestConsoleWindowSize(ConsoleHandle consoleHandle) return new Size(result.X, result.Y); } - - /// /// Wraps Win32 GetConsoleTitle. 1K is the safe limit experimentally. The 64K limit /// found in the docs is disregarded because it is essentially meaningless. /// /// - /// /// a string for the title of the window - /// /// /// /// If Win32's GetConsoleTitle fails @@ -2574,19 +2506,17 @@ internal static string GetConsoleWindowTitle() // the difference, we'll just return the empty string every time. if (result == 0) { - return String.Empty; + return string.Empty; } return consoleTitle.ToString(); } /// - /// Wraps Win32 SetConsoleTitle + /// Wraps Win32 SetConsoleTitle. /// /// - /// /// a string for the title of the window - /// /// /// /// If Win32's SetConsoleTitle fails @@ -2606,95 +2536,111 @@ internal static void SetConsoleWindowTitle(string consoleTitle) } } -#endregion Window + #endregion Window /// - /// - /// Wrap Win32 WriteConsole - /// + /// Wrap Win32 WriteConsole. /// /// - /// - /// handle for the console where the string is written - /// + /// Handle for the console where the string is written. /// /// - /// - /// string that is written - /// + /// String that is written. + /// + /// + /// New line is written. /// /// - /// - /// if the Win32's WriteConsole fails - /// + /// If the Win32's WriteConsole fails. /// - - internal static void WriteConsole(ConsoleHandle consoleHandle, string output) + internal static void WriteConsole(ConsoleHandle consoleHandle, ReadOnlySpan output, bool newLine) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); - if (String.IsNullOrEmpty(output)) + if (output.Length == 0) + { + if (newLine) + { + WriteConsole(consoleHandle, Environment.NewLine); + } + return; + } // Native WriteConsole doesn't support output buffer longer than 64K. // We need to chop the output string if it is too long. - int cursor = 0; // This records the chopping position in output string - const int maxBufferSize = 16383; // this is 64K/4 - 1 to account for possible width of each character. + const int MaxBufferSize = 16383; // this is 64K/4 - 1 to account for possible width of each character. while (cursor < output.Length) { - string outBuffer; + ReadOnlySpan outBuffer; - if (cursor + maxBufferSize < output.Length) + if (cursor + MaxBufferSize < output.Length) { - outBuffer = output.Substring(cursor, maxBufferSize); - cursor += maxBufferSize; + outBuffer = output.Slice(cursor, MaxBufferSize); + cursor += MaxBufferSize; + + WriteConsole(consoleHandle, outBuffer); } else { - outBuffer = output.Substring(cursor); + outBuffer = output.Slice(cursor); cursor = output.Length; + + if (newLine) + { + var endOfLine = Environment.NewLine.AsSpan(); + var endOfLineLength = endOfLine.Length; + Span outBufferLine = stackalloc char[outBuffer.Length + endOfLineLength]; + outBuffer.CopyTo(outBufferLine); + endOfLine.CopyTo(outBufferLine.Slice(outBufferLine.Length - endOfLineLength)); + WriteConsole(consoleHandle, outBufferLine); + } + else + { + WriteConsole(consoleHandle, outBuffer); + } } + } + } - DWORD charsWritten; - bool result = - NativeMethods.WriteConsole( - consoleHandle.DangerousGetHandle(), - outBuffer, - (DWORD)outBuffer.Length, - out charsWritten, - IntPtr.Zero); + private static void WriteConsole(ConsoleHandle consoleHandle, ReadOnlySpan buffer) + { + DWORD charsWritten; + bool result = + NativeMethods.WriteConsole( + consoleHandle.DangerousGetHandle(), + buffer, + (DWORD)buffer.Length, + out charsWritten, + IntPtr.Zero); - if (result == false) - { - int err = Marshal.GetLastWin32Error(); + if (result == false) + { + int err = Marshal.GetLastWin32Error(); - HostException e = CreateHostException(err, "WriteConsole", - ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleExceptionTemplate); - throw e; - } + HostException e = CreateHostException( + err, + "WriteConsole", + ErrorCategory.WriteError, + ConsoleControlStrings.WriteConsoleExceptionTemplate); + throw e; } } /// - /// Wraps Win32 SetConsoleTextAttribute + /// Wraps Win32 SetConsoleTextAttribute. /// /// - /// /// handle for the console where text attribute is set - /// /// /// - /// /// text attribute to set the console - /// /// /// - /// /// if the Win32's SetConsoleTextAttribute fails - /// /// internal static void SetConsoleTextAttribute(ConsoleHandle consoleHandle, WORD attribute) @@ -2715,47 +2661,100 @@ internal static void SetConsoleTextAttribute(ConsoleHandle consoleHandle, WORD a } #endif -#region Dealing with CJK + #region Dealing with CJK // Return the length of a VT100 control sequence character in str starting // at the given offset. // - // This code only handles the most common formatting sequences, which are - // all of the pattern: - // ESC '[' digits+ (';' digits)* 'm' + // This code only handles the following formatting sequences, corresponding to + // the patterns: + // CSI params? 'm' // SGR: Select Graphics Rendition + // CSI params? '#' [{}pq] // XTPUSHSGR ('{'), XTPOPSGR ('}'), or their aliases ('p' and 'q') // - // There are many other VT100 escape sequences, but this simple pattern - // is sufficient for our formatting system. We won't handle cursor movements - // or other attempts at animation. + // Where: + // params: digit+ (';' params)? + // CSI: C0_CSI | C1_CSI + // C0_CSI: \x001b '[' // ESC '[' + // C1_CSI: \x009b // - // Note that offset is adjusted past the escape sequence. + // There are many other VT100 escape sequences, but these text attribute sequences + // (color-related, underline, etc.) are sufficient for our formatting system. We + // won't handle cursor movements or other attempts at animation. + // + // Note that offset is adjusted past the escape sequence, or at least one + // character forward if there is no escape sequence at the specified position. internal static int ControlSequenceLength(string str, ref int offset) { var start = offset; - if (str[offset++] != (char)0x1B) + + // First, check for the CSI: + if ((str[offset] == (char)0x1b) && (str.Length > (offset + 1)) && (str[offset + 1] == '[')) + { + // C0 CSI + offset += 2; + } + else if (str[offset] == (char)0x9b) + { + // C1 CSI + offset += 1; + } + else + { + // No CSI at the current location, so we are done looking, but we still + // need to advance offset. + offset += 1; return 0; + } - if (offset >= str.Length || str[offset] != '[') + if (offset >= str.Length) + { return 0; + } - offset += 1; - while (offset < str.Length) + // Next, handle possible numeric arguments: + char c; + do { - var c = str[offset++]; - if (c == 'm') - break; + c = str[offset++]; + } + while ((offset < str.Length) && (char.IsDigit(c) || c == ';')); - if (char.IsDigit(c) || c == ';') - continue; + // Finally, handle the command characters for the specific sequences we + // handle: + if (c == 'm') + { + // SGR: Select Graphics Rendition + return offset - start; + } + // Maybe XTPUSHSGR or XTPOPSGR, but we need to read another char. Offset is + // already positioned on the next char (or past the end). + if (offset >= str.Length) + { return 0; } - return offset - start; + if (c == '#') + { + // '{' : XTPUSHSGR + // '}' : XTPOPSGR + // 'p' : alias for XTPUSHSGR + // 'q' : alias for XTPOPSGR + c = str[offset++]; + if ((c == '{') || + (c == '}') || + (c == 'p') || + (c == 'q')) + { + return offset - start; + } + } + + return 0; } /// - /// From IsConsoleFullWidth in \windows\core\ntcon\server\dbcs.c + /// From IsConsoleFullWidth in \windows\core\ntcon\server\dbcs.c. /// /// [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", @@ -2788,7 +2787,7 @@ internal static int LengthInBufferCells(string str, int offset, bool checkEscape #if !UNIX /// - /// Check if the output buffer code page is Japanese, Simplified Chinese, Korean, or Traditional Chinese + /// Check if the output buffer code page is Japanese, Simplified Chinese, Korean, or Traditional Chinese. /// /// /// @@ -2802,25 +2801,20 @@ internal static bool IsCJKOutputCodePage(out uint codePage) } #endif -#endregion Dealing with CJK + #endregion Dealing with CJK #if !UNIX -#region Cursor - + #region Cursor /// - /// Wraps Win32 SetConsoleCursorPosition + /// Wraps Win32 SetConsoleCursorPosition. /// /// - /// /// handle for the console where cursor position is set - /// /// /// - /// /// location to which the cursor will be set - /// /// /// /// If Win32's SetConsoleCursorPosition fails @@ -2848,20 +2842,14 @@ internal static void SetConsoleCursorPosition(ConsoleHandle consoleHandle, Coord } } - - /// - /// Wraps Win32 GetConsoleCursorInfo + /// Wraps Win32 GetConsoleCursorInfo. /// /// - /// /// handle for the console where cursor info is obtained - /// /// /// - /// /// cursor info - /// /// /// /// If Win32's GetConsoleCursorInfo fails @@ -2884,6 +2872,7 @@ internal static CONSOLE_CURSOR_INFO GetConsoleCursorInfo(ConsoleHandle consoleHa ErrorCategory.ResourceUnavailable, ConsoleControlStrings.GetConsoleCursorInfoExceptionTemplate); throw e; } + return cursorInfo; } @@ -2904,21 +2893,18 @@ internal static CONSOLE_FONT_INFO_EX GetConsoleFontInfo(ConsoleHandle consoleHan ErrorCategory.ResourceUnavailable, ConsoleControlStrings.GetConsoleFontInfoExceptionTemplate); throw e; } + return fontInfo; } /// - /// Wraps Win32 SetConsoleCursorInfo + /// Wraps Win32 SetConsoleCursorInfo. /// /// - /// /// handle for the console where cursor info is set - /// /// /// - /// /// cursor info to set the cursor - /// /// /// /// If Win32's SetConsoleCursorInfo fails @@ -2941,12 +2927,12 @@ internal static void SetConsoleCursorInfo(ConsoleHandle consoleHandle, CONSOLE_C } } -#endregion Cursor + #endregion Cursor -#region helper + #region helper /// - /// Helper function to create the proper HostException + /// Helper function to create the proper HostException. /// /// /// @@ -2962,14 +2948,14 @@ internal static void SetConsoleCursorInfo(ConsoleHandle consoleHandle, CONSOLE_C return e; } -#endregion helper + #endregion helper -#region + #region internal static int LengthInBufferCells(char c) { // The following is based on http://www.cl.cam.ac.uk/~mgk25/c/wcwidth.c - // which is derived from http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt + // which is derived from https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt bool isWide = c >= 0x1100 && (c <= 0x115f || /* Hangul Jamo init. consonants */ @@ -2982,16 +2968,16 @@ internal static int LengthInBufferCells(char c) (c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */ (c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */ (c >= 0xffe0 && c <= 0xffe6)); - // We can ignore these ranges because .Net strings use surrogate pairs - // for this range and we do not handle surrogage pairs. - // (c >= 0x20000 && c <= 0x2fffd) || - // (c >= 0x30000 && c <= 0x3fffd) + // We can ignore these ranges because .Net strings use surrogate pairs + // for this range and we do not handle surrogage pairs. + // (c >= 0x20000 && c <= 0x2fffd) || + // (c >= 0x30000 && c <= 0x3fffd) return 1 + (isWide ? 1 : 0); } -#endregion + #endregion -#region SendInput + #region SendInput internal static void MimicKeyPress(INPUT[] inputs) { @@ -3008,12 +2994,10 @@ internal static void MimicKeyPress(INPUT[] inputs) } } -#endregion SendInput + #endregion SendInput /// - /// /// Class to hold the Native Methods used in this file enclosing class. - /// /// internal static class NativeMethods @@ -3022,7 +3006,7 @@ internal static class NativeMethods internal const int FontTypeMask = 0x06; internal const int TrueTypeFont = 0x04; -#region CreateFile + #region CreateFile [Flags] internal enum AccessQualifiers : uint @@ -3062,14 +3046,14 @@ internal enum CreationDisposition : uint NakedWin32Handle templateFileWin32Handle ); -#endregion CreateFile + #endregion CreateFile -#region Code Page + #region Code Page [DllImport(PinvokeDllNames.GetConsoleOutputCPDllName, SetLastError = false, CharSet = CharSet.Unicode)] internal static extern uint GetConsoleOutputCP(); -#endregion Code Page + #endregion Code Page [DllImport(PinvokeDllNames.GetConsoleWindowDllName, SetLastError = true, CharSet = CharSet.Unicode)] internal static extern HWND GetConsoleWindow(); @@ -3081,9 +3065,11 @@ NakedWin32Handle templateFileWin32Handle internal static extern int ReleaseDC(HWND hwnd, HDC hdc); [DllImport(PinvokeDllNames.FlushConsoleInputBufferDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool FlushConsoleInputBuffer(NakedWin32Handle consoleInput); [DllImport(PinvokeDllNames.FillConsoleOutputAttributeDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool FillConsoleOutputAttribute ( NakedWin32Handle consoleOutput, @@ -3094,61 +3080,88 @@ NakedWin32Handle templateFileWin32Handle ); [DllImport(PinvokeDllNames.FillConsoleOutputCharacterDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool FillConsoleOutputCharacter ( NakedWin32Handle consoleOutput, - Char character, + char character, DWORD length, COORD writeCoord, out DWORD numberOfCharsWritten ); [DllImport(PinvokeDllNames.WriteConsoleDllName, SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern bool WriteConsole + [return: MarshalAs(UnmanagedType.Bool)] + private static extern unsafe bool WriteConsole ( NakedWin32Handle consoleOutput, - string buffer, + char* buffer, DWORD numberOfCharsToWrite, out DWORD numberOfCharsWritten, IntPtr reserved ); + internal static unsafe bool WriteConsole + ( + NakedWin32Handle consoleOutput, + ReadOnlySpan buffer, + DWORD numberOfCharsToWrite, + out DWORD numberOfCharsWritten, + IntPtr reserved + ) + { + fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer)) + { + return WriteConsole(consoleOutput, bufferPtr, numberOfCharsToWrite, out numberOfCharsWritten, reserved); + } + } + [DllImport(PinvokeDllNames.GetConsoleTitleDllName, SetLastError = true, CharSet = CharSet.Unicode)] internal static extern DWORD GetConsoleTitle(StringBuilder consoleTitle, DWORD size); [DllImport(PinvokeDllNames.SetConsoleTitleDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleTitle(string consoleTitle); [DllImport(PinvokeDllNames.GetConsoleModeDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetConsoleMode(NakedWin32Handle consoleHandle, out UInt32 mode); [DllImport(PinvokeDllNames.GetConsoleScreenBufferInfoDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetConsoleScreenBufferInfo(NakedWin32Handle consoleHandle, out CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo); - - internal enum FileType - { - Unknown, - Disk, - Char, - Pipe - }; - [DllImport(PinvokeDllNames.GetLargestConsoleWindowSizeDllName, SetLastError = true, CharSet = CharSet.Unicode)] internal static extern COORD GetLargestConsoleWindowSize(NakedWin32Handle consoleOutput); [DllImport(PinvokeDllNames.ReadConsoleDllName, SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern bool ReadConsole + [return: MarshalAs(UnmanagedType.Bool)] + private static extern unsafe bool ReadConsole ( NakedWin32Handle consoleInput, - StringBuilder buffer, + char* lpBuffer, DWORD numberOfCharsToRead, out DWORD numberOfCharsRead, - // This magical parameter is not documented, but is the secret to tab-completion. ref CONSOLE_READCONSOLE_CONTROL controlData ); + internal static unsafe bool ReadConsole + ( + NakedWin32Handle consoleInput, + Span buffer, + DWORD numberOfCharsToRead, + out DWORD numberOfCharsRead, + ref CONSOLE_READCONSOLE_CONTROL controlData + ) + { + fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer)) + { + return ReadConsole(consoleInput, bufferPtr, numberOfCharsToRead, out numberOfCharsRead, ref controlData); + } + } + [DllImport(PinvokeDllNames.PeekConsoleInputDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool PeekConsoleInput ( NakedWin32Handle consoleInput, @@ -3158,27 +3171,35 @@ internal enum FileType ); [DllImport(PinvokeDllNames.GetNumberOfConsoleInputEventsDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetNumberOfConsoleInputEvents(NakedWin32Handle consoleInput, out DWORD numberOfEvents); [DllImport(PinvokeDllNames.SetConsoleCtrlHandlerDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleCtrlHandler(BreakHandler handlerRoutine, bool add); [DllImport(PinvokeDllNames.SetConsoleCursorPositionDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleCursorPosition(NakedWin32Handle consoleOutput, COORD cursorPosition); [DllImport(PinvokeDllNames.SetConsoleModeDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleMode(NakedWin32Handle consoleHandle, DWORD mode); [DllImport(PinvokeDllNames.SetConsoleScreenBufferSizeDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleScreenBufferSize(NakedWin32Handle consoleOutput, COORD size); [DllImport(PinvokeDllNames.SetConsoleTextAttributeDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleTextAttribute(NakedWin32Handle consoleOutput, WORD attributes); [DllImport(PinvokeDllNames.SetConsoleWindowInfoDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleWindowInfo(NakedWin32Handle consoleHandle, bool absolute, ref SMALL_RECT windowInfo); [DllImport(PinvokeDllNames.WriteConsoleOutputDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool WriteConsoleOutput ( NakedWin32Handle consoleOutput, @@ -3189,6 +3210,7 @@ internal enum FileType ); [DllImport(PinvokeDllNames.ReadConsoleOutputDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool ReadConsoleOutput ( NakedWin32Handle consoleOutput, @@ -3199,6 +3221,7 @@ internal enum FileType ); [DllImport(PinvokeDllNames.ScrollConsoleScreenBufferDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool ScrollConsoleScreenBuffer ( NakedWin32Handle consoleOutput, @@ -3213,15 +3236,19 @@ internal enum FileType // There is no GetCurrentConsoleFontEx on Core [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetCurrentConsoleFontEx(NakedWin32Handle consoleOutput, bool bMaximumWindow, ref CONSOLE_FONT_INFO_EX consoleFontInfo); [DllImport(PinvokeDllNames.GetConsoleCursorInfoDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetConsoleCursorInfo(NakedWin32Handle consoleOutput, out CONSOLE_CURSOR_INFO consoleCursorInfo); [DllImport(PinvokeDllNames.SetConsoleCursorInfoDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleCursorInfo(NakedWin32Handle consoleOutput, ref CONSOLE_CURSOR_INFO consoleCursorInfo); [DllImport(PinvokeDllNames.ReadConsoleInputDllName, SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool ReadConsoleInput ( NakedWin32Handle consoleInput, @@ -3237,38 +3264,8 @@ internal enum CHAR_INFO_Attributes : uint } } - private const string StringsResourceBaseName = "ConsoleControlStrings"; - /*private const string AddBreakHandlerTemplateResource = ConsoleControlStrings.AddBreakHandlerExceptionTemplate; - private const string RemoveBreakHandlerTemplateResource = ConsoleControlStrings.RemoveBreakHandlerExceptionTemplate; - private const string AttachToParentConsoleTemplateResource = ConsoleControlStrings.AttachToParentConsoleExceptionTemplate; - private const string DetachFromConsoleTemplateResource = ConsoleControlStrings.DetachFromConsoleExceptionTemplate; - private const string GetInputHandleTemplateResource = ConsoleControlStrings.GetInputModeExceptionTemplate; - private const string GetActiveScreenBufferHandleTemplateResource = ConsoleControlStrings.GetActiveScreenBufferHandleExceptionTemplate; - private const string GetModeTemplateResource = ConsoleControlStrings.GetModeExceptionTemplate; - private const string SetModeTemplateResource = ConsoleControlStrings.SetModeExceptionTemplate; - private const string ReadConsoleTemplateResource = ConsoleControlStrings.ReadConsoleExceptionTemplate; - private const string ReadConsoleInputTemplateResource = ConsoleControlStrings.ReadConsoleInputExceptionTemplate; - private const string PeekConsoleInputTemplateResource = ConsoleControlStrings.PeekConsoleInputExceptionTemplate; - private const string GetNumberOfConsoleInputEventsTemplateResource = ConsoleControlStrings.GetNumberOfConsoleInputEventsExceptionTemplate; - private const string FlushConsoleInputBufferTemplateResource = ConsoleControlStrings.FlushConsoleInputBufferExceptionTemplate; - private const string GetConsoleScreenBufferInfoTemplateResource = ConsoleControlStrings.GetConsoleScreenBufferInfoExceptionTemplate; - private const string SetConsoleScreenBufferSizeTemplateResource = ConsoleControlStrings.SetConsoleScreenBufferSizeExceptionTemplate; - private const string WriteConsoleOutputTemplateResource = ConsoleControlStrings.WriteConsoleOutputExceptionTemplate; - private const string ReadConsoleOutputTemplateResource = ConsoleControlStrings.ReadConsoleOutputExceptionTemplate; - private const string FillConsoleOutputCharacterTemplateResource = ConsoleControlStrings.FillConsoleOutputCharacterExceptionTemplate; - private const string FillConsoleOutputAttributeTemplateResource = ConsoleControlStrings.FillConsoleOutputAttributeExceptionTemplate; - private const string ScrollConsoleScreenBufferTemplateResource = ConsoleControlStrings.ScrollConsoleScreenBufferExceptionTemplate; - private const string SetConsoleWindowInfoTemplateResource = ConsoleControlStrings.SetConsoleWindowInfoExceptionTemplate; - private const string GetLargestConsoleWindowSizeTemplateResource = ConsoleControlStrings.GetLargestConsoleWindowSizeExceptionTemplate; - private const string SetConsoleWindowTitleTemplateResource = ConsoleControlStrings.SetConsoleWindowTitleExceptionTemplate; - private const string WriteConsoleTemplateResource = ConsoleControlStrings.WriteConsoleExceptionTemplate; - private const string SetConsoleTextAttributeTemplateResource = ConsoleControlStrings.SetConsoleTextAttributeExceptionTemplate; - private const string SetConsoleCursorPositionTemplateResource = ConsoleControlStrings.SetConsoleCursorPositionExceptionTemplate; - private const string GetConsoleCursorInfoTemplateResource = ConsoleControlStrings.GetConsoleCursorInfoExceptionTemplate; - private const string SetConsoleCursorInfoTemplateResource = ConsoleControlStrings.SetConsoleCursorInfoExceptionTemplate;*/ - [TraceSourceAttribute("ConsoleControl", "Console control methods")] private static PSTraceSource tracer = PSTraceSource.GetTracer("ConsoleControl", "Console control methods"); #endif } -} // namespace +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 060fa942b566..3e657818e995 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -1,46 +1,44 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ -#pragma warning disable 1634, 1691 +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#pragma warning disable 1634, 1691 using System; -using System.Diagnostics.CodeAnalysis; -using System.Text; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; -using System.Reflection; using System.Management.Automation; using System.Management.Automation.Host; using System.Management.Automation.Internal; -using System.Management.Automation.Runspaces; +using System.Management.Automation.Language; using System.Management.Automation.Remoting; -using System.Management.Automation.Security; -using System.Threading; +using System.Management.Automation.Runspaces; +using System.Management.Automation.Tracing; +using System.Reflection; +using System.Runtime; using System.Runtime.InteropServices; -using System.Management.Automation.Language; +using System.Text; +using System.Threading; +using Microsoft.PowerShell.Telemetry; +using Microsoft.PowerShell.Commands; -using Dbg = System.Management.Automation.Diagnostics; using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle; -using NakedWin32Handle = System.IntPtr; -using System.Management.Automation.Tracing; +using Dbg = System.Management.Automation.Diagnostics; +using Debugger = System.Management.Automation.Debugger; + #if LEGACYTELEMETRY using Microsoft.PowerShell.Telemetry.Internal; #endif -using Debugger = System.Management.Automation.Debugger; namespace Microsoft.PowerShell { /// - /// /// Subclasses S.M.A.Host to implement a console-mode monad host. - /// /// - /// [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] internal sealed partial class ConsoleHost : @@ -54,33 +52,30 @@ internal sealed partial class ConsoleHost #region static methods internal const int ExitCodeSuccess = 0; - internal const int ExitCodeCtrlBreak = 128+21; // SIGBREAK + internal const int ExitCodeCtrlBreak = 128 + 21; // SIGBREAK internal const int ExitCodeInitFailure = 70; // Internal Software Error internal const int ExitCodeBadCommandLineParameter = 64; // Command Line Usage Error + private const uint SPI_GETSCREENREADER = 0x0046; + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref bool pvParam, uint fWinIni); // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 // Removed HandleUnexpectedExceptions infrastructure /// - /// - /// internal Entry point in msh console host implementation - /// + /// Internal Entry point in msh console host implementation. /// - /// /// /// Banner text to be displayed by ConsoleHost /// - /// /// /// Help text for minishell. This is displayed on 'minishell -?'. /// - /// /// - /// /// Command line parameters to pwsh.exe - /// /// /// - /// /// The exit code for the shell. /// /// NTRAID#Windows OS Bugs-1036968-2005/01/20-sburns The behavior here is related to monitor work. The low word of the @@ -105,7 +100,6 @@ internal sealed partial class ConsoleHost /// /// Anyone checking the exit code of the shell or monitor can mask off the hiword to determine the exit code passed /// by the script that the shell last executed. - /// /// internal static int Start( string bannerText, @@ -135,19 +129,14 @@ internal sealed partial class ConsoleHost try { - string profileDir; -#if UNIX - profileDir = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CACHE); -#else - profileDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + - @"\Microsoft\Windows\PowerShell"; - + string profileDir = Platform.CacheDirectory; +#if ! UNIX if (!Directory.Exists(profileDir)) { Directory.CreateDirectory(profileDir); } #endif - ClrFacade.SetProfileOptimizationRoot(profileDir); + ProfileOptimization.SetProfileRoot(profileDir); } catch { @@ -157,7 +146,7 @@ internal sealed partial class ConsoleHost uint exitCode = ExitCodeSuccess; - System.Threading.Thread.CurrentThread.Name = "ConsoleHost main thread"; + Thread.CurrentThread.Name = "ConsoleHost main thread"; try { @@ -173,18 +162,17 @@ internal sealed partial class ConsoleHost hostException = e; } - if (args == null) - { - args = new string[0]; - } - s_cpp = new CommandLineParameterParser( - (s_theConsoleHost != null) ? s_theConsoleHost.UI : (new NullHostUserInterface()), + (s_theConsoleHost != null) ? s_theConsoleHost.UI : new NullHostUserInterface(), bannerText, helpText); - string[] tempArgs = new string[args.GetLength(0)]; - args.CopyTo(tempArgs, 0); - s_cpp.Parse(tempArgs); + s_cpp.Parse(args); + +#if UNIX + // On Unix, logging has to be deferred until after command-line parsing + // completes to allow overriding logging options. + PSEtwLog.LogConsoleStartup(); +#endif if (s_cpp.ShowVersion) { @@ -203,32 +191,41 @@ internal sealed partial class ConsoleHost { s_theConsoleHost.ui.WriteErrorLine(ConsoleHostStrings.ConflictingServerModeParameters); } + return ExitCodeBadCommandLineParameter; } +#if !UNIX + TaskbarJumpList.CreateRunAsAdministratorJumpList(); +#endif + // First check for and handle PowerShell running in a server mode. if (s_cpp.ServerMode) { - ClrFacade.StartProfileOptimization("StartupProfileData-ServerMode"); + ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("ServerMode"); + ProfileOptimization.StartProfile("StartupProfileData-ServerMode"); System.Management.Automation.Remoting.Server.OutOfProcessMediator.Run(s_cpp.InitialCommand); exitCode = 0; } else if (s_cpp.NamedPipeServerMode) { - ClrFacade.StartProfileOptimization("StartupProfileData-NamedPipeServerMode"); + ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("NamedPipe"); + ProfileOptimization.StartProfile("StartupProfileData-NamedPipeServerMode"); System.Management.Automation.Remoting.RemoteSessionNamedPipeServer.RunServerMode( s_cpp.ConfigurationName); exitCode = 0; } else if (s_cpp.SSHServerMode) { - ClrFacade.StartProfileOptimization("StartupProfileData-SSHServerMode"); + ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SSHServer"); + ProfileOptimization.StartProfile("StartupProfileData-SSHServerMode"); System.Management.Automation.Remoting.Server.SSHProcessMediator.Run(s_cpp.InitialCommand); exitCode = 0; } else if (s_cpp.SocketServerMode) { - ClrFacade.StartProfileOptimization("StartupProfileData-SocketServerMode"); + ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SocketServerMode"); + ProfileOptimization.StartProfile("StartupProfileData-SocketServerMode"); System.Management.Automation.Remoting.Server.HyperVSocketMediator.Run(s_cpp.InitialCommand, s_cpp.ConfigurationName); exitCode = 0; @@ -242,16 +239,17 @@ internal sealed partial class ConsoleHost throw hostException; } + ProfileOptimization.StartProfile( + s_theConsoleHost.LoadPSReadline() + ? "StartupProfileData-Interactive" + : "StartupProfileData-NonInteractive"); + s_theConsoleHost.BindBreakHandler(); PSHost.IsStdOutputRedirected = Console.IsOutputRedirected; // Send startup telemetry for ConsoleHost startup - ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry(); + ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("Normal"); - ClrFacade.StartProfileOptimization( - s_theConsoleHost.LoadPSReadline() - ? "StartupProfileData-Interactive" - : "StartupProfileData-NonInteractive"); exitCode = s_theConsoleHost.Run(s_cpp, false); } } @@ -271,15 +269,12 @@ internal sealed partial class ConsoleHost return (int)exitCode; } } - private static CommandLineParameterParser s_cpp; - + private static CommandLineParameterParser s_cpp; #if UNIX /// - /// /// The break handler for the program. Dispatches a break event to the current Executor. - /// /// private static void MyBreakHandler(object sender, ConsoleCancelEventArgs args) { @@ -293,7 +288,7 @@ private static void MyBreakHandler(object sender, ConsoleCancelEventArgs args) case ConsoleSpecialKey.ControlBreak: if (s_cpp.NonInteractive) { - //ControlBreak mimics ControlC in Noninteractive shells + // ControlBreak mimics ControlC in Noninteractive shells SpinUpBreakHandlerThread(shouldEndSession: true); } else @@ -301,14 +296,13 @@ private static void MyBreakHandler(object sender, ConsoleCancelEventArgs args) // Break into script debugger. BreakIntoDebugger(); } + return; } } #else /// - /// /// The break handler for the program. Dispatches a break event to the current Executor. - /// /// /// /// @@ -319,7 +313,7 @@ private static bool MyBreakHandler(ConsoleControl.ConsoleBreakSignal signal) case ConsoleControl.ConsoleBreakSignal.CtrlBreak: if (s_cpp.NonInteractive) { - //ControlBreak mimics ControlC in Noninteractive shells + // ControlBreak mimics ControlC in Noninteractive shells SpinUpBreakHandlerThread(shouldEndSession: true); } else @@ -327,6 +321,7 @@ private static bool MyBreakHandler(ConsoleControl.ConsoleBreakSignal signal) // Break into script debugger. BreakIntoDebugger(); } + return true; // Run the break handler... @@ -366,6 +361,7 @@ private static bool BreakIntoDebugger() debugger = host._runspaceRef.Runspace.Debugger; } } + if (debugger != null) { debugger.SetDebuggerStepMode(true); @@ -376,15 +372,12 @@ private static bool BreakIntoDebugger() } /// - /// /// Spin up a new thread to cancel the current pipeline. This will allow subsequent break interrupts to be received even /// if the cancellation is blocked (which can be the case when the pipeline blocks and nothing implements Cmdlet.Stop /// properly). That is because the OS will not inject another thread when a break event occurs if one has already been /// injected and is running. - /// /// /// - /// /// if true, then flag the parent ConsoleHost that it should shutdown the session. If false, then only the current /// executing instance is stopped. /// @@ -517,9 +510,7 @@ internal static ConsoleHost SingletonInstance #region overrides /// - /// - /// See base class - /// + /// See base class. /// /// /// @@ -536,9 +527,7 @@ public override string Name } /// - /// - /// See base class - /// + /// See base class. /// /// /// @@ -553,9 +542,7 @@ public override System.Version Version } /// - /// - /// See base class - /// + /// See base class. /// /// /// @@ -563,9 +550,7 @@ public override System.Version Version public override System.Guid InstanceId { get; } = Guid.NewGuid(); /// - /// - /// See base class - /// + /// See base class. /// /// /// @@ -584,6 +569,7 @@ public override PSHostUserInterface UI public void PushRunspace(Runspace newRunspace) { if (_runspaceRef == null) { return; } + RemoteRunspace remoteRunspace = newRunspace as RemoteRunspace; Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null"); remoteRunspace.StateChanged += new EventHandler(HandleRemoteRunspaceStateChanged); @@ -601,7 +587,7 @@ public void PushRunspace(Runspace newRunspace) } // Connect a disconnected command. - this.runningCmd = Microsoft.PowerShell.Commands.EnterPSSessionCommand.ConnectRunningPipeline(remoteRunspace); + this.runningCmd = EnterPSSessionCommand.ConnectRunningPipeline(remoteRunspace); // Push runspace. _runspaceRef.Override(remoteRunspace, hostGlobalLock, out _isRunspacePushed); @@ -609,7 +595,7 @@ public void PushRunspace(Runspace newRunspace) if (this.runningCmd != null) { - Microsoft.PowerShell.Commands.EnterPSSessionCommand.ContinueCommand( + EnterPSSessionCommand.ContinueCommand( remoteRunspace, this.runningCmd, this, @@ -623,10 +609,10 @@ public void PushRunspace(Runspace newRunspace) /// /// Handles state changed event of the remote runspace. If the remote runspace /// gets into a broken or closed state, writes a message and pops out the - /// runspace + /// runspace. /// - /// not sure - /// arguments describing this event + /// Not sure. + /// Arguments describing this event. private void HandleRemoteRunspaceStateChanged(object sender, RunspaceStateEventArgs eventArgs) { RunspaceState state = eventArgs.RunspaceStateInfo.State; @@ -645,6 +631,7 @@ private void HandleRemoteRunspaceStateChanged(object sender, RunspaceStateEventA { PopRunspace(); } + break; } } @@ -704,6 +691,7 @@ public bool IsRunspacePushed return _isRunspacePushed; } } + private bool _isRunspacePushed = false; /// @@ -714,6 +702,7 @@ public Runspace Runspace get { if (this.RunspaceRef == null) { return null; } + return this.RunspaceRef.Runspace; } } @@ -726,7 +715,9 @@ internal LocalRunspace LocalRunspace { return RunspaceRef.OldRunspace as LocalRunspace; } + if (RunspaceRef == null) { return null; } + return RunspaceRef.Runspace as LocalRunspace; } } @@ -746,6 +737,7 @@ public ConsoleColor ErrorForegroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.ErrorForegroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.ErrorForegroundColor = value; } @@ -756,6 +748,7 @@ public ConsoleColor ErrorBackgroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.ErrorBackgroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.ErrorBackgroundColor = value; } @@ -766,6 +759,7 @@ public ConsoleColor WarningForegroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.WarningForegroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.WarningForegroundColor = value; } @@ -776,6 +770,7 @@ public ConsoleColor WarningBackgroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.WarningBackgroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.WarningBackgroundColor = value; } @@ -786,6 +781,7 @@ public ConsoleColor DebugForegroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.DebugForegroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.DebugForegroundColor = value; } @@ -796,6 +792,7 @@ public ConsoleColor DebugBackgroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.DebugBackgroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.DebugBackgroundColor = value; } @@ -806,6 +803,7 @@ public ConsoleColor VerboseForegroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.VerboseForegroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.VerboseForegroundColor = value; } @@ -816,6 +814,7 @@ public ConsoleColor VerboseBackgroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.VerboseBackgroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.VerboseBackgroundColor = value; } @@ -826,6 +825,7 @@ public ConsoleColor ProgressForegroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.ProgressForegroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.ProgressForegroundColor = value; } @@ -836,6 +836,7 @@ public ConsoleColor ProgressBackgroundColor [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] get { return _ui.ProgressBackgroundColor; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] set { _ui.ProgressBackgroundColor = value; } @@ -854,18 +855,14 @@ public override PSObject PrivateData return _consoleColorProxy ?? (_consoleColorProxy = PSObject.AsPSObject(new ConsoleColorProxy(ui))); } } - private PSObject _consoleColorProxy; - + private PSObject _consoleColorProxy; /// - /// - /// See base class - /// + /// See base class. /// /// /// - public override System.Globalization.CultureInfo CurrentCulture { get @@ -877,16 +874,11 @@ public override System.Globalization.CultureInfo CurrentCulture } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - public override System.Globalization.CultureInfo CurrentUICulture { get @@ -899,10 +891,8 @@ public override System.Globalization.CultureInfo CurrentUICulture } /// - /// /// /// - public override void SetShouldExit(int exitCode) { lock (hostGlobalLock) @@ -926,15 +916,11 @@ public override void SetShouldExit(int exitCode) } /// - /// /// If an input loop is running, then starts a new, nested input loop. If an input loop is not running, /// throws an exception. - /// /// /// - /// /// If a nested prompt is entered while the host is not running at least one prompt loop. - /// /// public override void EnterNestedPrompt() { @@ -952,6 +938,7 @@ public override void EnterNestedPrompt() { IsNested = oldCurrent != null || this.ui.IsCommandCompletionRunning; } + InputLoop.RunNewInputLoop(this, IsNested); } finally @@ -961,14 +948,10 @@ public override void EnterNestedPrompt() } /// - /// - /// See base class - /// + /// See base class. /// /// - /// /// If there is no nested prompt. - /// /// public override void ExitNestedPrompt() { @@ -979,9 +962,7 @@ public override void ExitNestedPrompt() } /// - /// - /// See base class - /// + /// See base class. /// public override void NotifyBeginApplication() { @@ -1006,9 +987,7 @@ public override void NotifyBeginApplication() } /// - /// /// See base class - /// /// /// public override void NotifyEndApplication() @@ -1041,23 +1020,25 @@ bool IHostProvidesTelemetryData.HostIsInteractive ((s_cpp.InitialCommand == null && s_cpp.File == null) || s_cpp.NoExit); } } + double IHostProvidesTelemetryData.ProfileLoadTimeInMS { get { return _profileLoadTimeInMS; } } + double IHostProvidesTelemetryData.ReadyForInputTimeInMS { get { return _readyForInputTimeInMS; } } + int IHostProvidesTelemetryData.InteractiveCommandCount { get { return _interactiveCommandCount; } } -#endif - private double _profileLoadTimeInMS; private double _readyForInputTimeInMS; private int _interactiveCommandCount; +#endif + + private double _profileLoadTimeInMS; #endregion overrides #region non-overrides /// - /// - /// Constructs a new instance - /// + /// Constructs a new instance. /// internal ConsoleHost() { @@ -1127,9 +1108,7 @@ private void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArg } /// - /// - /// Finalizes the instance - /// + /// Finalizes the instance. /// ~ConsoleHost() { @@ -1137,9 +1116,7 @@ private void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArg } /// - /// - /// Disposes of this instance, per the IDisposable pattern - /// + /// Disposes of this instance, per the IDisposable pattern. /// public void Dispose() { @@ -1166,14 +1143,17 @@ private void Dispose(bool isDisposingNotFinalizing) { StopTranscribing(); } + if (_outputSerializer != null) { _outputSerializer.End(); } + if (_errorSerializer != null) { _errorSerializer.End(); } + if (_runspaceRef != null) { // NTRAID#Windows Out Of Band Releases-925297-2005/12/14 @@ -1185,6 +1165,7 @@ private void Dispose(bool isDisposingNotFinalizing) { } } + _runspaceRef = null; ui = null; } @@ -1194,16 +1175,12 @@ private void Dispose(bool isDisposingNotFinalizing) } /// - /// /// Indicates if the session should be terminated or not. Typically set by the break handler for Close, Logoff, and /// Shutdown events. Note that the only valid transition for this property is from false to true: it is not legal to /// try to set it to false after is was set to true. - /// /// /// - /// /// true to shut down the session. false is only allowed if the property is already false. - /// /// internal bool ShouldEndSession { @@ -1219,6 +1196,7 @@ internal bool ShouldEndSession return result; } + set { lock (hostGlobalLock) @@ -1234,9 +1212,7 @@ internal bool ShouldEndSession } /// - /// /// The Runspace ref object being used by this Host instance. A host only opens one Runspace. - /// /// /// internal RunspaceRef RunspaceRef @@ -1249,6 +1225,7 @@ internal RunspaceRef RunspaceRef internal WrappedSerializer.DataFormat OutputFormat { get; private set; } + internal bool OutputFormatSpecified { get; private set; } internal WrappedSerializer.DataFormat InputFormat { get; private set; } @@ -1258,12 +1235,13 @@ internal WrappedDeserializer.DataFormat ErrorFormat { WrappedDeserializer.DataFormat format = OutputFormat; - //If this shell is invoked in minishell interop mode and error is redirected, - //always write data in error stream in xml format. - if (IsInteractive == false && Console.IsErrorRedirected && _wasInitialCommandEncoded) + // If this shell is invoked in non-interactive, error is redirected, and OutputFormat was not + // specified write data in error stream in xml format assuming PowerShell->PowerShell usage. + if (!OutputFormatSpecified && IsInteractive == false && Console.IsErrorRedirected && _wasInitialCommandEncoded) { format = Serialization.DataFormat.XML; } + return format; } } @@ -1290,6 +1268,7 @@ internal WrappedSerializer OutputSerializer "Output", Console.IsOutputRedirected ? Console.Out : ConsoleTextWriter); } + return _outputSerializer; } } @@ -1306,6 +1285,7 @@ internal WrappedSerializer ErrorSerializer "Error", Console.IsErrorRedirected ? Console.Error : ConsoleTextWriter); } + return _errorSerializer; } } @@ -1330,29 +1310,21 @@ internal TextWriter ConsoleTextWriter } /// - /// /// The main run loop of the program: processes command line parameters, and starts up a runspace. - /// /// - /// /// /// Commandline parameter parser. The commandline parameter parser is expected to parse all the /// arguments before calling this method. /// - /// /// /// Is there any warning at startup /// - /// /// - /// /// The process exit code to be returned by Main. - /// /// - private uint Run(CommandLineParameterParser cpp, bool isPrestartWarned) { - Dbg.Assert(null != cpp, "CommandLine parameter parser cannot be null."); + Dbg.Assert(cpp != null, "CommandLine parameter parser cannot be null."); uint exitCode = ExitCodeSuccess; do @@ -1377,6 +1349,7 @@ private uint Run(CommandLineParameterParser cpp, bool isPrestartWarned) } OutputFormat = cpp.OutputFormat; + OutputFormatSpecified = cpp.OutputFormatSpecified; InputFormat = cpp.InputFormat; _wasInitialCommandEncoded = cpp.WasInitialCommandEncoded; @@ -1388,20 +1361,22 @@ private uint Run(CommandLineParameterParser cpp, bool isPrestartWarned) #if !UNIX // See if we need to change the process-wide execution // policy - if (!String.IsNullOrEmpty(cpp.ExecutionPolicy)) + if (!string.IsNullOrEmpty(cpp.ExecutionPolicy)) { ExecutionPolicy executionPolicy = SecuritySupport.ParseExecutionPolicy(cpp.ExecutionPolicy); SecuritySupport.SetExecutionPolicy(ExecutionPolicyScope.Process, executionPolicy, null); } #endif + // If the debug pipe name was specified, create the custom IPC channel. + if (!string.IsNullOrEmpty(cpp.CustomPipeName)) + { + RemoteSessionNamedPipeServer.CreateCustomNamedPipeServer(cpp.CustomPipeName); + } + // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 // Removed HandleUnexpectedExceptions infrastructure -#if STAMODE exitCode = DoRunspaceLoop(cpp.InitialCommand, cpp.SkipProfiles, cpp.Args, cpp.StaMode, cpp.ConfigurationName); -#else - exitCode = DoRunspaceLoop(cpp.InitialCommand, cpp.SkipProfiles, cpp.Args, false, cpp.ConfigurationName); -#endif } while (false); @@ -1409,31 +1384,10 @@ private uint Run(CommandLineParameterParser cpp, bool isPrestartWarned) } /// - /// This method is retained to make V1 tests compatible with V2 as signature of this method - /// is slightly changed in v2. - /// - /// - /// - /// - /// - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private uint Run(string bannerText, string helpText, bool isPrestartWarned, string[] args) - { - s_cpp = new CommandLineParameterParser(this.UI, bannerText, helpText); - s_cpp.Parse(args); - return Run(s_cpp, isPrestartWarned); - } - - /// - /// /// Loops over the Host's sole Runspace; opens the runspace, initializes it, then recycles it if the Runspace fails. - /// /// /// - /// /// The process exit code to be returned by Main. - /// /// private uint DoRunspaceLoop(string initialCommand, bool skipProfiles, Collection initialCommandArgs, bool staMode, string configurationName) { @@ -1480,12 +1434,12 @@ private uint DoRunspaceLoop(string initialCommand, bool skipProfiles, Collection _runspaceRef.Runspace.Close(); _runspaceRef = null; -#if STAMODE - if (staMode) // don't recycle the Runspace in STA mode + + if (staMode) { + // don't continue the session in STA mode ShouldEndSession = true; } -#endif } return ExitCode; @@ -1493,7 +1447,7 @@ private uint DoRunspaceLoop(string initialCommand, bool skipProfiles, Collection private Exception InitializeRunspaceHelper(string command, Executor exec, Executor.ExecutionOptions options) { - Dbg.Assert(!String.IsNullOrEmpty(command), "command should have a value"); + Dbg.Assert(!string.IsNullOrEmpty(command), "command should have a value"); Dbg.Assert(exec != null, "non-null Executor instance needed"); s_runspaceInitTracer.WriteLine("running command {0}", command); @@ -1508,6 +1462,7 @@ private Exception InitializeRunspaceHelper(string command, Executor exec, Execut { exec.ExecuteCommand(command, out e, options); } + if (e != null) { ReportException(e, exec); @@ -1523,11 +1478,7 @@ private void CreateRunspace(object runspaceCreationArgs) { args = runspaceCreationArgs as RunspaceCreationEventArgs; Dbg.Assert(args != null, "Event Arguments to CreateRunspace should not be null"); -#if STAMODE DoCreateRunspace(args.InitialCommand, args.SkipProfiles, args.StaMode, args.ConfigurationName, args.InitialCommandArgs); -#else - DoCreateRunspace(args.InitialCommand, args.SkipProfiles, false, args.ConfigurationName, args.InitialCommandArgs); -#endif } catch (ConsoleHostStartupException startupException) { @@ -1537,12 +1488,32 @@ private void CreateRunspace(object runspaceCreationArgs) } /// - /// This method is here only to make V1 tests compatible with V2. DO NOT USE THIS FUNCTION! Use DoCreateRunspace instead + /// Check if a screen reviewer utility is running. + /// When a screen reader is running, we don't auto-load the PSReadLine module at startup, + /// since PSReadLine is not accessibility-firendly enough as of today. /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private void InitializeRunspace(string initialCommand, bool skipProfiles, Collection initialCommandArgs) + private bool IsScreenReaderActive() { - DoCreateRunspace(initialCommand, skipProfiles, staMode: false, configurationName: null, initialCommandArgs: initialCommandArgs); + if (_screenReaderActive.HasValue) + { + return _screenReaderActive.Value; + } + + _screenReaderActive = false; + if (Platform.IsWindowsDesktop) + { + // Note: this API can detect if a third-party screen reader is active, such as NVDA, but not the in-box Windows Narrator. + // Quoted from https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa about the + // accessibility parameter 'SPI_GETSCREENREADER': + // "Narrator, the screen reader that is included with Windows, does not set the SPI_SETSCREENREADER or SPI_GETSCREENREADER flags." + bool enabled = false; + if (SystemParametersInfo(SPI_GETSCREENREADER, 0, ref enabled, 0)) + { + _screenReaderActive = enabled; + } + } + + return _screenReaderActive.Value; } private bool LoadPSReadline() @@ -1559,10 +1530,8 @@ private bool LoadPSReadline() } /// - /// /// Opens and Initializes the Host's sole Runspace. Processes the startup scripts and runs any command passed on the /// command line. - /// /// private void DoCreateRunspace(string initialCommand, bool skipProfiles, bool staMode, string configurationName, Collection initialCommandArgs) @@ -1577,6 +1546,7 @@ private void DoCreateRunspace(string initialCommand, bool skipProfiles, bool sta bool psReadlineFailed = false; // Load PSReadline by default unless there is no use: + // - screen reader is active, such as NVDA, indicating non-visual access // - we're running a command/file and just exiting // - stdin is redirected by a parent process // - we're not interactive @@ -1584,21 +1554,29 @@ private void DoCreateRunspace(string initialCommand, bool skipProfiles, bool sta // It's also important to have a scenario where PSReadline is not loaded so it can be updated, e.g. // powershell -command "Update-Module PSReadline" // This should work just fine as long as no other instances of PowerShell are running. - ReadOnlyCollection defaultImportModulesList = null; + ReadOnlyCollection defaultImportModulesList = null; if (LoadPSReadline()) { - // Create and open Runspace with PSReadline. - defaultImportModulesList = DefaultInitialSessionState.Modules; - DefaultInitialSessionState.ImportPSModule(new[] { "PSReadLine" }); - consoleRunspace = RunspaceFactory.CreateRunspace(this, DefaultInitialSessionState); - try + if (IsScreenReaderActive()) { - OpenConsoleRunspace(consoleRunspace, staMode); + s_theConsoleHost.UI.WriteLine(ManagedEntranceStrings.PSReadLineDisabledWhenScreenReaderIsActive); + s_theConsoleHost.UI.WriteLine(); } - catch (Exception) + else { - consoleRunspace = null; - psReadlineFailed = true; + // Create and open Runspace with PSReadline. + defaultImportModulesList = DefaultInitialSessionState.Modules; + DefaultInitialSessionState.ImportPSModule(new[] { "PSReadLine" }); + consoleRunspace = RunspaceFactory.CreateRunspace(this, DefaultInitialSessionState); + try + { + OpenConsoleRunspace(consoleRunspace, staMode); + } + catch (Exception) + { + consoleRunspace = null; + psReadlineFailed = true; + } } } @@ -1610,10 +1588,12 @@ private void DoCreateRunspace(string initialCommand, bool skipProfiles, bool sta DefaultInitialSessionState.ClearPSModules(); DefaultInitialSessionState.ImportPSModule(defaultImportModulesList); } + consoleRunspace = RunspaceFactory.CreateRunspace(this, DefaultInitialSessionState); OpenConsoleRunspace(consoleRunspace, staMode); } + Runspace.PrimaryRunspace = consoleRunspace; _runspaceRef = new RunspaceRef(consoleRunspace); if (psReadlineFailed) @@ -1637,31 +1617,25 @@ private void DoCreateRunspace(string initialCommand, bool skipProfiles, bool sta PSTask.PowershellConsoleStartup, PSKeyword.UseAlwaysOperational); } +#if LEGACYTELEMETRY // Record how long it took from process start to runspace open for telemetry. _readyForInputTimeInMS = (DateTime.Now - Process.GetCurrentProcess().StartTime).TotalMilliseconds; +#endif DoRunspaceInitialization(skipProfiles, initialCommand, configurationName, initialCommandArgs); } private void OpenConsoleRunspace(Runspace runspace, bool staMode) { -#if STAMODE - // staMode will have following values: - // On FullPS: 'true'/'false' = default('true'=STA) + possibility of overload through cmdline parameter '-mta' - // On NanoPS: always 'false' = default('false'=MTA) + NO possibility of overload through cmdline parameter '-mta' - // ThreadOptions should match on FullPS and NanoPS for corresponding ApartmentStates. - if (staMode) + if (staMode && Platform.IsWindowsDesktop) { - // we can't change ApartmentStates on CoreCLR runspace.ApartmentState = ApartmentState.STA; } -#endif + runspace.ThreadOptions = PSThreadOptions.ReuseThread; runspace.EngineActivityId = EtwActivity.GetActivityId(); - Runspace.PrimaryRunspace = runspace; s_runspaceInitTracer.WriteLine("Calling Runspace.Open"); - runspace.Open(); } @@ -1675,6 +1649,31 @@ private void DoRunspaceInitialization(bool skipProfiles, string initialCommand, Executor exec = new Executor(this, false, false); + // If working directory was specified, set it + if (s_cpp != null && s_cpp.WorkingDirectory != null) + { + Pipeline tempPipeline = exec.CreatePipeline(); + var command = new Command("Set-Location"); + command.Parameters.Add("LiteralPath", s_cpp.WorkingDirectory); + tempPipeline.Commands.Add(command); + + Exception exception; + if (IsRunningAsync) + { + exec.ExecuteCommandAsyncHelper(tempPipeline, out exception, Executor.ExecutionOptions.AddOutputter); + } + else + { + exec.ExecuteCommandHelper(tempPipeline, out exception, Executor.ExecutionOptions.AddOutputter); + } + + if (exception != null) + { + _lastRunspaceInitializationException = exception; + ReportException(exception, exec); + } + } + if (!string.IsNullOrEmpty(configurationName)) { // If an endpoint configuration is specified then create a loop-back remote runspace targeting @@ -1699,10 +1698,7 @@ private void DoRunspaceInitialization(bool skipProfiles, string initialCommand, // If the system lockdown policy says "Enforce", do so. Do this after types / formatting, default functions, etc // are loaded so that they are trusted. (Validation of their signatures is done in F&O) - if (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Enforce) - { - _runspaceRef.Runspace.ExecutionContext.LanguageMode = PSLanguageMode.ConstrainedLanguage; - } + Utils.EnforceSystemLockDownLanguageMode(_runspaceRef.Runspace.ExecutionContext); string allUsersProfile = HostUtilities.GetFullProfileFileName(null, false); string allUsersHostSpecificProfile = HostUtilities.GetFullProfileFileName(shellId, false); @@ -1774,6 +1770,7 @@ private void DoRunspaceInitialization(bool skipProfiles, string initialCommand, { c = new Command(filePath, false, false); } + tempPipeline.Commands.Add(c); if (initialCommandArgs != null) @@ -1837,7 +1834,7 @@ private void DoRunspaceInitialization(bool skipProfiles, string initialCommand, ReportException(e1, exec); } } - else if (!String.IsNullOrEmpty(initialCommand)) + else if (!string.IsNullOrEmpty(initialCommand)) { // Run the command passed on the command line @@ -1892,7 +1889,7 @@ private void DoRunspaceInitialization(bool skipProfiles, string initialCommand, private void RunProfile(string profileFileName, Executor exec) { - if (!String.IsNullOrEmpty(profileFileName)) + if (!string.IsNullOrEmpty(profileFileName)) { s_runspaceInitTracer.WriteLine("checking profile" + profileFileName); @@ -1919,11 +1916,8 @@ private void RunProfile(string profileFileName, Executor exec) } } - /// - /// - /// Escapes backtick and tick characters with a backtick, returns the result - /// + /// Escapes backtick and tick characters with a backtick, returns the result. /// /// /// @@ -1940,6 +1934,7 @@ internal static string EscapeSingleQuotes(string str) { sb.Append(c); } + sb.Append(c); } @@ -1985,9 +1980,10 @@ private void ReportException(Exception e, Executor exec) error = (object)new ErrorRecord(e, "ConsoleHost.ReportException", ErrorCategory.NotSpecified, null); } - PSObject wrappedError = new PSObject(error); - PSNoteProperty note = new PSNoteProperty("writeErrorStream", true); - wrappedError.Properties.Add(note); + PSObject wrappedError = new PSObject(error) + { + WriteStream = WriteStreamType.Error + }; Exception e1 = null; @@ -2010,19 +2006,13 @@ private void ReportException(Exception e, Executor exec) } /// - /// /// Reports an exception according to the exception reporting settings in effect. - /// /// /// - /// /// The exception to report. - /// /// /// - /// /// Optional header message. Empty or null means "no header" - /// /// private void ReportExceptionFallback(Exception e, string header) { @@ -2062,22 +2052,21 @@ private void ReportExceptionFallback(Exception e, string header) } /// - /// raised when the host pops a runspace + /// Raised when the host pops a runspace. /// internal event EventHandler RunspacePopped; /// - /// raised when the host pushes a runspace + /// Raised when the host pushes a runspace. /// internal event EventHandler RunspacePushed; - #endregion non-overrides #region debugger /// - /// Handler for debugger events + /// Handler for debugger events. /// private void OnExecutionSuspended(object sender, DebuggerStopEventArgs e) { @@ -2107,7 +2096,7 @@ private void OnExecutionSuspended(object sender, DebuggerStopEventArgs e) if (_displayDebuggerBanner) { WriteDebuggerMessage(ConsoleHostStrings.EnteringDebugger); - WriteDebuggerMessage(""); + WriteDebuggerMessage(string.Empty); _displayDebuggerBanner = false; } @@ -2120,10 +2109,10 @@ private void OnExecutionSuspended(object sender, DebuggerStopEventArgs e) foreach (Breakpoint breakpoint in e.Breakpoints) { - WriteDebuggerMessage(String.Format(CultureInfo.CurrentCulture, format, breakpoint)); + WriteDebuggerMessage(string.Format(CultureInfo.CurrentCulture, format, breakpoint)); } - WriteDebuggerMessage(""); + WriteDebuggerMessage(string.Empty); } // @@ -2151,7 +2140,7 @@ private void OnExecutionSuspended(object sender, DebuggerStopEventArgs e) } /// - /// Returns true if the host is in debug mode + /// Returns true if the host is in debug mode. /// private bool InDebugMode { get; set; } @@ -2219,7 +2208,7 @@ private void ExitDebugMode(DebuggerResumeAction resumeAction) } /// - /// Writes a line using the debugger colors + /// Writes a line using the debugger colors. /// private void WriteDebuggerMessage(string line) { @@ -2231,13 +2220,11 @@ private void WriteDebuggerMessage(string line) #region aux classes /// - /// /// InputLoop represents the prompt-input-execute loop of the interactive host. Input loops can be nested, meaning that /// one input loop can be interrupted and another started; when the second ends, the first resumes. /// /// Neither this class' instances nor its static data is threadsafe. Caller is responsible for ensuring threadsafe /// access. - /// /// private class InputLoop { @@ -2267,13 +2254,10 @@ internal static void RunNewInputLoop(ConsoleHost parent, bool isNested) // Presently, this will not work if the Run loop is blocked on a ReadLine call. Whether that's a // problem or not depends on when we expect calls to this function to be made. /// - /// /// /// True if next input loop is nested, False otherwise. /// - /// /// when there is no instanceStack.Count == 0 - /// /// internal static bool ExitCurrentLoop() @@ -2331,10 +2315,10 @@ private void HandleRunspacePushed(object sender, EventArgs e) /// /// When a runspace is popped, we need to reevaluate the - /// prompt + /// prompt. /// - /// sender of this event, unused - /// arguments describing this event, unused + /// Sender of this event, unused. + /// Arguments describing this event, unused. private void HandleRunspacePopped(object sender, EventArgs eventArgs) { lock (_syncObject) @@ -2347,10 +2331,8 @@ private void HandleRunspacePopped(object sender, EventArgs eventArgs) // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 // Removed HandleUnexpectedExceptions infrastructure /// - /// /// Evaluates the prompt, displays it, gets a command from the console, and executes it. Repeats until the command /// is "exit", or until the shutdown flag is set. - /// /// internal void Run(bool inputLoopIsNested) { @@ -2398,13 +2380,16 @@ internal void Run(bool inputLoopIsNested) { prompt = EvaluateDebugPrompt(); } + if (prompt == null) { prompt = EvaluatePrompt(); } } + ui.Write(prompt); } + previousResponseWasEmpty = false; // There could be a profile. So there could be a user defined custom readline command line = ui.ReadLineWithTabCompletion(_exec); @@ -2423,6 +2408,7 @@ internal void Run(bool inputLoopIsNested) // the output... ui.WriteLine(); } + inBlockMode = false; if (Console.IsInputRedirected) @@ -2470,7 +2456,7 @@ internal void Run(bool inputLoopIsNested) if (_parent.InDebugMode) { - DebuggerCommandResults results = ProcessDebugCommand(line.Trim(), out e); + DebuggerCommandResults results = ProcessDebugCommand(line, out e); if (results.ResumeAction != null) { @@ -2548,8 +2534,10 @@ internal void Run(bool inputLoopIsNested) } } +#if LEGACYTELEMETRY if (!inBlockMode) s_theConsoleHost._interactiveCommandCount += 1; +#endif } } // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 @@ -2558,7 +2546,7 @@ internal void Run(bool inputLoopIsNested) { _parent._isRunningPromptLoop = false; } - } // end while + } } internal void BlockCommandOutput() @@ -2720,7 +2708,7 @@ private string EvaluatePrompt() Exception unused = null; string promptString = _promptExec.ExecuteCommandAndGetResultAsString("prompt", out unused); - if (String.IsNullOrEmpty(promptString)) + if (string.IsNullOrEmpty(promptString)) { promptString = ConsoleHostStrings.DefaultPrompt; } @@ -2846,19 +2834,20 @@ private class ConsoleHostStartupException : Exception private ConsoleControl.ConsoleModes _savedConsoleMode = ConsoleControl.ConsoleModes.Unknown; private ConsoleControl.ConsoleModes _initialConsoleMode = ConsoleControl.ConsoleModes.Unknown; #endif - private System.Threading.Thread _breakHandlerThread; + private Thread _breakHandlerThread; private bool _isDisposed; internal ConsoleHostUserInterface ui; internal Lazy ConsoleIn { get; } = new Lazy(() => Console.In); - private string _savedWindowTitle = ""; + private string _savedWindowTitle = string.Empty; private Version _ver = PSVersionInfo.PSVersion; private int _exitCodeFromRunspace; private bool _noExit = true; private bool _setShouldExitCalled; private bool _isRunningPromptLoop; private bool _wasInitialCommandEncoded; + private bool? _screenReaderActive; // hostGlobalLock is used to sync public method calls (in case multiple threads call into the host) and access to // state that persists across method calls, like progress data. It's internal because the ui object also @@ -2885,11 +2874,8 @@ private class ConsoleHostStartupException : Exception private static ConsoleHost s_theConsoleHost; - internal static InitialSessionState DefaultInitialSessionState; - - [TraceSource("ConsoleHost", "ConsoleHost subclass of S.M.A.PSHost")] private static PSTraceSource s_tracer = PSTraceSource.GetTracer("ConsoleHost", "ConsoleHost subclass of S.M.A.PSHost"); @@ -2897,44 +2883,35 @@ private static [TraceSource("ConsoleHostRunspaceInit", "Initialization code for ConsoleHost's Runspace")] private static PSTraceSource s_runspaceInitTracer = PSTraceSource.GetTracer("ConsoleHostRunspaceInit", "Initialization code for ConsoleHost's Runspace", false); - } // ConsoleHost + } /// - /// Defines arguments passed to ConsoleHost.CreateRunspace + /// Defines arguments passed to ConsoleHost.CreateRunspace. /// internal sealed class RunspaceCreationEventArgs : EventArgs { /// - /// Constructs RunspaceCreationEventArgs + /// Constructs RunspaceCreationEventArgs. /// - /// - /// - /// - /// - /// - internal RunspaceCreationEventArgs(string initialCommand, - bool skipProfiles, - bool staMode, - string configurationName, - Collection initialCommandArgs) + internal RunspaceCreationEventArgs( + string initialCommand, + bool skipProfiles, + bool staMode, + string configurationName, + Collection initialCommandArgs) { InitialCommand = initialCommand; SkipProfiles = skipProfiles; -#if STAMODE StaMode = staMode; -#endif ConfigurationName = configurationName; InitialCommandArgs = initialCommandArgs; } internal string InitialCommand { get; set; } internal bool SkipProfiles { get; set; } -#if STAMODE internal bool StaMode { get; set; } -#endif internal string ConfigurationName { get; set; } internal Collection InitialCommandArgs { get; set; } } } // namespace - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs index af6f660c6281..af9d754861c8 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs @@ -1,9 +1,7 @@ -#if !UNIX -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#if !UNIX using System; using System.Management.Automation; @@ -19,26 +17,19 @@ using WORD = System.UInt16; using DWORD = System.UInt32; - - namespace Microsoft.PowerShell { /// - /// - /// implementation of RawConsole for powershell - /// + /// Implementation of RawConsole for powershell. /// internal sealed class ConsoleHostRawUserInterface : System.Management.Automation.Host.PSHostRawUserInterface { /// - /// /// /// - /// /// If obtaining the buffer's foreground and background color failed - /// /// internal @@ -76,22 +67,16 @@ class ConsoleHostRawUserInterface : System.Management.Automation.Host.PSHostRawU } /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If set to an invalid ConsoleColor - /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleTextAttribute - /// /// public override @@ -109,6 +94,7 @@ public override ConsoleControl.WORDToColor(bufferInfo.Attributes, out foreground, out unused); return foreground; } + set { if (ConsoleControl.IsConsoleColor(value)) @@ -131,25 +117,17 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If set to an invalid ConsoleColor - /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleTextAttribute - /// /// public override @@ -167,6 +145,7 @@ public override ConsoleControl.WORDToColor(bufferInfo.Attributes, out unused, out background); return background; } + set { if (ConsoleControl.IsConsoleColor(value)) @@ -189,25 +168,17 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If set to outside of the buffer - /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleCursorPosition failed - /// /// public override Coordinates @@ -221,6 +192,7 @@ public override Coordinates c = new Coordinates(bufferInfo.CursorPosition.X, bufferInfo.CursorPosition.Y); return c; } + set { // cursor position can't be outside the buffer area @@ -234,31 +206,21 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// - /// /// Cursor size - /// /// /// - /// /// If set to under 0 or over 100 - /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// Win32's GetConsoleCursorInfo failed /// OR /// Win32's SetConsoleCursorInfo failed - /// /// public override @@ -272,6 +234,7 @@ public override return size; } + set { const int MinCursorSize = 0; @@ -303,25 +266,17 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If set outside of the buffer - /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleWindowInfo failed - /// /// public override @@ -337,6 +292,7 @@ public override return c; } + set { ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO bufferInfo; @@ -375,27 +331,19 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If setting to an invalid size - /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// obtaining information about the buffer failed /// OR /// Win32's SetConsoleScreenBufferSize failed - /// /// public override @@ -408,6 +356,7 @@ public override GetBufferInfo(out bufferInfo); return new Size(bufferInfo.BufferSize.X, bufferInfo.BufferSize.Y); } + set { // looking in windows/core/ntcon/server/output.c, it looks like the minimum size is 1 row X however many @@ -436,26 +385,18 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If setting width or height to less than 1, larger than the screen buffer, /// over the maximum window size allowed - /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleWindowInfo failed - /// /// public override @@ -474,6 +415,7 @@ public override return s; } + set { ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO bufferInfo; @@ -570,18 +512,12 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If obtaining information about the buffer failed - /// /// public override @@ -598,20 +534,14 @@ public override } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// Win32's GetLargestConsoleWindowSize failed - /// /// public override @@ -626,7 +556,7 @@ public override } /// - /// Helper method to create and trace PipelineStoppedException + /// Helper method to create and trace PipelineStoppedException. /// /// private PipelineStoppedException NewPipelineStoppedException() @@ -636,10 +566,10 @@ private PipelineStoppedException NewPipelineStoppedException() } /// - /// Used by ReadKey, cache KeyEvent based on if input.RepeatCount > 1 + /// Used by ReadKey, cache KeyEvent based on if input.RepeatCount > 1. /// - /// Input key event record - /// Cache key event + /// Input key event record. + /// Cache key event. private static void CacheKeyEvent(ConsoleControl.KEY_EVENT_RECORD input, ref ConsoleControl.KEY_EVENT_RECORD cache) { if (input.RepeatCount > 1) @@ -650,7 +580,6 @@ private static void CacheKeyEvent(ConsoleControl.KEY_EVENT_RECORD input, ref Con } /// - /// /// See base class /// This method unwraps the repeat count in KEY_EVENT_RECORD by caching repeated keystrokes /// in a logical queue. The implications are: @@ -659,24 +588,19 @@ private static void CacheKeyEvent(ConsoleControl.KEY_EVENT_RECORD input, ref Con /// key events: {Ctrl, KeyDown}, {Ctrl-c KeyDown}, {Ctrl, KeyUp}, {c, KeyUp} if Ctrl is released before c. /// In this case, {Ctrl, KeyUp}, {c, KeyUp} would be returned. /// 2) If the cache is non-empty, a call to ReadLine will not return the cached keys. This - /// behavior is the same as that of System.Console.ReadKey - /// + /// behavior is the same as that of System.Console.ReadKey. /// /// /// /// - /// /// If neither IncludeKeyDown or IncludeKeyUp is set in - /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// Win32's setting input buffer mode to disregard window and mouse input failed /// OR /// Win32's ReadConsoleInput failed - /// /// public override @@ -709,6 +633,7 @@ public override cachedKeyEvent.RepeatCount = 0; } } + if (cachedKeyEvent.RepeatCount > 0) { KEY_EVENT_RECORDToKeyInfo(cachedKeyEvent, out keyInfo); @@ -780,16 +705,12 @@ public override if ((options & ReadKeyOptions.NoEcho) == 0) { - parent.WriteToConsole( - keyInfo.Character.ToString(), - true); + parent.WriteToConsole(keyInfo.Character, transcribeResult: true); } return keyInfo; } - - private static void KEY_EVENT_RECORDToKeyInfo(ConsoleControl.KEY_EVENT_RECORD keyEventRecord, out KeyInfo keyInfo) @@ -801,19 +722,13 @@ private static keyEventRecord.KeyDown); } - - /// - /// - /// See base class - /// + /// See base class. /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// Win32's FlushConsoleInputBuffer failed - /// /// public override @@ -826,22 +741,16 @@ public override cachedKeyEvent.RepeatCount = 0; } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// Win32's GetNumberOfConsoleInputEvents failed /// OR /// Win32's PeekConsoleInput failed - /// /// public override @@ -876,6 +785,7 @@ public override // represent a keystroke. continue; } + return true; } } @@ -884,29 +794,20 @@ public override } } - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If set to null - /// /// /// - /// /// If set to a string whose length is not between 1 to 1023 - /// /// /// - /// /// If Win32's GetConsoleWindowTitle failed /// OR /// Win32's SetConsoleWindowTitle failed - /// /// public override string WindowTitle { @@ -914,6 +815,7 @@ public override string WindowTitle { return ConsoleControl.GetConsoleWindowTitle(); } + set { const int MaxWindowTitleLength = 1023; @@ -948,39 +850,28 @@ public override string WindowTitle } /// - /// /// See base class. - /// - /// /// /// - /// /// location on screen buffer where contents will be written - /// /// /// - /// /// array of info to be written - /// /// /// /// - /// /// If is outside of the screen buffer. /// OR /// is an ill-formed BufferCell array /// OR /// it is illegal to write at in the buffer - /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// obtaining information about the buffer failed /// OR /// there is not enough memory to complete calls to Win32's WriteConsoleOutput - /// /// public override @@ -1004,48 +895,34 @@ public override ConsoleControl.WriteConsoleOutput(handle, origin, contents); } - - /// - /// /// If is completely outside of the screen buffer, it's a no-op. - /// /// /// - /// /// region with all elements = -1 means "entire screen buffer" - /// /// /// - /// /// character and attribute to fill the screen buffer - /// /// /// - /// /// Provided for clearing regions -- less chatty than passing an array of cells. /// Clear screen is: /// SetBufferContents(new Rectangle(-1, -1, -1, -1), ' ', ForegroundColor, BackgroundColor); /// CursorPosition = new Coordinates(0, 0); /// /// fill.Type is ignored - /// /// /// - /// /// If 's Left exceeds Right or Bottom exceeds Top /// OR /// it is illegal to set in the buffer with - /// /// /// - /// /// If Win32's CreateFile fails /// OR /// Win32's GetConsoleScreenBufferInfo fails /// OR /// there is not enough memory to complete calls to Win32's WriteConsoleOutput - /// /// public override void @@ -1168,11 +1045,13 @@ public override } } } + if (lineLength % 2 == 1) { lineLength++; } } + for (int row = firstRow; row <= lastRow; ++row) { origin.Y = row; @@ -1185,37 +1064,25 @@ public override } } - - /// - /// /// See base class. /// If the rectangle is invalid, ie, Right exceeds Left OR Bottom exceeds Top, - /// /// /// - /// /// area on screen buffer to be read - /// /// /// - /// /// an array of BufferCell containing screen buffer contents - /// /// /// - /// /// If 's Left exceeds Right or Bottom exceeds Top. - /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// obtaining information about the buffer failed /// OR /// there is not enough memory to complete calls to Win32's ReadConsoleOutput - /// /// public override @@ -1271,39 +1138,25 @@ public override return contents; } - - /// - /// - /// See base class - /// + /// See base class. /// /// - /// /// area to be moved - /// /// /// - /// /// top left corner to which source to be moved - /// /// /// - /// /// area to be updated caused by the move - /// /// /// - /// /// character and attribute to fill the area vacated by the move - /// /// /// - /// /// If obtaining the active screen buffer failed /// OR /// Call to Win32's ScrollConsoleScreenBuffer failed - /// /// public override void @@ -1348,14 +1201,12 @@ BufferCell fill } /// - /// See base class + /// See base class. /// /// /// /// - /// /// If Win32's WideCharToMultiByte fails - /// /// public override @@ -1365,15 +1216,13 @@ int LengthInBufferCells(string s) } /// - /// See base class + /// See base class. /// /// /// /// /// - /// /// If Win32's WideCharToMultiByte fails - /// /// public override @@ -1383,21 +1232,17 @@ int LengthInBufferCells(string s, int offset) { throw PSTraceSource.NewArgumentNullException("str"); } + return ConsoleControl.LengthInBufferCells(s, offset, parent.SupportsVirtualTerminal); } - /// - /// - /// See base class - /// + /// See base class. /// /// /// /// - /// /// If Win32's WideCharToMultiByte fails - /// /// public override @@ -1406,12 +1251,10 @@ int LengthInBufferCells(char c) return ConsoleControl.LengthInBufferCells(c); } -#region internal + #region internal /// - /// - /// Clear the ReadKey cache - /// + /// Clear the ReadKey cache. /// /// internal void ClearKeyCache() @@ -1419,14 +1262,12 @@ internal void ClearKeyCache() cachedKeyEvent.RepeatCount = 0; } -#endregion internal - -#region helpers + #endregion internal + #region helpers // pass-by-ref for speed. /// - /// /// /// /// @@ -1455,9 +1296,8 @@ private static } } - /// - /// Get output buffer info + /// Get output buffer info. /// /// /// @@ -1475,9 +1315,7 @@ private static return result; } - - -#endregion helpers + #endregion helpers private ConsoleColor defaultForeground = ConsoleColor.Gray; @@ -1511,7 +1349,7 @@ private static namespace Microsoft.PowerShell { - // this is all originally from https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx + // this is all originally from https://msdn.microsoft.com/library/ee706570%28v=vs.85%29.aspx internal sealed class ConsoleHostRawUserInterface : PSHostRawUserInterface { @@ -1530,6 +1368,7 @@ internal ConsoleHostRawUserInterface(ConsoleHostUserInterface mshConsole) : base public override ConsoleColor BackgroundColor { get { return Console.BackgroundColor; } + set { Console.BackgroundColor = value; } } @@ -1549,6 +1388,7 @@ public override Size BufferSize ? s_wrapSize : new Size(Console.BufferWidth, Console.BufferHeight); } + set { Console.SetBufferSize(value.Width, value.Height); } } @@ -1558,6 +1398,7 @@ public override Size BufferSize public override Coordinates CursorPosition { get { return new Coordinates(Console.CursorLeft, Console.CursorTop); } + set { Console.SetCursorPosition(value.X < 0 ? 0 : value.X, @@ -1574,6 +1415,7 @@ public override int CursorSize // Future porting note: this API throws on Windows when output is // redirected, but never throws on Unix because it's fake. get { return Console.CursorSize; } + set { Console.CursorSize = value; } } @@ -1584,6 +1426,7 @@ public override int CursorSize public override ConsoleColor ForegroundColor { get { return Console.ForegroundColor; } + set { Console.ForegroundColor = value; } } @@ -1632,6 +1475,7 @@ public override Size MaxWindowSize public override Coordinates WindowPosition { get { return new Coordinates(Console.WindowLeft, Console.WindowTop); } + set { Console.SetWindowPosition(value.X, value.Y); } } @@ -1650,13 +1494,14 @@ public override Size WindowSize ? s_wrapSize : new Size(Console.WindowWidth, Console.WindowHeight); } + set { Console.SetWindowSize(value.Width, value.Height); } } /// - /// Cached Window Title, for systems that needs it + /// Cached Window Title, for systems that needs it. /// - private string _title = String.Empty; + private string _title = string.Empty; /// /// Gets or sets the title of the displayed window. The example @@ -1722,7 +1567,7 @@ internal struct SMALL_RECT public override string ToString() { - return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", Left, Top, Right, Bottom); + return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", Left, Top, Right, Bottom); } } @@ -1774,16 +1619,15 @@ public override void ScrollBufferContents(Rectangle source, Coordinates destinat public override void SetBufferContents(Coordinates origin, BufferCell[,] contents) { - //if there are no contents, there is nothing to set the buffer to + // if there are no contents, there is nothing to set the buffer to if (contents == null) { PSTraceSource.NewArgumentNullException("contents"); } - - //if the cursor is on the last line, we need to make more space to print the specified buffer + // if the cursor is on the last line, we need to make more space to print the specified buffer if (origin.Y == BufferSize.Height - 1 && origin.X >= BufferSize.Width) { - //for each row in the buffer, create a new line + // for each row in the buffer, create a new line int rows = contents.GetLength(0); ScrollBuffer(rows); // for each row in the buffer, move the cursor y up to the beginning of the created blank space @@ -1794,25 +1638,33 @@ public override void ScrollBufferContents(Rectangle source, Coordinates destinat } } - //iterate through the buffer to set +#if UNIX + // Make sure that the physical cursor position matches where we think it is. + // This is a problem on *nix, because input that the user types is echoed + // and that moves the cursor. As a consequence, the cursor needs to be repositioned + // before we update the screen. + CursorPosition = origin; +#endif + + // iterate through the buffer to set foreach (var charitem in contents) { - //set the cursor to false to prevent cursor flicker + // set the cursor to false to prevent cursor flicker Console.CursorVisible = false; - //if x is exceeding buffer width, reset to the next line + // if x is exceeding buffer width, reset to the next line if (origin.X >= BufferSize.Width) { origin.X = 0; } - //write the character from contents + // write the character from contents Console.Out.Write(charitem.Character); } - //reset the cursor to the original position + // reset the cursor to the original position CursorPosition = origin; - //reset the cursor to visible + // reset the cursor to visible Console.CursorVisible = true; } @@ -1821,7 +1673,7 @@ public override void ScrollBufferContents(Rectangle source, Coordinates destinat /// color to a region of the screen buffer. In this example this /// functionality is not needed so the method throws a /// NotImplementException exception./// - /// Defines the area to be filled. + /// Defines the area to be filled. /// Defines the fill character. public override void SetBufferContents(Rectangle rectangle, BufferCell fill) { @@ -1829,7 +1681,7 @@ public override void SetBufferContents(Rectangle rectangle, BufferCell fill) } /// - /// See base class + /// See base class. /// /// /// @@ -1841,7 +1693,7 @@ int LengthInBufferCells(string s) } /// - /// See base class + /// See base class. /// /// /// @@ -1854,6 +1706,7 @@ int LengthInBufferCells(string s, int offset) { throw PSTraceSource.NewArgumentNullException("str"); } + return ConsoleControl.LengthInBufferCells(s, offset, _parent.SupportsVirtualTerminal); } } diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostTranscript.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostTranscript.cs index b9143e878ea6..fe3b37a77ba9 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostTranscript.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostTranscript.cs @@ -1,30 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.IO; using System.Management.Automation.Host; using System.Management.Automation.Internal; - using Dbg = System.Management.Automation.Diagnostics; - - namespace Microsoft.PowerShell { - internal sealed partial - class ConsoleHost - : - PSHost, - IDisposable + internal sealed partial class ConsoleHost : PSHost, IDisposable { - internal - bool - IsTranscribing + internal bool IsTranscribing { get { @@ -32,13 +20,14 @@ class ConsoleHost return _isTranscribing; } + set { _isTranscribing = value; } } - private bool _isTranscribing; + private bool _isTranscribing; /* internal void StartTranscribing(string transcriptFilename, bool shouldAppend) @@ -72,13 +61,9 @@ internal void StartTranscribing(string transcriptFilename, bool shouldAppend) } } */ - private string _transcriptFileName = String.Empty; - + private string _transcriptFileName = string.Empty; - - internal - string - StopTranscribing() + internal string StopTranscribing() { lock (_transcriptionStateLock) { @@ -113,26 +98,36 @@ internal void StartTranscribing(string transcriptFilename, bool shouldAppend) } } + internal void WriteToTranscript(ReadOnlySpan text) + { + WriteToTranscript(text, newLine: false); + } + internal void WriteLineToTranscript(ReadOnlySpan text) + { + WriteToTranscript(text, newLine: true); + } - internal - void - WriteToTranscript(string text) + internal void WriteToTranscript(ReadOnlySpan text, bool newLine) { lock (_transcriptionStateLock) { if (_isTranscribing && _transcriptionWriter != null) { - _transcriptionWriter.Write(text); + if (newLine) + { + _transcriptionWriter.WriteLine(text); + } + else + { + _transcriptionWriter.Write(text); + } } } } - - private StreamWriter _transcriptionWriter; private object _transcriptionStateLock = new object(); } } // namespace - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs index 6d1788498711..0fd679b3c10e 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs @@ -1,18 +1,19 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.IO; -using System.Diagnostics.CodeAnalysis; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Linq; -using System.Management.Automation.Runspaces; -using System.Text; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; +using System.Management.Automation.Runspaces; +using System.Runtime.CompilerServices; using System.Security; +using System.Text; + using Dbg = System.Management.Automation.Diagnostics; #if !UNIX using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle; @@ -23,15 +24,13 @@ namespace Microsoft.PowerShell using PowerShell = System.Management.Automation.PowerShell; /// - /// - /// ConsoleHostUserInterface implements console-mode user interface for powershell - /// + /// ConsoleHostUserInterface implements console-mode user interface for powershell. /// [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] internal partial class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInterface { /// - /// Command completion implementation object + /// Command completion implementation object. /// private PowerShell _commandCompletionPowerShell; @@ -41,14 +40,12 @@ internal partial class ConsoleHostUserInterface : System.Management.Automation.H private static PSHostUserInterface s_h = null; /// - /// Return true if the console supports a VT100 like virtual terminal + /// Return true if the console supports a VT100 like virtual terminal. /// public override bool SupportsVirtualTerminal { get; } /// - /// - /// Constructs an instance - /// + /// Constructs an instance. /// /// /// @@ -87,9 +84,7 @@ internal ConsoleHostUserInterface(ConsoleHost parent) } /// - /// /// Supplies an implementation of PSHostRawUserInterface that provides low-level console mode UI facilities. - /// /// /// /// @@ -113,10 +108,10 @@ public override PSHostRawUserInterface RawUI ///// ///// - //internal - //PSHost - //Parent - //{ + // internal + // PSHost + // Parent + // { // get // { // using (tracer.TraceProperty()) @@ -126,13 +121,10 @@ public override PSHostRawUserInterface RawUI // return parent; // } // } - //} - + // } /// - /// - /// true if command completion is currently running - /// + /// True if command completion is currently running. /// internal bool IsCommandCompletionRunning @@ -145,17 +137,13 @@ internal bool IsCommandCompletionRunning } /// - /// - /// true if the Read* functions should read from the stdin stream instead of from the win32 console. - /// + /// True if the Read* functions should read from the stdin stream instead of from the win32 console. /// internal bool ReadFromStdin { get; set; } /// - /// - /// true if the host shouldn't write out prompts. - /// + /// True if the host shouldn't write out prompts. /// internal bool NoPrompt { get; set; } @@ -163,13 +151,10 @@ internal bool IsCommandCompletionRunning #region Line-oriented interaction /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If Win32's SetConsoleMode fails /// OR /// Win32's ReadConsole fails @@ -177,7 +162,6 @@ internal bool IsCommandCompletionRunning /// obtaining information about the buffer failed /// OR /// Win32's SetConsoleCursorPosition failed - /// /// public override string ReadLine() @@ -187,30 +171,22 @@ public override string ReadLine() // call our internal version such that it does not end input on a tab ReadLineResult unused; - return ReadLine(false, "", out unused, true, true); + return ReadLine(false, string.Empty, out unused, true, true); } - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// Win32's setting input buffer mode to disregard window and mouse input failed /// OR /// Win32's ReadConsole failed - /// - /// /// /// - /// /// If Ctrl-C is entered by user - /// /// public override SecureString ReadLineAsSecureString() @@ -226,6 +202,7 @@ public override SecureString ReadLineAsSecureString() { result = ReadLineSafe(true, printToken); } + SecureString secureResult = result as SecureString; System.Management.Automation.Diagnostics.Assert(secureResult != null, "ReadLineSafe did not return a SecureString"); @@ -233,7 +210,6 @@ public override SecureString ReadLineAsSecureString() } /// - /// /// Implementation based on NT CredUI's GetPasswdStr. /// Use Win32.ReadConsole to construct a SecureString. The advantage of ReadConsole over ReadKey is /// Alt-ddd where d is {0-9} is allowed. @@ -244,21 +220,15 @@ public override SecureString ReadLineAsSecureString() /// Secondary implementation for Unix based on Console.ReadKey(), where /// the advantage is portability through abstraction. Does not support /// arrow key movement, but supports backspace. - /// /// /// - /// /// True to specify reading a SecureString; false reading a string - /// /// /// - /// /// string for output echo - /// /// /// /// - /// /// If obtaining a handle to the active screen buffer failed /// OR /// Win32's setting input buffer mode to disregard window and mouse input failed @@ -268,12 +238,9 @@ public override SecureString ReadLineAsSecureString() /// obtaining information about the buffer failed /// OR /// Win32's SetConsoleCursorPosition failed - /// /// /// - /// /// If Ctrl-C is entered by user - /// /// private object ReadLineSafe(bool isSecureString, char? printToken) @@ -303,7 +270,7 @@ private object ReadLineSafe(bool isSecureString, char? printToken) #else // Ensure that we're in the proper line-input mode. - ConsoleControl.ConsoleModes desiredMode = + const ConsoleControl.ConsoleModes DesiredMode = ConsoleControl.ConsoleModes.Extended | ConsoleControl.ConsoleModes.QuickEdit; @@ -313,19 +280,20 @@ private object ReadLineSafe(bool isSecureString, char? printToken) bool shouldUnsetMouseInput = shouldUnsetMode(ConsoleControl.ConsoleModes.MouseInput, ref m); bool shouldUnsetProcessInput = shouldUnsetMode(ConsoleControl.ConsoleModes.ProcessedInput, ref m); - if ((m & desiredMode) != desiredMode || + if ((m & DesiredMode) != DesiredMode || shouldUnsetMouseInput || shouldUnsetEchoInput || shouldUnsetLineInput || shouldUnsetProcessInput) { - m |= desiredMode; + m |= DesiredMode; ConsoleControl.SetMode(handle, m); } else { isModeChanged = false; } + _rawui.ClearKeyCache(); #endif @@ -341,8 +309,9 @@ private object ReadLineSafe(bool isSecureString, char? printToken) #if UNIX ConsoleKeyInfo keyInfo = Console.ReadKey(true); #else - uint unused = 0; - string key = ConsoleControl.ReadConsole(handle, string.Empty, 1, false, out unused); + const int CharactersToRead = 1; + Span inputBuffer = stackalloc char[CharactersToRead + 1]; + string key = ConsoleControl.ReadConsole(handle, initialContentLength: 0, inputBuffer, charactersToRead: CharactersToRead, endOnTab: false, out _); #endif #if UNIX @@ -387,7 +356,7 @@ private object ReadLineSafe(bool isSecureString, char? printToken) } } #if UNIX - else if (Char.IsControl(keyInfo.KeyChar)) + else if (char.IsControl(keyInfo.KeyChar)) { // blacklist control characters continue; @@ -414,6 +383,7 @@ private object ReadLineSafe(bool isSecureString, char? printToken) result.Append(key); #endif } + if (!string.IsNullOrEmpty(printTokenString)) { WritePrintToken(printTokenString, ref originalCursorPos); @@ -440,6 +410,7 @@ private object ReadLineSafe(bool isSecureString, char? printToken) } #endif } + WriteLineToConsole(); PostRead(result.ToString()); if (isSecureString) @@ -452,28 +423,19 @@ private object ReadLineSafe(bool isSecureString, char? printToken) } } - /// - /// - /// Handle writing print token with proper cursor adjustment for ReadLineSafe - /// + /// Handle writing print token with proper cursor adjustment for ReadLineSafe. /// /// - /// /// token output for each char input. It must be a one-char string - /// /// /// - /// /// it is the cursor position where ReadLineSafe begins - /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleCursorPosition failed - /// /// private void WritePrintToken( @@ -497,27 +459,20 @@ private object ReadLineSafe(bool isSecureString, char? printToken) originalCursorPosition.Y--; } } + WriteToConsole(printToken, false); } - - /// - /// - /// Handle backspace with proper cursor adjustment for ReadLineSafe - /// + /// Handle backspace with proper cursor adjustment for ReadLineSafe. /// /// - /// /// it is the cursor position where ReadLineSafe begins - /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleCursorPosition failed - /// /// private void WriteBackSpace(Coordinates originalCursorPosition) @@ -548,12 +503,10 @@ private void WriteBackSpace(Coordinates originalCursorPosition) // do nothing if cursorPosition.X is left of screen } - - /// /// Blank out at and move rawui.CursorPosition to /// - /// Position to blank out + /// Position to blank out. private void BlankAtCursor(Coordinates cursorPosition) { _rawui.CursorPosition = cursorPosition; @@ -561,26 +514,19 @@ private void BlankAtCursor(Coordinates cursorPosition) _rawui.CursorPosition = cursorPosition; } - #if !UNIX /// - /// /// If is set on , unset it and return true; - /// otherwise return false - /// + /// otherwise return false. /// /// - /// /// a flag in ConsoleControl.ConsoleModes to be unset in - /// /// /// /// /// - /// /// true if is set on /// false otherwise - /// /// private static bool shouldUnsetMode( ConsoleControl.ConsoleModes flagToUnset, @@ -591,29 +537,42 @@ private void BlankAtCursor(Coordinates cursorPosition) m &= ~flagToUnset; return true; } + return false; } #endif #region WriteToConsole - internal void WriteToConsole(string value, bool transcribeResult) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteToConsole(char c, bool transcribeResult) + { + ReadOnlySpan value = stackalloc char[1] { c }; + WriteToConsole(value, transcribeResult); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteToConsole(ReadOnlySpan value, bool transcribeResult) + { + WriteToConsole(value, transcribeResult, newLine: false); + } + + private void WriteToConsole(ReadOnlySpan value, bool transcribeResult, bool newLine) { #if !UNIX ConsoleHandle handle = ConsoleControl.GetActiveScreenBufferHandle(); // Ensure that we're in the proper line-output mode. We don't lock here as it does not matter if we // attempt to set the mode from multiple threads at once. - ConsoleControl.ConsoleModes m = ConsoleControl.GetMode(handle); - const ConsoleControl.ConsoleModes desiredMode = - ConsoleControl.ConsoleModes.ProcessedOutput + const ConsoleControl.ConsoleModes DesiredMode = + ConsoleControl.ConsoleModes.ProcessedOutput | ConsoleControl.ConsoleModes.WrapEndOfLine; - if ((m & desiredMode) != desiredMode) + if ((m & DesiredMode) != DesiredMode) { - m |= desiredMode; + m |= DesiredMode; ConsoleControl.SetMode(handle, m); } #endif @@ -621,21 +580,20 @@ internal void WriteToConsole(string value, bool transcribeResult) PreWrite(); // This is atomic, so we don't lock here... - #if !UNIX - ConsoleControl.WriteConsole(handle, value); + ConsoleControl.WriteConsole(handle, value, newLine); #else - Console.Out.Write(value); + ConsoleOutWriteHelper(value, newLine); #endif if (_isInteractiveTestToolListening && Console.IsOutputRedirected) { - Console.Out.Write(value); + ConsoleOutWriteHelper(value, newLine); } if (transcribeResult) { - PostWrite(value); + PostWrite(value, newLine); } else { @@ -643,52 +601,73 @@ internal void WriteToConsole(string value, bool transcribeResult) } } - - - private void WriteToConsole(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string text) + private void WriteToConsole(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string text, bool newLine = false) { - ConsoleColor fg = RawUI.ForegroundColor; - ConsoleColor bg = RawUI.BackgroundColor; + // Sync access so that we don't race on color settings if called from multiple threads. + lock (_instanceLock) + { + ConsoleColor fg = RawUI.ForegroundColor; + ConsoleColor bg = RawUI.BackgroundColor; - RawUI.ForegroundColor = foregroundColor; - RawUI.BackgroundColor = backgroundColor; + RawUI.ForegroundColor = foregroundColor; + RawUI.BackgroundColor = backgroundColor; - try + try + { + WriteToConsole(text, transcribeResult: true, newLine); + } + finally + { + RawUI.ForegroundColor = fg; + RawUI.BackgroundColor = bg; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ConsoleOutWriteHelper(ReadOnlySpan value, bool newLine) + { + if (newLine) { - WriteToConsole(text, true); + Console.Out.WriteLine(value); } - finally + else { - RawUI.ForegroundColor = fg; - RawUI.BackgroundColor = bg; + Console.Out.Write(value); } } - private void WriteLineToConsole(string text) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteLineToConsole(ReadOnlySpan value, bool transcribeResult) { - WriteToConsole(text, true); - WriteToConsole(Crlf, true); + WriteToConsole(value, transcribeResult, newLine: true); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteLineToConsole(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string text) + { + WriteToConsole(foregroundColor, backgroundColor, text, newLine: true); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteLineToConsole(string text) + { + WriteLineToConsole(text, transcribeResult: true); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteLineToConsole() { - WriteToConsole(Crlf, true); + WriteToConsole(Environment.NewLine, transcribeResult: true, newLine: false); } #endregion WriteToConsole - - /// - /// /// See base class. - /// /// /// /// - /// /// If Win32's CreateFile fails /// OR /// Win32's GetConsoleMode fails @@ -696,20 +675,32 @@ private void WriteLineToConsole() /// Win32's SetConsoleMode fails /// OR /// Win32's WriteConsole fails - /// /// public override void Write(string value) { - if (string.IsNullOrEmpty(value)) - { - // do nothing + WriteImpl(value, newLine: false); + } + private void WriteImpl(string value, bool newLine) + { + if (string.IsNullOrEmpty(value) && !newLine) + { return; } // If the test hook is set, write to it and continue. - if (s_h != null) s_h.Write(value); + if (s_h != null) + { + if (newLine) + { + s_h.WriteLine(value); + } + else + { + s_h.Write(value); + } + } TextWriter writer = Console.IsOutputRedirected ? Console.Out : _parent.ConsoleTextWriter; @@ -718,25 +709,57 @@ public override void Write(string value) Dbg.Assert(writer == _parent.OutputSerializer.textWriter, "writers should be the same"); _parent.OutputSerializer.Serialize(value); + + if (newLine) + { + _parent.OutputSerializer.Serialize(Environment.NewLine); + } } else { - writer.Write(value); + if (newLine) + { + writer.WriteLine(value); + } + else + { + writer.Write(value); + } } } + /// + /// See base class. + /// + /// + /// + /// + /// + /// If obtaining information about the buffer failed + /// OR + /// Win32's SetConsoleTextAttribute + /// OR + /// Win32's CreateFile fails + /// OR + /// Win32's GetConsoleMode fails + /// OR + /// Win32's SetConsoleMode fails + /// OR + /// Win32's WriteConsole fails + /// + public override void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value) + { + Write(foregroundColor, backgroundColor, value, newLine: false); + } /// - /// - /// See base class - /// + /// See base class. /// /// /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleTextAttribute @@ -748,13 +771,15 @@ public override void Write(string value) /// Win32's SetConsoleMode fails /// OR /// Win32's WriteConsole fails - /// /// + public override void WriteLine(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value) + { + Write(foregroundColor, backgroundColor, value, newLine: true); + } - public override void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value) + private void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value, bool newLine) { // Sync access so that we don't race on color settings if called from multiple threads. - lock (_instanceLock) { ConsoleColor fg = RawUI.ForegroundColor; @@ -765,7 +790,7 @@ public override void Write(ConsoleColor foregroundColor, ConsoleColor background try { - this.Write(value); + this.WriteImpl(value, newLine); } finally { @@ -775,16 +800,11 @@ public override void Write(ConsoleColor foregroundColor, ConsoleColor background } } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// Win32's CreateFile fails /// OR /// Win32's GetConsoleMode fails @@ -792,26 +812,32 @@ public override void Write(ConsoleColor foregroundColor, ConsoleColor background /// Win32's SetConsoleMode fails /// OR /// Win32's WriteConsole fails - /// /// - public override void WriteLine(string value) { - // lock here so that the newline is written atomically with the value + this.WriteImpl(value, newLine: true); + } - lock (_instanceLock) - { - this.Write(value); - this.Write(Crlf); - } + /// + /// See base class. + /// + /// + /// Win32's CreateFile fails + /// OR + /// Win32's GetConsoleMode fails + /// OR + /// Win32's SetConsoleMode fails + /// OR + /// Win32's WriteConsole fails + /// + public override void WriteLine() + { + this.WriteImpl(Environment.NewLine, newLine: false); } #region Word Wrapping - - /// - /// /// This is a poor-man's word-wrapping routine. It breaks a single string into segments small enough to fit within a /// given number of cells. A break is determined by the last occurrence of whitespace that allows all prior characters /// on a line to be written within a given number of cells. If there is no whitespace found within that span, then the @@ -820,25 +846,18 @@ public override void WriteLine(string value) /// The problem is complicated by the fact that a single character may consume more than one cell. Conceptually, this /// is the same case as placing an upper bound on the length of a line while also having a strlen function that /// arbitrarily considers the length of any single character to be 1 or greater. - /// /// /// - /// /// Text to be emitted. /// Each tab character in the text is replaced with a space in the results. - /// /// /// - /// /// Max width, in buffer cells, of a single line. Note that a single character may consume more than one cell. The /// number of cells consumed is determined by calling ConsoleHostRawUserInterface.LengthInBufferCells. - /// /// /// - /// /// A list of strings representing the text broken into "lines" each of which are guaranteed not to exceed /// maxWidthInBufferCells. - /// /// internal List WrapText(string text, int maxWidthInBufferCells) @@ -868,6 +887,7 @@ internal List WrapText(string text, int maxWidthInBufferCells) Dbg.Assert(RawUI.LengthInBufferCells(l) <= maxWidthInBufferCells, "line is too long"); result.Add(l); } + break; } @@ -928,15 +948,10 @@ internal List WrapText(string text, int maxWidthInBufferCells) return result; } - - /// - /// - /// Struct used by WrapText - /// + /// Struct used by WrapText. /// - [Flags] internal enum WordFlags { @@ -951,44 +966,32 @@ internal struct Word internal WordFlags Flags; } - - /// - /// /// Chops text into "words," where a word is defined to be a sequence of whitespace characters, or a sequence of /// non-whitespace characters, each sequence being no longer than a given maximum. Therefore, in the text "this is a /// string" there are 7 words: 4 sequences of non-whitespace characters and 3 sequences of whitespace characters. /// /// Whitespace is considered to be spaces or tabs. Each tab character is replaced with a single space. - /// /// /// - /// /// The text to be chopped up. - /// /// /// - /// /// The maximum number of buffer cells that each word may consume. - /// /// /// - /// /// A list of words, in the same order they appear in the source text. - /// /// /// - /// /// This can be made faster by, instead of creating little strings for each word, creating indices of the start and end /// range of a word. That would reduce the string allocations. - /// /// internal List ChopTextIntoWords(string text, int maxWidthInBufferCells) { List result = new List(); - if (String.IsNullOrEmpty(text)) + if (string.IsNullOrEmpty(text)) { return result; } @@ -1042,6 +1045,7 @@ internal List ChopTextIntoWords(string text, int maxWidthInBufferCells) AddWord(text, startIndex, wordEnd, maxWidthInBufferCells, inWs, ref result); startIndex = wordEnd; } + inWs = true; } else @@ -1053,6 +1057,7 @@ internal List ChopTextIntoWords(string text, int maxWidthInBufferCells) AddWord(text, startIndex, wordEnd, maxWidthInBufferCells, inWs, ref result); startIndex = wordEnd; } + inWs = false; } @@ -1063,46 +1068,31 @@ internal List ChopTextIntoWords(string text, int maxWidthInBufferCells) { AddWord(text, startIndex, text.Length, maxWidthInBufferCells, inWs, ref result); } + return result; } - - /// - /// /// Helper for ChopTextIntoWords. Takes a span of characters in a string and adds it to the word list, further /// subdividing the span as needed so that each subdivision fits within the limit. - /// /// /// - /// /// The string of characters in which the span is to be extracted. - /// /// /// - /// /// index into text of the start of the word to be added. - /// /// /// - /// /// index of the char after the last char to be included in the word. - /// /// /// - /// /// The maximum number of buffer cells that each word may consume. - /// /// /// - /// /// true if the span is whitespace, false if not. - /// /// /// - /// /// The list into which the words will be added. - /// /// internal void AddWord(string text, int startIndex, int endIndex, @@ -1162,23 +1152,20 @@ internal string WrapToCurrentWindowWidth(string text) sb.Append(s); if (++count != lines.Count) { - sb.Append(Crlf); + sb.Append(Environment.NewLine); } } return sb.ToString(); } -#endregion Word Wrapping + #endregion Word Wrapping /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleTextAttribute @@ -1190,7 +1177,6 @@ internal string WrapToCurrentWindowWidth(string text) /// Win32's SetConsoleMode fails /// OR /// Win32's WriteConsole fails - /// /// public override void WriteDebugLine(string message) { @@ -1198,7 +1184,7 @@ public override void WriteDebugLine(string message) bool unused; message = HostUtilities.RemoveGuidFromMessage(message, out unused); - //We should write debug to error stream only if debug is redirected.) + // We should write debug to error stream only if debug is redirected.) if (_parent.ErrorFormat == Serialization.DataFormat.XML) { _parent.ErrorSerializer.Serialize(message, "debug"); @@ -1214,14 +1200,12 @@ public override void WriteDebugLine(string message) } /// - /// - /// See base class - /// + /// See base class. /// /// public override void WriteInformation(InformationRecord record) { - //We should write information to error stream only if redirected.) + // We should write information to error stream only if redirected.) if (_parent.ErrorFormat == Serialization.DataFormat.XML) { _parent.ErrorSerializer.Serialize(record, "information"); @@ -1233,13 +1217,10 @@ public override void WriteInformation(InformationRecord record) } /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleTextAttribute @@ -1251,7 +1232,6 @@ public override void WriteInformation(InformationRecord record) /// Win32's SetConsoleMode fails /// OR /// Win32's WriteConsole fails - /// /// public override void WriteVerboseLine(string message) @@ -1274,15 +1254,11 @@ public override void WriteVerboseLine(string message) } } - /// - /// - /// See base class - /// + /// See base class. /// /// /// - /// /// If obtaining information about the buffer failed /// OR /// Win32's SetConsoleTextAttribute @@ -1294,7 +1270,6 @@ public override void WriteVerboseLine(string message) /// Win32's SetConsoleMode fails /// OR /// Win32's WriteConsole fails - /// /// public override void WriteWarningLine(string message) @@ -1318,9 +1293,7 @@ public override void WriteWarningLine(string message) } /// - /// /// Invoked by CommandBase.WriteProgress to display a progress record. - /// /// public override void WriteProgress(Int64 sourceId, ProgressRecord record) @@ -1356,14 +1329,10 @@ record = new ProgressRecord(record) { CurrentOperation = currentOperation }; } } - - public override void WriteErrorLine(string value) { if (string.IsNullOrEmpty(value)) { - // do nothing - return; } @@ -1375,14 +1344,14 @@ public override void WriteErrorLine(string value) { Dbg.Assert(writer == _parent.ErrorSerializer.textWriter, "writers should be the same"); - _parent.ErrorSerializer.Serialize(value + Crlf); + _parent.ErrorSerializer.Serialize(value + Environment.NewLine); } else { if (writer == _parent.ConsoleTextWriter) WriteLine(ErrorForegroundColor, ErrorBackgroundColor, value); else - Console.Error.Write(value + Crlf); + Console.Error.WriteLine(value); } } @@ -1408,11 +1377,8 @@ public override void WriteErrorLine(string value) #endregion Line-oriented interaction - #region implementation - - // We use System.Environment.NewLine because we are platform-agnostic internal static string Crlf = System.Environment.NewLine; @@ -1426,51 +1392,35 @@ internal enum ReadLineResult endedOnBreak = 3 } - private const int maxInputLineLength = 8192; + private const int MaxInputLineLength = 1024; /// - /// /// Reads a line of input from the console. Returns when the user hits enter, a break key, a break event occurs. In /// the case that stdin has been redirected, reads from the stdin stream instead of the console. - /// /// /// - /// /// true to end input when the user hits the tab or shift-tab keys, false to only end on the enter key (or a break /// event). Ignored if not reading from the console device. - /// /// /// - /// /// The initial contents of the input buffer. Nice if you want to have a default result. Ignored if not reading from the /// console device. - /// /// /// - /// /// Receives an enum value indicating how input was ended. - /// /// /// - /// /// TBD - /// /// /// - /// /// true to include the results in any transcription that might be happening. - /// /// - /// /// - /// /// The string read from either the console or the stdin stream. null if: /// - stdin was read and EOF was reached on the stream, or /// - the console was read, and input was terminated with Ctrl-C, Ctrl-Break, or Close. - /// /// /// - /// /// If Win32's SetConsoleMode fails /// OR /// Win32's ReadConsole fails @@ -1478,7 +1428,6 @@ internal enum ReadLineResult /// obtaining information about the buffer failed /// OR /// Win32's SetConsoleCursorPosition failed - /// /// internal string ReadLine(bool endOnTab, string initialContent, out ReadLineResult result, bool calledFromPipeline, bool transcribeResult) @@ -1541,6 +1490,7 @@ private string ReadLineFromFile(string initialContent) if (!NoPrompt) Console.Out.Write('\n'); consoleIn.Read(); } + break; } @@ -1573,15 +1523,15 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca ConsoleHandle handle = ConsoleControl.GetConioDeviceHandle(); ConsoleControl.ConsoleModes m = ConsoleControl.GetMode(handle); - const ConsoleControl.ConsoleModes desiredMode = + const ConsoleControl.ConsoleModes DesiredMode = ConsoleControl.ConsoleModes.LineInput | ConsoleControl.ConsoleModes.EchoInput | ConsoleControl.ConsoleModes.ProcessedInput; - if ((m & desiredMode) != desiredMode || (m & ConsoleControl.ConsoleModes.MouseInput) > 0) + if ((m & DesiredMode) != DesiredMode || (m & ConsoleControl.ConsoleModes.MouseInput) > 0) { m &= ~ConsoleControl.ConsoleModes.MouseInput; - m |= desiredMode; + m |= DesiredMode; ConsoleControl.SetMode(handle, m); } #endif @@ -1613,7 +1563,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca { ConsoleKeyInfo keyInfo; - string s = ""; + string s = string.Empty; int index = 0; int cursorLeft = Console.CursorLeft; int cursorCurrent = cursorLeft; @@ -1622,14 +1572,20 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca #else _rawui.ClearKeyCache(); uint keyState = 0; - string s = ""; + string s = string.Empty; + Span inputBuffer = stackalloc char[MaxInputLineLength + 1]; + if (initialContent.Length > 0) + { + initialContent.AsSpan().CopyTo(inputBuffer); + } + #endif - do - { + do + { #if UNIX keyInfo = Console.ReadKey(true); #else - s += ConsoleControl.ReadConsole(handle, initialContent, maxInputLineLength, endOnTab, out keyState); + s += ConsoleControl.ReadConsole(handle, initialContent.Length, inputBuffer, MaxInputLineLength, endOnTab, out keyState); Dbg.Assert(s != null, "s should never be null"); #endif @@ -1639,34 +1595,35 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca #else if (s.Length == 0) #endif - { - result = ReadLineResult.endedOnBreak; - s = null; + { + result = ReadLineResult.endedOnBreak; + s = null; - if (calledFromPipeline) - { - // make sure that the pipeline that called us is stopped + if (calledFromPipeline) + { + // make sure that the pipeline that called us is stopped - throw new PipelineStoppedException(); - } - break; + throw new PipelineStoppedException(); } + break; + } + #if UNIX if (keyInfo.Key == ConsoleKey.Enter) #else - if (s.EndsWith(Crlf, StringComparison.CurrentCulture)) + if (s.EndsWith(Environment.NewLine, StringComparison.Ordinal)) #endif - { - result = ReadLineResult.endedOnEnter; + { + result = ReadLineResult.endedOnEnter; #if UNIX // We're intercepting characters, so we need to echo the newline Console.Out.WriteLine(); #else - s = s.Remove(s.Length - Crlf.Length); + s = s.Remove(s.Length - Environment.NewLine.Length); #endif - break; - } + break; + } #if UNIX if (keyInfo.Key == ConsoleKey.Tab) @@ -1675,7 +1632,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca continue; } #else - int i = s.IndexOf(Tab, StringComparison.CurrentCulture); + int i = s.IndexOf(Tab, StringComparison.Ordinal); if (endOnTab && i != -1) { @@ -1738,6 +1695,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca Console.Out.Write(s.PadRight(length)); Console.CursorLeft = cursorCurrent - 1; } + continue; } @@ -1753,6 +1711,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca Console.Out.Write(s.PadRight(length)); Console.CursorLeft = cursorCurrent; } + continue; } @@ -1764,6 +1723,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca Console.CursorLeft--; index--; } + continue; } @@ -1775,6 +1735,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca Console.CursorLeft++; index++; } + continue; } @@ -1807,7 +1768,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca { Console.CursorLeft = cursorLeft; index = s.Length; - s = ""; + s = string.Empty; continue; } @@ -1818,17 +1779,24 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca continue; } - if (Char.IsControl(keyInfo.KeyChar)) + if (char.IsControl(keyInfo.KeyChar)) { // blacklist control characters continue; } + // Handle case where terminal gets reset and the index is outside of the buffer + if (index > s.Length) + { + index = s.Length; + } + // Modify string - if (!insertMode) // then overwrite mode + if (!insertMode && index < s.Length) // then overwrite mode { s = s.Remove(index, 1); } + s = s.Insert(index, keyInfo.KeyChar.ToString()); index++; @@ -1838,15 +1806,15 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca Console.Out.Write(s); Console.CursorLeft = cursorCurrent + 1; #endif - } - while (true); + } + while (true); - Dbg.Assert( - (s == null && result == ReadLineResult.endedOnBreak) - || (s != null && result != ReadLineResult.endedOnBreak), - "s should only be null if input ended with a break"); + Dbg.Assert( + (s == null && result == ReadLineResult.endedOnBreak) + || (s != null && result != ReadLineResult.endedOnBreak), + "s should only be null if input ended with a break"); - return s; + return s; #if UNIX } finally @@ -1860,7 +1828,7 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca /// /// Get the character at the cursor when the user types 'tab' in the middle of line. /// - /// the cursor position where 'tab' is hit + /// The cursor position where 'tab' is hit. /// private char GetCharacterUnderCursor(Coordinates cursorPosition) { @@ -1886,11 +1854,10 @@ private char GetCharacterUnderCursor(Coordinates cursorPosition) } #endif - /// /// Strip nulls from a string... /// - /// The string to process + /// The string to process. /// The string with any \0 characters removed... private string RemoveNulls(string input) { @@ -1902,38 +1869,31 @@ private string RemoveNulls(string input) if (c != '\0') sb.Append(c); } + return sb.ToString(); } - /// - /// /// Reads a line, and completes the input for the user if they hit tab. - /// /// /// - /// /// The Executor instance on which to run any pipelines that are needed to find matches - /// /// - /// /// - /// /// null on a break event /// the completed line otherwise - /// /// internal string ReadLineWithTabCompletion(Executor exec) { string input = null; - string lastInput = ""; + string lastInput = string.Empty; ReadLineResult rlResult = ReadLineResult.endedOnEnter; #if !UNIX ConsoleHandle handle = ConsoleControl.GetActiveScreenBufferHandle(); - string lastCompletion = ""; + string lastCompletion = string.Empty; Size screenBufferSize = RawUI.BufferSize; // Save the cursor position at the end of the prompt string so that we can restore it later to write the @@ -1973,7 +1933,7 @@ internal string ReadLineWithTabCompletion(Executor exec) if (rlResult == ReadLineResult.endedOnTab || rlResult == ReadLineResult.endedOnShiftTab) { - int tabIndex = input.IndexOf(Tab, StringComparison.CurrentCulture); + int tabIndex = input.IndexOf(Tab, StringComparison.Ordinal); Dbg.Assert(tabIndex != -1, "tab should appear in the input"); string restOfLine = string.Empty; @@ -1987,6 +1947,7 @@ internal string ReadLineWithTabCompletion(Executor exec) input = input.Remove(input.Length - 1); restOfLine = input.Substring(tabIndex + 1); } + input = input.Remove(tabIndex); if (input != lastCompletion || commandCompletion == null) @@ -2011,9 +1972,9 @@ internal string ReadLineWithTabCompletion(Executor exec) completedInput += restOfLine; } - if (completedInput.Length > (maxInputLineLength - 2)) + if (completedInput.Length > (MaxInputLineLength - 2)) { - completedInput = completedInput.Substring(0, maxInputLineLength - 2); + completedInput = completedInput.Substring(0, MaxInputLineLength - 2); } // Remove any nulls from the string... @@ -2084,7 +2045,7 @@ internal string ReadLineWithTabCompletion(Executor exec) { // Reads always terminate with the enter key, so add that. - _parent.WriteToTranscript(input + Crlf); + _parent.WriteLineToTranscript(input); } return input; @@ -2208,8 +2169,8 @@ private bool TryInvokeUserDefinedReadLine(out string input) private object _instanceLock = new object(); - //If this is true, class throws on read or prompt method which require - //access to console. + // If this is true, class throws on read or prompt method which require + // access to console. internal bool ThrowOnReadAndPrompt { set @@ -2217,6 +2178,7 @@ internal bool ThrowOnReadAndPrompt _throwOnReadAndPrompt = value; } } + private bool _throwOnReadAndPrompt; internal void HandleThrowOnReadAndPrompt() diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceProgress.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceProgress.cs index 6c9350802cc6..afe2cbd8d635 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceProgress.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceProgress.cs @@ -1,14 +1,11 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; -using Dbg = System.Management.Automation.Diagnostics; using System.Threading; +using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell { @@ -16,10 +13,8 @@ internal partial class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInterface { /// - /// /// Called at the end of a prompt loop to take down any progress display that might have appeared and purge any /// outstanding progress activity state. - /// /// internal @@ -51,17 +46,14 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt _progPane.Hide(); _progPane = null; } + _pendingProgress = null; } } - - /// - /// /// Invoked by ConsoleHostUserInterface.WriteProgress to update the set of outstanding activities for which /// ProgressRecords have been received. - /// /// private @@ -94,7 +86,7 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt progPaneUpdateFlag = 1; // The timer will be auto restarted every 'UpdateTimerThreshold' ms - _progPaneUpdateTimer = new Timer( new TimerCallback(ProgressPaneUpdateTimerElapsed), null, UpdateTimerThreshold, UpdateTimerThreshold); + _progPaneUpdateTimer = new Timer(new TimerCallback(ProgressPaneUpdateTimerElapsed), null, UpdateTimerThreshold, UpdateTimerThreshold); } } @@ -106,12 +98,8 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } - - /// - /// /// TimerCallback for '_progPaneUpdateTimer' to update 'progPaneUpdateFlag' - /// /// private @@ -131,8 +119,6 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } - - private void PostWrite() @@ -143,11 +129,9 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } - - private void - PostWrite(string value) + PostWrite(ReadOnlySpan value, bool newLine) { PostWrite(); @@ -155,7 +139,7 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt { try { - _parent.WriteToTranscript(value); + _parent.WriteToTranscript(value, newLine); } catch (Exception) { @@ -164,8 +148,6 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } - - private void PreRead() @@ -176,8 +158,6 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } - - private void PostRead() @@ -188,8 +168,6 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } - - private void PostRead(string value) @@ -201,7 +179,7 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt try { // Reads always terminate with the enter key, so add that. - _parent.WriteToTranscript(value + Crlf); + _parent.WriteLineToTranscript(value); } catch (Exception) { @@ -210,8 +188,6 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } - - private ProgressPane _progPane = null; private PendingProgress _pendingProgress = null; // The timer set up 'progPaneUpdateFlag' every 'UpdateTimerThreshold' milliseconds to update 'ProgressPane' @@ -221,5 +197,3 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt } } // namespace - - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePrompt.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePrompt.cs index 660cd741436a..9e0368860596 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePrompt.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePrompt.cs @@ -1,24 +1,20 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Globalization; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Text; +using System.Globalization; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Security; +using System.Text; + using Dbg = System.Management.Automation.Diagnostics; using InternalHostUserInterface = System.Management.Automation.Internal.Host.InternalHostUserInterface; - - namespace Microsoft.PowerShell { internal partial @@ -26,26 +22,24 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt { /// /// Used by Prompt to indicate any common errors when converting the user input string to - /// the type of the parameter + /// the type of the parameter. /// private enum PromptCommonInputErrors { /// - /// No error or not an error prompt handles + /// No error or not an error prompt handles. /// None, /// - /// Format error + /// Format error. /// Format, /// - /// Overflow error + /// Overflow error. /// Overflow } - - private static bool AtLeastOneHelpMessageIsPresent(Collection descriptions) @@ -54,7 +48,7 @@ private static { if (fd != null) { - if (!String.IsNullOrEmpty(fd.HelpMessage)) + if (!string.IsNullOrEmpty(fd.HelpMessage)) { return true; } @@ -64,46 +58,34 @@ private static return false; } - - /// - /// - /// See base class - /// + /// See base class. /// /// /// /// /// /// - /// /// If is null /// OR /// at least one FieldDescription in is null - /// /// /// - /// /// If count is less than 1 /// OR /// at least one FieldDescription.AssemblyFullName in is /// null or empty - /// /// /// - /// /// If a FieldDescription in specifies one of SecureString or /// PSCredential and the type can not be loaded. /// OR /// at least one FieldDescription in specifies an array /// whose rank is less than 1. - /// /// /// - /// /// If the converting the user input to the prompt field type fails unless it is caused by /// OverflowException or FormatException - /// /// public override @@ -130,17 +112,17 @@ public override { Dictionary results = new Dictionary(); - Boolean cancelInput = false; + bool cancelInput = false; - if (!String.IsNullOrEmpty(caption)) + if (!string.IsNullOrEmpty(caption)) { // Should be a skin lookup WriteLineToConsole(); - WriteToConsole(PromptColor, RawUI.BackgroundColor, WrapToCurrentWindowWidth(caption)); - WriteLineToConsole(); + WriteLineToConsole(PromptColor, RawUI.BackgroundColor, WrapToCurrentWindowWidth(caption)); } - if (!String.IsNullOrEmpty(message)) + + if (!string.IsNullOrEmpty(message)) { WriteLineToConsole(WrapToCurrentWindowWidth(message)); } @@ -161,6 +143,7 @@ public override ConsoleHostUserInterfaceStrings.NullErrorTemplate, string.Format(CultureInfo.InvariantCulture, "descriptions[{0}]", descIndex)); } + PSObject inputPSObject = null; string fieldPrompt = null; fieldPrompt = desc.Name; @@ -225,8 +208,8 @@ public override { fieldPromptList.Append( string.Format(CultureInfo.InvariantCulture, "{0}]: ", inputList.Count)); - Boolean inputListEnd = false; - Object convertedObj = null; + bool inputListEnd = false; + object convertedObj = null; string inputString = PromptForSingleItem(elementType, fieldPromptList.ToString(), fieldPrompt, caption, message, desc, fieldEchoOnPrompt, true, out inputListEnd, out cancelInput, out convertedObj); @@ -260,8 +243,8 @@ public override string printFieldPrompt = StringUtil.Format(ConsoleHostUserInterfaceStrings.PromptFieldPromptInputSeparatorTemplate, fieldPrompt); // field is not a list - Object convertedObj = null; - Boolean dummy = false; + object convertedObj = null; + bool dummy = false; PromptForSingleItem(fieldType, printFieldPrompt, fieldPrompt, caption, message, desc, fieldEchoOnPrompt, false, out dummy, out cancelInput, out convertedObj); @@ -270,6 +253,7 @@ public override inputPSObject = PSObject.AsPSObject(convertedObj); } } + if (cancelInput) { s_tracer.WriteLine("Prompt canceled"); @@ -277,8 +261,10 @@ public override results.Clear(); break; } + results.Add(desc.Name, PSObject.AsPSObject(inputPSObject)); } + return results; } } @@ -348,13 +334,13 @@ public override /// /// Called by Prompt. Reads user input and processes tilde commands. /// - /// prompt written to host for the field - /// the field to be read - /// true to echo user input - /// true if the field is a list - /// valid only if listInput is true. set to true if the input signals end of list input - /// true iff the input is canceled, e.g., by Ctrl-C or Ctrl-Break - /// processed input string to be converted with LanguagePrimitives.ConvertTo + /// Prompt written to host for the field. + /// The field to be read. + /// True to echo user input. + /// True if the field is a list. + /// Valid only if listInput is true. set to true if the input signals end of list input. + /// True iff the input is canceled, e.g., by Ctrl-C or Ctrl-Break. + /// Processed input string to be converted with LanguagePrimitives.ConvertTo. private string PromptReadInput(string fieldPrompt, FieldDescription desc, bool fieldEchoOnPrompt, bool listInput, out bool endListInput, out bool cancelled) { @@ -381,6 +367,7 @@ public override System.Management.Automation.Diagnostics.Assert(userInputString != null, "ReadLineSafe did not return a string"); rawInputString = userInputString; } + if (rawInputString == null) { // processedInputString is null as well. No need to assign null to it. @@ -388,7 +375,7 @@ public override break; } else - if (rawInputString.StartsWith(PromptCommandPrefix, StringComparison.CurrentCulture)) + if (!string.IsNullOrEmpty(desc.Label) && rawInputString.StartsWith(PromptCommandPrefix, StringComparison.Ordinal)) { processedInputString = PromptCommandMode(rawInputString, desc, out inputDone); } @@ -398,10 +385,12 @@ public override { endListInput = true; } + processedInputString = rawInputString; break; } } + return processedInputString; } @@ -409,12 +398,12 @@ public override /// Uses LanguagePrimitives.ConvertTo to parse inputString for fieldType. Handles two most common parse /// exceptions: OverflowException and FormatException. /// - /// the type that inputString is to be interpreted - /// is the call coming from a remote host - /// the string to be converted + /// The type that inputString is to be interpreted. + /// Is the call coming from a remote host. + /// The string to be converted. /// if there's no error in the conversion, the converted object will be assigned here; /// otherwise, this will be the same as the inputString - /// an object of type fieldType that inputString represents + /// An object of type fieldType that inputString represents. private PromptCommonInputErrors PromptTryConvertTo(Type fieldType, bool isFromRemoteHost, string inputString, out object convertedObj) { Dbg.Assert(fieldType != null, "fieldType should never be null when PromptTryConvertTo is called"); @@ -456,6 +445,7 @@ private PromptCommonInputErrors PromptTryConvertTo(Type fieldType, bool isFromRe WrapToCurrentWindowWidth( string.Format(CultureInfo.CurrentCulture, errMsgTemplate, fieldType, inputString))); } + return PromptCommonInputErrors.Format; } else @@ -466,6 +456,7 @@ private PromptCommonInputErrors PromptTryConvertTo(Type fieldType, bool isFromRe { } } + return PromptCommonInputErrors.None; } @@ -478,7 +469,7 @@ private PromptCommonInputErrors PromptTryConvertTo(Type fieldType, bool isFromRe /// !h prints out field's Quick Help, returns null /// All others tilde comments are invalid and return null /// - /// returns null iff there's nothing the caller can process + /// returns null iff there's nothing the caller can process. /// /// /// @@ -497,6 +488,7 @@ private string PromptCommandMode(string input, FieldDescription desc, out bool i { return command; } + if (command.Length == 1) { if (command[0] == '?') @@ -517,9 +509,11 @@ private string PromptCommandMode(string input, FieldDescription desc, out bool i { ReportUnrecognizedPromptCommand(input); } + inputDone = false; return null; } + if (command.Length == 2) { if (0 == string.Compare(command, "\"\"", StringComparison.OrdinalIgnoreCase)) @@ -527,6 +521,7 @@ private string PromptCommandMode(string input, FieldDescription desc, out bool i return string.Empty; } } + if (0 == string.Compare(command, "$null", StringComparison.OrdinalIgnoreCase)) { return null; diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePromptForChoice.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePromptForChoice.cs index 369a9385443c..660877be1e18 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePromptForChoice.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfacePromptForChoice.cs @@ -1,17 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Globalization; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Text; +using System.Globalization; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; +using System.Text; using Dbg = System.Management.Automation.Diagnostics; using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle; @@ -22,9 +19,7 @@ namespace Microsoft.PowerShell internal partial class ConsoleHostUserInterface : PSHostUserInterface, IHostUISupportsMultipleChoiceSelection { /// - /// - /// See base class - /// + /// See base class. /// /// /// @@ -32,25 +27,17 @@ internal partial class ConsoleHostUserInterface : PSHostUserInterface, IHostUISu /// /// /// - /// /// If is null. - /// /// /// - /// /// If .Count is 0. - /// /// /// - /// /// If is greater than /// the length of . - /// /// /// - /// /// when prompt is canceled by, for example, Ctrl-c. - /// /// public override int PromptForChoice(string caption, string message, Collection choices, int defaultChoice) @@ -83,8 +70,7 @@ public override int PromptForChoice(string caption, string message, Collection defaultChoiceKeys = new Dictionary(); - if (null != defaultChoices) + if (defaultChoices != null) { foreach (int defaultChoice in defaultChoices) { @@ -229,8 +215,7 @@ public override int PromptForChoice(string caption, string message, Collection 0) { - string prepend = ""; + string prepend = string.Empty; StringBuilder defaultChoicesBuilder = new StringBuilder(); foreach (int defaultChoice in defaultChoiceKeys.Keys) { @@ -373,6 +358,7 @@ public override int PromptForChoice(string caption, string message, Collection choices, string[,] hotkeysAndPlainLabels) { Dbg.Assert(choices != null, "choices: expected a value"); @@ -437,7 +436,7 @@ private void ShowChoiceHelp(Collection choices, string[,] hot WriteLineToConsole( WrapToCurrentWindowWidth( - String.Format(CultureInfo.InvariantCulture, "{0} - {1}", s, choices[i].HelpMessage))); + string.Format(CultureInfo.InvariantCulture, "{0} - {1}", s, choices[i].HelpMessage))); } } @@ -476,4 +475,3 @@ private ConsoleColor DefaultPromptColor } } } // namespace - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs index b945d24dc218..f78e5b9304bc 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs @@ -1,20 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Security; +using System.Globalization; using System.Management.Automation; using System.Management.Automation.Internal; +using System.Security; + using Microsoft.Win32; -using System.Globalization; namespace Microsoft.PowerShell { /// - /// - /// ConsoleHostUserInterface implements console-mode user interface for powershell - /// + /// ConsoleHostUserInterface implements console-mode user interface for powershell. /// internal partial class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInterface @@ -25,18 +23,12 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt /// In future, when we have Credential object from the security team, /// this function will be modified to prompt using secure-path /// if so configured. - /// /// - /// name of the user whose creds are to be prompted for. If set to null or empty string, the function will prompt for user name first. - /// - /// name of the target for which creds are being collected - /// - /// message to be displayed. - /// - /// caption for the message. - /// - /// PSCredential object - /// + /// Name of the user whose creds are to be prompted for. If set to null or empty string, the function will prompt for user name first. + /// Name of the target for which creds are being collected. + /// Message to be displayed. + /// Caption for the message. + /// PSCredential object. public override PSCredential PromptForCredential( string caption, @@ -55,20 +47,13 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt /// /// Prompt for credentials. /// - /// name of the user whose creds are to be prompted for. If set to null or empty string, the function will prompt for user name first. - /// - /// name of the target for which creds are being collected - /// - /// message to be displayed. - /// - /// caption for the message. - /// - /// what type of creds can be supplied by the user - /// - /// options that control the cred gathering UI behavior - /// - /// PSCredential object, or null if input was cancelled (or if reading from stdin and stdin at EOF) - /// + /// Name of the user whose creds are to be prompted for. If set to null or empty string, the function will prompt for user name first. + /// Name of the target for which creds are being collected. + /// Message to be displayed. + /// Caption for the message. + /// What type of creds can be supplied by the user. + /// Options that control the cred gathering UI behavior. + /// PSCredential object, or null if input was cancelled (or if reading from stdin and stdin at EOF). public override PSCredential PromptForCredential( string caption, @@ -88,8 +73,7 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt // Should be a skin lookup WriteLineToConsole(); - WriteToConsole(PromptColor, RawUI.BackgroundColor, WrapToCurrentWindowWidth(caption)); - WriteLineToConsole(); + WriteLineToConsole(PromptColor, RawUI.BackgroundColor, WrapToCurrentWindowWidth(caption)); } if (!string.IsNullOrEmpty(message)) @@ -128,6 +112,7 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt { return null; } + WriteLineToConsole(); cred = new PSCredential(userName, password); diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs index 89703712e500..5f34692cd02d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs @@ -1,9 +1,9 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.Management.Automation; using System.Management.Automation.Runspaces; +using System.Runtime.CompilerServices; namespace Microsoft.PowerShell { @@ -16,19 +16,36 @@ public static class ConsoleShell { /// Entry point in to ConsoleShell. This method is called by main of minishell. - /// Banner text to be displayed by ConsoleHost + /// Banner text to be displayed by ConsoleHost. /// Help text for minishell. This is displayed on 'minishell -?'. /// Commandline parameters specified by user. /// An integer value which should be used as exit code for the process. public static int Start(string bannerText, string helpText, string[] args) { + return Start(InitialSessionState.CreateDefault2(), bannerText, helpText, args); + } + + /// Entry point in to ConsoleShell. Used to create a custom Powershell console application. + /// InitialSessionState to be used by the ConsoleHost. + /// Banner text to be displayed by ConsoleHost. + /// Help text for the shell. + /// Commandline parameters specified by user. + /// An integer value which should be used as exit code for the process. + public static int Start(InitialSessionState initialSessionState, string bannerText, string helpText, string[] args) + { + if (initialSessionState == null) + { + throw PSTraceSource.NewArgumentNullException(nameof(initialSessionState)); + } + if (args == null) { - throw PSTraceSource.NewArgumentNullException("args"); + throw PSTraceSource.NewArgumentNullException(nameof(args)); } + ConsoleHost.DefaultInitialSessionState = initialSessionState; + return ConsoleHost.Start(bannerText, helpText, args); } } } - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs index 7e14ca9d8cd9..590ad7c1a21d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs @@ -1,20 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Text; using System.IO; -using Dbg = System.Management.Automation.Diagnostics; +using System.Text; + using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle; -using HRESULT = System.UInt32; +using Dbg = System.Management.Automation.Diagnostics; using DWORD = System.UInt32; +using HRESULT = System.UInt32; using NakedWin32Handle = System.IntPtr; - - namespace Microsoft.PowerShell { internal @@ -30,8 +26,6 @@ class ConsoleTextWriter : TextWriter _ui = ui; } - - public override Encoding Encoding @@ -42,55 +36,63 @@ public override } } - - public override void Write(string value) { - _ui.WriteToConsole(value, true); + _ui.WriteToConsole(value, transcribeResult: true); } - + public override + void + Write(ReadOnlySpan value) + { + _ui.WriteToConsole(value, transcribeResult: true); + } public override void WriteLine(string value) { - this.Write(value + ConsoleHostUserInterface.Crlf); + _ui.WriteLineToConsole(value, transcribeResult: true); } - - public override void - Write(Boolean b) + WriteLine(ReadOnlySpan value) { - this.Write(b.ToString()); + _ui.WriteLineToConsole(value, transcribeResult: true); } - - public override void - Write(Char c) + Write(bool b) { - this.Write(new String(c, 1)); + if (b) + { + _ui.WriteToConsole(bool.TrueString, transcribeResult: true); + } + else + { + _ui.WriteToConsole(bool.FalseString, transcribeResult: true); + } } - - public override void - Write(Char[] a) + Write(char c) { - this.Write(new String(a)); + ReadOnlySpan c1 = stackalloc char[1] { c }; + _ui.WriteToConsole(c1, transcribeResult: true); } - + public override + void + Write(char[] a) + { + _ui.WriteToConsole(a, transcribeResult: true); + } private ConsoleHostUserInterface _ui; } -} // namespace - - +} diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs index b3ba10f1ec30..e432b01f6da0 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs @@ -1,20 +1,20 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Management.Automation; -using System.Management.Automation.Runspaces; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Language; +using System.Management.Automation.Runspaces; using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell { /// - /// /// Executor wraps a Pipeline instance, and provides helper methods for executing commands in that pipeline. It is used to /// provide bookkeeping and structure to the use of pipeline in such a way that they can be interrupted and cancelled by a /// break event handler, and track nesting of pipelines (which happens with interrupted input loops (aka subshells) and use @@ -23,7 +23,6 @@ namespace Microsoft.PowerShell /// /// The class' instance methods manage a single pipeline. The class' static methods track the outstanding instances to /// ensure that only one instance is 'active' (and therefore cancellable) at a time. - /// /// internal class Executor @@ -38,26 +37,18 @@ internal enum ExecutionOptions } /// - /// - /// Constructs a new instance - /// + /// Constructs a new instance. /// /// - /// /// A reference to the parent ConsoleHost that created this instance. - /// /// /// - /// /// true if the executor is supposed to use nested pipelines; false if not. - /// /// /// - /// /// True if the instance will be used to execute the prompt function, which will delay stopping the pipeline by some /// milliseconds. This we prevent us from stopping the pipeline so quickly that when the user leans on the ctrl-c key /// that the prompt "stops working" (because it is being stopped faster than it can run to completion). - /// /// internal Executor(ConsoleHost parent, bool useNestedPipelines, bool isPromptFunctionExecutor) { @@ -91,8 +82,6 @@ private void OutputObjectStreamHandler(object sender, EventArgs e) } } - - // called on the pipeline thread private void ErrorObjectStreamHandler(object sender, EventArgs e) @@ -114,9 +103,8 @@ private void ErrorObjectStreamHandler(object sender, EventArgs e) } } - /// - /// This method handles the failure in executing pipeline asynchronously + /// This method handles the failure in executing pipeline asynchronously. /// /// private void AsyncPipelineFailureHandler(Exception ex) @@ -126,8 +114,8 @@ private void AsyncPipelineFailureHandler(Exception ex) if (cer != null) { er = cer.ErrorRecord; - //Exception inside the error record is ParentContainsErrorRecordException which - //doesn't have stack trace. Replace it with top level exception. + // Exception inside the error record is ParentContainsErrorRecordException which + // doesn't have stack trace. Replace it with top level exception. er = new ErrorRecord(er, ex); } @@ -135,6 +123,7 @@ private void AsyncPipelineFailureHandler(Exception ex) { er = new ErrorRecord(ex, "ConsoleHostAsyncPipelineFailure", ErrorCategory.NotSpecified, null); } + _parent.ErrorSerializer.Serialize(er); } @@ -167,13 +156,25 @@ private void PipelineStateChangedHandler(object sender, PipelineStateEventArgs e internal void ExecuteCommandAsync(string command, out Exception exceptionThrown, ExecutionOptions options) { Dbg.Assert(!useNestedPipelines, "can't async invoke a nested pipeline"); - Dbg.Assert(!String.IsNullOrEmpty(command), "command should have a value"); + Dbg.Assert(!string.IsNullOrEmpty(command), "command should have a value"); bool addToHistory = (options & ExecutionOptions.AddToHistory) > 0; Pipeline tempPipeline = _parent.RunspaceRef.CreatePipeline(command, addToHistory, false); ExecuteCommandAsyncHelper(tempPipeline, out exceptionThrown, options); } + /// + /// Executes a pipeline in the console when we are running asnyc. + /// + /// + /// The pipeline to execute. + /// + /// + /// Any exception thrown trying to run the pipeline. + /// + /// + /// The options to use to execute the pipeline. + /// internal void ExecuteCommandAsyncHelper(Pipeline tempPipeline, out Exception exceptionThrown, ExecutionOptions options) { Dbg.Assert(!_isPromptFunctionExecutor, "should not async invoke the prompt"); @@ -206,7 +207,14 @@ internal void ExecuteCommandAsyncHelper(Pipeline tempPipeline, out Exception exc tempPipeline.Output.DataReady += new EventHandler(OutputObjectStreamHandler); tempPipeline.Error.DataReady += new EventHandler(ErrorObjectStreamHandler); - PipelineFinishedWaitHandle waiterThereIsAFlyInMySoup = new PipelineFinishedWaitHandle(tempPipeline); + PipelineFinishedWaitHandle pipelineWaiter = new PipelineFinishedWaitHandle(tempPipeline); + + // close the input pipeline so the command will do something + // if we are not reading input + if ((options & Executor.ExecutionOptions.ReadInputObjects) == 0) + { + tempPipeline.Input.Close(); + } tempPipeline.InvokeAsync(); if ((options & ExecutionOptions.ReadInputObjects) > 0 && Console.IsInputRedirected) @@ -227,30 +235,31 @@ internal void ExecuteCommandAsyncHelper(Pipeline tempPipeline, out Exception exc } catch (PipelineClosedException) { - //This exception can occurs when input is closed. This can happen - //for various reasons. For ex:Command in the pipeline is invalid and - //command discovery throws exception which closes the pipeline and - //hence the Input pipe. + // This exception can occurs when input is closed. This can happen + // for various reasons. For ex:Command in the pipeline is invalid and + // command discovery throws exception which closes the pipeline and + // hence the Input pipe. break; } }; des.End(); } + tempPipeline.Input.Close(); - waiterThereIsAFlyInMySoup.Wait(); + pipelineWaiter.Wait(); - //report error if pipeline failed + // report error if pipeline failed if (tempPipeline.PipelineStateInfo.State == PipelineState.Failed && tempPipeline.PipelineStateInfo.Reason != null) { if (_parent.OutputFormat == Serialization.DataFormat.Text) { - //Report the exception using normal error reporting + // Report the exception using normal error reporting exceptionThrown = tempPipeline.PipelineStateInfo.Reason; } else { - //serialize the error record + // serialize the error record AsyncPipelineFailureHandler(tempPipeline.PipelineStateInfo.Reason); } } @@ -285,12 +294,11 @@ internal Pipeline CreatePipeline() internal Pipeline CreatePipeline(string command, bool addToHistory) { - Dbg.Assert(!String.IsNullOrEmpty(command), "command should have a value"); + Dbg.Assert(!string.IsNullOrEmpty(command), "command should have a value"); return _parent.RunspaceRef.CreatePipeline(command, addToHistory, useNestedPipelines); } /// - /// /// All calls to the Runspace to execute a command line must be done with this function, which properly synchronizes /// access to the running pipeline between the main thread and the break handler thread. This synchronization is /// necessary so that executions can be aborted with Ctrl-C (including evaluation of the prompt and collection of @@ -298,32 +306,39 @@ internal Pipeline CreatePipeline(string command, bool addToHistory) /// /// On any given Executor instance, ExecuteCommand should be called at most once at a time by any one thread. It is NOT /// reentrant. - /// /// /// - /// /// The command line to be executed. Must be non-null. - /// /// /// - /// /// Receives the Exception thrown by the execution of the command, if any. If no exception is thrown, then set to null. /// Can be tested to see if the execution was successful or not. - /// /// /// - /// /// options to govern the execution - /// /// /// - /// /// the object stream resulting from the execution. May be null. - /// /// internal Collection ExecuteCommand(string command, out Exception exceptionThrown, ExecutionOptions options) { - Dbg.Assert(!String.IsNullOrEmpty(command), "command should have a value"); + Dbg.Assert(!string.IsNullOrEmpty(command), "command should have a value"); + + // Experimental: + // Check for implicit remoting commands that can be batched, and execute as batched if able. + if (ExperimentalFeature.IsEnabled("PSImplicitRemotingBatching")) + { + var addOutputter = ((options & ExecutionOptions.AddOutputter) > 0); + if (addOutputter && + !_parent.RunspaceRef.IsRunspaceOverridden && + _parent.RunspaceRef.Runspace.ExecutionContext.Modules != null && + _parent.RunspaceRef.Runspace.ExecutionContext.Modules.IsImplicitRemotingModuleLoaded && + Utils.TryRunAsImplicitBatch(command, _parent.RunspaceRef.Runspace)) + { + exceptionThrown = null; + return null; + } + } Pipeline tempPipeline = CreatePipeline(command, (options & ExecutionOptions.AddToHistory) > 0); @@ -425,7 +440,6 @@ internal Collection ExecuteCommandHelper(Pipeline tempPipeline, out Ex return results; } - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Needed by ProfileTests as mentioned in bug 140572")] internal Collection ExecuteCommand(string command) { @@ -439,6 +453,7 @@ internal Collection ExecuteCommand(string command) { break; } + if (result == null) { break; @@ -449,27 +464,19 @@ internal Collection ExecuteCommand(string command) } /// - /// /// Executes a command (by calling this.ExecuteCommand), and coerces the first result object to a string. Any Exception /// thrown in the course of execution is returned thru the exceptionThrown parameter. - /// /// /// - /// /// The command to execute. May be any valid monad command. - /// /// /// - /// /// Receives the Exception thrown by the execution of the command, if any. If no exception is thrown, then set to null. /// Can be tested to see if the execution was successful or not. - /// /// /// - /// /// The string representation of the first result object returned, or null if an exception was thrown or no objects were /// returned by the command. - /// /// internal string ExecuteCommandAndGetResultAsString(string command, out Exception exceptionThrown) { @@ -493,7 +500,7 @@ internal string ExecuteCommandAndGetResultAsString(string command, out Exception // we got back one or more objects. Pick off the first result. if (streamResults[0] == null) - return String.Empty; + return string.Empty; // And convert the base object into a string. We can't use the proxied // ToString() on the PSObject because there is no default runspace @@ -510,62 +517,48 @@ internal string ExecuteCommandAndGetResultAsString(string command, out Exception } /// - /// /// Executes a command (by calling this.ExecuteCommand), and coerces the first result object to a bool. Any Exception /// thrown in the course of execution is caught and ignored. - /// /// /// - /// /// The command to execute. May be any valid monad command. - /// /// /// - /// /// The Nullable`bool representation of the first result object returned, or null if an exception was thrown or no /// objects were returned by the command. - /// /// - internal Nullable ExecuteCommandAndGetResultAsBool(string command) + internal bool? ExecuteCommandAndGetResultAsBool(string command) { Exception unused = null; - Nullable result = ExecuteCommandAndGetResultAsBool(command, out unused); + bool? result = ExecuteCommandAndGetResultAsBool(command, out unused); return result; } /// - /// /// Executes a command (by calling this.ExecuteCommand), and coerces the first result object to a bool. Any Exception /// thrown in the course of execution is returned thru the exceptionThrown parameter. - /// /// /// - /// /// The command to execute. May be any valid monad command. - /// /// /// - /// /// Receives the Exception thrown by the execution of the command, if any. If no exception is thrown, then set to null. /// Can be tested to see if the execution was successful or not. - /// /// /// - /// /// The Nullable`bool representation of the first result object returned, or null if an exception was thrown or no /// objects were returned by the command. - /// /// - internal Nullable ExecuteCommandAndGetResultAsBool(string command, out Exception exceptionThrown) + internal bool? ExecuteCommandAndGetResultAsBool(string command, out Exception exceptionThrown) { exceptionThrown = null; - Dbg.Assert(!String.IsNullOrEmpty(command), "command should have a value"); + Dbg.Assert(!string.IsNullOrEmpty(command), "command should have a value"); - Nullable result = null; + bool? result = null; do { @@ -591,10 +584,8 @@ internal Nullable ExecuteCommandAndGetResultAsBool(string command, out Exc } /// - /// /// Cancels execution of the current instance. If the current instance is not running, then does nothing. Called in /// response to a break handler, by the static Executor.Cancel method. - /// /// private void Cancel() { @@ -640,9 +631,7 @@ internal void ResumeCommandOutput() } /// - /// /// Resets the instance to its post-ctor state. Does not cancel execution. - /// /// private void Reset() { @@ -654,18 +643,13 @@ private void Reset() } /// - /// /// Makes the given instance the "current" instance, that is, the instance that will receive a Cancel call if the break /// handler is triggered and calls the static Cancel method. - /// /// /// - /// /// The instance to make current. Null is allowed. - /// /// /// - /// /// Here are some state-transition cases to illustrate the use of CurrentExecutor /// /// null is current @@ -698,7 +682,6 @@ private void Reset() /// Summary: /// ExecuteCommand always saves/sets/restores CurrentExecutor /// Host.EnterNestedPrompt always saves/clears/restores CurrentExecutor - /// /// internal static Executor CurrentExecutor { @@ -713,6 +696,7 @@ internal static Executor CurrentExecutor return result; } + set { lock (s_staticStateLock) @@ -725,10 +709,8 @@ internal static Executor CurrentExecutor } /// - /// /// Cancels the execution of the current instance (the instance last passed to PushCurrentExecutor), if any. If no /// instance is Current, then does nothing. - /// /// internal static void CancelCurrentExecutor() { diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs index c8e233c20fbe..eb9b588d414e 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs @@ -1,26 +1,25 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Reflection; +using System.Globalization; using System.Management.Automation; using System.Management.Automation.Internal; using System.Management.Automation.Runspaces; using System.Management.Automation.Tracing; -using System.Globalization; -using System.Threading; +using System.Reflection; using System.Runtime.InteropServices; +using System.Threading; namespace Microsoft.PowerShell { /// - /// Defines an entry point from unmanaged code to managed Msh + /// Defines an entry point from unmanaged code to managed Msh. /// public sealed class UnmanagedPSEntry { /// - /// Starts managed MSH + /// Starts managed MSH. /// /// /// Deprecated: Console file used to create a runspace configuration to start MSH @@ -28,22 +27,20 @@ public sealed class UnmanagedPSEntry /// /// Command line arguments to the managed MSH /// -#pragma warning disable 1573 + /// public static int Start(string consoleFilePath, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)]string[] args, int argc) -#pragma warning restore 1573 { + // Warm up some components concurrently on background threads. System.Management.Automation.Runspaces.EarlyStartup.Init(); - // Set ETW activity Id - Guid activityId = EtwActivity.GetActivityId(); + // We need to read the settings file before we create the console host + Microsoft.PowerShell.CommandLineParameterParser.EarlyParse(args); - if (activityId == Guid.Empty) - { - EtwActivity.SetActivityId(EtwActivity.CreateActivityId()); - } - - PSEtwLog.LogOperationalInformation(PSEventId.Perftrack_ConsoleStartupStart, PSOpcode.WinStart, - PSTask.PowershellConsoleStartup, PSKeyword.UseAlwaysOperational); +#if !UNIX + // NOTE: On Unix, logging has to be deferred until after command-line parsing + // complete. On Windows, deferring the call is not needed. + PSEtwLog.LogConsoleStartup(); +#endif // Windows Vista and later support non-traditional UI fallback ie., a // user on an Arabic machine can choose either French or English(US) as @@ -56,17 +53,17 @@ public static int Start(string consoleFilePath, [MarshalAs(UnmanagedType.LPArray Thread.CurrentThread.CurrentCulture = NativeCultureResolver.Culture; #if DEBUG - if (args.Length > 0 && !String.IsNullOrEmpty(args[0]) && args[0].Equals("-isswait", StringComparison.OrdinalIgnoreCase)) + if (args.Length > 0 && !string.IsNullOrEmpty(args[0]) && args[0].Equals("-isswait", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("Attach the debugger to continue..."); - while (!System.Diagnostics.Debugger.IsAttached) { + while (!System.Diagnostics.Debugger.IsAttached) + { Thread.Sleep(100); } + System.Diagnostics.Debugger.Break(); } #endif - ConsoleHost.DefaultInitialSessionState = InitialSessionState.CreateDefault2(); - int exitCode = 0; try { @@ -74,7 +71,7 @@ public static int Start(string consoleFilePath, [MarshalAs(UnmanagedType.LPArray var formattedBanner = string.Format(CultureInfo.InvariantCulture, banner, PSVersionInfo.GitCommitId); exitCode = Microsoft.PowerShell.ConsoleShell.Start( formattedBanner, - ManagedEntranceStrings.ShellHelp, + ManagedEntranceStrings.UsageHelp, args); } catch (System.Management.Automation.Host.HostException e) @@ -91,12 +88,14 @@ public static int Start(string consoleFilePath, [MarshalAs(UnmanagedType.LPArray return exitCode; } } + System.Environment.FailFast(e.Message, e); } catch (Exception e) { System.Environment.FailFast(e.Message, e); } + return exitCode; } } diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs index c2be475e02c0..e0c2b011d4cf 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs @@ -1,8 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -12,11 +9,9 @@ using Dbg = System.Management.Automation.Diagnostics; - namespace Microsoft.PowerShell { /// - /// /// Represents all of the outstanding progress activities received by the host, and includes methods to update that state /// upon receipt of new ProgressRecords, and to render that state into an array of strings such that ProgressPane can /// display it. @@ -28,7 +23,6 @@ namespace Microsoft.PowerShell /// /// This class uses lots of nearly identical helper functions to recursively traverse the tree. If I weren't so pressed /// for time, I would see if generic methods could be used to collapse the number of traversers. - /// /// internal @@ -37,22 +31,16 @@ class PendingProgress #region Updating Code /// - /// /// Update the data structures that represent the outstanding progress records reported so far. - /// /// /// - /// /// Identifier of the source of the event. This is used as part of the "key" for matching newly received records with /// records that have already been received. For a record to match (meaning that they refer to the same activity), both /// the source and activity identifiers need to match. - /// /// /// - /// /// The ProgressRecord received that will either update the status of an activity which we are already tracking, or /// represent a new activity that we need to track. - /// /// internal @@ -84,6 +72,7 @@ class PendingProgress RemoveNodeAndPromoteChildren(listWhereFound, indexWhereFound); break; } + if (record.ParentActivityId == foundNode.ParentActivityId) { // record is an update to an existing activity. Copy the record data into the found node, and @@ -157,8 +146,6 @@ class PendingProgress AgeNodesAndResetStyle(); } - - private void EvictNode() @@ -183,21 +170,14 @@ class PendingProgress } } - /// - /// /// Removes a node from the tree. - /// /// /// - /// /// List in the tree from which the node is to be removed. - /// /// /// - /// /// Index into the list of the node to be removed. - /// /// private @@ -221,7 +201,6 @@ class PendingProgress #endif } - private void RemoveNodeAndPromoteChildren(ArrayList nodes, int indexToRemove) @@ -267,22 +246,14 @@ class PendingProgress } } - - /// - /// /// Adds a node to the tree, first removing the oldest node if the tree is too large. - /// /// /// - /// /// List in the tree where the node is to be added. - /// /// /// - /// /// Node to be added. - /// /// private @@ -298,8 +269,6 @@ class PendingProgress #endif } - - private class FindOldestNodeVisitor : NodeVisitor { @@ -318,30 +287,21 @@ internal override return true; } - - internal ProgressNode FoundNode; - - internal ArrayList ListWhereFound; - - internal int IndexWhereFound = -1; - private int _oldestSoFar; } - - private ProgressNode FindOldestLeafmostNodeHelper(ArrayList treeToSearch, out ArrayList listWhereFound, out int indexWhereFound) @@ -367,7 +327,6 @@ internal override return v.FoundNode; } - private ProgressNode FindOldestLeafmostNode(out ArrayList listWhereFound, out int indexWhereFound) @@ -394,12 +353,8 @@ internal override return result; } - - /// - /// /// Convenience overload. - /// /// private @@ -412,8 +367,6 @@ internal override FindNodeById(sourceId, activityId, out listWhereFound, out indexWhereFound); } - - private class FindByIdNodeVisitor : NodeVisitor { @@ -424,8 +377,6 @@ class FindByIdNodeVisitor : NodeVisitor _idToFind = activityIdToFind; } - - internal override bool Visit(ProgressNode node, ArrayList listWhereFound, int indexWhereFound) @@ -437,65 +388,44 @@ internal override this.IndexWhereFound = indexWhereFound; return false; } + return true; } - - internal ProgressNode FoundNode; - - internal ArrayList ListWhereFound; - - internal int IndexWhereFound = -1; - - private int _idToFind = -1; private Int64 _sourceIdToFind; } - - /// - /// /// Finds a node with a given ActivityId in provided set of nodes. Recursively walks the set of nodes and their children. - /// /// /// - /// /// Identifier of the source of the record. - /// /// /// - /// /// ActivityId to search for. - /// /// /// - /// /// Receives reference to the List where the found node was located, or null if no suitable node was found. - /// /// /// - /// /// Receives the index into listWhereFound that indicating where in the list the node was located, or -1 if /// no suitable node was found. - /// /// /// - /// /// The found node, or null if no suitable node was located. - /// /// private @@ -521,31 +451,19 @@ internal override return v.FoundNode; } - - /// - /// /// Finds the oldest node with a given rendering style that is at least as old as a given age. - /// /// /// - /// /// List of nodes to search. Child lists of each node in this list will also be searched. - /// /// /// - /// /// The minimum age of the node to be located. To find the oldest node, pass 0. - /// /// - /// /// The rendering style of the node to be located. - /// /// /// - /// /// The found node, or null if no suitable node was located. - /// /// private @@ -593,8 +511,6 @@ internal override return found; } - - private class AgeAndResetStyleVisitor : NodeVisitor { @@ -608,15 +524,11 @@ internal override } } - - /// - /// /// Increments the age of each of the nodes in the given list, and all their children. Also sets the rendering /// style of each node to "full." /// /// All nodes are aged every time a new ProgressRecord is received. - /// /// private @@ -627,41 +539,27 @@ internal override NodeVisitor.VisitNodes(_topLevelNodes, arsv); } - - #endregion // Updating Code #region Rendering Code - - /// - /// /// Generates an array of strings representing as much of the outstanding progress activities as possible within the given /// space. As more outstanding activities are collected, nodes are "compressed" (i.e. rendered in an increasing terse /// fashion) in order to display as many as possible. Ultimately, some nodes may be compressed to the point of /// invisibility. The oldest nodes are compressed first. - /// /// /// - /// /// The maximum width (in BufferCells) that the rendering may consume. - /// /// /// - /// /// The maximum height (in BufferCells) that the rendering may consume. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// /// - /// /// An array of strings containing the textual representation of the outstanding progress activities. - /// /// internal @@ -715,37 +613,23 @@ internal override return (string[])result.ToArray(typeof(string)); } - - /// - /// /// Helper function for Render(). Recursively renders nodes. - /// /// /// - /// /// The rendered strings so far. Additional rendering will be appended. - /// /// /// - /// /// The nodes to be rendered. All child nodes will also be rendered. - /// /// /// - /// /// The current indentation level (in BufferCells). - /// /// /// - /// /// The maximum number of BufferCells that the rendering can consume, horizontally. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// private @@ -777,8 +661,6 @@ internal override } } - - private class HeightTallyer : NodeVisitor { @@ -812,30 +694,19 @@ internal override } /// - /// /// Tallies up the number of BufferCells vertically that will be required to show all the ProgressNodes in the given /// list, and all of their children. - /// /// /// - /// /// The maximum height (in BufferCells) that the rendering may consume. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// /// - /// /// The vertical height (in BufferCells) that will be required to show all of the nodes in the given list. - /// /// /// - /// - /// - /// /// private int TallyHeight(PSHostRawUserInterface rawUi, int maxHeight, int maxWidth) @@ -845,13 +716,10 @@ private int TallyHeight(PSHostRawUserInterface rawUi, int maxHeight, int maxWidt return ht.Tally; } - #if DEBUG || ASSERTIONS_TRACE /// - /// /// Debugging code. Verifies that all of the nodes in the given list have the given style. - /// /// /// /// @@ -875,6 +743,7 @@ private int TallyHeight(PSHostRawUserInterface rawUi, int maxHeight, int maxWidt { return false; } + if (node.Children != null) { if (!AllNodesHaveGivenStyle(node.Children, style)) @@ -887,12 +756,8 @@ private int TallyHeight(PSHostRawUserInterface rawUi, int maxHeight, int maxWidt return true; } - - /// - /// /// Debugging code. NodeVisitor that counts up the number of nodes in the tree. - /// /// private @@ -912,17 +777,11 @@ internal override Count; } - - /// - /// /// Debugging code. Counts the number of nodes in the tree of nodes. - /// /// /// - /// /// The number of nodes in the tree. - /// /// private @@ -936,50 +795,33 @@ internal override #endif - /// - /// /// Helper function to CompressToFit. Considers compressing nodes from one level to another. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// /// - /// /// The maximum height (in BufferCells) that the rendering may consume. - /// /// /// - /// /// The maximum width (in BufferCells) that the rendering may consume. - /// /// /// - /// /// Receives the number of nodes that were compressed. If the result of the method is false, then this will be the total /// number of nodes being tracked (i.e. all of them will have been compressed). - /// /// /// - /// /// The rendering style (e.g. "compression level") that the nodes are expected to currently have. - /// /// /// - /// /// The new rendering style that a node will have when it is compressed. If the result of the method is false, then all /// nodes will have this rendering style. - /// /// /// - /// /// true to indicate that the nodes are compressed to the point that their rendering will fit within the constraint, or /// false to indicate that all of the nodes are compressed to a given level, but that the rendering still can't fit /// within the constraint. - /// /// private @@ -1030,10 +872,7 @@ internal override return false; } - - /// - /// /// "Compresses" the nodes representing the outstanding progress activities until their rendering will fit within a /// "given height, or until they are compressed to a given level. The oldest nodes are compressed first. /// @@ -1041,25 +880,17 @@ internal override /// tree and change their rendering style to a more compact style. As soon as the rendering of the nodes will fit within /// the maxHeight, we stop. The result is that the most recent nodes will be the least compressed, the idea being that /// the rendering should show the most recently updated activities with the most complete rendering for them possible. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// /// - /// /// The maximum height (in BufferCells) that the rendering may consume. - /// /// /// - /// /// The maximum width (in BufferCells) that the rendering may consume. - /// /// /// - /// /// The number of nodes that were made invisible during the compression. /// /// @@ -1130,42 +961,27 @@ internal override return 0; } - - - #endregion // Rendering Code #region Utility Code - - private abstract class NodeVisitor { /// - /// /// Called for each node in the tree. - /// /// /// - /// /// The node being visited. - /// /// /// - /// /// The list in which the node resides. - /// /// /// - /// /// The index into listWhereFound of the node. - /// /// /// - /// /// true to continue visiting nodes, false if not. - /// /// internal abstract @@ -1199,16 +1015,11 @@ internal static } } - #endregion - - private ArrayList _topLevelNodes = new ArrayList(); private int _nodeCount; private const int maxNodeCount = 128; } } // namespace - - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs index 159a1d5c78aa..c3965908bfb8 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs @@ -1,8 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -12,14 +9,11 @@ using Dbg = System.Management.Automation.Diagnostics; - namespace Microsoft.PowerShell { /// - /// /// ProgressNode is an augmentation of the ProgressRecord type that adds extra fields for the purposes of tracking /// outstanding activities received by the host, and rendering them in the console. - /// /// internal @@ -27,9 +21,7 @@ namespace Microsoft.PowerShell ProgressNode : ProgressRecord { /// - /// /// Indicates the various layouts for rendering a particular node. Each style is progressively less terse. - /// /// internal @@ -42,7 +34,7 @@ namespace Microsoft.PowerShell /// /// Allocate only one line for displaying the StatusDescription or the CurrentOperation, - /// truncate the rest if the StatusDescription or CurrentOperation doesn't fit in one line + /// truncate the rest if the StatusDescription or CurrentOperation doesn't fit in one line. /// Full = 3, @@ -52,12 +44,8 @@ namespace Microsoft.PowerShell FullPlus = 4, }; - - /// - /// /// Constructs an instance from a ProgressRecord. - /// /// internal @@ -76,33 +64,21 @@ namespace Microsoft.PowerShell this.SourceId = sourceId; } - - /// - /// /// Renders a single progress node as strings of text according to that node's style. The text is appended to the /// supplied list of strings. - /// /// /// - /// /// List of strings to which the node's rendering will be appended. - /// /// /// - /// /// The indentation level (in BufferCells) at which the node should be rendered. - /// /// /// - /// /// The maximum number of BufferCells that the rendering is allowed to consume. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// internal @@ -137,34 +113,22 @@ namespace Microsoft.PowerShell } /// - /// /// Renders a node in the "Full" style. - /// /// /// - /// /// List of strings to which the node's rendering will be appended. - /// /// /// - /// /// The indentation level (in BufferCells) at which the node should be rendered. - /// /// /// - /// /// The maximum number of BufferCells that the rendering is allowed to consume. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// /// - /// /// Indicate if the full StatusDescription and CurrentOperation should be displayed. - /// /// private @@ -233,7 +197,7 @@ namespace Microsoft.PowerShell // Fifth and Sixth lines: The current operation - if (!String.IsNullOrEmpty(CurrentOperation)) + if (!string.IsNullOrEmpty(CurrentOperation)) { strCollection.Add(" "); RenderFullDescription(this.CurrentOperation, indent, maxWidth, rawUI, strCollection, isFullPlus); @@ -262,29 +226,19 @@ private static void RenderFullDescription(string description, string indent, int } /// - /// /// Renders a node in the "Compact" style. - /// /// /// - /// /// List of strings to which the node's rendering will be appended. - /// /// /// - /// /// The indentation level (in BufferCells) at which the node should be rendered. - /// /// /// - /// /// The maximum number of BufferCells that the rendering is allowed to consume. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// private @@ -305,13 +259,13 @@ private static void RenderFullDescription(string description, string indent, int // Second line: the status description with percentage and time remaining, if applicable. - string percent = ""; + string percent = string.Empty; if (PercentComplete >= 0) { percent = StringUtil.Format("{0}% ", PercentComplete); } - string secRemain = ""; + string secRemain = string.Empty; if (SecondsRemaining >= 0) { TimeSpan span = new TimeSpan(0, 0, SecondsRemaining); @@ -331,7 +285,7 @@ private static void RenderFullDescription(string description, string indent, int // Third line: The current operation - if (!String.IsNullOrEmpty(CurrentOperation)) + if (!string.IsNullOrEmpty(CurrentOperation)) { strCollection.Add( StringUtil.TruncateToBufferCellWidth( @@ -340,32 +294,20 @@ private static void RenderFullDescription(string description, string indent, int } } - - /// - /// /// Renders a node in the "Minimal" style. - /// /// /// - /// /// List of strings to which the node's rendering will be appended. - /// /// /// - /// /// The indentation level (in BufferCells) at which the node should be rendered. - /// /// /// - /// /// The maximum number of BufferCells that the rendering is allowed to consume. - /// /// /// - /// /// The PSHostRawUserInterface used to gauge string widths in the rendering. - /// /// private @@ -376,13 +318,13 @@ private static void RenderFullDescription(string description, string indent, int // First line: Everything mushed into one line - string percent = ""; + string percent = string.Empty; if (PercentComplete >= 0) { percent = StringUtil.Format("{0}% ", PercentComplete); } - string secRemain = ""; + string secRemain = string.Empty; if (SecondsRemaining >= 0) { TimeSpan span = new TimeSpan(0, 0, SecondsRemaining); @@ -402,22 +344,15 @@ private static void RenderFullDescription(string description, string indent, int maxWidth)); } - - /// - /// /// The nodes that have this node as their parent. - /// /// internal ArrayList Children; - - /// - /// /// The "age" of the node. A node's age is incremented by PendingProgress.Update each time a new ProgressRecord is /// received by the host. A node's age is reset when a corresponding ProgressRecord is received. Thus, the age of /// a node reflects the number of ProgressRecord that have been received since the node was last updated. @@ -426,42 +361,30 @@ private static void RenderFullDescription(string description, string indent, int /// display has finite size, it may be possible to have many more outstanding progress activities than will fit in that /// space. The rendering of nodes can be progressively "compressed" into a more terse format, or not rendered at all in /// order to fit as many nodes as possible in the available space. The oldest nodes are compressed or skipped first. - /// /// internal int Age; - - /// - /// /// The style in which this node should be rendered. - /// /// internal RenderStyle Style = RenderStyle.FullPlus; - - /// - /// /// Identifies the source of the progress record. - /// /// internal Int64 SourceId; - /// - /// /// The number of vertical BufferCells that are required to render the node in its current style. - /// /// /// @@ -494,11 +417,8 @@ internal int LinesRequiredMethod(PSHostRawUserInterface rawUi, int maxWidth) return 0; } - /// - /// /// The number of vertical BufferCells that are required to render the node in the Full style. - /// /// /// @@ -531,11 +451,13 @@ private int LinesRequiredInFullStyleMethod(PSHostRawUserInterface rawUi, int max { ++lines; } + if (SecondsRemaining >= 0) { ++lines; } - if (!String.IsNullOrEmpty(CurrentOperation)) + + if (!string.IsNullOrEmpty(CurrentOperation)) { if (isFullPlus) { @@ -553,11 +475,8 @@ private int LinesRequiredInFullStyleMethod(PSHostRawUserInterface rawUi, int max return lines; } - /// - /// /// The number of vertical BufferCells that are required to render the node in the Compact style. - /// /// /// @@ -575,7 +494,7 @@ private int LinesRequiredInFullStyleMethod(PSHostRawUserInterface rawUi, int max // Start with 1 for the Activity, and 1 for the Status. int lines = 2; - if (!String.IsNullOrEmpty(CurrentOperation)) + if (!string.IsNullOrEmpty(CurrentOperation)) { ++lines; } @@ -586,4 +505,3 @@ private int LinesRequiredInFullStyleMethod(PSHostRawUserInterface rawUi, int max } } // namespace - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressPane.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressPane.cs index b1d20c83140f..e2f1bfeb850d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressPane.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressPane.cs @@ -1,19 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation.Host; using Dbg = System.Management.Automation.Diagnostics; - namespace Microsoft.PowerShell { /// - /// /// ProgressPane is a class that represents the "window" in which outstanding activities for which the host has received /// progress updates are shown. /// @@ -23,14 +18,10 @@ namespace Microsoft.PowerShell class ProgressPane { /// - /// /// Constructs a new instance. - /// /// /// - /// /// An implementation of the PSHostRawUserInterface with which the pane will be shown and hidden. - /// /// internal @@ -41,15 +32,10 @@ class ProgressPane _rawui = ui.RawUI; } - - /// - /// /// Indicates whether the pane is visible on the screen buffer or not. - /// /// /// - /// /// true if the pane is visible, false if not. /// /// @@ -64,13 +50,9 @@ class ProgressPane } } - - /// - /// /// Shows the pane in the screen buffer. Saves off the content of the region of the buffer that will be overwritten so /// that it can be restored again. - /// /// internal @@ -105,19 +87,24 @@ class ProgressPane _rawui.CursorPosition = _location; } - //if the cursor is at the bottom, create screen buffer space by scrolling + // if the cursor is at the bottom, create screen buffer space by scrolling int scrollRows = rows - ((_rawui.BufferSize.Height - 1) - _location.Y); - for (int i = 0; i < rows; i++) - { - Console.Out.Write('\n'); - } if (scrollRows > 0) { + // Scroll the console screen up by 'scrollRows' + var bottomLocation = _location; + bottomLocation.Y = _rawui.BufferSize.Height; + _rawui.CursorPosition = bottomLocation; + for (int i = 0; i < scrollRows; i++) + { + Console.Out.Write('\n'); + } + _location.Y -= scrollRows; _savedCursor.Y -= scrollRows; } - //create cleared region to clear progress bar later + // create cleared region to clear progress bar later _savedRegion = tempProgressRegion; for(int row = 0; row < rows; row++) { @@ -127,7 +114,7 @@ class ProgressPane } } - //put cursor back to where output should be + // put cursor back to where output should be _rawui.CursorPosition = _location; #else _location = _rawui.WindowPosition; @@ -149,13 +136,9 @@ class ProgressPane } } - - /// - /// /// Hides the pane by restoring the saved contents of the region of the buffer that the pane occupies. If the pane is /// not showing, then does nothing. - /// /// internal @@ -175,17 +158,11 @@ class ProgressPane } } - - /// - /// /// Updates the pane with the rendering of the supplied PendingProgress, and shows it. - /// /// /// - /// /// A PendingProgress instance that represents the outstanding activities that should be shown. - /// /// internal @@ -248,6 +225,7 @@ class ProgressPane { Hide(); } + Show(); } else @@ -257,8 +235,6 @@ class ProgressPane } } - - private Coordinates _location = new Coordinates(0, 0); private Coordinates _savedCursor; private Size _bufSize; @@ -269,6 +245,3 @@ class ProgressPane } } // namespace - - - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Serialization.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/Serialization.cs index 9eefb0e3b97b..e24823da6ccb 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Serialization.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/Serialization.cs @@ -1,63 +1,47 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.IO; using System.Management.Automation; using System.Xml; - using Dbg = System.Management.Automation.Diagnostics; - - namespace Microsoft.PowerShell { /// - /// /// Wraps Hitesh's xml serializer in such a way that it will select the proper serializer based on the data /// format. - /// /// internal class Serialization { /// - /// /// Describes the format of the data streamed between minishells, e.g. the allowed arguments to the minishell /// -outputformat and -inputformat command line parameters. - /// /// internal enum DataFormat { /// - /// - /// text format -- i.e. stream text just as out-default would display it. - /// + /// Text format -- i.e. stream text just as out-default would display it. /// Text = 0, /// - /// - /// XML-serialized format - /// + /// XML-serialized format. /// XML = 1, /// - /// /// Indicates that the data should be discarded instead of processed. - /// /// None = 2 } - - protected Serialization(DataFormat dataFormat, string streamName) { @@ -67,16 +51,12 @@ internal enum DataFormat this.streamName = streamName; } - - protected static string XmlCliTag = "#< CLIXML"; protected string streamName; protected DataFormat format; } - - internal class WrappedSerializer : Serialization { @@ -106,8 +86,6 @@ class WrappedSerializer : Serialization } } - - internal void Serialize(object o) @@ -129,6 +107,7 @@ class WrappedSerializer : Serialization _firstCall = false; textWriter.WriteLine(Serialization.XmlCliTag); } + _xmlSerializer.Serialize(o, streamName); break; case DataFormat.Text: @@ -138,7 +117,6 @@ class WrappedSerializer : Serialization } } - internal void End() @@ -162,15 +140,12 @@ class WrappedSerializer : Serialization } } - internal TextWriter textWriter; private XmlWriter _xmlWriter; private Serializer _xmlSerializer; private bool _firstCall = true; } - - internal class WrappedDeserializer : Serialization { @@ -187,7 +162,7 @@ class WrappedDeserializer : Serialization textReader = input; _firstLine = textReader.ReadLine(); - if (String.Compare(_firstLine, Serialization.XmlCliTag, StringComparison.OrdinalIgnoreCase) == 0) + if (string.Compare(_firstLine, Serialization.XmlCliTag, StringComparison.OrdinalIgnoreCase) == 0) { // format should be XML @@ -197,7 +172,7 @@ class WrappedDeserializer : Serialization switch (format) { case DataFormat.XML: - _xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { XmlResolver = null }); + _xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { XmlResolver = null }); _xmlDeserializer = new Deserializer(_xmlReader); break; case DataFormat.Text: @@ -208,8 +183,6 @@ class WrappedDeserializer : Serialization } } - - internal object Deserialize() @@ -232,6 +205,7 @@ class WrappedDeserializer : Serialization { return null; } + if (_firstLine != null) { o = _firstLine; @@ -245,13 +219,13 @@ class WrappedDeserializer : Serialization _atEnd = true; } } + break; } + return o; } - - internal bool AtEnd @@ -275,12 +249,11 @@ class WrappedDeserializer : Serialization result = _atEnd; break; } + return result; } } - - internal void End() @@ -297,7 +270,6 @@ class WrappedDeserializer : Serialization } } - internal TextReader textReader; private XmlReader _xmlReader; private Deserializer _xmlDeserializer; @@ -306,4 +278,3 @@ class WrappedDeserializer : Serialization } } // namespace - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/StartTranscriptCmdlet.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/StartTranscriptCmdlet.cs index 6739e770736e..ed602725cf27 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/StartTranscriptCmdlet.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/StartTranscriptCmdlet.cs @@ -1,8 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.ObjectModel; @@ -10,25 +7,20 @@ using System.Management.Automation; using System.Management.Automation.Internal; - namespace Microsoft.PowerShell.Commands { /// - /// - /// Implements the start-transcript cmdlet - /// + /// Implements the start-transcript cmdlet. /// [Cmdlet(VerbsLifecycle.Start, "Transcript", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113408")] - [OutputType(typeof(String))] + [OutputType(typeof(string))] public sealed class StartTranscriptCommand : PSCmdlet { /// - /// /// The name of the file in which to write the transcript. If not provided, the file indicated by the variable /// $TRANSCRIPT is used. If neither the filename is supplied or $TRANSCRIPT is not set, the filename shall be $HOME/My - /// Documents/PowerShell_transcript.YYYYMMDDmmss.txt - /// + /// Documents/PowerShell_transcript.YYYYMMDDmmss.txt. /// /// @@ -40,6 +32,7 @@ public string Path { return _outFilename; } + set { _isFilenameSet = true; @@ -51,7 +44,7 @@ public string Path /// The literal name of the file in which to write the transcript. /// [Parameter(Position = 0, ParameterSetName = "ByLiteralPath")] - [Alias("PSPath")] + [Alias("PSPath", "LP")] [ValidateNotNullOrEmpty] public string LiteralPath { @@ -59,6 +52,7 @@ public string LiteralPath { return _outFilename; } + set { _isFilenameSet = true; @@ -66,6 +60,7 @@ public string LiteralPath _isLiteralPath = true; } } + private bool _isLiteralPath = false; /// @@ -79,9 +74,7 @@ public string OutputDirectory } /// - /// /// Describes the current state of the activity. - /// /// /// @@ -92,6 +85,7 @@ public SwitchParameter Append { return _shouldAppend; } + set { _shouldAppend = value; @@ -113,11 +107,13 @@ public SwitchParameter Force { return _force; } + set { _force = value; } } + private bool _force; /// @@ -131,11 +127,13 @@ public SwitchParameter NoClobber { return _noclobber; } + set { _noclobber = value; } } + private bool _noclobber; /// @@ -147,10 +145,17 @@ public SwitchParameter IncludeInvocationHeader get; set; } + /// + /// Gets or sets whether to use minimal transcript header. + /// + [Parameter] + public SwitchParameter UseMinimalHeader + { + get; set; + } /// - /// - /// Starts the transcription + /// Starts the transcription. /// protected override void BeginProcessing() { @@ -209,13 +214,13 @@ protected override void BeginProcessing() // Save some disk write time by checking whether file is readonly.. if (Force) { - //Make sure the file is not read only + // Make sure the file is not read only // Note that we will not clear the ReadOnly flag later fInfo.Attributes &= ~(FileAttributes.ReadOnly); } else { - string errorMessage = String.Format( + string errorMessage = string.Format( System.Globalization.CultureInfo.CurrentCulture, TranscriptStrings.TranscriptFileReadOnly, effectiveFilePath); @@ -224,16 +229,16 @@ protected override void BeginProcessing() } } - // If they didn't specify -Append, delete the file + // If they didn't specify -Append, empty the file if (!_shouldAppend) { - System.IO.File.Delete(effectiveFilePath); + System.IO.File.WriteAllText(effectiveFilePath, string.Empty); } } System.Management.Automation.Remoting.PSSenderInfo psSenderInfo = this.SessionState.PSVariable.GetValue("PSSenderInfo") as System.Management.Automation.Remoting.PSSenderInfo; - Host.UI.StartTranscribing(effectiveFilePath, psSenderInfo, IncludeInvocationHeader.ToBool()); + Host.UI.StartTranscribing(effectiveFilePath, psSenderInfo, IncludeInvocationHeader.ToBool(), UseMinimalHeader.IsPresent); // ch.StartTranscribing(effectiveFilePath, Append); @@ -255,7 +260,7 @@ protected override void BeginProcessing() { } - string errorMessage = String.Format( + string errorMessage = string.Format( System.Globalization.CultureInfo.CurrentCulture, TranscriptStrings.CannotStartTranscription, e.Message); @@ -301,6 +306,7 @@ private string ResolveFilePath(string filePath, bool isLiteralPath) { path = null; } + if (string.IsNullOrEmpty(path)) { CmdletProviderContext cmdletProviderContext = new CmdletProviderContext(this); @@ -315,6 +321,7 @@ private string ResolveFilePath(string filePath, bool isLiteralPath) ReportWrongProviderType(provider.FullName); } } + return path; } @@ -344,5 +351,3 @@ private void ReportMultipleFilesNotSupported() } } - - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs index 8c058a5e7875..dd065963ec37 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs @@ -1,29 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; using System.Management.Automation.Internal; - namespace Microsoft.PowerShell.Commands { /// - /// - /// Implements the stop-transcript cmdlet - /// + /// Implements the stop-transcript cmdlet. /// [Cmdlet(VerbsLifecycle.Stop, "Transcript", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113415")] - [OutputType(typeof(String))] + [OutputType(typeof(string))] public sealed class StopTranscriptCommand : PSCmdlet { /// - /// - /// Starts the transcription + /// Starts the transcription. /// protected override @@ -49,6 +42,3 @@ protected override } } } - - - diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Telemetry.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/Telemetry.cs deleted file mode 100644 index 58987b322a36..000000000000 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Telemetry.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using Microsoft.ApplicationInsights; -using Microsoft.ApplicationInsights.DataContracts; -using Microsoft.ApplicationInsights.Extensibility; -using System.Management.Automation; -using System.Security.Cryptography; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.IO; - -namespace Microsoft.PowerShell -{ - /// - /// send up telemetry for startup - /// - internal static class ApplicationInsightsTelemetry - { - // The semaphore file which indicates whether telemetry should be sent - // This is temporary code waiting on the acceptance and implementation of the configuration spec - // The name of the file by when present in $PSHOME will enable telemetry. - // If this file is not present, no telemetry will be sent. - private const string TelemetrySemaphoreFilename = "DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY"; - - // The path to the semaphore file which enables telemetry - private static string TelemetrySemaphoreFilePath = Path.Combine( - Utils.DefaultPowerShellAppBase, - TelemetrySemaphoreFilename); - - // Telemetry client to be reused when we start sending more telemetry - private static TelemetryClient _telemetryClient = null; - - // Set this to true to reduce the latency of sending the telemetry - private static bool _developerMode = false; - - // PSCoreInsight2 telemetry key - private const string _psCoreTelemetryKey = "ee4b2115-d347-47b0-adb6-b19c2c763808"; - - static ApplicationInsightsTelemetry() - { - TelemetryConfiguration.Active.InstrumentationKey = _psCoreTelemetryKey; - TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = _developerMode; - } - - /// - /// Send the telemetry - /// - private static void SendTelemetry(string eventName, Dictionarypayload) - { - try - { - // if the semaphore file exists, try to send telemetry - if (Utils.NativeFileExists(TelemetrySemaphoreFilePath)) - { - if ( _telemetryClient == null ) - { - _telemetryClient = new TelemetryClient(); - } - _telemetryClient.TrackEvent(eventName, payload, null); - } - } - catch (Exception) - { - ; // Do nothing, telemetry can't be sent - } - } - - /// - /// Create the startup payload and send it up - /// - internal static void SendPSCoreStartupTelemetry() - { - var properties = new Dictionary(); - properties.Add("GitCommitID", PSVersionInfo.GitCommitId); - properties.Add("OSDescription", RuntimeInformation.OSDescription); - SendTelemetry("ConsoleHostStartup", properties); - } - } -} diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx index 7ad30993383d..0cbbd09f0eb8 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx @@ -186,7 +186,34 @@ Cannot process the command because -Configuration requires an argument that is a remote endpoint configuration name. Specify this argument and try again. + + Cannot process the command because -CustomPipeName requires an argument that is a name of the pipe you want to use. Specify this argument and try again. + + + Cannot process the command because -CustomPipeName specified is too long. Pipe names on this platform can be up to {0} characters long. Your pipe name '{1}' is {2} characters. + + + Cannot process the command because -SettingsFile requires an argument that is a file path. + + + Processing -SettingsFile '{0}' failed: {1}. Specify a valid path for the -SettingsFile parameter. + + + The argument '{0}' passed to the -SettingsFile does not exist. Provide the path to an existing json file as an argument to the -SettingsFile parameter. + Invalid argument '{0}', did you mean: + + Parameter -WindowStyle is not implemented on this platform. + + + Cannot process the command because -WorkingDirectory requires an argument that is a directory path. + + + Parameter -MTA is not supported on this platform. + + + Parameter -STA is not supported on this platform. + diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx index e7a3d10ec30e..7296bb30feb5 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx @@ -188,4 +188,7 @@ The current session does not support debugging; execution will continue. Loading personal and system profiles took {0}ms. + + Run as Administrator + diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx index 46e84767cb03..c82668c8eaea 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx @@ -121,121 +121,257 @@ PowerShell {0} Copyright (c) Microsoft Corporation. All rights reserved. -https://aka.ms/pscore6-docs +https://aka.ms/powershell Type 'help' to get help. - - Usage: pwsh[.exe] [[-File] <filePath> [args]] + + Warning: PowerShell detected that you might be using a screen reader and has disabled PSReadLine for compatibility purposes. If you want to re-enable it, run 'Import-Module PSReadLine'. + + + Usage: pwsh[.exe] [-Login] [[-File] <filePath> [args]] [-Command { - | <script-block> [-args <arg-array>] | <string> [<CommandParameters>] } ] - [-ConfigurationName <string>] [-EncodedCommand <Base64EncodedCommand>] + [-ConfigurationName <string>] [-CustomPipeName <string>] + [-EncodedCommand <Base64EncodedCommand>] [-ExecutionPolicy <ExecutionPolicy>] [-InputFormat {Text | XML}] - [-Interactive] [-NoExit] [-NoLogo] [-NonInteractive] [-NoProfile] - [-OutputFormat {Text | XML}] [-Version] [-WindowStyle <style>] + [-Interactive] [-MTA] [-NoExit] [-NoLogo] [-NonInteractive] [-NoProfile] + [-OutputFormat {Text | XML}] [-SettingsFile <filePath>] [-STA] [-Version] + [-WindowStyle <style>] [-WorkingDirectory <directoryPath>] pwsh[.exe] -h | -Help | -? | /? -PowerShell Online Help https://aka.ms/pscore6-docs +PowerShell Online Help https://aka.ms/powershell-docs + +All parameters are case-insensitive. + + + -All parameters are case-insensitive. +-File | -f + + If the value of File is "-", the command text is read from standard input. + Running "pwsh -File -" without redirected standard input starts a regular + session. This is the same as not specifying the File parameter at all. + + This is the default parameter if no parameters are present but values are + present in the command line. The specified script runs in the local scope + ("dot-sourced"), so that the functions and variables that the script + creates are available in the current session. Enter the script file path + and any parameters. File must be the last parameter in the command, because + all characters typed after the File parameter name are interpreted as the + script file path followed by the script parameters. + + Typically, the switch parameters of a script are either included or + omitted. For example, the following command uses the All parameter of the + Get-Script.ps1 script file: "-File .\Get-Script.ps1 -All" + + In rare cases, you might need to provide a Boolean value for a switch + parameter. To provide a Boolean value for a switch parameter in the value + of the File parameter, enclose the parameter name and value in curly + braces, such as the following: "-File .\Get-Script.ps1 {-All:$False}." + + Parameters passed to the script are passed as literal strings, after + interpretation by the current shell. For example, if you are in cmd.exe and + want to pass an environment variable value, you would use the cmd.exe + syntax: "pwsh -File .\test.ps1 -TestParam %windir%" + + In contrast, running "pwsh -File .\test.ps1 -TestParam $env:windir" in + cmd.exe results in the script receiving the literal string "$env:windir" + because it has no special meaning to the current cmd.exe shell. The + "$env:windir" style of environment variable reference can be used inside a + Command parameter, since there it will be interpreted as PowerShell code. -Command | -c - Executes the specified commands (and any parameters) as though they were typed - at the PowerShell command prompt, and then exits, unless NoExit is specified. - The value of Command can be "-", a string. or a script block. - If the value of Command is "-", the command text is read from standard input. + Executes the specified commands (and any parameters) as though they were + typed at the PowerShell command prompt, and then exits, unless the NoExit + parameter is specified. - If the value of Command is a script block, the script block must be enclosed - in braces ({}). You can specify a script block only when running 'pwsh' - in a PowerShell session. The results of the script block are returned to the - parent shell as deserialized XML objects, not live objects. + The value of Command can be "-", a script block, or a string. If the value + of Command is "-", the command text is read from standard input. - If the value of Command is a string, Command must be the last parameter in the command, - because any characters typed after the command are interpreted as the command arguments. + The Command parameter only accepts a script block for execution when it can + recognize the value passed to Command as a ScriptBlock type. This is only + possible when running pwsh from another PowerShell host. The ScriptBlock + type may be contained in an existing variable, returned from an expression, + or parsed by the PowerShell host as a literal script block enclosed in + curly braces "{}", before being passed to pwsh. - To write a string that runs a PowerShell command, use the format: - "& {<command>}" - where the quotation marks indicate a string and the invoke operator (&) - causes the command to be executed. - Example: - pwsh -Command {Get-WinEvent -LogName security} - pwsh -command "& {Get-WinEvent -LogName security}" + pwsh -Command {Get-WinEvent -LogName security} + + In cmd.exe, there is no such thing as a script block (or ScriptBlock type), + so the value passed to Command will always be a string. You can write a + script block inside the string, but instead of being executed it will + behave exactly as though you typed it at a typical PowerShell prompt, + printing the contents of the script block back out to you. + + A string passed to Command will still be executed as PowerShell, so the + script block curly braces are often not required in the first place when + running from cmd.exe. To execute an inline script block defined inside a + string, the call operator "&" can be used: + + pwsh -Command "& {Get-WinEvent -LogName security}" + + If the value of Command is a string, Command must be the last parameter for + pwsh, because all arguments following it are interpreted as part of the + command to execute. + + The results are returned to the parent shell as deserialized XML objects, + not live objects. + + If the value of Command is "-", the command text is read from standard + input. You must redirect standard input when using the Command parameter + with standard input. For example: + + + @' + "in" + + "hi" | + % { "$_ there" } + + "out" + '@ | powershell -NoProfile -Command - + + This example produces the following output: + + """Output + in + hi there + out -ConfigurationName | -config - Specifies a configuration endpoint in which PowerShell is run. - This can be any endpoint registered on the local machine including the default PowerShell - remoting endpoints or a custom endpoint having specific user role capabilities. - Example: pwsh -configurationmame AdminRoles + Specifies a configuration endpoint in which PowerShell is run. This can be + any endpoint registered on the local machine including the default + PowerShell remoting endpoints or a custom endpoint having specific user + role capabilities. + + Example: "pwsh -ConfigurationName AdminRoles" + +-CustomPipeName + + Specifies the name to use for an additional IPC server (named pipe) used + for debugging and other cross-process communication. This offers a + predictable mechanism for connecting to other PowerShell instances. + Typically used with the CustomPipeName parameter on "Enter-PSHostProcess". + + For example: + + + # PowerShell instance 1 + pwsh -CustomPipeName mydebugpipe + # PowerShell instance 2 + Enter-PSHostProcess -CustomPipeName mydebugpipe -EncodedCommand | -e | -ec - Accepts a base64 encoded string version of a command. Use this parameter to submit - commands to PowerShell that require complex quotation marks or curly braces. - Example: - $command = 'dir "c:\program files" ' - $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) - $encodedCommand = [Convert]::ToBase64String($bytes) - pwsh -encodedcommand $encodedCommand + Accepts a base64-encoded string version of a command. Use this parameter to + submit commands to PowerShell that require complex quotation marks or curly + braces. The string must be formatted using UTF-16 character encoding. --ExecutionPolicy | -ex | -ep - Sets the default execution policy for the current session and saves it - in the $env:PSExecutionPolicyPreference environment variable. - This parameter does not change the PowerShell execution policy - that is set in the registry. + For example: - Example: pwsh -ExecutionPolicy RemoteSigned --File | -f - Default parameter if no parameters is present but any values is present in the command line. - Runs the specified script in the local scope ("dot-sourced"), so that the functions - and variables that the script creates are available in the current session. - Enter the script file path and any parameters. File must be the last parameter - in the command, because all characters typed after the File parameter name are interpreted - as the script file path followed by the script parameters. + $command = 'dir "c:\program files" ' + $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) + $encodedCommand = [Convert]::ToBase64String($bytes) + pwsh -encodedcommand $encodedCommand - Example: pwsh HelloWorld.ps1 +-ExecutionPolicy | -ex | -ep --Help | -h | -? | /? - Shows this help message. + Sets the default execution policy for the current session and saves it in + the "$env:PSExecutionPolicyPreference" environment variable. This parameter + does not change the PowerShell execution policy that is set in the + registry. -InputFormat | -in | -if - Describes the format of data sent to PowerShell. - Valid values are "Text" (text strings) or "XML" (serialized CLIXML format). + + Describes the format of data sent to PowerShell. Valid values are "Text" + (text strings) or "XML" (serialized CLIXML format). -Interactive | -i - Present an interactive prompt to the user. Inverse for NonInteractive parameter. + + Present an interactive prompt to the user. Inverse for NonInteractive + parameter. + +-Login | -l + + On Linux and macOS, starts PowerShell as a login shell, + using /bin/sh to execute login profiles such as /etc/profile and ~/.profile. + On Windows, this switch does nothing. + + Note that "-Login" is only supported as the first parameter to pwsh. + +-MTA + + Start the shell using a multi-threaded apartment. + Only available on Windows. -NoExit | -noe + Does not exit after running startup commands. - Example: pwsh -NoExit -Command Get-Date + Example: "pwsh -NoExit -Command Get-Date" -NoLogo | -nol - Hides the copyright banner at startup. + +Hides the copyright banner at startup. -NonInteractive | -noni - Does not present an interactive prompt to the user. Inverse for Interactive parameter. + + Does not present an interactive prompt to the user. -NoProfile | -nop - Does not load the PowerShell profiles. + + Does not load the PowerShell profile. -OutputFormat | -o | -of - Determines how output from PowerShell is formatted. Valid values - are "Text" (text strings) or "XML" (serialized CLIXML format). - Default is "Text". - Example: pwsh -o XML -c Get-Date + Determines how output from PowerShell is formatted. Valid values are "Text" + (text strings) or "XML" (serialized CLIXML format). + + Example: "pwsh -o XML -c Get-Date" + +-SettingsFile | -settings + + Overrides the system-wide "powershell.config.json" settings file for the + session. By default, system-wide settings are read from the + "powershell.config.json" in the "$PSHOME" directory. + + Note that these settings are not used by the endpoint specified by the + "-ConfigurationName" argument. + + Example: "pwsh -SettingsFile c:\myproject\powershell.config.json" + +-STA + + Start the shell using a single-threaded apartment. This is the default. + Only available on Windows. -Version | -v - Shows the version of PowerShell and exits. Additional arguments are ignored. - Example: pwsh -v + Displays the version of PowerShell. Additional parameters are ignored. -WindowStyle | -w - Sets the window style to Normal, Minimized, Maximized or Hidden. + + Sets the window style for the session. Valid values are Normal, Minimized, + Maximized and Hidden. + +-WorkingDirectory | -wd + + Sets the initial working directory by executing + "Set-Location -LiteralPath <path>" at startup. Any valid PowerShell file + path is supported. + + To start PowerShell in your home directory, use: "pwsh -WorkingDirectory ~" + +-Help, -?, /? + + Displays help for pwsh. If you are typing a pwsh command in PowerShell, + prepend the command parameters with a hyphen (-), not a forward slash (/). + You can use either a hyphen or forward slash in Cmd.exe. diff --git a/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/EngineInstaller.cs b/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/EngineInstaller.cs index d768faabd923..19fb671ae9b6 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/EngineInstaller.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/EngineInstaller.cs @@ -1,18 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.ComponentModel; -using System.Reflection; using System.IO; using System.Management.Automation; +using System.Reflection; namespace Microsoft.PowerShell { /// - /// /// EngineInstaller is a class for facilitating registry of necessary /// information for monad engine. /// @@ -26,13 +24,12 @@ namespace Microsoft.PowerShell /// This class derives from base class PSInstaller. PSInstaller will /// handle the details about how information got written into registry. /// Here, the information about registry content is provided. - /// /// [RunInstaller(true)] public sealed class EngineInstaller : PSInstaller { /// - /// Constructor + /// Constructor. /// public EngineInstaller() : base() @@ -40,7 +37,6 @@ public EngineInstaller() } /// - /// /// internal sealed override string RegKey { @@ -60,7 +56,6 @@ private static string EngineVersion private Dictionary _regValues = null; /// - /// /// internal sealed override Dictionary RegValues { diff --git a/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/MshHostMshSnapin.cs b/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/MshHostMshSnapin.cs index 62d6c4c25b11..f06bd4e0b64d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/MshHostMshSnapin.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/singleshell/installer/MshHostMshSnapin.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System.ComponentModel; using System.Management.Automation; @@ -8,15 +7,12 @@ namespace Microsoft.PowerShell { /// - /// /// PSHostMshSnapin (or PSHostMshSnapinInstaller) is a class for facilitating registry /// of necessary information for monad host mshsnapin. /// /// This class will be built with monad host engine dll /// (Microsoft.PowerShell.ConsoleHost.dll). - /// /// - /// [RunInstaller(true)] public sealed class PSHostPSSnapIn : PSSnapIn { diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/AssemblyInfo.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/AssemblyInfo.cs index a504b27b2861..e007c82fc81c 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/AssemblyInfo.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/AssemblyInfo.cs @@ -1,3 +1,6 @@ -using System.Runtime.CompilerServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System.Reflection; +using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("System.Management.Automation,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventDescriptor.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventDescriptor.cs index 36244513e78a..0dd474169d99 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventDescriptor.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventDescriptor.cs @@ -1,12 +1,9 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; -using System.Diagnostics.CodeAnalysis; namespace System.Diagnostics.Eventing { @@ -92,6 +89,7 @@ public byte Channel return _channel; } } + public byte Level { get diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProvider.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProvider.cs index b628b885f10b..90d1b51be9fe 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProvider.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProvider.cs @@ -1,15 +1,12 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; -using System.ComponentModel; -using System.Threading; using System.Security; -using System.Diagnostics.CodeAnalysis; +using System.Threading; namespace System.Diagnostics.Eventing { @@ -40,7 +37,7 @@ public class EventProvider : IDisposable [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] public enum WriteEventErrorCode : int { - //check mapping to runtime codes + // check mapping to runtime codes NoError = 0, NoFreeBuffers = 1, EventTooBig = 2 @@ -149,7 +146,6 @@ protected virtual void Dispose(bool disposing) /// /// This method deregisters the controlGuid of this class with ETW. - /// /// public virtual void Close() { @@ -198,7 +194,7 @@ private unsafe void Deregister() } /// - /// IsEnabled, method used to test if provider is enabled + /// IsEnabled, method used to test if provider is enabled. /// public bool IsEnabled() { @@ -206,7 +202,7 @@ public bool IsEnabled() } /// - /// IsEnabled, method used to test if event is enabled + /// IsEnabled, method used to test if event is enabled. /// /// /// Level to test @@ -266,7 +262,6 @@ private static void SetLastError(int error) } } - [System.Security.SecurityCritical] private static unsafe string EncodeObject(ref object data, EventData* dataDescriptor, byte* dataBuffer) /*++ @@ -411,14 +406,14 @@ private static unsafe string EncodeObject(ref object data, EventData* dataDescri } else if (data is Boolean) { - dataDescriptor->Size = (uint)sizeof(Boolean); + dataDescriptor->Size = (uint)sizeof(bool); Boolean* booleanptr = (Boolean*)dataBuffer; - *booleanptr = (Boolean)data; + *booleanptr = (bool)data; dataDescriptor->DataPointer = (ulong)booleanptr; } else { - //To our eyes, everything else is a just a string + // To our eyes, everything else is a just a string sRet = data.ToString(); dataDescriptor->Size = (uint)((sRet.Length + 1) * 2); return sRet; @@ -427,7 +422,6 @@ private static unsafe string EncodeObject(ref object data, EventData* dataDescri return null; } - /// /// WriteMessageEvent, method to write a string with level and Keyword. /// The activity ID will be propagated only if the call stays on the same native thread as SetActivityId(). @@ -458,6 +452,7 @@ public bool WriteMessageEvent(string eventMessage, byte eventLevel, long eventKe t_returnCode = WriteEventErrorCode.EventTooBig; return false; } + unsafe { fixed (char* pdata = eventMessage) @@ -472,6 +467,7 @@ public bool WriteMessageEvent(string eventMessage, byte eventLevel, long eventKe } } } + return true; } @@ -487,9 +483,8 @@ public bool WriteMessageEvent(string eventMessage) return WriteMessageEvent(eventMessage, 0, 0); } - /// - /// WriteEvent method to write parameters with event schema properties + /// WriteEvent method to write parameters with event schema properties. /// /// /// Event Descriptor for this event. @@ -502,7 +497,7 @@ public bool WriteEvent(ref EventDescriptor eventDescriptor, params object[] even } /// - /// WriteEvent, method to write a string with event schema properties + /// WriteEvent, method to write a string with event schema properties. /// /// /// Event Descriptor for this event. @@ -556,11 +551,12 @@ public bool WriteEvent(ref EventDescriptor eventDescriptor, string data) SetLastError((int)status); return false; } + return true; } /// - /// WriteEvent, method to be used by generated code on a derived class + /// WriteEvent, method to be used by generated code on a derived class. /// /// /// Event Descriptor for this event. @@ -594,12 +590,12 @@ protected bool WriteEvent(ref EventDescriptor eventDescriptor, int dataCount, In SetLastError((int)status); return false; } + return true; } - /// - /// WriteTransferEvent, method to write a parameters with event schema properties + /// WriteTransferEvent, method to write a parameters with event schema properties. /// /// /// Event Descriptor for this event. @@ -628,7 +624,7 @@ public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, Guid related if (argCount > s_etwMaxNumberArguments) { // - //too many arguments to log + // too many arguments to log // throw new ArgumentOutOfRangeException("eventPayload", string.Format(CultureInfo.CurrentCulture, DotNetEventingStrings.ArgumentOutOfRange_MaxArgExceeded, s_etwMaxNumberArguments)); @@ -637,7 +633,7 @@ public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, Guid related uint totalEventSize = 0; int index; int stringIndex = 0; - int[] stringPosition = new int[s_etwAPIMaxStringCount]; //used to keep the position of strings in the eventPayload parameter + int[] stringPosition = new int[s_etwAPIMaxStringCount]; // used to keep the position of strings in the eventPayload parameter string[] dataString = new string[s_etwAPIMaxStringCount]; // string arrays from the eventPayload parameter EventData* userData = stackalloc EventData[argCount]; // allocation for the data descriptors userDataPtr = (EventData*)userData; @@ -687,30 +683,37 @@ public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, Guid related { userDataPtr[stringPosition[0]].DataPointer = (ulong)v0; } + if (dataString[1] != null) { userDataPtr[stringPosition[1]].DataPointer = (ulong)v1; } + if (dataString[2] != null) { userDataPtr[stringPosition[2]].DataPointer = (ulong)v2; } + if (dataString[3] != null) { userDataPtr[stringPosition[3]].DataPointer = (ulong)v3; } + if (dataString[4] != null) { userDataPtr[stringPosition[4]].DataPointer = (ulong)v4; } + if (dataString[5] != null) { userDataPtr[stringPosition[5]].DataPointer = (ulong)v5; } + if (dataString[6] != null) { userDataPtr[stringPosition[6]].DataPointer = (ulong)v6; } + if (dataString[7] != null) { userDataPtr[stringPosition[7]].DataPointer = (ulong)v7; @@ -732,6 +735,7 @@ public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, Guid related SetLastError((int)status); return false; } + return true; } @@ -758,6 +762,7 @@ protected bool WriteTransferEvent(ref EventDescriptor eventDescriptor, Guid rela SetLastError((int)status); return false; } + return true; } @@ -767,7 +772,6 @@ private static Guid GetActivityId() return t_activityId; } - [System.Security.SecurityCritical] public static void SetActivityId(ref Guid id) { diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProviderTraceListener.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProviderTraceListener.cs index f692701cbc93..45927d2c076c 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProviderTraceListener.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/EventProviderTraceListener.cs @@ -1,12 +1,9 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. -using System.Text; -using System.Globalization; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Text; namespace System.Diagnostics.Eventing { @@ -164,7 +161,7 @@ public sealed override void TraceData(TraceEventCache eventCache, string source, (long)eventType & s_keyWordMask); } - public sealed override void TraceData(TraceEventCache eventCache, String source, TraceEventType eventType, int id, params object[] data) + public sealed override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data) { if (!_provider.IsEnabled()) { @@ -225,7 +222,7 @@ public sealed override void TraceEvent(TraceEventCache eventCache, string source return; } - _provider.WriteMessageEvent(String.Empty, + _provider.WriteMessageEvent(string.Empty, (byte)eventType, (long)eventType & s_keyWordMask); } @@ -270,7 +267,7 @@ public sealed override void TraceEvent(TraceEventCache eventCache, string source } else { - _provider.WriteMessageEvent(String.Format(CultureInfo.InvariantCulture, format, args), + _provider.WriteMessageEvent(string.Format(CultureInfo.InvariantCulture, format, args), (byte)eventType, (long)eventType & s_keyWordMask); } diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemSafeHandle.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemSafeHandle.cs index 120738c142e1..71be5f4ca3ea 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemSafeHandle.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemSafeHandle.cs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. /*============================================================ ** @@ -34,7 +36,6 @@ internal IntPtr GetMemory() return handle; } - public override bool IsInvalid { get diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemUnicodeSafeHandle.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemUnicodeSafeHandle.cs index eecfcb274e57..6e7694949a67 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemUnicodeSafeHandle.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/CoTaskMemUnicodeSafeHandle.cs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. /*============================================================ ** @@ -40,7 +42,6 @@ internal IntPtr GetMemory() return handle; } - public override bool IsInvalid { get diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventBookmark.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventBookmark.cs deleted file mode 100644 index 8b700059f051..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventBookmark.cs +++ /dev/null @@ -1,42 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class represents an opaque Event Bookmark obtained -** from an EventRecord. The bookmark denotes a unique identifier -** for the event instance as well as marks the location in the -** the result set of the EventReader that the event instance was -** obtained from. -** -============================================================*/ - -namespace System.Diagnostics.Eventing.Reader -{ - // - // NOTE: This class must be generic enough to be used across - // eventing base implementations. Cannot add anything - // that ties it to one particular implementation. - // - - /// - /// Represents an opaque Event Bookmark obtained from an EventRecord. - /// The bookmark denotes a unique identifier for the event instance as - /// well as marks the location in the the result set of the EventReader - /// that the event instance was obtained from. - /// - public class EventBookmark - { - private string _bookmark; - - internal EventBookmark(string bookmarkText) - { - if (bookmarkText == null) - throw new ArgumentNullException("bookmarkText"); - _bookmark = bookmarkText; - } - - internal string BookmarkText { get { return _bookmark; } } - } -} - diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventKeyword.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventKeyword.cs deleted file mode 100644 index 435556b01480..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventKeyword.cs +++ /dev/null @@ -1,99 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes the metadata for a specific Keyword -** defined by a Provider. An instance of this class is obtained from -** a ProviderMetadata object. -** -============================================================*/ - -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Describes the metadata for a specific Keyword defined by a Provider. - /// An instance of this class is obtained from a ProviderMetadata object. - /// - public sealed class EventKeyword - { - private long _value; - private string _name; - private string _displayName; - private bool _dataReady; - private ProviderMetadata _pmReference; - private object _syncObject; - - //called from EventMetadata - internal EventKeyword(long value, ProviderMetadata pmReference) - { - _value = value; - _pmReference = pmReference; - _syncObject = new object(); - } - - //called from ProviderMetadata - internal EventKeyword(string name, long value, string displayName) - { - _value = value; - _name = name; - _displayName = displayName; - _dataReady = true; - _syncObject = new object(); - } - - internal void PrepareData() - { - if (_dataReady == true) return; - - lock (_syncObject) - { - if (_dataReady == true) return; - - IEnumerable result = _pmReference.Keywords; - - _name = null; - _displayName = null; - _dataReady = true; - - foreach (EventKeyword key in result) - { - if (key.Value == _value) - { - _name = key.Name; - _displayName = key.DisplayName; - break; - } - } - } - } - - public string Name - { - get - { - PrepareData(); - return _name; - } - } - - public long Value - { - get - { - return _value; - } - } - - public string DisplayName - { - get - { - PrepareData(); - return _displayName; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLevel.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLevel.cs deleted file mode 100644 index 909f18f5ad01..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLevel.cs +++ /dev/null @@ -1,97 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes the metadata for a specific Level -** defined by a Provider. An instance of this class is obtained from -** a ProviderMetadata object. -** -============================================================*/ - -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Describes the metadata for a specific Level defined by a Provider. - /// An instance of this class is obtained from a ProviderMetadata object. - /// - public sealed class EventLevel - { - private int _value; - private string _name; - private string _displayName; - private bool _dataReady; - private ProviderMetadata _pmReference; - private object _syncObject; - - //called from EventMetadata - internal EventLevel(int value, ProviderMetadata pmReference) - { - _value = value; - _pmReference = pmReference; - _syncObject = new object(); - } - - //called from ProviderMetadata - internal EventLevel(string name, int value, string displayName) - { - _value = value; - _name = name; - _displayName = displayName; - _dataReady = true; - _syncObject = new object(); - } - - internal void PrepareData() - { - if (_dataReady == true) return; - - lock (_syncObject) - { - if (_dataReady == true) return; - - IEnumerable result = _pmReference.Levels; - _name = null; - _displayName = null; - _dataReady = true; - foreach (EventLevel lev in result) - { - if (lev.Value == _value) - { - _name = lev.Name; - _displayName = lev.DisplayName; - break; - } - } - } - } - - public string Name - { - get - { - PrepareData(); - return _name; - } - } - - public int Value - { - get - { - return _value; - } - } - - public string DisplayName - { - get - { - PrepareData(); - return _displayName; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogConfiguration.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogConfiguration.cs deleted file mode 100644 index 88a9942df0ef..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogConfiguration.cs +++ /dev/null @@ -1,295 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class allows accessing static channel information and -** configures channel publishing and logging properties. An instance -** of this class is obtained from EventLogManagement class. -** -============================================================*/ - -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Log Type - /// - public enum EventLogType - { - Administrative = 0, - Operational, - Analytical, - Debug - } - - /// - /// Log Isolation - /// - public enum EventLogIsolation - { - Application = 0, - System, - Custom - } - - /// - /// Log Mode - /// - public enum EventLogMode - { - Circular = 0, - AutoBackup, - Retain - } - - /// - /// Provides access to static log information and configures - /// log publishing and log file properties. - /// - public class EventLogConfiguration : IDisposable - { - // - // access to the data member reference is safe, while - // invoking methods on it is marked SecurityCritical as appropriate. - // - private EventLogHandle _handle = EventLogHandle.Zero; - - private EventLogSession _session = null; - private string _channelName; - - public EventLogConfiguration(string logName) : this(logName, null) { } - - // marked as SecurityCritical because allocates SafeHandles. - // marked as Safe because performs Demand check. - [System.Security.SecurityCritical] - public EventLogConfiguration(string logName, EventLogSession session) - { - if (session == null) - session = EventLogSession.GlobalSession; - - _session = session; - _channelName = logName; - - _handle = NativeWrapper.EvtOpenChannelConfig(_session.Handle, _channelName, 0); - } - - public string LogName - { - get - { - return _channelName; - } - } - - public EventLogType LogType - { - get - { - return (EventLogType)((uint)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigType)); - } - } - - public EventLogIsolation LogIsolation - { - get - { - return (EventLogIsolation)((uint)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigIsolation)); - } - } - - public bool IsEnabled - { - get - { - return (bool)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigEnabled); - } - set - { - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigEnabled, (object)value); - } - } - - public bool IsClassicLog - { - get - { - return (bool)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigClassicEventlog); - } - } - - public string SecurityDescriptor - { - get - { - return (string)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess); - } - set - { - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess, (object)value); - } - } - - public string LogFilePath - { - get - { - return (string)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath); - } - set - { - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath, (object)value); - } - } - - public long MaximumSizeInBytes - { - get - { - return (long)((ulong)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize)); - } - set - { - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize, (object)value); - } - } - - public EventLogMode LogMode - { - get - { - object nativeRetentionObject = NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention); - object nativeAutoBackupObject = NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup); - - bool nativeRetention = nativeRetentionObject == null ? false : (bool)nativeRetentionObject; - bool nativeAutoBackup = nativeAutoBackupObject == null ? false : (bool)nativeAutoBackupObject; - - if (nativeAutoBackup) - return EventLogMode.AutoBackup; - - if (nativeRetention) - return EventLogMode.Retain; - - return EventLogMode.Circular; - } - set - { - switch (value) - { - case EventLogMode.Circular: - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, (object)false); - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, (object)false); - break; - case EventLogMode.AutoBackup: - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, (object)true); - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, (object)true); - break; - case EventLogMode.Retain: - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, (object)false); - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, (object)true); - break; - } - } - } - - public string OwningProviderName - { - get - { - return (string)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigOwningPublisher); - } - } - - public IEnumerable ProviderNames - { - get - { - return (string[])NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublisherList); - } - } - - public int? ProviderLevel - { - get - { - return (int?)((uint?)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel)); - } - set - { - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel, (object)value); - } - } - - public long? ProviderKeywords - { - get - { - return (long?)((ulong?)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords)); - } - set - { - NativeWrapper.EvtSetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords, (object)value); - } - } - - public int? ProviderBufferSize - { - get - { - return (int?)((uint?)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigBufferSize)); - } - } - - public int? ProviderMinimumNumberOfBuffers - { - get - { - return (int?)((uint?)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigMinBuffers)); - } - } - - public int? ProviderMaximumNumberOfBuffers - { - get - { - return (int?)((uint?)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigMaxBuffers)); - } - } - - public int? ProviderLatency - { - get - { - return (int?)((uint?)NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLatency)); - } - } - - public Guid? ProviderControlGuid - { - get - { - return (Guid?)(NativeWrapper.EvtGetChannelConfigProperty(_handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigControlGuid)); - } - } - - public void SaveChanges() - { - NativeWrapper.EvtSaveChannelConfig(_handle, 0); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - - [System.Security.SecuritySafeCritical] - protected virtual void Dispose(bool disposing) - { - if (_handle != null && !_handle.IsInvalid) - _handle.Dispose(); - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogException.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogException.cs deleted file mode 100644 index 14010a4bdb4d..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogException.cs +++ /dev/null @@ -1,119 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes an exception thrown from Event -** Log related classes. -** -============================================================*/ - -using System.ComponentModel; - -namespace System.Diagnostics.Eventing.Reader -{ - public class EventLogException : Exception - { - internal static void Throw(int errorCode) - { - switch (errorCode) - { - case 2: - case 3: - case 15007: - case 15027: - case 15028: - case 15002: - throw new EventLogNotFoundException(errorCode); - - case 13: - case 15005: - throw new EventLogInvalidDataException(errorCode); - - case 1818: // RPC_S_CALL_CANCELED is converted to ERROR_CANCELLED - case 1223: - throw new OperationCanceledException(); - - case 15037: - throw new EventLogProviderDisabledException(errorCode); - - case 5: - throw new UnauthorizedAccessException(); - - case 15011: - case 15012: - throw new EventLogReadingException(errorCode); - - default: throw new EventLogException(errorCode); - } - } - - public EventLogException() { } - public EventLogException(string message) : base(message) { } - public EventLogException(string message, Exception innerException) : base(message, innerException) { } - protected EventLogException(int errorCode) { _errorCode = errorCode; } - - public override string Message - { - // marked as SecurityCritical because it uses Win32Exception. - // marked as TreatAsSafe because it performs Demand. - [System.Security.SecurityCritical] - get - { - Win32Exception win32Exception = new Win32Exception(_errorCode); - return win32Exception.Message; - } - } - - private int _errorCode; - } - - /// - /// The object requested by the operation is not found. - /// - public class EventLogNotFoundException : EventLogException - { - public EventLogNotFoundException() { } - public EventLogNotFoundException(string message) : base(message) { } - public EventLogNotFoundException(string message, Exception innerException) : base(message, innerException) { } - internal EventLogNotFoundException(int errorCode) : base(errorCode) { } - } - - /// - /// The state of the reader cursor has become invalid, most likely due to the fact - /// that the log has been cleared. User needs to obtain a new reader object if - /// they wish to continue navigating result set. - /// - public class EventLogReadingException : EventLogException - { - public EventLogReadingException() { } - public EventLogReadingException(string message) : base(message) { } - public EventLogReadingException(string message, Exception innerException) : base(message, innerException) { } - internal EventLogReadingException(int errorCode) : base(errorCode) { } - } - - /// - /// Provider has been uninstalled while ProviderMetadata operations are being performed. - /// Obtain a new ProviderMetadata object, when provider is reinstalled, to continue navigating - /// provider's metadata. - /// - public class EventLogProviderDisabledException : EventLogException - { - public EventLogProviderDisabledException() { } - public EventLogProviderDisabledException(string message) : base(message) { } - public EventLogProviderDisabledException(string message, Exception innerException) : base(message, innerException) { } - internal EventLogProviderDisabledException(int errorCode) : base(errorCode) { } - } - - /// - /// Data obtained from the eventlog service, for the current operation, is invalid . - /// - public class EventLogInvalidDataException : EventLogException - { - public EventLogInvalidDataException() { } - public EventLogInvalidDataException(string message) : base(message) { } - public EventLogInvalidDataException(string message, Exception innerException) : base(message, innerException) { } - internal EventLogInvalidDataException(int errorCode) : base(errorCode) { } - } -} - diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogHandle.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogHandle.cs index fbb5dd8b66ca..06222aa8081f 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogHandle.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogHandle.cs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. /*============================================================ ** diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogInformation.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogInformation.cs deleted file mode 100644 index 6311574009f4..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogInformation.cs +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** The objects of this class allow access to the run-time -** properties of logs and external log files. An instance of this -** class is obtained from EventLogSession. -** -============================================================*/ - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Describes the run-time properties of logs and external log files. An instance - /// of this class is obtained from EventLogSession. - /// - public sealed class EventLogInformation - { - private DateTime? _creationTime; - private DateTime? _lastAccessTime; - private DateTime? _lastWriteTime; - private long? _fileSize; - private int? _fileAttributes; - private long? _recordCount; - private long? _oldestRecordNumber; - private bool? _isLogFull; - - - [System.Security.SecuritySafeCritical] - internal EventLogInformation(EventLogSession session, string channelName, PathType pathType) - { - EventLogHandle logHandle = NativeWrapper.EvtOpenLog(session.Handle, channelName, pathType); - - using (logHandle) - { - _creationTime = (DateTime?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogCreationTime); - _lastAccessTime = (DateTime?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogLastAccessTime); - _lastWriteTime = (DateTime?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogLastWriteTime); - _fileSize = (long?)((ulong?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogFileSize)); - _fileAttributes = (int?)((uint?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogAttributes)); - _recordCount = (long?)((ulong?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogNumberOfLogRecords)); - _oldestRecordNumber = (long?)((ulong?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogOldestRecordNumber)); - _isLogFull = (bool?)NativeWrapper.EvtGetLogInfo(logHandle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogFull); - } - } - - public DateTime? CreationTime { get { return _creationTime; } } - public DateTime? LastAccessTime { get { return _lastAccessTime; } } - public DateTime? LastWriteTime { get { return _lastWriteTime; } } - public long? FileSize { get { return _fileSize; } } - public int? Attributes { get { return _fileAttributes; } } - public long? RecordCount { get { return _recordCount; } } - public long? OldestRecordNumber { get { return _oldestRecordNumber; } } - public bool? IsLogFull { get { return _isLogFull; } } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogLink.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogLink.cs deleted file mode 100644 index c40819565fac..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogLink.cs +++ /dev/null @@ -1,117 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes the metadata for a specific Log -** Reference defined by a Provider. An instance of this class is obtained from -** a ProviderMetadata object. -** -============================================================*/ - -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Describes the metadata for a specific Log Reference defined - /// by a Provider. An instance of this class is obtained from - /// a ProviderMetadata object. - /// - public sealed class EventLogLink - { - private string _channelName; - private bool _isImported; - private string _displayName; - private uint _channelId; - - private bool _dataReady; - private ProviderMetadata _pmReference; - private object _syncObject; - - internal EventLogLink(uint channelId, ProviderMetadata pmReference) - { - _channelId = channelId; - _pmReference = pmReference; - _syncObject = new object(); - } - - internal EventLogLink(string channelName, bool isImported, string displayName, uint channelId) - { - _channelName = channelName; - _isImported = isImported; - _displayName = displayName; - _channelId = channelId; - - _dataReady = true; - _syncObject = new object(); - } - - private void PrepareData() - { - if (_dataReady == true) return; - - lock (_syncObject) - { - if (_dataReady == true) return; - - IEnumerable result = _pmReference.LogLinks; - - _channelName = null; - _isImported = false; - _displayName = null; - _dataReady = true; - - foreach (EventLogLink ch in result) - { - if (ch.ChannelId == _channelId) - { - _channelName = ch.LogName; - _isImported = ch.IsImported; - _displayName = ch.DisplayName; - - _dataReady = true; - - break; - } - } - } - } - - - public string LogName - { - get - { - this.PrepareData(); - return _channelName; - } - } - - public bool IsImported - { - get - { - this.PrepareData(); - return _isImported; - } - } - - public string DisplayName - { - get - { - this.PrepareData(); - return _displayName; - } - } - - internal uint ChannelId - { - get - { - return _channelId; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogPropertySelector.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogPropertySelector.cs deleted file mode 100644 index c9bed16f3b5e..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogPropertySelector.cs +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** Public class that encapsulates the information for fast -** access to Event Values of an EventLogRecord. Implements -** the EventPropertyContext abstract class. An instance of this -** class is constructed and then passed to -** EventLogRecord.GetEventPropertyValues. -** -============================================================*/ - -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Encapsulates the information for fast access to Event Values - /// of an EventLogRecord. An instance of this class is constructed - /// and then passed to EventLogRecord.GetEventPropertyValues. - /// - public class EventLogPropertySelector : IDisposable - { - // - // access to the data member reference is safe, while - // invoking methods on it is marked SecurityCritical as appropriate. - // - private EventLogHandle _renderContextHandleValues; - - [System.Security.SecurityCritical] - public EventLogPropertySelector(IEnumerable propertyQueries) - { - if (propertyQueries == null) - throw new ArgumentNullException("propertyQueries"); - - string[] paths; - - ICollection coll = propertyQueries as ICollection; - if (coll != null) - { - paths = new string[coll.Count]; - coll.CopyTo(paths, 0); - } - else - { - List queries; - queries = new List(propertyQueries); - paths = queries.ToArray(); - } - - _renderContextHandleValues = NativeWrapper.EvtCreateRenderContext(paths.Length, paths, UnsafeNativeMethods.EvtRenderContextFlags.EvtRenderContextValues); - } - - internal EventLogHandle Handle - { - // just returning reference to security critical type, the methods - // of that type are protected by SecurityCritical as appropriate. - get - { - return _renderContextHandleValues; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - [System.Security.SecuritySafeCritical] - protected virtual void Dispose(bool disposing) - { - if (_renderContextHandleValues != null && !_renderContextHandleValues.IsInvalid) - _renderContextHandleValues.Dispose(); - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogQuery.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogQuery.cs deleted file mode 100644 index 570a8811a4a3..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogQuery.cs +++ /dev/null @@ -1,115 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class allows a user to define events of interest. -** An instance of this class is passed to an EventReader to actually -** obtain the EventRecords. The EventLogQuery can be as -** simple specifying that all events are of interest, or it can contain -** query / xpath expressions that indicate exactly what characteristics -** events should have. -** -============================================================*/ - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Allows a user to define events of interest. An instance of this - /// class is passed to an EventReader to actually obtain the EventRecords. - /// The EventLogQuery can be as simple specifying that all events are of - /// interest, or it can contain query / xpath expressions that indicate exactly - /// what characteristics events should have. - /// - public class EventLogQuery - { - private string _query; - private string _path; - private EventLogSession _session; - private PathType _pathType; - private bool _tolerateErrors = false; - private bool _reverseDirection = false; - - public EventLogQuery(string path, PathType pathType) - : this(path, pathType, null) - { - } - - public EventLogQuery(string path, PathType pathType, string query) - { - _session = EventLogSession.GlobalSession; - _path = path; // can be null - _pathType = pathType; - - if (query == null) - { - if (path == null) - throw new ArgumentNullException("path"); - } - else - { - _query = query; - } - } - - public EventLogSession Session - { - get - { - return _session; - } - set - { - _session = value; - } - } - - public bool TolerateQueryErrors - { - get - { - return _tolerateErrors; - } - set - { - _tolerateErrors = value; - } - } - - public bool ReverseDirection - { - get - { - return _reverseDirection; - } - set - { - _reverseDirection = value; - } - } - - internal string Path - { - get - { - return _path; - } - } - - internal PathType ThePathType - { - get - { - return _pathType; - } - } - - internal string Query - { - get - { - return _query; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogReader.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogReader.cs deleted file mode 100644 index 668e02a1a823..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogReader.cs +++ /dev/null @@ -1,348 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class is used for reading event records from event log. -** -============================================================*/ - -using System.IO; -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// This public class is used for reading event records from event log. - /// - public class EventLogReader : IDisposable - { - private EventLogQuery _eventQuery; - - private int _batchSize; - - // - // access to the data member reference is safe, while - // invoking methods on it is marked SecurityCritical as appropriate. - // - private EventLogHandle _handle; - - /// - /// events buffer holds batched event (handles). - /// - private IntPtr[] _eventsBuffer; - /// - /// The current index where the function GetNextEvent is (inside the eventsBuffer). - /// - private int _currentIndex; - /// - /// The number of events read from the batch into the eventsBuffer - /// - private int _eventCount; - - /// - /// When the reader finishes (will always return only ERROR_NO_MORE_ITEMS). - /// For subscription, this means we need to wait for next event. - /// - private bool _isEof; - - /// - /// Maintains cached display / metadata information returned from - /// EventRecords that were obtained from this reader. - /// - private ProviderMetadataCachedInformation _cachedMetadataInformation; - - public EventLogReader(string path) - : this(new EventLogQuery(path, PathType.LogName), null) - { - } - - public EventLogReader(string path, PathType pathType) - : this(new EventLogQuery(path, pathType), null) - { - } - - public EventLogReader(EventLogQuery eventQuery) - : this(eventQuery, null) - { - } - - [System.Security.SecurityCritical] - public EventLogReader(EventLogQuery eventQuery, EventBookmark bookmark) - { - if (eventQuery == null) - throw new ArgumentNullException("eventQuery"); - - string logfile = null; - if (eventQuery.ThePathType == PathType.FilePath) - logfile = eventQuery.Path; - - _cachedMetadataInformation = new ProviderMetadataCachedInformation(eventQuery.Session, logfile, 50); - - //explicit data - _eventQuery = eventQuery; - - //implicit - _batchSize = 64; - _eventsBuffer = new IntPtr[_batchSize]; - - // - // compute the flag. - // - int flag = 0; - - if (_eventQuery.ThePathType == PathType.LogName) - flag |= (int)UnsafeNativeMethods.EvtQueryFlags.EvtQueryChannelPath; - else - flag |= (int)UnsafeNativeMethods.EvtQueryFlags.EvtQueryFilePath; - - if (_eventQuery.ReverseDirection) - flag |= (int)UnsafeNativeMethods.EvtQueryFlags.EvtQueryReverseDirection; - - if (_eventQuery.TolerateQueryErrors) - flag |= (int)UnsafeNativeMethods.EvtQueryFlags.EvtQueryTolerateQueryErrors; - - _handle = NativeWrapper.EvtQuery(_eventQuery.Session.Handle, - _eventQuery.Path, _eventQuery.Query, - flag); - - EventLogHandle bookmarkHandle = EventLogRecord.GetBookmarkHandleFromBookmark(bookmark); - - if (!bookmarkHandle.IsInvalid) - { - using (bookmarkHandle) - { - NativeWrapper.EvtSeek(_handle, 1, bookmarkHandle, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToBookmark); - } - } - } - - public int BatchSize - { - get - { - return _batchSize; - } - set - { - if (value < 1) - throw new ArgumentOutOfRangeException("value"); - _batchSize = value; - } - } - - [System.Security.SecurityCritical] - private bool GetNextBatch(TimeSpan ts) - { - int timeout; - if (ts == TimeSpan.MaxValue) - timeout = -1; - else - timeout = (int)ts.TotalMilliseconds; - - // batchSize was changed by user, reallocate buffer. - if (_batchSize != _eventsBuffer.Length) _eventsBuffer = new IntPtr[_batchSize]; - - int newEventCount = 0; - bool results = NativeWrapper.EvtNext(_handle, _batchSize, _eventsBuffer, timeout, 0, ref newEventCount); - - if (!results) - { - _eventCount = 0; - _currentIndex = 0; - return false; //no more events in the result set - } - - _currentIndex = 0; - _eventCount = newEventCount; - return true; - } - - public EventRecord ReadEvent() - { - return ReadEvent(TimeSpan.MaxValue); - } - - // security critical because allocates SafeHandle. - // marked as safe because performs Demand check. - [System.Security.SecurityCritical] - public EventRecord ReadEvent(TimeSpan timeout) - { - if (_isEof) - throw new InvalidOperationException(); - - if (_currentIndex >= _eventCount) - { - // buffer is empty, get next batch. - GetNextBatch(timeout); - - if (_currentIndex >= _eventCount) - { - _isEof = true; - return null; - } - } - - EventLogRecord eventInstance = new EventLogRecord(new EventLogHandle(_eventsBuffer[_currentIndex], true), _eventQuery.Session, _cachedMetadataInformation); - _currentIndex++; - return eventInstance; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - [System.Security.SecuritySafeCritical] - protected virtual void Dispose(bool disposing) - { - while (_currentIndex < _eventCount) - { - NativeWrapper.EvtClose(_eventsBuffer[_currentIndex]); - _currentIndex++; - } - - if (_handle != null && !_handle.IsInvalid) - _handle.Dispose(); - } - - [System.Security.SecurityCritical] - internal void SeekReset() - { - // - //close all unread event handles in the buffer - // - while (_currentIndex < _eventCount) - { - NativeWrapper.EvtClose(_eventsBuffer[_currentIndex]); - _currentIndex++; - } - - //reset the indexes used by Next - _currentIndex = 0; - _eventCount = 0; - _isEof = false; - } - - // marked as SecurityCritical because it allocates SafeHandle. - [System.Security.SecurityCritical] - internal void SeekCommon(long offset) - { - // - // modify offset that we're going to send to service to account for the - // fact that we've already read some events in our buffer that the user - // hasn't seen yet. - // - offset = offset - (_eventCount - _currentIndex); - - SeekReset(); - - NativeWrapper.EvtSeek(_handle, offset, EventLogHandle.Zero, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToCurrent); - } - - public void Seek(EventBookmark bookmark) - { - Seek(bookmark, 0); - } - - [System.Security.SecurityCritical] - public void Seek(EventBookmark bookmark, long offset) - { - if (bookmark == null) - throw new ArgumentNullException("bookmark"); - - SeekReset(); - using (EventLogHandle bookmarkHandle = EventLogRecord.GetBookmarkHandleFromBookmark(bookmark)) - { - NativeWrapper.EvtSeek(_handle, offset, bookmarkHandle, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToBookmark); - } - } - - [System.Security.SecurityCritical] - public void Seek(SeekOrigin origin, long offset) - { - switch (origin) - { - case SeekOrigin.Begin: - - SeekReset(); - NativeWrapper.EvtSeek(_handle, offset, EventLogHandle.Zero, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToFirst); - return; - - case SeekOrigin.End: - - SeekReset(); - NativeWrapper.EvtSeek(_handle, offset, EventLogHandle.Zero, 0, UnsafeNativeMethods.EvtSeekFlags.EvtSeekRelativeToLast); - return; - - case SeekOrigin.Current: - if (offset >= 0) - { - //we can reuse elements in the batch. - if (_currentIndex + offset < _eventCount) - { - // - // We don't call Seek here, we can reposition within the batch. - // - - // close all event handles between [currentIndex, currentIndex + offset) - int index = _currentIndex; - while (index < _currentIndex + offset) - { - NativeWrapper.EvtClose(_eventsBuffer[index]); - index++; - } - - _currentIndex = (int)(_currentIndex + offset); - //leave the eventCount unchanged - //leave the same Eof - } - else - { - SeekCommon(offset); - } - } - else - { - SeekCommon(offset); - } - return; - } - } - - public void CancelReading() - { - NativeWrapper.EvtCancel(_handle); - } - - public IList LogStatus - { - [System.Security.SecurityCritical] - get - { - List list = null; - string[] channelNames = null; - int[] errorStatuses = null; - EventLogHandle queryHandle = _handle; - - if (queryHandle.IsInvalid) - throw new InvalidOperationException(); - - channelNames = (string[])NativeWrapper.EvtGetQueryInfo(queryHandle, UnsafeNativeMethods.EvtQueryPropertyId.EvtQueryNames); - errorStatuses = (int[])NativeWrapper.EvtGetQueryInfo(queryHandle, UnsafeNativeMethods.EvtQueryPropertyId.EvtQueryStatuses); - - if (channelNames.Length != errorStatuses.Length) - throw new InvalidOperationException(); - - list = new List(channelNames.Length); - for (int i = 0; i < channelNames.Length; i++) - { - EventLogStatus cs = new EventLogStatus(channelNames[i], errorStatuses[i]); - list.Add(cs); - } - return list.AsReadOnly(); - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogRecord.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogRecord.cs deleted file mode 100644 index d71761c08a4e..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogRecord.cs +++ /dev/null @@ -1,452 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class is an EventLog implementation of EventRecord. An -** instance of this is obtained from an EventLogReader. -** -============================================================*/ - -using System.Collections.Generic; -using System.Text; - -namespace System.Diagnostics.Eventing.Reader -{ - public class EventLogRecord : EventRecord - { - private const int SYSTEM_PROPERTY_COUNT = 18; - - // - // access to the data member reference is safe, while - // invoking methods on it is marked SecurityCritical as appropriate. - // - [System.Security.SecuritySafeCritical] - private EventLogHandle _handle; - - private EventLogSession _session; - - private NativeWrapper.SystemProperties _systemProperties; - private string _containerChannel; - private int[] _matchedQueryIds; - - //a dummy object which is used only for the locking. - private object _syncObject; - - //cached DisplayNames for each instance - private string _levelName = null; - private string _taskName = null; - private string _opcodeName = null; - private IEnumerable _keywordsNames = null; - - //cached DisplayNames for each instance - private bool _levelNameReady; - private bool _taskNameReady; - private bool _opcodeNameReady; - - private ProviderMetadataCachedInformation _cachedMetadataInformation; - - // marking as TreatAsSafe because just passing around a reference to an EventLogHandle is safe. - [System.Security.SecuritySafeCritical] - internal EventLogRecord(EventLogHandle handle, EventLogSession session, ProviderMetadataCachedInformation cachedMetadataInfo) - { - _cachedMetadataInformation = cachedMetadataInfo; - _handle = handle; - _session = session; - _systemProperties = new NativeWrapper.SystemProperties(); - _syncObject = new object(); - } - - internal EventLogHandle Handle - { - // just returning reference to security critical type, the methods - // of that type are protected by SecurityCritical as appropriate. - [System.Security.SecuritySafeCritical] - get - { - return _handle; - } - } - - - internal void PrepareSystemData() - { - if (_systemProperties.filled) - return; - - //prepare the System Context, if it is not already initialized. - _session.SetupSystemContext(); - - lock (_syncObject) - { - if (_systemProperties.filled == false) - { - NativeWrapper.EvtRenderBufferWithContextSystem(_session.renderContextHandleSystem, _handle, UnsafeNativeMethods.EvtRenderFlags.EvtRenderEventValues, _systemProperties, SYSTEM_PROPERTY_COUNT); - _systemProperties.filled = true; - } - } - } - - public override int Id - { - get - { - PrepareSystemData(); - if (_systemProperties.Id == null) - return 0; - return (int)_systemProperties.Id; - } - } - - public override byte? Version - { - get - { - PrepareSystemData(); - return _systemProperties.Version; - } - } - - public override int? Qualifiers - { - get - { - PrepareSystemData(); - return (int?)(uint?)_systemProperties.Qualifiers; - } - } - - public override byte? Level - { - get - { - PrepareSystemData(); - return _systemProperties.Level; - } - } - - public override int? Task - { - get - { - PrepareSystemData(); - return (int?)(uint?)_systemProperties.Task; - } - } - - public override short? Opcode - { - get - { - PrepareSystemData(); - return (short?)(ushort?)_systemProperties.Opcode; - } - } - - public override long? Keywords - { - get - { - PrepareSystemData(); - return (long?)_systemProperties.Keywords; - } - } - - public override long? RecordId - { - get - { - PrepareSystemData(); - return (long?)_systemProperties.RecordId; - } - } - - public override string ProviderName - { - get - { - PrepareSystemData(); - return _systemProperties.ProviderName; - } - } - - public override Guid? ProviderId - { - get - { - PrepareSystemData(); - return _systemProperties.ProviderId; - } - } - - public override string LogName - { - get - { - PrepareSystemData(); - return _systemProperties.ChannelName; - } - } - - public override int? ProcessId - { - get - { - PrepareSystemData(); - return (int?)_systemProperties.ProcessId; - } - } - - public override int? ThreadId - { - get - { - PrepareSystemData(); - return (int?)_systemProperties.ThreadId; - } - } - - public override string MachineName - { - get - { - PrepareSystemData(); - return _systemProperties.ComputerName; - } - } - - public override System.Security.Principal.SecurityIdentifier UserId - { - get - { - PrepareSystemData(); - return _systemProperties.UserId; - } - } - - public override DateTime? TimeCreated - { - get - { - PrepareSystemData(); - return _systemProperties.TimeCreated; - } - } - - public override Guid? ActivityId - { - get - { - PrepareSystemData(); - return _systemProperties.ActivityId; - } - } - - public override Guid? RelatedActivityId - { - get - { - PrepareSystemData(); - return _systemProperties.RelatedActivityId; - } - } - - public string ContainerLog - { - get - { - if (_containerChannel != null) - return _containerChannel; - lock (_syncObject) - { - if (_containerChannel == null) - { - _containerChannel = (string)NativeWrapper.EvtGetEventInfo(this.Handle, UnsafeNativeMethods.EvtEventPropertyId.EvtEventPath); - } - return _containerChannel; - } - } - } - - public IEnumerable MatchedQueryIds - { - get - { - if (_matchedQueryIds != null) - return _matchedQueryIds; - lock (_syncObject) - { - if (_matchedQueryIds == null) - { - _matchedQueryIds = (int[])NativeWrapper.EvtGetEventInfo(this.Handle, UnsafeNativeMethods.EvtEventPropertyId.EvtEventQueryIDs); - } - return _matchedQueryIds; - } - } - } - - - public override EventBookmark Bookmark - { - [System.Security.SecuritySafeCritical] - get - { - EventLogHandle bookmarkHandle = NativeWrapper.EvtCreateBookmark(null); - NativeWrapper.EvtUpdateBookmark(bookmarkHandle, _handle); - string bookmarkText = NativeWrapper.EvtRenderBookmark(bookmarkHandle); - - return new EventBookmark(bookmarkText); - } - } - - public override string FormatDescription() - { - return _cachedMetadataInformation.GetFormatDescription(this.ProviderName, _handle); - } - - public override string FormatDescription(IEnumerable values) - { - if (values == null) return this.FormatDescription(); - - //copy the value IEnumerable to an array. - string[] theValues = new string[0]; - int i = 0; - foreach (object o in values) - { - if (theValues.Length == i) - Array.Resize(ref theValues, i + 1); - theValues[i] = o.ToString(); - i++; - } - - return _cachedMetadataInformation.GetFormatDescription(this.ProviderName, _handle, theValues); - } - - public override string LevelDisplayName - { - get - { - if (_levelNameReady) - return _levelName; - lock (_syncObject) - { - if (_levelNameReady == false) - { - _levelNameReady = true; - _levelName = _cachedMetadataInformation.GetLevelDisplayName(this.ProviderName, _handle); - } - return _levelName; - } - } - } - - - public override string OpcodeDisplayName - { - get - { - lock (_syncObject) - { - if (_opcodeNameReady == false) - { - _opcodeNameReady = true; - _opcodeName = _cachedMetadataInformation.GetOpcodeDisplayName(this.ProviderName, _handle); - } - return _opcodeName; - } - } - } - - public override string TaskDisplayName - { - get - { - if (_taskNameReady == true) - return _taskName; - lock (_syncObject) - { - if (_taskNameReady == false) - { - _taskNameReady = true; - _taskName = _cachedMetadataInformation.GetTaskDisplayName(this.ProviderName, _handle); - } - return _taskName; - } - } - } - - public override IEnumerable KeywordsDisplayNames - { - get - { - if (_keywordsNames != null) - return _keywordsNames; - lock (_syncObject) - { - if (_keywordsNames == null) - { - _keywordsNames = _cachedMetadataInformation.GetKeywordDisplayNames(this.ProviderName, _handle); - } - return _keywordsNames; - } - } - } - - - public override IList Properties - { - get - { - _session.SetupUserContext(); - IList properties = NativeWrapper.EvtRenderBufferWithContextUserOrValues(_session.renderContextHandleUser, _handle); - List list = new List(); - foreach (object value in properties) - { - list.Add(new EventProperty(value)); - } - return list; - } - } - - public IList GetPropertyValues(EventLogPropertySelector propertySelector) - { - if (propertySelector == null) - throw new ArgumentNullException("propertySelector"); - return NativeWrapper.EvtRenderBufferWithContextUserOrValues(propertySelector.Handle, _handle); - } - - // marked as SecurityCritical because it allocates SafeHandle - // marked as TreatAsSafe because it performs Demand. - [System.Security.SecuritySafeCritical] - public override string ToXml() - { - StringBuilder renderBuffer = new StringBuilder(2000); - NativeWrapper.EvtRender(EventLogHandle.Zero, _handle, UnsafeNativeMethods.EvtRenderFlags.EvtRenderEventXml, renderBuffer); - return renderBuffer.ToString(); - } - - [System.Security.SecuritySafeCritical] - protected override void Dispose(bool disposing) - { - try - { - if (_handle != null && !_handle.IsInvalid) - _handle.Dispose(); - } - finally - { - base.Dispose(disposing); - } - } - - // marked as SecurityCritical because allocates SafeHandle. - [System.Security.SecurityCritical] - internal static EventLogHandle GetBookmarkHandleFromBookmark(EventBookmark bookmark) - { - if (bookmark == null) - return EventLogHandle.Zero; - EventLogHandle handle = NativeWrapper.EvtCreateBookmark(bookmark.BookmarkText); - return handle; - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogSession.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogSession.cs deleted file mode 100644 index 8ed35125315d..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogSession.cs +++ /dev/null @@ -1,296 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** Defines a session for Event Log operations. The session can -** be configured for a remote machine and can use specific -** user credentials. -============================================================*/ - -using System.Security; -using System.Collections.Generic; -using System.Globalization; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Session Login Type - /// - public enum SessionAuthentication - { - Default = 0, - Negotiate = 1, - Kerberos = 2, - Ntlm = 3 - } - - /// - /// The type: log / external log file to query - /// - public enum PathType - { - LogName = 1, - FilePath = 2 - } - - public class EventLogSession : IDisposable - { - // - //the two context handles for rendering (for EventLogRecord). - //the system and user context handles. They are both common for all the event instances and can be created only once. - //access to the data member references is safe, while - //invoking methods on it is marked SecurityCritical as appropriate. - // - internal EventLogHandle renderContextHandleSystem = EventLogHandle.Zero; - internal EventLogHandle renderContextHandleUser = EventLogHandle.Zero; - - //the dummy sync object for the two contexts. - private object _syncObject = null; - - private string _server; - private string _user; - private string _domain; - private SessionAuthentication _logOnType; - //we do not maintain the password here. - - // - //access to the data member references is safe, while - //invoking methods on it is marked SecurityCritical as appropriate. - // - private EventLogHandle _handle = EventLogHandle.Zero; - - - //setup the System Context, once for all the EventRecords. - [System.Security.SecuritySafeCritical] - internal void SetupSystemContext() - { - if (!this.renderContextHandleSystem.IsInvalid) - return; - lock (_syncObject) - { - if (this.renderContextHandleSystem.IsInvalid) - { - //create the SYSTEM render context - //call the EvtCreateRenderContext to get the renderContextHandleSystem, so that we can get the system/values/user properties. - this.renderContextHandleSystem = NativeWrapper.EvtCreateRenderContext(0, null, UnsafeNativeMethods.EvtRenderContextFlags.EvtRenderContextSystem); - } - } - } - - [System.Security.SecuritySafeCritical] - internal void SetupUserContext() - { - lock (_syncObject) - { - if (this.renderContextHandleUser.IsInvalid) - { - //create the USER render context - this.renderContextHandleUser = NativeWrapper.EvtCreateRenderContext(0, null, UnsafeNativeMethods.EvtRenderContextFlags.EvtRenderContextUser); - } - } - } - - // marked as SecurityCritical because allocates SafeHandle. - // marked as TreatAsSafe because performs Demand(). - [System.Security.SecurityCritical] - public EventLogSession() - { - //handle = EventLogHandle.Zero; - _syncObject = new object(); - } - - public EventLogSession(string server) - : - this(server, null, null, (SecureString)null, SessionAuthentication.Default) - { - } - - // marked as TreatAsSafe because performs Demand(). - [System.Security.SecurityCritical] - public EventLogSession(string server, string domain, string user, SecureString password, SessionAuthentication logOnType) - { - if (server == null) - server = "localhost"; - - _syncObject = new object(); - - _server = server; - _domain = domain; - _user = user; - _logOnType = logOnType; - - UnsafeNativeMethods.EvtRpcLogin erLogin = new UnsafeNativeMethods.EvtRpcLogin(); - erLogin.Server = _server; - erLogin.User = _user; - erLogin.Domain = _domain; - erLogin.Flags = (int)_logOnType; - erLogin.Password = CoTaskMemUnicodeSafeHandle.Zero; - - try - { - if (password != null) - erLogin.Password.SetMemory(SecureStringMarshal.SecureStringToCoTaskMemUnicode(password)); - //open a session using the erLogin structure. - _handle = NativeWrapper.EvtOpenSession(UnsafeNativeMethods.EvtLoginClass.EvtRpcLogin, ref erLogin, 0, 0); - } - finally - { - erLogin.Password.Dispose(); - } - } - - internal EventLogHandle Handle - { - get - { - return _handle; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - [System.Security.SecuritySafeCritical] - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (this == s_globalSession) - throw new InvalidOperationException(); - } - - if (this.renderContextHandleSystem != null && - !this.renderContextHandleSystem.IsInvalid) - this.renderContextHandleSystem.Dispose(); - - if (this.renderContextHandleUser != null && - !this.renderContextHandleUser.IsInvalid) - this.renderContextHandleUser.Dispose(); - - if (_handle != null && !_handle.IsInvalid) - _handle.Dispose(); - } - - public void CancelCurrentOperations() - { - NativeWrapper.EvtCancel(_handle); - } - - private static EventLogSession s_globalSession = new EventLogSession(); - public static EventLogSession GlobalSession - { - get { return s_globalSession; } - } - - [System.Security.SecurityCritical] - public IEnumerable GetProviderNames() - { - List namesList = new List(100); - - using (EventLogHandle ProviderEnum = NativeWrapper.EvtOpenProviderEnum(this.Handle, 0)) - { - bool finish = false; - - do - { - string s = NativeWrapper.EvtNextPublisherId(ProviderEnum, ref finish); - if (finish == false) namesList.Add(s); - } - while (finish == false); - - return namesList; - } - } - - [System.Security.SecurityCritical] - public IEnumerable GetLogNames() - { - List namesList = new List(100); - - using (EventLogHandle channelEnum = NativeWrapper.EvtOpenChannelEnum(this.Handle, 0)) - { - bool finish = false; - - do - { - string s = NativeWrapper.EvtNextChannelPath(channelEnum, ref finish); - if (finish == false) namesList.Add(s); - } - while (finish == false); - - return namesList; - } - } - - public EventLogInformation GetLogInformation(string logName, PathType pathType) - { - if (logName == null) - throw new ArgumentNullException("logName"); - - return new EventLogInformation(this, logName, pathType); - } - - public void ExportLog(string path, PathType pathType, string query, string targetFilePath) - { - this.ExportLog(path, pathType, query, targetFilePath, false); - } - - public void ExportLog(string path, PathType pathType, string query, string targetFilePath, bool tolerateQueryErrors) - { - if (path == null) - throw new ArgumentNullException("path"); - - if (targetFilePath == null) - throw new ArgumentNullException("targetFilePath"); - - UnsafeNativeMethods.EvtExportLogFlags flag; - switch (pathType) - { - case PathType.LogName: - flag = UnsafeNativeMethods.EvtExportLogFlags.EvtExportLogChannelPath; - break; - case PathType.FilePath: - flag = UnsafeNativeMethods.EvtExportLogFlags.EvtExportLogFilePath; - break; - default: - throw new ArgumentOutOfRangeException("pathType"); - } - - if (tolerateQueryErrors == false) - NativeWrapper.EvtExportLog(this.Handle, path, query, targetFilePath, (int)flag); - else - NativeWrapper.EvtExportLog(this.Handle, path, query, targetFilePath, (int)flag | (int)UnsafeNativeMethods.EvtExportLogFlags.EvtExportLogTolerateQueryErrors); - } - - public void ExportLogAndMessages(string path, PathType pathType, string query, string targetFilePath) - { - this.ExportLogAndMessages(path, pathType, query, targetFilePath, false, CultureInfo.CurrentCulture); - } - - public void ExportLogAndMessages(string path, PathType pathType, string query, string targetFilePath, bool tolerateQueryErrors, CultureInfo targetCultureInfo) - { - if (targetCultureInfo == null) - targetCultureInfo = CultureInfo.CurrentCulture; - ExportLog(path, pathType, query, targetFilePath, tolerateQueryErrors); - // Ignore the CultureInfo, pass 0 to use the calling thread's locale - NativeWrapper.EvtArchiveExportedLog(this.Handle, targetFilePath, 0, 0); - } - - public void ClearLog(string logName) - { - this.ClearLog(logName, null); - } - - public void ClearLog(string logName, string backupPath) - { - if (logName == null) - throw new ArgumentNullException("logName"); - - NativeWrapper.EvtClearLog(this.Handle, logName, backupPath, 0); - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogStatus.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogStatus.cs deleted file mode 100644 index 0b12cedf3e00..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventLogStatus.cs +++ /dev/null @@ -1,46 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes the status of a particular -** log with respect to an instantiated EventLogReader. -** Since it is possible to instantiate an EventLogReader -** with a query containing multiple logs and the reader can -** be configured to tolerate errors in attaching to those logs, -** this class allows the user to determine exactly what the status -** of those logs is. -============================================================*/ - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Describes the status of a particular log with respect to - /// an instantiated EventLogReader. Since it is possible to - /// instantiate an EventLogReader with a query containing - /// multiple logs and the reader can be configured to tolerate - /// errors in attaching to those logs, this class allows the - /// user to determine exactly what the status of those logs is. - /// - public sealed class EventLogStatus - { - private string _channelName; - private int _win32ErrorCode; - - internal EventLogStatus(string channelName, int win32ErrorCode) - { - _channelName = channelName; - _win32ErrorCode = win32ErrorCode; - } - - public string LogName - { - get { return _channelName; } - } - - public int StatusCode - { - get { return _win32ErrorCode; } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventMetadata.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventMetadata.cs deleted file mode 100644 index c6ae17d208e6..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventMetadata.cs +++ /dev/null @@ -1,153 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes the metadata for a specific event -** raised by Provider. An instance of this class is obtained from -** ProviderMetadata class. -** -============================================================*/ - -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Event Metadata - /// - public sealed class EventMetadata - { - private long _id; - private byte _version; - private byte _channelId; - private byte _level; - private short _opcode; - private int _task; - private long _keywords; - private string _template; - private string _description; - - private ProviderMetadata _pmReference; - - internal EventMetadata(uint id, byte version, byte channelId, - byte level, byte opcode, short task, long keywords, - string template, string description, ProviderMetadata pmReference) - { - _id = id; - _version = version; - _channelId = channelId; - _level = level; - _opcode = opcode; - _task = task; - _keywords = keywords; - _template = template; - _description = description; - _pmReference = pmReference; - } - - // - // Max value will be UINT32.MaxValue - it is a long because this property - // is really a UINT32. The legacy API allows event message ids to be declared - // as UINT32 and these event/messages may be migrated into a Provider's - // manifest as UINT32. Note that EventRecord ids are - // still declared as int, because those ids max value is UINT16.MaxValue - // and rest of the bits of the legacy event id would be stored in - // Qualifiers property. - // - public long Id - { - get - { - return _id; - } - } - - public byte Version - { - get - { - return _version; - } - } - - public EventLogLink LogLink - { - get - { - return new EventLogLink((uint)_channelId, _pmReference); - } - } - - public EventLevel Level - { - get - { - return new EventLevel(_level, _pmReference); - } - } - - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Opcode", Justification = "matell: Shipped public in 3.5, breaking change to fix now.")] - public EventOpcode Opcode - { - get - { - return new EventOpcode(_opcode, _pmReference); - } - } - - public EventTask Task - { - get - { - return new EventTask(_task, _pmReference); - } - } - - - public IEnumerable Keywords - { - get - { - List list = new List(); - - ulong theKeywords = unchecked((ulong)_keywords); - ulong mask = 0x8000000000000000; - - //for every bit - //for (int i = 0; i < 64 && theKeywords != 0; i++) - for (int i = 0; i < 64; i++) - { - //if this bit is set - if ((theKeywords & mask) > 0) - { - //the mask is the keyword we will be searching for. - list.Add(new EventKeyword(unchecked((long)mask), _pmReference)); - //theKeywords = theKeywords - mask; - } - //modify the mask to check next bit. - mask = mask >> 1; - } - - return list; - } - } - - public string Template - { - get - { - return _template; - } - } - - public string Description - { - get - { - return _description; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventOpcode.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventOpcode.cs deleted file mode 100644 index f6bc7ad2ea76..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventOpcode.cs +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes the metadata for a specific Opcode -** defined by a Provider. An instance of this class is obtained from -** a ProviderMetadata object. -** -============================================================*/ - -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace System.Diagnostics.Eventing.Reader -{ - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Opcode", Justification = "matell: Shipped public in 3.5, breaking change to fix now.")] - public sealed class EventOpcode - { - private int _value; - private string _name; - private string _displayName; - private bool _dataReady; - private ProviderMetadata _pmReference; - private object _syncObject; - - //call from EventMetadata - internal EventOpcode(int value, ProviderMetadata pmReference) - { - _value = value; - _pmReference = pmReference; - _syncObject = new object(); - } - - //call from ProviderMetadata - internal EventOpcode(string name, int value, string displayName) - { - _value = value; - _name = name; - _displayName = displayName; - _dataReady = true; - _syncObject = new object(); - } - - internal void PrepareData() - { - lock (_syncObject) - { - if (_dataReady == true) return; - - // get the data - IEnumerable result = _pmReference.Opcodes; - //set the names and display names to null - _name = null; - _displayName = null; - _dataReady = true; - foreach (EventOpcode op in result) - { - if (op.Value == _value) - { - _name = op.Name; - _displayName = op.DisplayName; - _dataReady = true; - break; - } - } - } - }//End Prepare Data - - public string Name - { - get - { - PrepareData(); - return _name; - } - } - - public int Value - { - get - { - return _value; - } - } - - public string DisplayName - { - get - { - PrepareData(); - return _displayName; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventProperty.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventProperty.cs deleted file mode 100644 index 4cde07513abb..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventProperty.cs +++ /dev/null @@ -1,31 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class defines the methods / properties for the -** individual Data Values of an EventRecord. Instances of this -** class are obtained from EventRecord. -** -============================================================*/ - -namespace System.Diagnostics.Eventing.Reader -{ - public sealed class EventProperty - { - private object _value; - - internal EventProperty(object value) - { - _value = value; - } - - public object Value - { - get - { - return _value; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventPropertyContext.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventPropertyContext.cs deleted file mode 100644 index 035d053edd2e..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventPropertyContext.cs +++ /dev/null @@ -1,25 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public abstract class defines the methods / properties -** for a context object used to access a set of Data Values from -** an EventRecord. -** -============================================================*/ - -namespace System.Diagnostics.Eventing.Reader -{ - public abstract class EventPropertyContext : IDisposable - { - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - protected virtual void Dispose(bool disposing) - { - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventRecord.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventRecord.cs deleted file mode 100644 index 671b8312892e..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventRecord.cs +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public abstract class defines the methods / properties -** that all events should support. -** -============================================================*/ - -using System.Collections.Generic; -using System.Security.Principal; -using System.Diagnostics.CodeAnalysis; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Represents an event obtained from an EventReader. - /// - public abstract class EventRecord : IDisposable - { - public abstract int Id { get; } - public abstract byte? Version { get; } - public abstract byte? Level { get; } - public abstract int? Task { get; } - - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Opcode", Justification = "matell: Shipped public in 3.5, breaking change to fix now.")] - public abstract short? Opcode { get; } - public abstract long? Keywords { get; } - - public abstract long? RecordId { get; } - - public abstract string ProviderName { get; } - public abstract Guid? ProviderId { get; } - public abstract string LogName { get; } - - public abstract int? ProcessId { get; } - public abstract int? ThreadId { get; } - public abstract string MachineName { get; } - public abstract SecurityIdentifier UserId { get; } - public abstract DateTime? TimeCreated { get; } - - public abstract Guid? ActivityId { get; } - public abstract Guid? RelatedActivityId { get; } - public abstract int? Qualifiers { get; } - - public abstract string FormatDescription(); - public abstract string FormatDescription(IEnumerable values); - - public abstract string LevelDisplayName { get; } - - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Opcode", Justification = "matell: Shipped public in 3.5, breaking change to fix now.")] - public abstract string OpcodeDisplayName { get; } - public abstract string TaskDisplayName { get; } - public abstract IEnumerable KeywordsDisplayNames { get; } - - public abstract EventBookmark Bookmark { get; } - - public abstract IList Properties { get; } - - public abstract string ToXml(); - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - protected virtual void Dispose(bool disposing) { } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventTask.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventTask.cs deleted file mode 100644 index 620d71355233..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/EventTask.cs +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class describes the metadata for a specific Task -** defined by a Provider. An instance of this class is obtained -** from a ProviderMetadata object. -** -============================================================*/ - -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Describes the metadata for a specific Task defined by a Provider. - /// An instance of this class is obtained from a ProviderMetadata object. - /// - public sealed class EventTask - { - private int _value; - private string _name; - private string _displayName; - private Guid _guid; - private bool _dataReady; - private ProviderMetadata _pmReference; - private object _syncObject; - - - //called from EventMetadata - internal EventTask(int value, ProviderMetadata pmReference) - { - _value = value; - _pmReference = pmReference; - _syncObject = new object(); - } - - //called from ProviderMetadata - internal EventTask(string name, int value, string displayName, Guid guid) - { - _value = value; - _name = name; - _displayName = displayName; - _guid = guid; - _dataReady = true; - _syncObject = new object(); - } - - internal void PrepareData() - { - lock (_syncObject) - { - if (_dataReady == true) return; - - IEnumerable result = _pmReference.Tasks; - - _name = null; - _displayName = null; - _guid = Guid.Empty; - _dataReady = true; - - foreach (EventTask task in result) - { - if (task.Value == _value) - { - _name = task.Name; - _displayName = task.DisplayName; - _guid = task.EventGuid; - _dataReady = true; - break; - } - } - } - } - - public string Name - { - get - { - PrepareData(); - return _name; - } - } - - public int Value - { - get - { - return _value; - } - } - - public string DisplayName - { - get - { - PrepareData(); - return _displayName; - } - } - - public Guid EventGuid - { - get - { - PrepareData(); - return _guid; - } - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/NativeWrapper.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/NativeWrapper.cs index 73a8d428ce96..a94c0142c41b 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/NativeWrapper.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/NativeWrapper.cs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. /*============================================================ ** @@ -13,6 +15,7 @@ ============================================================*/ using System.Collections.Generic; +using System.ComponentModel; using System.Runtime.InteropServices; using System.Text; using System.Security.Principal; @@ -23,7 +26,7 @@ internal class NativeWrapper { public class SystemProperties { - //indicates if the SystemProperties values were already computed (for this event Instance, surely). + // indicates if the SystemProperties values were already computed (for this event Instance, surely). public bool filled = false; public ushort? Id = null; @@ -50,6 +53,43 @@ public SystemProperties() } } + private static void ThrowEventLogException(int errorCode) + { + string message = new Win32Exception(errorCode).Message; + + switch (errorCode) + { + case 2: + case 3: + case 15007: + case 15027: + case 15028: + case 15002: + throw new EventLogNotFoundException(message); + + case 13: + case 15005: + throw new EventLogInvalidDataException(message); + + case 1818: // RPC_S_CALL_CANCELED is converted to ERROR_CANCELLED + case 1223: + throw new OperationCanceledException(); + + case 15037: + throw new EventLogProviderDisabledException(message); + + case 5: + throw new UnauthorizedAccessException(); + + case 15011: + case 15012: + throw new EventLogReadingException(message); + + default: + throw new EventLogException(message); + } + } + [System.Security.SecurityCritical] public static EventLogHandle EvtQuery( EventLogHandle session, @@ -60,11 +100,10 @@ public SystemProperties() EventLogHandle handle = UnsafeNativeMethods.EvtQuery(session, path, query, flags); int win32Error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return handle; } - [System.Security.SecurityCritical] public static void EvtSeek( EventLogHandle resultSet, @@ -76,7 +115,7 @@ public SystemProperties() bool status = UnsafeNativeMethods.EvtSeek(resultSet, position, bookmark, timeout, flags); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } [System.Security.SecurityCritical] @@ -91,7 +130,7 @@ public SystemProperties() bool status = UnsafeNativeMethods.EvtNext(queryHandle, eventSize, events, timeout, flags, ref returned); int win32Error = Marshal.GetLastWin32Error(); if (!status && win32Error != UnsafeNativeMethods.ERROR_NO_MORE_ITEMS) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return win32Error == 0; } @@ -101,7 +140,7 @@ public static void EvtCancel(EventLogHandle handle) if (!UnsafeNativeMethods.EvtCancel(handle)) { int win32Error = Marshal.GetLastWin32Error(); - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } } @@ -132,7 +171,7 @@ public static void EvtClose(IntPtr handle) int win32Error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return handle; } @@ -143,7 +182,7 @@ public static int EvtGetObjectArraySize(EventLogHandle objectArray) bool status = UnsafeNativeMethods.EvtGetObjectArraySize(objectArray, out arraySize); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return arraySize; } @@ -153,7 +192,7 @@ public static EventLogHandle EvtOpenEventMetadataEnum(EventLogHandle ProviderMet EventLogHandle emEnumHandle = UnsafeNativeMethods.EvtOpenEventMetadataEnum(ProviderMetadata, flags); int win32Error = Marshal.GetLastWin32Error(); if (emEnumHandle.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return emEnumHandle; } @@ -167,7 +206,7 @@ public static EventLogHandle EvtNextEventMetadata(EventLogHandle eventMetadataEn if (emHandle.IsInvalid) { if (win32Error != UnsafeNativeMethods.ERROR_NO_MORE_ITEMS) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return null; } @@ -180,7 +219,7 @@ public static EventLogHandle EvtOpenChannelEnum(EventLogHandle session, int flag EventLogHandle channelEnum = UnsafeNativeMethods.EvtOpenChannelEnum(session, flags); int win32Error = Marshal.GetLastWin32Error(); if (channelEnum.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return channelEnum; } @@ -190,17 +229,17 @@ public static EventLogHandle EvtOpenProviderEnum(EventLogHandle session, int fla EventLogHandle pubEnum = UnsafeNativeMethods.EvtOpenPublisherEnum(session, flags); int win32Error = Marshal.GetLastWin32Error(); if (pubEnum.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return pubEnum; } [System.Security.SecurityCritical] - public static EventLogHandle EvtOpenChannelConfig(EventLogHandle session, String channelPath, int flags) + public static EventLogHandle EvtOpenChannelConfig(EventLogHandle session, string channelPath, int flags) { EventLogHandle handle = UnsafeNativeMethods.EvtOpenChannelConfig(session, channelPath, flags); int win32Error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return handle; } @@ -210,17 +249,16 @@ public static void EvtSaveChannelConfig(EventLogHandle channelConfig, int flags) bool status = UnsafeNativeMethods.EvtSaveChannelConfig(channelConfig, flags); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } - [System.Security.SecurityCritical] public static EventLogHandle EvtOpenLog(EventLogHandle session, string path, PathType flags) { EventLogHandle logHandle = UnsafeNativeMethods.EvtOpenLog(session, path, flags); int win32Error = Marshal.GetLastWin32Error(); if (logHandle.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return logHandle; } @@ -236,7 +274,7 @@ public static EventLogHandle EvtOpenLog(EventLogHandle session, string path, Pat status = UnsafeNativeMethods.EvtExportLog(session, channelPath, query, targetFilePath, flags); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } [System.Security.SecuritySafeCritical] @@ -250,7 +288,7 @@ public static EventLogHandle EvtOpenLog(EventLogHandle session, string path, Pat status = UnsafeNativeMethods.EvtArchiveExportedLog(session, logFilePath, locale, flags); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } [System.Security.SecuritySafeCritical] @@ -264,19 +302,19 @@ public static EventLogHandle EvtOpenLog(EventLogHandle session, string path, Pat status = UnsafeNativeMethods.EvtClearLog(session, channelPath, targetFilePath, flags); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } [System.Security.SecurityCritical] public static EventLogHandle EvtCreateRenderContext( Int32 valuePathsCount, - String[] valuePaths, + string[] valuePaths, UnsafeNativeMethods.EvtRenderContextFlags flags) { EventLogHandle renderContextHandleValues = UnsafeNativeMethods.EvtCreateRenderContext(valuePathsCount, valuePaths, flags); int win32Error = Marshal.GetLastWin32Error(); if (renderContextHandleValues.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return renderContextHandleValues; } @@ -296,14 +334,15 @@ public static EventLogHandle EvtOpenLog(EventLogHandle session, string path, Pat { if (win32Error == UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) { - //reallocate the new RenderBuffer with the right size. + // reallocate the new RenderBuffer with the right size. buffer.Capacity = buffUsed; status = UnsafeNativeMethods.EvtRender(context, eventHandle, flags, buffer.Capacity, buffer, out buffUsed, out propCount); win32Error = Marshal.GetLastWin32Error(); } + if (!status) { - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } } } @@ -314,7 +353,7 @@ public static EventLogHandle EvtOpenSession(UnsafeNativeMethods.EvtLoginClass lo EventLogHandle handle = UnsafeNativeMethods.EvtOpenSession(loginClass, ref login, timeout, flags); int win32Error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return handle; } @@ -324,7 +363,7 @@ public static EventLogHandle EvtCreateBookmark(string bookmarkXml) EventLogHandle handle = UnsafeNativeMethods.EvtCreateBookmark(bookmarkXml); int win32Error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return handle; } @@ -334,7 +373,7 @@ public static void EvtUpdateBookmark(EventLogHandle bookmark, EventLogHandle eve bool status = UnsafeNativeMethods.EvtUpdateBookmark(bookmark, eventHandle); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } [System.Security.SecuritySafeCritical] @@ -352,13 +391,14 @@ public static object EvtGetEventInfo(EventLogHandle handle, UnsafeNativeMethods. if (error == UnsafeNativeMethods.ERROR_SUCCESS) { } else if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetEventInfo(handle, enumType, bufferNeeded, buffer, out bufferNeeded); error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(error); + ThrowEventLogException(error); UnsafeNativeMethods.EvtVariant varVal = Marshal.PtrToStructure(buffer); return ConvertToObject(varVal); @@ -382,13 +422,14 @@ public static object EvtGetQueryInfo(EventLogHandle handle, UnsafeNativeMethods. if (!status) { if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetQueryInfo(handle, enumType, bufferNeeded, buffer, ref bufferNeeded); error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(error); + ThrowEventLogException(error); UnsafeNativeMethods.EvtVariant varVal = Marshal.PtrToStructure(buffer); return ConvertToObject(varVal); @@ -412,13 +453,14 @@ public static object EvtGetPublisherMetadataProperty(EventLogHandle pmHandle, Un if (!status) { if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetPublisherMetadataProperty(pmHandle, thePropertyId, 0, bufferNeeded, buffer, out bufferNeeded); error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(error); + ThrowEventLogException(error); UnsafeNativeMethods.EvtVariant varVal = Marshal.PtrToStructure(buffer); return ConvertToObject(varVal); @@ -429,7 +471,6 @@ public static object EvtGetPublisherMetadataProperty(EventLogHandle pmHandle, Un } } - [System.Security.SecurityCritical] internal static EventLogHandle EvtGetPublisherMetadataPropertyHandle(EventLogHandle pmHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId thePropertyId) { @@ -442,13 +483,14 @@ internal static EventLogHandle EvtGetPublisherMetadataPropertyHandle(EventLogHan if (!status) { if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetPublisherMetadataProperty(pmHandle, thePropertyId, 0, bufferNeeded, buffer, out bufferNeeded); error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(error); + ThrowEventLogException(error); // // note: there is a case where returned variant does have allocated native resources @@ -466,7 +508,6 @@ internal static EventLogHandle EvtGetPublisherMetadataPropertyHandle(EventLogHan } } - // implies UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageId flag. [System.Security.SecurityCritical] public static string EvtFormatMessage(EventLogHandle handle, uint msgId) @@ -491,8 +532,9 @@ public static string EvtFormatMessage(EventLogHandle handle, uint msgId) case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return null; } + if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } sb.EnsureCapacity(bufferNeeded); @@ -512,12 +554,15 @@ public static string EvtFormatMessage(EventLogHandle handle, uint msgId) case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return null; } + if (error == UnsafeNativeMethods.ERROR_EVT_UNRESOLVED_VALUE_INSERT) { return null; } - EventLogException.Throw(error); + + ThrowEventLogException(error); } + return sb.ToString(); } @@ -535,13 +580,14 @@ public static object EvtGetObjectArrayProperty(EventLogHandle objArrayHandle, in if (!status) { if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetObjectArrayProperty(objArrayHandle, thePropertyId, index, 0, bufferNeeded, buffer, out bufferNeeded); error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(error); + ThrowEventLogException(error); UnsafeNativeMethods.EvtVariant varVal = Marshal.PtrToStructure(buffer); return ConvertToObject(varVal); @@ -565,13 +611,14 @@ public static object EvtGetEventMetadataProperty(EventLogHandle handle, UnsafeNa if (!status) { if (win32Error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetEventMetadataProperty(handle, enumType, 0, bufferNeeded, buffer, out bufferNeeded); win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); UnsafeNativeMethods.EvtVariant varVal = Marshal.PtrToStructure(buffer); return ConvertToObject(varVal); @@ -596,13 +643,14 @@ public static object EvtGetChannelConfigProperty(EventLogHandle handle, UnsafeNa if (!status) { if (win32Error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetChannelConfigProperty(handle, enumType, 0, bufferNeeded, buffer, out bufferNeeded); win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); // // note: there is a case where returned variant does have allocated native resources @@ -640,6 +688,7 @@ public static void EvtSetChannelConfigProperty(EventLogHandle handle, UnsafeNati if ((bool)val == true) varVal.Bool = 1; else varVal.Bool = 0; } + break; case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess: { @@ -647,6 +696,7 @@ public static void EvtSetChannelConfigProperty(EventLogHandle handle, UnsafeNati taskMem.SetMemory(Marshal.StringToCoTaskMemUni((string)val)); varVal.StringVal = taskMem.GetMemory(); } + break; case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath: { @@ -654,24 +704,28 @@ public static void EvtSetChannelConfigProperty(EventLogHandle handle, UnsafeNati taskMem.SetMemory(Marshal.StringToCoTaskMemUni((string)val)); varVal.StringVal = taskMem.GetMemory(); } + break; case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize: { varVal.Type = (uint)UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt64; varVal.ULong = (ulong)((long)val); } + break; case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel: { varVal.Type = (uint)UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt32; varVal.UInteger = (uint)((int)val); } + break; case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords: { varVal.Type = (uint)UnsafeNativeMethods.EvtVariantType.EvtVarTypeUInt64; varVal.ULong = (ulong)((long)val); } + break; case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention: { @@ -679,6 +733,7 @@ public static void EvtSetChannelConfigProperty(EventLogHandle handle, UnsafeNati if ((bool)val == true) varVal.Bool = 1; else varVal.Bool = 0; } + break; case UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup: { @@ -686,6 +741,7 @@ public static void EvtSetChannelConfigProperty(EventLogHandle handle, UnsafeNati if ((bool)val == true) varVal.Bool = 1; else varVal.Bool = 0; } + break; default: throw new InvalidOperationException(); @@ -695,10 +751,11 @@ public static void EvtSetChannelConfigProperty(EventLogHandle handle, UnsafeNati { varVal.Type = (uint)UnsafeNativeMethods.EvtVariantType.EvtVarTypeNull; } + bool status = UnsafeNativeMethods.EvtSetChannelConfigProperty(handle, enumType, 0, ref varVal); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } } @@ -719,14 +776,14 @@ public static string EvtNextChannelPath(EventLogHandle handle, ref bool finish) } if (win32Error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } sb.EnsureCapacity(channelNameNeeded); status = UnsafeNativeMethods.EvtNextChannelPath(handle, channelNameNeeded, sb, out channelNameNeeded); win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return sb.ToString(); } @@ -748,14 +805,14 @@ public static string EvtNextPublisherId(EventLogHandle handle, ref bool finish) } if (win32Error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } sb.EnsureCapacity(ProviderIdNeeded); status = UnsafeNativeMethods.EvtNextPublisherId(handle, ProviderIdNeeded, sb, out ProviderIdNeeded); win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); return sb.ToString(); } @@ -773,13 +830,14 @@ public static object EvtGetLogInfo(EventLogHandle handle, UnsafeNativeMethods.Ev if (!status) { if (win32Error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); } + buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtGetLogInfo(handle, enumType, bufferNeeded, buffer, out bufferNeeded); win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); UnsafeNativeMethods.EvtVariant varVal = Marshal.PtrToStructure(buffer); return ConvertToObject(varVal); @@ -806,20 +864,20 @@ public static void EvtRenderBufferWithContextSystem(EventLogHandle contextHandle { int error = Marshal.GetLastWin32Error(); if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtRender(contextHandle, eventHandle, flag, bufferNeeded, buffer, out bufferNeeded, out propCount); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); if (propCount != SYSTEM_PROPERTY_COUNT) throw new InvalidOperationException("We do not have " + SYSTEM_PROPERTY_COUNT + " variants given for the UnsafeNativeMethods.EvtRenderFlags.EvtRenderEventValues flag. (System Properties)"); pointer = buffer; - //read each Variant structure + // read each Variant structure for (int i = 0; i < propCount; i++) { UnsafeNativeMethods.EvtVariant varVal = Marshal.PtrToStructure(pointer); @@ -880,6 +938,7 @@ public static void EvtRenderBufferWithContextSystem(EventLogHandle contextHandle systemProperties.Version = (byte?)ConvertToObject(varVal, UnsafeNativeMethods.EvtVariantType.EvtVarTypeByte); break; } + pointer = new IntPtr(((Int64)pointer + Marshal.SizeOf(varVal))); } } @@ -890,8 +949,8 @@ public static void EvtRenderBufferWithContextSystem(EventLogHandle contextHandle } } - //EvtRenderContextFlags can be both: EvtRenderContextFlags.EvtRenderContextUser and EvtRenderContextFlags.EvtRenderContextValues - //Render with Context = ContextUser or ContextValues (with user defined Xpath query strings) + // EvtRenderContextFlags can be both: EvtRenderContextFlags.EvtRenderContextUser and EvtRenderContextFlags.EvtRenderContextValues + // Render with Context = ContextUser or ContextValues (with user defined Xpath query strings) [System.Security.SecuritySafeCritical] public static IList EvtRenderBufferWithContextUserOrValues(EventLogHandle contextHandle, EventLogHandle eventHandle) { @@ -908,14 +967,14 @@ public static IList EvtRenderBufferWithContextUserOrValues(EventLogHandl { int error = Marshal.GetLastWin32Error(); if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtRender(contextHandle, eventHandle, flag, bufferNeeded, buffer, out bufferNeeded, out propCount); int win32Error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(win32Error); + ThrowEventLogException(win32Error); List valuesList = new List(propCount); if (propCount > 0) @@ -928,6 +987,7 @@ public static IList EvtRenderBufferWithContextUserOrValues(EventLogHandl pointer = new IntPtr(((Int64)pointer + Marshal.SizeOf(varVal))); } } + return valuesList; } finally @@ -963,8 +1023,9 @@ public static string EvtFormatMessageRenderName(EventLogHandle pmHandle, EventLo case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return null; } + if (error != (int)UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } sb.EnsureCapacity(bufferNeeded); @@ -982,13 +1043,14 @@ public static string EvtFormatMessageRenderName(EventLogHandle pmHandle, EventLo case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return null; } - EventLogException.Throw(error); + + ThrowEventLogException(error); } + return sb.ToString(); } - - //The EvtFormatMessage used for the obtaining of the Keywords names. + // The EvtFormatMessage used for the obtaining of the Keywords names. [System.Security.SecuritySafeCritical] public static IEnumerable EvtFormatMessageRenderKeywords(EventLogHandle pmHandle, EventLogHandle eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags flag) { @@ -1012,8 +1074,9 @@ public static IEnumerable EvtFormatMessageRenderKeywords(EventLogHandle case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return keywordsList.AsReadOnly(); } + if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } buffer = Marshal.AllocHGlobal(bufferNeeded * 2); @@ -1030,7 +1093,8 @@ public static IEnumerable EvtFormatMessageRenderKeywords(EventLogHandle case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return keywordsList; } - EventLogException.Throw(error); + + ThrowEventLogException(error); } IntPtr pointer = buffer; @@ -1038,10 +1102,10 @@ public static IEnumerable EvtFormatMessageRenderKeywords(EventLogHandle while (true) { string s = Marshal.PtrToStringUni(pointer); - if (String.IsNullOrEmpty(s)) + if (string.IsNullOrEmpty(s)) break; keywordsList.Add(s); - //nr of bytes = # chars * 2 + 2 bytes for character '\0'. + // nr of bytes = # chars * 2 + 2 bytes for character '\0'. pointer = new IntPtr((Int64)pointer + (s.Length * 2) + 2); } @@ -1069,14 +1133,14 @@ public static string EvtRenderBookmark(EventLogHandle eventHandle) if (!status) { if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } buffer = Marshal.AllocHGlobal((int)bufferNeeded); status = UnsafeNativeMethods.EvtRender(EventLogHandle.Zero, eventHandle, flag, bufferNeeded, buffer, out bufferNeeded, out propCount); error = Marshal.GetLastWin32Error(); if (!status) - EventLogException.Throw(error); + ThrowEventLogException(error); return Marshal.PtrToStringUni(buffer); } @@ -1087,8 +1151,7 @@ public static string EvtRenderBookmark(EventLogHandle eventHandle) } } - - //Get the formatted description, using the msgId for FormatDescription(string []) + // Get the formatted description, using the msgId for FormatDescription(string []) [System.Security.SecuritySafeCritical] public static string EvtFormatMessageFormatDescription(EventLogHandle handle, EventLogHandle eventHandle, string[] values) { @@ -1122,8 +1185,9 @@ public static string EvtFormatMessageFormatDescription(EventLogHandle handle, Ev case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return null; } + if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER) - EventLogException.Throw(error); + ThrowEventLogException(error); } sb.EnsureCapacity(bufferNeeded); @@ -1141,8 +1205,10 @@ public static string EvtFormatMessageFormatDescription(EventLogHandle handle, Ev case UnsafeNativeMethods.ERROR_MUI_FILE_NOT_FOUND: return null; } - EventLogException.Throw(error); + + ThrowEventLogException(error); } + return sb.ToString(); } @@ -1199,32 +1265,32 @@ private static object ConvertToObject(UnsafeNativeMethods.EvtVariant val) else return false; case (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeBinary: case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeByte): - if (val.Reference == IntPtr.Zero) return new Byte[0]; - Byte[] arByte = new Byte[val.Count]; + if (val.Reference == IntPtr.Zero) return Array.Empty(); + byte[] arByte = new byte[val.Count]; Marshal.Copy(val.Reference, arByte, 0, (int)val.Count); return arByte; case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeInt16): - if (val.Reference == IntPtr.Zero) return new Int16[0]; + if (val.Reference == IntPtr.Zero) return Array.Empty(); Int16[] arInt16 = new Int16[val.Count]; Marshal.Copy(val.Reference, arInt16, 0, (int)val.Count); return arInt16; case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeInt32): - if (val.Reference == IntPtr.Zero) return new Int32[0]; + if (val.Reference == IntPtr.Zero) return Array.Empty(); Int32[] arInt32 = new Int32[val.Count]; Marshal.Copy(val.Reference, arInt32, 0, (int)val.Count); return arInt32; case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeInt64): - if (val.Reference == IntPtr.Zero) return new Int64[0]; + if (val.Reference == IntPtr.Zero) return Array.Empty(); Int64[] arInt64 = new Int64[val.Count]; Marshal.Copy(val.Reference, arInt64, 0, (int)val.Count); return arInt64; case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeSingle): - if (val.Reference == IntPtr.Zero) return new Single[0]; + if (val.Reference == IntPtr.Zero) return Array.Empty(); Single[] arSingle = new Single[val.Count]; Marshal.Copy(val.Reference, arSingle, 0, (int)val.Count); return arSingle; case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeDouble): - if (val.Reference == IntPtr.Zero) return new Double[0]; + if (val.Reference == IntPtr.Zero) return Array.Empty(); Double[] arDouble = new Double[val.Count]; Marshal.Copy(val.Reference, arDouble, 0, (int)val.Count); return arDouble; @@ -1250,9 +1316,9 @@ private static object ConvertToObject(UnsafeNativeMethods.EvtVariant val) return ConvertToFileTimeArray(val); case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeSysTime): return ConvertToSysTimeArray(val); - case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeBinary): //both length and count in the manifest: tracrpt supports, Crimson APIs don't - case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeSizeT): //unused: array of win:pointer is returned as HexIntXX - case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeSid): //unsupported by native APIs + case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeBinary): // both length and count in the manifest: tracrpt supports, Crimson APIs don't + case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeSizeT): // unused: array of win:pointer is returned as HexIntXX + case ((int)UnsafeNativeMethods.EvtMasks.EVT_VARIANT_TYPE_ARRAY | (int)UnsafeNativeMethods.EvtVariantType.EvtVarTypeSid): // unsupported by native APIs default: throw new EventLogInvalidDataException(); } @@ -1265,7 +1331,6 @@ public static object ConvertToObject(UnsafeNativeMethods.EvtVariant val, UnsafeN if (val.Type != (int)desiredType) throw new EventLogInvalidDataException(); - return ConvertToObject(val); } @@ -1287,7 +1352,6 @@ public static string ConvertToAnsiString(UnsafeNativeMethods.EvtVariant val) return Marshal.PtrToStringAnsi(val.AnsiString); } - [System.Security.SecurityCritical] public static EventLogHandle ConvertToSafeHandle(UnsafeNativeMethods.EvtVariant val) { @@ -1297,7 +1361,6 @@ public static EventLogHandle ConvertToSafeHandle(UnsafeNativeMethods.EvtVariant return new EventLogHandle(val.Handle, true); } - [System.Security.SecurityCritical] public static Array ConvertToArray(UnsafeNativeMethods.EvtVariant val, int size) where T : struct { @@ -1314,6 +1377,7 @@ public static EventLogHandle ConvertToSafeHandle(UnsafeNativeMethods.EvtVariant array.SetValue(Marshal.PtrToStructure(ptr), i); ptr = new IntPtr((Int64)ptr + size); } + return array; } } @@ -1321,11 +1385,11 @@ public static EventLogHandle ConvertToSafeHandle(UnsafeNativeMethods.EvtVariant [System.Security.SecurityCritical] public static Array ConvertToBoolArray(UnsafeNativeMethods.EvtVariant val) { - //NOTE: booleans are padded to 4 bytes in ETW + // NOTE: booleans are padded to 4 bytes in ETW IntPtr ptr = val.Reference; if (ptr == IntPtr.Zero) { - return new bool[0]; + return Array.Empty(); } else { @@ -1336,6 +1400,7 @@ public static Array ConvertToBoolArray(UnsafeNativeMethods.EvtVariant val) array[i] = value; ptr = new IntPtr((Int64)ptr + 4); } + return array; } } @@ -1346,7 +1411,7 @@ public static Array ConvertToFileTimeArray(UnsafeNativeMethods.EvtVariant val) IntPtr ptr = val.Reference; if (ptr == IntPtr.Zero) { - return new DateTime[0]; + return Array.Empty(); } else { @@ -1356,6 +1421,7 @@ public static Array ConvertToFileTimeArray(UnsafeNativeMethods.EvtVariant val) array[i] = DateTime.FromFileTime(Marshal.ReadInt64(ptr)); ptr = new IntPtr((Int64)ptr + 8 * sizeof(byte)); // FILETIME values are 8 bytes } + return array; } } @@ -1366,7 +1432,7 @@ public static Array ConvertToSysTimeArray(UnsafeNativeMethods.EvtVariant val) IntPtr ptr = val.Reference; if (ptr == IntPtr.Zero) { - return new DateTime[0]; + return Array.Empty(); } else { @@ -1377,17 +1443,17 @@ public static Array ConvertToSysTimeArray(UnsafeNativeMethods.EvtVariant val) array[i] = new DateTime(sysTime.Year, sysTime.Month, sysTime.Day, sysTime.Hour, sysTime.Minute, sysTime.Second, sysTime.Milliseconds); ptr = new IntPtr((Int64)ptr + 16 * sizeof(byte)); // SystemTime values are 16 bytes } + return array; } } - [System.Security.SecurityCritical] public static string[] ConvertToStringArray(UnsafeNativeMethods.EvtVariant val, bool ansi) { if (val.Reference == IntPtr.Zero) { - return new string[0]; + return Array.Empty(); } else { @@ -1399,6 +1465,7 @@ public static string[] ConvertToStringArray(UnsafeNativeMethods.EvtVariant val, { stringArray[i] = ansi ? Marshal.PtrToStringAnsi(pointersToString[i]) : Marshal.PtrToStringUni(pointersToString[i]); } + return stringArray; } } diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/ProviderMetadata.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/ProviderMetadata.cs deleted file mode 100644 index 0843386d611c..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/ProviderMetadata.cs +++ /dev/null @@ -1,588 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This public class exposes all the metadata for a specific -** Provider. An instance of this class is obtained from -** EventLogManagement and is scoped to a single Locale. -** -============================================================*/ - -using System.Globalization; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// Exposes all the metadata for a specific event Provider. An instance - /// of this class is obtained from EventLogManagement and is scoped to a - /// single Locale. - /// - public class ProviderMetadata : IDisposable - { - // - // access to the data member reference is safe, while - // invoking methods on it is marked SecurityCritical as appropriate. - // - private EventLogHandle _handle = EventLogHandle.Zero; - - private EventLogHandle _defaultProviderHandle = EventLogHandle.Zero; - - private EventLogSession _session = null; - - private string _providerName; - private CultureInfo _cultureInfo; - private string _logFilePath; - - //caching of the IEnumerable, , , on the ProviderMetadata - //they do not change with every call. - private IList _levels = null; - private IList _opcodes = null; - private IList _tasks = null; - private IList _keywords = null; - private IList _standardLevels = null; - private IList _standardOpcodes = null; - private IList _standardTasks = null; - private IList _standardKeywords = null; - private IList _channelReferences = null; - - private object _syncObject; - - public ProviderMetadata(string providerName) - : this(providerName, null, null, null) - { - } - - public ProviderMetadata(string providerName, EventLogSession session, CultureInfo targetCultureInfo) - : this(providerName, session, targetCultureInfo, null) - { - } - - // SecurityCritical since it allocates SafeHandles. - // Marked TreatAsSafe since we perform the Demand check. - [System.Security.SecuritySafeCritical] - internal ProviderMetadata(string providerName, EventLogSession session, CultureInfo targetCultureInfo, string logFilePath) - { - if (targetCultureInfo == null) - targetCultureInfo = CultureInfo.CurrentCulture; - - if (session == null) - session = EventLogSession.GlobalSession; - - _session = session; - _providerName = providerName; - _cultureInfo = targetCultureInfo; - _logFilePath = logFilePath; - - _handle = NativeWrapper.EvtOpenProviderMetadata(_session.Handle, _providerName, _logFilePath, 0, 0); - - _syncObject = new object(); - } - - internal EventLogHandle Handle - { - get - { - return _handle; - } - } - - public string Name - { - get { return _providerName; } - } - - public Guid Id - { - get - { - return (Guid)NativeWrapper.EvtGetPublisherMetadataProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataPublisherGuid); - } - } - - public string MessageFilePath - { - get - { - return (string)NativeWrapper.EvtGetPublisherMetadataProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataMessageFilePath); - } - } - - public string ResourceFilePath - { - get - { - return (string)NativeWrapper.EvtGetPublisherMetadataProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataResourceFilePath); - } - } - - public string ParameterFilePath - { - get - { - return (string)NativeWrapper.EvtGetPublisherMetadataProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataParameterFilePath); - } - } - - public Uri HelpLink - { - get - { - string helpLinkStr = (string)NativeWrapper.EvtGetPublisherMetadataProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataHelpLink); - if (helpLinkStr == null || helpLinkStr.Length == 0) - return null; - return new Uri(helpLinkStr); - } - } - - private uint ProviderMessageID - { - get - { - return (uint)NativeWrapper.EvtGetPublisherMetadataProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataPublisherMessageID); - } - } - - public string DisplayName - { - [System.Security.SecurityCritical] - get - { - uint msgId = (uint)this.ProviderMessageID; - - if (msgId == 0xffffffff) - return null; - - return NativeWrapper.EvtFormatMessage(_handle, msgId); - } - } - - public IList LogLinks - { - [System.Security.SecurityCritical] - get - { - EventLogHandle elHandle = EventLogHandle.Zero; - try - { - lock (_syncObject) - { - if (_channelReferences != null) - return _channelReferences; - - elHandle = NativeWrapper.EvtGetPublisherMetadataPropertyHandle(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataChannelReferences); - - int arraySize = NativeWrapper.EvtGetObjectArraySize(elHandle); - - List channelList = new List(arraySize); - - - for (int index = 0; index < arraySize; index++) - { - string channelName = (string)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataChannelReferencePath); - - uint channelId = (uint)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataChannelReferenceID); - - uint flag = (uint)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataChannelReferenceFlags); - - bool isImported; - if (flag == (int)UnsafeNativeMethods.EvtChannelReferenceFlags.EvtChannelReferenceImported) isImported = true; - else isImported = false; - - int channelRefMessageId = unchecked((int)((uint)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataChannelReferenceMessageID))); - string channelRefDisplayName; - - //if channelRefMessageId == -1, we do not have anything in the message table. - if (channelRefMessageId == -1) - { - channelRefDisplayName = null; - } - else - { - channelRefDisplayName = NativeWrapper.EvtFormatMessage(_handle, unchecked((uint)channelRefMessageId)); - } - - if (channelRefDisplayName == null && isImported) - { - if (String.Compare(channelName, "Application", StringComparison.OrdinalIgnoreCase) == 0) - channelRefMessageId = 256; - else if (String.Compare(channelName, "System", StringComparison.OrdinalIgnoreCase) == 0) - channelRefMessageId = 258; - else if (String.Compare(channelName, "Security", StringComparison.OrdinalIgnoreCase) == 0) - channelRefMessageId = 257; - else - channelRefMessageId = -1; - - if (channelRefMessageId != -1) - { - if (_defaultProviderHandle.IsInvalid) - { - _defaultProviderHandle = NativeWrapper.EvtOpenProviderMetadata(_session.Handle, null, null, 0, 0); - } - - channelRefDisplayName = NativeWrapper.EvtFormatMessage(_defaultProviderHandle, unchecked((uint)channelRefMessageId)); - } - } - - channelList.Add(new EventLogLink(channelName, isImported, channelRefDisplayName, channelId)); - } - - _channelReferences = channelList.AsReadOnly(); - } - - return _channelReferences; - } - finally - { - elHandle.Dispose(); - } - } - } - - internal enum ObjectTypeName - { - Level = 0, - Opcode = 1, - Task = 2, - Keyword = 3 - } - - internal string FindStandardLevelDisplayName(string name, uint value) - { - if (_standardLevels == null) - _standardLevels = (List)GetProviderListProperty(_defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevels); - foreach (EventLevel standardLevel in _standardLevels) - { - if (standardLevel.Name == name && standardLevel.Value == value) - return standardLevel.DisplayName; - } - return null; - } - internal string FindStandardOpcodeDisplayName(string name, uint value) - { - if (_standardOpcodes == null) - _standardOpcodes = (List)GetProviderListProperty(_defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodes); - foreach (EventOpcode standardOpcode in _standardOpcodes) - { - if (standardOpcode.Name == name && standardOpcode.Value == value) - return standardOpcode.DisplayName; - } - return null; - } - internal string FindStandardKeywordDisplayName(string name, long value) - { - if (_standardKeywords == null) - _standardKeywords = (List)GetProviderListProperty(_defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywords); - foreach (EventKeyword standardKeyword in _standardKeywords) - { - if (standardKeyword.Name == name && standardKeyword.Value == value) - return standardKeyword.DisplayName; - } - return null; - } - internal string FindStandardTaskDisplayName(string name, uint value) - { - if (_standardTasks == null) - _standardTasks = (List)GetProviderListProperty(_defaultProviderHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks); - foreach (EventTask standardTask in _standardTasks) - { - if (standardTask.Name == name && standardTask.Value == value) - return standardTask.DisplayName; - } - return null; - } - - [System.Security.SecuritySafeCritical] - internal object GetProviderListProperty(EventLogHandle providerHandle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId metadataProperty) - { - EventLogHandle elHandle = EventLogHandle.Zero; - - try - { - UnsafeNativeMethods.EvtPublisherMetadataPropertyId propName; - UnsafeNativeMethods.EvtPublisherMetadataPropertyId propValue; - UnsafeNativeMethods.EvtPublisherMetadataPropertyId propMessageId; - ObjectTypeName objectTypeName; - - List levelList = null; - List opcodeList = null; - List keywordList = null; - List taskList = null; - - elHandle = NativeWrapper.EvtGetPublisherMetadataPropertyHandle(providerHandle, metadataProperty); - - int arraySize = NativeWrapper.EvtGetObjectArraySize(elHandle); - - switch (metadataProperty) - { - case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevels: - propName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevelName; - propValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevelValue; - propMessageId = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevelMessageID; - objectTypeName = ObjectTypeName.Level; - levelList = new List(arraySize); - break; - - case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodes: - propName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodeName; - propValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodeValue; - propMessageId = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodeMessageID; - objectTypeName = ObjectTypeName.Opcode; - opcodeList = new List(arraySize); - break; - - case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywords: - propName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywordName; - propValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywordValue; - propMessageId = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywordMessageID; - objectTypeName = ObjectTypeName.Keyword; - keywordList = new List(arraySize); - break; - - case UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks: - propName = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTaskName; - propValue = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTaskValue; - propMessageId = UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTaskMessageID; - objectTypeName = ObjectTypeName.Task; - taskList = new List(arraySize); - break; - - default: - return null; - } - for (int index = 0; index < arraySize; index++) - { - string generalName = (string)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)propName); - - uint generalValue = 0; - long generalValueKeyword = 0; - if (objectTypeName != ObjectTypeName.Keyword) - { - generalValue = (uint)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)propValue); - } - else - { - generalValueKeyword = unchecked((long)((ulong)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)propValue))); - } - - int generalMessageId = unchecked((int)((uint)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)propMessageId))); - - string generalDisplayName = null; - - if (generalMessageId == -1) - { - if (providerHandle != _defaultProviderHandle) - { - if (_defaultProviderHandle.IsInvalid) - { - _defaultProviderHandle = NativeWrapper.EvtOpenProviderMetadata(_session.Handle, null, null, 0, 0); - } - - switch (objectTypeName) - { - case ObjectTypeName.Level: - generalDisplayName = FindStandardLevelDisplayName(generalName, generalValue); - break; - case ObjectTypeName.Opcode: - generalDisplayName = FindStandardOpcodeDisplayName(generalName, generalValue >> 16); - break; - case ObjectTypeName.Keyword: - generalDisplayName = FindStandardKeywordDisplayName(generalName, generalValueKeyword); - break; - case ObjectTypeName.Task: - generalDisplayName = FindStandardTaskDisplayName(generalName, generalValue); - break; - default: - generalDisplayName = null; - break; - } - } - } - else - { - generalDisplayName = NativeWrapper.EvtFormatMessage(providerHandle, unchecked((uint)generalMessageId)); - } - - - switch (objectTypeName) - { - case ObjectTypeName.Level: - levelList.Add(new EventLevel(generalName, (int)generalValue, generalDisplayName)); - break; - case ObjectTypeName.Opcode: - opcodeList.Add(new EventOpcode(generalName, (int)(generalValue >> 16), generalDisplayName)); - break; - case ObjectTypeName.Keyword: - keywordList.Add(new EventKeyword(generalName, (long)generalValueKeyword, generalDisplayName)); - break; - case ObjectTypeName.Task: - Guid taskGuid = (Guid)NativeWrapper.EvtGetObjectArrayProperty(elHandle, index, (int)UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTaskEventGuid); - taskList.Add(new EventTask(generalName, (int)generalValue, generalDisplayName, taskGuid)); - break; - default: - return null; - } - } - - switch (objectTypeName) - { - case ObjectTypeName.Level: - return levelList; - case ObjectTypeName.Opcode: - return opcodeList; - case ObjectTypeName.Keyword: - return keywordList; - case ObjectTypeName.Task: - return taskList; - } - return null; - } - finally - { - elHandle.Dispose(); - } - } - - - public IList Levels - { - get - { - List el; - lock (_syncObject) - { - if (_levels != null) - return _levels; - - el = (List)this.GetProviderListProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataLevels); - _levels = el.AsReadOnly(); - } - return _levels; - } - } - - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Opcodes", Justification = "matell: Shipped public in 3.5, breaking change to fix now.")] - public IList Opcodes - { - get - { - List eo; - lock (_syncObject) - { - if (_opcodes != null) - return _opcodes; - - eo = (List)this.GetProviderListProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataOpcodes); - _opcodes = eo.AsReadOnly(); - } - return _opcodes; - } - } - - public IList Keywords - { - get - { - List ek; - lock (_syncObject) - { - if (_keywords != null) - return _keywords; - - ek = (List)this.GetProviderListProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataKeywords); - _keywords = ek.AsReadOnly(); - } - return _keywords; - } - } - - - public IList Tasks - { - get - { - List et; - lock (_syncObject) - { - if (_tasks != null) - return _tasks; - - et = (List)this.GetProviderListProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks); - _tasks = et.AsReadOnly(); - } - return _tasks; - } - } - - - public IEnumerable Events - { - [System.Security.SecurityCritical] - get - { - List emList = new List(); - - EventLogHandle emEnumHandle = NativeWrapper.EvtOpenEventMetadataEnum(_handle, 0); - - using (emEnumHandle) - { - while (true) - { - EventLogHandle emHandle = emHandle = NativeWrapper.EvtNextEventMetadata(emEnumHandle, 0); - if (emHandle == null) - break; - - using (emHandle) - { - unchecked - { - uint emId = (uint)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventID); - byte emVersion = (byte)((uint)(NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventVersion))); - byte emChannelId = (byte)((uint)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventChannel)); - byte emLevel = (byte)((uint)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventLevel)); - byte emOpcode = (byte)((uint)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventOpcode)); - short emTask = (short)((uint)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventTask)); - long emKeywords = (long)(ulong)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventKeyword); - string emTemplate = (string)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventTemplate); - int messageId = (int)((uint)NativeWrapper.EvtGetEventMetadataProperty(emHandle, UnsafeNativeMethods.EvtEventMetadataPropertyId.EventMetadataEventMessageID)); - - string emMessage = (messageId == -1) - ? null - : NativeWrapper.EvtFormatMessage(_handle, (uint)messageId); - - EventMetadata em = new EventMetadata(emId, emVersion, emChannelId, emLevel, emOpcode, emTask, emKeywords, emTemplate, emMessage, this); - emList.Add(em); - } - } - } - return emList.AsReadOnly(); - } - } - } - - // throws if Provider metadata has been uninstalled since this object was created. - - internal void CheckReleased() - { - lock (_syncObject) - { - this.GetProviderListProperty(_handle, UnsafeNativeMethods.EvtPublisherMetadataPropertyId.EvtPublisherMetadataTasks); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - [System.Security.SecuritySafeCritical] - protected virtual void Dispose(bool disposing) - { - if (_handle != null && !_handle.IsInvalid) - _handle.Dispose(); - } - } -} diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/ProviderMetadataCachedInformation.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/ProviderMetadataCachedInformation.cs deleted file mode 100644 index 6fedf2f149fe..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/ProviderMetadataCachedInformation.cs +++ /dev/null @@ -1,307 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** This internal class exposes a limited set of cached Provider -** metadata information. It is meant to support the Metadata -** -============================================================*/ - -using System.Globalization; -using System.Collections.Generic; - -namespace System.Diagnostics.Eventing.Reader -{ - // - // this class does not expose underlying Provider metadata objects. Instead it - // exposes a limited set of Provider metadata information from the cache. The reason - // for this is so the cache can easily Dispose the metadata object without worrying - // about who is using it. - // - internal class ProviderMetadataCachedInformation - { - private Dictionary _cache; - private int _maximumCacheSize; - private EventLogSession _session; - private string _logfile; - - private class ProviderMetadataId - { - private string _providerName; - private CultureInfo _cultureInfo; - - public ProviderMetadataId(string providerName, CultureInfo cultureInfo) - { - _providerName = providerName; - _cultureInfo = cultureInfo; - } - - public override bool Equals(object obj) - { - ProviderMetadataId rhs = obj as ProviderMetadataId; - if (rhs == null) return false; - if (_providerName.Equals(rhs._providerName) && (_cultureInfo == rhs._cultureInfo)) - return true; - return false; - } - - public override int GetHashCode() - { - return _providerName.GetHashCode() ^ _cultureInfo.GetHashCode(); - } - - public string ProviderName - { - get - { - return _providerName; - } - } - public CultureInfo TheCultureInfo - { - get - { - return _cultureInfo; - } - } - } - - private class CacheItem - { - private ProviderMetadata _pm; - private DateTime _theTime; - - public CacheItem(ProviderMetadata pm) - { - _pm = pm; - _theTime = DateTime.Now; - } - - public DateTime TheTime - { - get - { - return _theTime; - } - set - { - _theTime = value; - } - } - - public ProviderMetadata ProviderMetadata - { - get - { - return _pm; - } - } - } - - public ProviderMetadataCachedInformation(EventLogSession session, string logfile, int maximumCacheSize) - { - Debug.Assert(session != null); - _session = session; - _logfile = logfile; - _cache = new Dictionary(); - _maximumCacheSize = maximumCacheSize; - } - - private bool IsCacheFull() - { - return _cache.Count == _maximumCacheSize; - } - - private bool IsProviderinCache(ProviderMetadataId key) - { - return _cache.ContainsKey(key); - } - - private void DeleteCacheEntry(ProviderMetadataId key) - { - if (!IsProviderinCache(key)) - return; - - CacheItem value = _cache[key]; - _cache.Remove(key); - - value.ProviderMetadata.Dispose(); - } - - - private void AddCacheEntry(ProviderMetadataId key, ProviderMetadata pm) - { - if (IsCacheFull()) - FlushOldestEntry(); - - CacheItem value = new CacheItem(pm); - _cache.Add(key, value); - return; - } - - private void FlushOldestEntry() - { - double maxPassedTime = -10; - DateTime timeNow = DateTime.Now; - ProviderMetadataId keyToDelete = null; - - //get the entry in the cache which was not accessed for the longest time. - foreach (KeyValuePair kvp in _cache) - { - //the time difference (in ms) between the timeNow and the last used time of each entry - TimeSpan timeDifference = timeNow.Subtract(kvp.Value.TheTime); - - //for the "unused" items (with ReferenceCount == 0) -> can possible be deleted. - if (timeDifference.TotalMilliseconds >= maxPassedTime) - { - maxPassedTime = timeDifference.TotalMilliseconds; - keyToDelete = kvp.Key; - } - } - - if (keyToDelete != null) - DeleteCacheEntry(keyToDelete); - } - - private static void UpdateCacheValueInfoForHit(CacheItem cacheItem) - { - cacheItem.TheTime = DateTime.Now; - } - - private ProviderMetadata GetProviderMetadata(ProviderMetadataId key) - { - if (!IsProviderinCache(key)) - { - ProviderMetadata pm; - try - { - pm = new ProviderMetadata(key.ProviderName, _session, key.TheCultureInfo, _logfile); - } - catch (EventLogNotFoundException) - { - pm = new ProviderMetadata(key.ProviderName, _session, key.TheCultureInfo); - } - AddCacheEntry(key, pm); - return pm; - } - else - { - CacheItem cacheItem = _cache[key]; - - ProviderMetadata pm = cacheItem.ProviderMetadata; - - // - // check Provider metadata to be sure it's hasn't been - // uninstalled since last time it was used. - // - - try - { - pm.CheckReleased(); - UpdateCacheValueInfoForHit(cacheItem); - } - catch (EventLogException) - { - DeleteCacheEntry(key); - try - { - pm = new ProviderMetadata(key.ProviderName, _session, key.TheCultureInfo, _logfile); - } - catch (EventLogNotFoundException) - { - pm = new ProviderMetadata(key.ProviderName, _session, key.TheCultureInfo); - } - AddCacheEntry(key, pm); - } - - return pm; - } - } - - // marking as TreatAsSafe because just passing around a reference to an EventLogHandle is safe. - [System.Security.SecuritySafeCritical] - public string GetFormatDescription(string ProviderName, EventLogHandle eventHandle) - { - lock (this) - { - ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); - - try - { - ProviderMetadata pm = GetProviderMetadata(key); - return NativeWrapper.EvtFormatMessageRenderName(pm.Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageEvent); - } - catch (EventLogNotFoundException) - { - return null; - } - } - } - - public string GetFormatDescription(string ProviderName, EventLogHandle eventHandle, string[] values) - { - lock (this) - { - ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); - ProviderMetadata pm = GetProviderMetadata(key); - try - { - return NativeWrapper.EvtFormatMessageFormatDescription(pm.Handle, eventHandle, values); - } - catch (EventLogNotFoundException) - { - return null; - } - } - } - - // marking as TreatAsSafe because just passing around a reference to an EventLogHandle is safe. - [System.Security.SecuritySafeCritical] - public string GetLevelDisplayName(string ProviderName, EventLogHandle eventHandle) - { - lock (this) - { - ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); - ProviderMetadata pm = GetProviderMetadata(key); - return NativeWrapper.EvtFormatMessageRenderName(pm.Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageLevel); - } - } - - // marking as TreatAsSafe because just passing around a reference to an EventLogHandle is safe. - [System.Security.SecuritySafeCritical] - public string GetOpcodeDisplayName(string ProviderName, EventLogHandle eventHandle) - { - lock (this) - { - ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); - ProviderMetadata pm = GetProviderMetadata(key); - return NativeWrapper.EvtFormatMessageRenderName(pm.Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageOpcode); - } - } - - // marking as TreatAsSafe because just passing around a reference to an EventLogHandle is safe. - [System.Security.SecuritySafeCritical] - public string GetTaskDisplayName(string ProviderName, EventLogHandle eventHandle) - { - lock (this) - { - ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); - ProviderMetadata pm = GetProviderMetadata(key); - return NativeWrapper.EvtFormatMessageRenderName(pm.Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageTask); - } - } - - // marking as TreatAsSafe because just passing around a reference to an EventLogHandle is safe. - [System.Security.SecuritySafeCritical] - public IEnumerable GetKeywordDisplayNames(string ProviderName, EventLogHandle eventHandle) - { - lock (this) - { - ProviderMetadataId key = new ProviderMetadataId(ProviderName, CultureInfo.CurrentCulture); - ProviderMetadata pm = GetProviderMetadata(key); - return NativeWrapper.EvtFormatMessageRenderKeywords(pm.Handle, eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageKeyword); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/Winmeta.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/Winmeta.cs deleted file mode 100644 index 47746d768683..000000000000 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/Reader/Winmeta.cs +++ /dev/null @@ -1,156 +0,0 @@ - -/*============================================================ -** -** -** Purpose: -** Contains eventing constants defined by the Windows -** environment. -** -============================================================*/ - -using System.Diagnostics.CodeAnalysis; - -namespace System.Diagnostics.Eventing.Reader -{ - /// - /// WindowsEventLevel - /// - public enum StandardEventLevel - { - /// - /// Log always - /// - LogAlways = 0, - /// - /// Only critical errors - /// - Critical, - /// - /// All errors, including previous levels - /// - Error, - /// - /// All warnings, including previous levels - /// - Warning, - /// - /// All informational events, including previous levels - /// - Informational, - /// - /// All events, including previous levels - /// - Verbose - } - /// - /// WindowsEventTask - /// - public enum StandardEventTask - { - /// - /// Undefined task - /// - None = 0 - } - - /// - /// EventOpcode - /// - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Opcode", Justification = "matell: Shipped public in 3.5, breaking change to fix now.")] - public enum StandardEventOpcode - { - /// - /// An informational event - /// - Info = 0, - /// - /// An activity start event - /// - Start, - /// - /// An activity end event - /// - Stop, - /// - /// A trace collection start event - /// - DataCollectionStart, - /// - /// A trace collection end event - /// - DataCollectionStop, - /// - /// An extensional event - /// - Extension, - /// - /// A reply event - /// - Reply, - /// - /// An event representing the activity resuming from the suspension - /// - Resume, - /// - /// An event representing the activity is suspended, pending another activity's completion - /// - Suspend, - /// - /// An event representing the activity is transferred to another component, and can continue to work - /// - Send, - /// - /// An event representing receiving an activity transfer from another component - /// - Receive = 240 - } - - /// - /// EventOpcode - /// - [Flags] - public enum StandardEventKeywords : long - { - /// - /// Wild card value - /// - None = 0x0, - /// - /// Events providing response time information - /// - ResponseTime = 0x01000000000000, - /// - /// WDI context events - /// - WdiContext = 0x02000000000000, - /// - /// WDI diagnostic events - /// - WdiDiagnostic = 0x04000000000000, - /// - /// SQM events - /// - Sqm = 0x08000000000000, - /// - /// FAiled security audits - /// - AuditFailure = 0x10000000000000, - /// - /// Successful security audits - /// - AuditSuccess = 0x20000000000000, - /// - /// Incorrect CorrelationHint value mistakenly shipped in .NET 3.5. Don't use: duplicates AuditFailure. - /// - [Obsolete("Incorrect value: use CorrelationHint2 instead", false)] - CorrelationHint = 0x10000000000000, - /// - /// Transfer events where the related Activity ID is a computed value and not a GUID - /// - CorrelationHint2 = 0x40000000000000, - /// - /// Events raised using classic eventlog API - /// - EventLogClassic = 0x80000000000000 - } -} \ No newline at end of file diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/UnsafeNativeMethods.cs b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/UnsafeNativeMethods.cs index c2a43ba09e9c..bcd15c67b9ed 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/UnsafeNativeMethods.cs +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/DotNetCode/Eventing/UnsafeNativeMethods.cs @@ -1,13 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Diagnostics.Eventing.Reader; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; namespace System.Diagnostics.Eventing { - using System; - using System.Runtime.InteropServices; - using System.Security; - using System.Text; - using System.Diagnostics.Eventing.Reader; - internal static class UnsafeNativeMethods { private const string FormatMessageDllName = "api-ms-win-core-localization-l1-2-0.dll"; @@ -16,7 +17,6 @@ internal static class UnsafeNativeMethods private static readonly IntPtr s_NULL = IntPtr.Zero; // WinError.h codes: - internal const int ERROR_SUCCESS = 0x0; internal const int ERROR_FILE_NOT_FOUND = 0x2; internal const int ERROR_PATH_NOT_FOUND = 0x3; @@ -60,7 +60,6 @@ internal static class UnsafeNativeMethods internal const int ERROR_RESOURCE_LANG_NOT_FOUND = 0x717; // 1815 // Event log specific codes: - internal const int ERROR_EVT_MESSAGE_NOT_FOUND = 15027; internal const int ERROR_EVT_MESSAGE_ID_NOT_FOUND = 15028; internal const int ERROR_EVT_UNRESOLVED_VALUE_INSERT = 15029; @@ -69,16 +68,12 @@ internal static class UnsafeNativeMethods internal const int ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND = 15033; internal const int ERROR_MUI_FILE_NOT_FOUND = 15100; - // // ErrorCode & format - // - // for win32 error message formatting private const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; private const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; - [DllImport(FormatMessageDllName, CharSet = CharSet.Unicode, BestFitMapping = false)] [SecurityCritical] internal static extern int FormatMessage(int dwFlags, IntPtr lpSource, @@ -87,7 +82,7 @@ internal static class UnsafeNativeMethods // Gets an error message for a Win32 error code. [SecurityCritical] - internal static String GetMessage(int errorCode) + internal static string GetMessage(int errorCode) { StringBuilder sb = new StringBuilder(512); int result = UnsafeNativeMethods.FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | @@ -98,7 +93,7 @@ internal static String GetMessage(int errorCode) // result is the # of characters copied to the StringBuilder on NT, // but on Win9x, it appears to be the number of MBCS buffer. // Just give up and return the String as-is... - String s = sb.ToString(); + string s = sb.ToString(); return s; } else @@ -107,12 +102,8 @@ internal static String GetMessage(int errorCode) } } - // // ETW Methods - // - // // Callback - // [SecurityCritical] internal unsafe delegate void EtwEnableCallback( [In] ref Guid sourceId, @@ -124,9 +115,7 @@ internal static String GetMessage(int errorCode) [In] void* callbackContext ); - // // Registration APIs - // [DllImport(EventProviderDllName, ExactSpelling = true, EntryPoint = "EventRegister", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] [SecurityCritical] internal static extern unsafe uint EventRegister( @@ -140,10 +129,7 @@ internal static String GetMessage(int errorCode) [SecurityCritical] internal static extern int EventUnregister([In] long registrationHandle); - - // // Control (Is Enabled) APIs - // [DllImport(EventProviderDllName, ExactSpelling = true, EntryPoint = "EventEnabled", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] [SecurityCritical] internal static extern int EventEnabled([In] long registrationHandle, [In] ref System.Diagnostics.Eventing.EventDescriptor eventDescriptor); @@ -152,9 +138,7 @@ internal static String GetMessage(int errorCode) [SecurityCritical] internal static extern int EventProviderEnabled([In] long registrationHandle, [In] byte level, [In] long keywords); - // // Writing (Publishing/Logging) APIs - // [DllImport(EventProviderDllName, ExactSpelling = true, EntryPoint = "EventWrite", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] [SecurityCritical] internal static extern unsafe uint EventWrite( @@ -164,9 +148,7 @@ internal static String GetMessage(int errorCode) [In] void* userData ); - // // Writing (Publishing/Logging) APIs - // [DllImport(EventProviderDllName, ExactSpelling = true, EntryPoint = "EventWrite", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] [SecurityCritical] internal static extern unsafe uint EventWrite( @@ -195,16 +177,12 @@ internal static String GetMessage(int errorCode) [In] long keywords, [In] char* message ); - // // ActivityId Control APIs - // [DllImport(EventProviderDllName, ExactSpelling = true, EntryPoint = "EventActivityIdControl", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] [SecurityCritical] internal static extern unsafe uint EventActivityIdControl([In] int ControlCode, [In][Out] ref Guid ActivityId); - // // EventLog - // [Flags] internal enum EvtQueryFlags { @@ -216,7 +194,7 @@ internal enum EvtQueryFlags } /// - /// Evt Variant types + /// Evt Variant types. /// internal enum EvtVariantType { @@ -245,7 +223,7 @@ internal enum EvtVariantType // these types used internally EvtVarTypeEvtHandle = 32, EvtVarTypeEvtXml = 35, - //Array = 128 + // Array = 128 EvtVarTypeStringArray = 129, EvtVarTypeUInt32Array = 136 } @@ -338,16 +316,16 @@ internal enum EvtEventPropertyId } /// - /// The query flags to get information about query + /// The query flags to get information about query. /// internal enum EvtQueryPropertyId { - EvtQueryNames = 0, //String; //Variant will be array of EvtVarTypeString - EvtQueryStatuses = 1 //UInt32; //Variant will be Array of EvtVarTypeUInt32 + EvtQueryNames = 0, // String; // Variant will be array of EvtVarTypeString + EvtQueryStatuses = 1 // UInt32; // Variant will be Array of EvtVarTypeUInt32 } /// - /// Publisher Metadata properties + /// Publisher Metadata properties. /// internal enum EvtPublisherMetadataPropertyId { @@ -384,8 +362,8 @@ internal enum EvtPublisherMetadataPropertyId EvtPublisherMetadataKeywords = 25, // EvtVarTypeEvtHandle, ObjectArray EvtPublisherMetadataKeywordName = 26, // EvtVarTypeString EvtPublisherMetadataKeywordValue = 27, // EvtVarTypeUInt64 - EvtPublisherMetadataKeywordMessageID = 28//, // EvtVarTypeUInt32 - //EvtPublisherMetadataPropertyIdEND + EvtPublisherMetadataKeywordMessageID = 28 // EvtVarTypeUInt32 + // EvtPublisherMetadataPropertyIdEND } internal enum EvtChannelReferenceFlags @@ -404,10 +382,10 @@ internal enum EvtEventMetadataPropertyId EventMetadataEventKeyword, // EvtVarTypeUInt64 EventMetadataEventMessageID,// EvtVarTypeUInt32 EventMetadataEventTemplate // EvtVarTypeString - //EvtEventMetadataPropertyIdEND + // EvtEventMetadataPropertyIdEND } - //CHANNEL CONFIGURATION + // CHANNEL CONFIGURATION internal enum EvtChannelConfigPropertyId { EvtChannelConfigEnabled = 0, // EvtVarTypeBoolean @@ -433,7 +411,7 @@ internal enum EvtChannelConfigPropertyId EvtChannelConfigPropertyIdEND } - //LOG INFORMATION + // LOG INFORMATION internal enum EvtLogPropertyId { EvtLogCreationTime = 0, // EvtVarTypeFileTime @@ -453,7 +431,7 @@ internal enum EvtExportLogFlags EvtExportLogTolerateQueryErrors = 0x1000 } - //RENDERING + // RENDERING internal enum EvtRenderContextFlags { EvtRenderContextValues = 0, // Render specific properties @@ -504,7 +482,7 @@ internal enum EvtSystemPropertyId EvtSystemPropertyIdEND } - //SESSION + // SESSION internal enum EvtLoginClass { EvtRpcLogin = 1 @@ -524,8 +502,7 @@ internal struct EvtRpcLogin public int Flags; } - - //SEEK + // SEEK [Flags] internal enum EvtSeekFlags { @@ -545,7 +522,7 @@ internal enum EvtSeekFlags [MarshalAs(UnmanagedType.LPWStr)]string query, int flags); - //SEEK + // SEEK [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] [return: MarshalAs(UnmanagedType.Bool)] @@ -590,7 +567,7 @@ IntPtr eventHandle [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool EvtGetEventInfo( EventLogHandle eventHandle, - //int propertyId + // int propertyId [MarshalAs(UnmanagedType.I4)]EvtEventPropertyId propertyId, int bufferSize, IntPtr bufferPtr, @@ -608,7 +585,7 @@ IntPtr eventHandle ref int bufferRequired ); - //PUBLISHER METADATA + // PUBLISHER METADATA [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtOpenPublisherMetadata( @@ -631,8 +608,7 @@ int flags out int publisherMetadataPropertyBufferUsed ); - //NEW - + // NEW [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] [return: MarshalAs(UnmanagedType.Bool)] @@ -654,7 +630,7 @@ int flags out int propertyValueBufferUsed ); - //NEW 2 + // NEW 2 [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtOpenEventMetadataEnum( @@ -664,7 +640,7 @@ int flags [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] - //public static extern IntPtr EvtNextEventMetadata( + // public static extern IntPtr EvtNextEventMetadata( internal static extern EventLogHandle EvtNextEventMetadata( EventLogHandle eventMetadataEnum, int flags @@ -682,9 +658,7 @@ int flags out int eventMetadataPropertyBufferUsed ); - - //Channel Configuration Native Api - + // Channel Configuration Native Api [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtOpenChannelEnum( @@ -698,12 +672,11 @@ int flags internal static extern bool EvtNextChannelPath( EventLogHandle channelEnum, int channelPathBufferSize, - //StringBuilder channelPathBuffer, + // StringBuilder channelPathBuffer, [Out, MarshalAs(UnmanagedType.LPWStr)]StringBuilder channelPathBuffer, out int channelPathBufferUsed ); - [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtOpenPublisherEnum( @@ -737,7 +710,6 @@ int flags int flags ); - [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] [return: MarshalAs(UnmanagedType.Bool)] @@ -748,7 +720,6 @@ int flags ref EvtVariant propertyValue ); - [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] [return: MarshalAs(UnmanagedType.Bool)] @@ -761,8 +732,7 @@ int flags out int propertyValueBufferUsed ); - //Log Information Native Api - + // Log Information Native API [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtOpenLog( @@ -771,7 +741,6 @@ int flags [MarshalAs(UnmanagedType.I4)]PathType flags ); - [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] [return: MarshalAs(UnmanagedType.Bool)] @@ -783,8 +752,7 @@ int flags out int propertyValueBufferUsed ); - //LOG MANIPULATION - + // LOG MANIPULATION [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] [return: MarshalAs(UnmanagedType.Bool)] @@ -816,13 +784,13 @@ int flags int flags ); - //RENDERING + // RENDERING [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtCreateRenderContext( Int32 valuePathsCount, [MarshalAs(UnmanagedType.LPArray,ArraySubType = UnmanagedType.LPWStr)] - String[] valuePaths, + string[] valuePaths, [MarshalAs(UnmanagedType.I4)]EvtRenderContextFlags flags ); @@ -839,7 +807,6 @@ int flags out int propCount ); - [DllImport(WEVTAPI, EntryPoint = "EvtRender", CallingConvention = CallingConvention.Winapi, SetLastError = true)] [SecurityCritical] [return: MarshalAs(UnmanagedType.Bool)] @@ -853,7 +820,6 @@ int flags out int propCount ); - [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] internal struct EvtStringVariant { @@ -895,7 +861,7 @@ internal struct EvtStringVariant out int bufferUsed ); - //SESSION + // SESSION [DllImport(WEVTAPI, CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtOpenSession( @@ -905,7 +871,7 @@ internal struct EvtStringVariant int flags ); - //BOOKMARK + // BOOKMARK [DllImport(WEVTAPI, EntryPoint = "EvtCreateBookmark", CharSet = CharSet.Unicode, SetLastError = true)] [SecurityCritical] internal static extern EventLogHandle EvtCreateBookmark( diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index e222112cfb66..307d115ae4dd 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -1,29 +1,14 @@  - PowerShell Core's Microsoft.PowerShell.CoreCLR.Eventing project + PowerShell's Microsoft.PowerShell.CoreCLR.Eventing project $(NoWarn);CS1591 Microsoft.PowerShell.CoreCLR.Eventing - - $(DefineConstants);CORECLR - - - - portable - - - - $(DefineConstants);UNIX - - - - full - - - + + diff --git a/src/Microsoft.PowerShell.GlobalTool.Shim/GlobalToolShim.cs b/src/Microsoft.PowerShell.GlobalTool.Shim/GlobalToolShim.cs new file mode 100644 index 000000000000..79c13b4efc59 --- /dev/null +++ b/src/Microsoft.PowerShell.GlobalTool.Shim/GlobalToolShim.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace Microsoft.PowerShell.GlobalTool.Shim +{ + /// + /// Shim layer to chose the appropriate runtime for PowerShell DotNet Global tool. + /// + public class EntryPoint + { + private const string PwshDllName = "pwsh.dll"; + + private const string WinFolderName = "win"; + + private const string UnixFolderName = "unix"; + + /// + /// Entry point for the global tool. + /// + /// Arguments passed to the global tool.' + /// Exit code returned by pwsh. + public static int Main(string[] args) + { + var currentPath = new FileInfo(System.Reflection.Assembly.GetEntryAssembly().Location).Directory.FullName; + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + string platformFolder = isWindows ? WinFolderName : UnixFolderName; + + string argsString = args.Length > 0 ? string.Join(" ", args) : null; + var pwshPath = Path.Combine(currentPath, platformFolder, PwshDllName); + string processArgs = string.IsNullOrEmpty(argsString) ? $"\"{pwshPath}\"" : $"\"{pwshPath}\" {argsString}"; + + if (File.Exists(pwshPath)) + { + var process = System.Diagnostics.Process.Start("dotnet", processArgs); + process.WaitForExit(); + return process.ExitCode; + } + else + { + throw new FileNotFoundException(pwshPath); + } + } + } +} diff --git a/src/Microsoft.PowerShell.GlobalTool.Shim/Microsoft.PowerShell.GlobalTool.Shim.csproj b/src/Microsoft.PowerShell.GlobalTool.Shim/Microsoft.PowerShell.GlobalTool.Shim.csproj new file mode 100644 index 000000000000..aa845a7817d4 --- /dev/null +++ b/src/Microsoft.PowerShell.GlobalTool.Shim/Microsoft.PowerShell.GlobalTool.Shim.csproj @@ -0,0 +1,17 @@ + + + + + Shim for global tool to select appropriate runtime + Microsoft.PowerShell.GlobalTool.Shim + EXE + Microsoft.PowerShell.GlobalTool.Shim + + + + + + + + + diff --git a/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json b/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json new file mode 100644 index 000000000000..8ba6dc2eba97 --- /dev/null +++ b/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json @@ -0,0 +1,4 @@ +// This is required to roll forward to runtime 3.x when 2.x is not installed +{ + "rollForwardOnNoCandidateFx": 2 +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs index 65540314dcc7..d799a70d9db6 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Collections.Generic; @@ -11,7 +14,6 @@ using System.Diagnostics.CodeAnalysis; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -40,8 +42,10 @@ public class AddLocalGroupMemberCommand : PSCmdlet public Microsoft.PowerShell.Commands.LocalGroup Group { get { return this.group;} + set { this.group = value; } } + private Microsoft.PowerShell.Commands.LocalGroup group; /// @@ -59,8 +63,10 @@ public Microsoft.PowerShell.Commands.LocalGroup Group public Microsoft.PowerShell.Commands.LocalPrincipal[] Member { get { return this.member;} + set { this.member = value; } } + private Microsoft.PowerShell.Commands.LocalPrincipal[] member; /// @@ -74,8 +80,10 @@ public Microsoft.PowerShell.Commands.LocalPrincipal[] Member public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -89,12 +97,13 @@ public string Name public System.Security.Principal.SecurityIdentifier SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier sid; #endregion Parameter Properties - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -104,7 +113,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -125,7 +133,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -203,13 +210,13 @@ private LocalPrincipal MakePrincipal(string groupId, LocalPrincipal member) } } } + if (CheckShouldProcess(principal, groupId)) return principal; return null; } - /// /// Determine if a principal should be processed. /// Just a wrapper around Cmdlet.ShouldProcess, with localized string @@ -245,10 +252,10 @@ private void ProcessGroup(LocalGroup group) foreach (var member in this.Member) { LocalPrincipal principal = MakePrincipal(groupId, member); - if (null != principal) + if (principal != null) { var ex = sam.AddLocalGroupMember(group, principal); - if (null != ex) + if (ex != null) { WriteError(ex.MakeErrorRecord()); } @@ -279,10 +286,10 @@ private void ProcessSid(SecurityIdentifier groupSid) foreach (var member in this.Member) { LocalPrincipal principal = MakePrincipal(groupSid.ToString(), member); - if (null != principal) + if (principal != null) { var ex = sam.AddLocalGroupMember(groupSid, principal); - if (null != ex) + if (ex != null) { WriteError(ex.MakeErrorRecord()); } @@ -291,7 +298,7 @@ private void ProcessSid(SecurityIdentifier groupSid) } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs index 9d7d4c5ca3c6..5125f28c88ee 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Collections.Generic; @@ -10,7 +13,6 @@ using System.Diagnostics.CodeAnalysis; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -48,8 +50,10 @@ public class DisableLocalUserCommand : Cmdlet public Microsoft.PowerShell.Commands.LocalUser[] InputObject { get { return this.inputobject; } + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalUser[] inputobject; /// @@ -67,8 +71,10 @@ public Microsoft.PowerShell.Commands.LocalUser[] InputObject public string[] Name { get { return this.name; } + set { this.name = value; } } + private string[] name; /// @@ -86,12 +92,13 @@ public string[] Name public System.Security.Principal.SecurityIdentifier[] SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier[] sid; #endregion Parameter Properties - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -101,7 +108,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -119,7 +125,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -135,7 +140,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process users requested by -Name + /// Process users requested by -Name. /// /// /// All arguments to -Name will be treated as names, @@ -161,7 +166,7 @@ private void ProcessNames() } /// - /// Process users requested by -SID + /// Process users requested by -SID. /// private void ProcessSids() { @@ -183,7 +188,7 @@ private void ProcessSids() } /// - /// Process users requested by -InputObject + /// Process users requested by -InputObject. /// private void ProcessUsers() { @@ -209,7 +214,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionDisableUser); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs index cf0562f23f5a..60f7f21c3fd0 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Collections.Generic; @@ -10,7 +13,6 @@ using System.Diagnostics.CodeAnalysis; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -48,8 +50,10 @@ public class EnableLocalUserCommand : Cmdlet public Microsoft.PowerShell.Commands.LocalUser[] InputObject { get { return this.inputobject; } + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalUser[] inputobject; /// @@ -67,8 +71,10 @@ public Microsoft.PowerShell.Commands.LocalUser[] InputObject public string[] Name { get { return this.name; } + set { this.name = value; } } + private string[] name; /// @@ -86,14 +92,13 @@ public string[] Name public System.Security.Principal.SecurityIdentifier[] SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier[] sid; #endregion Parameter Properties - - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -103,7 +108,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -121,7 +125,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -137,7 +140,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process users requested by -Name + /// Process users requested by -Name. /// /// /// All arguments to -Name will be treated as names, @@ -163,7 +166,7 @@ private void ProcessNames() } /// - /// Process users requested by -SID + /// Process users requested by -SID. /// private void ProcessSids() { @@ -185,7 +188,7 @@ private void ProcessSids() } /// - /// Process users requested by -InputObject + /// Process users requested by -InputObject. /// private void ProcessUsers() { @@ -211,7 +214,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionEnableUser); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs index bd93d56fa6e8..74836e1aa148 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -8,7 +11,6 @@ using System.Diagnostics.CodeAnalysis; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -39,8 +41,10 @@ public class GetLocalGroupCommand : Cmdlet public string[] Name { get { return this.name; } + set { this.name = value; } } + private string[] name; /// @@ -56,14 +60,13 @@ public string[] Name public System.Security.Principal.SecurityIdentifier[] SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier[] sid; #endregion Parameter Properties - - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -73,7 +76,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -91,7 +93,6 @@ protected override void ProcessRecord() ProcessSids(); } - /// /// EndProcessing method. /// @@ -107,7 +108,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process groups requested by -Name + /// Process groups requested by -Name. /// /// /// All arguments to -Name will be treated as names, @@ -144,7 +145,7 @@ private void ProcessNames() } /// - /// Process groups requested by -SID + /// Process groups requested by -SID. /// private void ProcessSids() { @@ -164,7 +165,7 @@ private void ProcessSids() } } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs index 0acb4d03dede..e3853d73ccbb 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Collections.Generic; @@ -8,7 +11,6 @@ using System.Management.Automation.SecurityAccountsManager.Extensions; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -38,8 +40,10 @@ public class GetLocalGroupMemberCommand : Cmdlet public Microsoft.PowerShell.Commands.LocalGroup Group { get { return this.group;} + set { this.group = value; } } + private Microsoft.PowerShell.Commands.LocalGroup group; /// @@ -53,8 +57,10 @@ public Microsoft.PowerShell.Commands.LocalGroup Group public string Member { get { return this.member;} + set { this.member = value; } } + private string member; /// @@ -70,8 +76,10 @@ public string Member public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -87,12 +95,13 @@ public string Name public System.Security.Principal.SecurityIdentifier SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier sid; #endregion Parameter Properties - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -102,7 +111,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -128,7 +136,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -150,12 +157,12 @@ private IEnumerable ProcessesMembership(IEnumerable(membership); } else { - //var rv = new List(); + // var rv = new List(); rv = new List(); if (WildcardPattern.ContainsWildcardCharacters(Member)) @@ -223,7 +230,7 @@ private IEnumerable ProcessSid(SecurityIdentifier groupSid) return ProcessesMembership(sam.GetLocalGroupMembers(groupSid)); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs index e37acc706116..f25791df48c7 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Collections.Generic; @@ -8,7 +11,6 @@ using System.Management.Automation.SecurityAccountsManager.Extensions; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -44,6 +46,7 @@ public string[] Name set { this.name = value; } } + private string[] name; /// @@ -59,13 +62,13 @@ public string[] Name public System.Security.Principal.SecurityIdentifier[] SID { get { return this.sid; } + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier[] sid; #endregion Parameter Properties - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -75,7 +78,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -93,7 +95,6 @@ protected override void ProcessRecord() ProcessSids(); } - /// /// EndProcessing method. /// @@ -109,7 +110,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process users requested by -Name + /// Process users requested by -Name. /// /// /// All arguments to -Name will be treated as names, @@ -146,7 +147,7 @@ private void ProcessNames() } /// - /// Process users requested by -SID + /// Process users requested by -SID. /// private void ProcessSids() { @@ -166,7 +167,7 @@ private void ProcessSids() } } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs index 35a6272de968..2c2f28d6173a 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -8,7 +11,6 @@ using Microsoft.PowerShell.LocalAccounts; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -35,8 +37,10 @@ public class NewLocalGroupCommand : Cmdlet public string Description { get { return this.description;} + set { this.description = value; } } + private string description; /// @@ -52,13 +56,13 @@ public string Description public string Name { get { return this.name;} + set { this.name = value; } } + private string name; #endregion Parameter Properties - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -68,7 +72,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -93,7 +96,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -113,7 +115,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionNewGroup); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs index 70690eb85842..a5d012e187f1 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -8,7 +11,6 @@ using Microsoft.PowerShell.LocalAccounts; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -48,8 +50,10 @@ public class NewLocalUserCommand : PSCmdlet public System.DateTime AccountExpires { get { return this.accountexpires;} + set { this.accountexpires = value; } } + private System.DateTime accountexpires; // This parameter added by hand (copied from SetLocalUserCommand), not by Cmdlet Designer @@ -61,8 +65,10 @@ public System.DateTime AccountExpires public System.Management.Automation.SwitchParameter AccountNeverExpires { get { return this.accountneverexpires;} + set { this.accountneverexpires = value; } } + private System.Management.Automation.SwitchParameter accountneverexpires; /// @@ -74,8 +80,10 @@ public System.Management.Automation.SwitchParameter AccountNeverExpires public string Description { get { return this.description;} + set { this.description = value; } } + private string description; /// @@ -86,8 +94,10 @@ public string Description public System.Management.Automation.SwitchParameter Disabled { get { return this.disabled;} + set { this.disabled = value; } } + private System.Management.Automation.SwitchParameter disabled; /// @@ -100,8 +110,10 @@ public System.Management.Automation.SwitchParameter Disabled public string FullName { get { return this.fullname;} + set { this.fullname = value; } } + private string fullname; /// @@ -118,8 +130,10 @@ public string FullName public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -134,8 +148,10 @@ public string Name public System.Security.SecureString Password { get { return this.password;} + set { this.password = value; } } + private System.Security.SecureString password; /// @@ -148,8 +164,10 @@ public System.Security.SecureString Password public System.Management.Automation.SwitchParameter NoPassword { get { return this.nopassword; } + set { this.nopassword = value; } } + private System.Management.Automation.SwitchParameter nopassword; /// @@ -161,8 +179,10 @@ public System.Management.Automation.SwitchParameter NoPassword public System.Management.Automation.SwitchParameter PasswordNeverExpires { get { return this.passwordneverexpires; } + set { this.passwordneverexpires = value; } } + private System.Management.Automation.SwitchParameter passwordneverexpires; /// @@ -174,13 +194,13 @@ public System.Management.Automation.SwitchParameter PasswordNeverExpires public System.Management.Automation.SwitchParameter UserMayNotChangePassword { get { return this.usermaynotchangepassword;} + set { this.usermaynotchangepassword = value; } } + private System.Management.Automation.SwitchParameter usermaynotchangepassword; #endregion Parameter Properties - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -192,10 +212,10 @@ protected override void BeginProcessing() InvalidParametersException ex = new InvalidParametersException("AccountExpires", "AccountNeverExpires"); ThrowTerminatingError(ex.MakeErrorRecord()); } + sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -250,7 +270,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -270,7 +289,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionNewUser); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs index cb93071ca5da..2fc7c3321111 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -9,7 +12,6 @@ using System.Diagnostics.CodeAnalysis; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -41,8 +43,10 @@ public class RemoveLocalGroupCommand : Cmdlet public Microsoft.PowerShell.Commands.LocalGroup[] InputObject { get { return this.inputobject; } + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalGroup[] inputobject; /// @@ -60,8 +64,10 @@ public Microsoft.PowerShell.Commands.LocalGroup[] InputObject public string[] Name { get { return this.name; } + set { this.name = value; } } + private string[] name; /// @@ -79,12 +85,13 @@ public string[] Name public System.Security.Principal.SecurityIdentifier[] SID { get { return this.sid; } + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier[] sid; #endregion Parameter Properties - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -94,7 +101,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -112,7 +118,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -128,7 +133,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process groups requested by -Name + /// Process groups requested by -Name. /// /// /// All arguments to -Name will be treated as names, @@ -154,7 +159,7 @@ private void ProcessNames() } /// - /// Process groups requested by -SID + /// Process groups requested by -SID. /// private void ProcessSids() { @@ -176,7 +181,7 @@ private void ProcessSids() } /// - /// Process groups given through -InputObject + /// Process groups given through -InputObject. /// private void ProcessGroups() { @@ -202,7 +207,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionRemoveGroup); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs index b8c87bef98a5..0ed137b08f4c 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Collections.Generic; @@ -11,7 +14,6 @@ using System.Diagnostics.CodeAnalysis; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -40,8 +42,10 @@ public class RemoveLocalGroupMemberCommand : PSCmdlet public Microsoft.PowerShell.Commands.LocalGroup Group { get { return this.group;} + set { this.group = value; } } + private Microsoft.PowerShell.Commands.LocalGroup group; /// @@ -59,8 +63,10 @@ public Microsoft.PowerShell.Commands.LocalGroup Group public Microsoft.PowerShell.Commands.LocalPrincipal[] Member { get { return this.member;} + set { this.member = value; } } + private Microsoft.PowerShell.Commands.LocalPrincipal[] member; /// @@ -74,8 +80,10 @@ public Microsoft.PowerShell.Commands.LocalPrincipal[] Member public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -89,12 +97,13 @@ public string Name public System.Security.Principal.SecurityIdentifier SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier sid; #endregion Parameter Properties - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -104,7 +113,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -125,7 +133,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -244,10 +251,10 @@ private void ProcessGroup(LocalGroup group) foreach (var member in this.Member) { LocalPrincipal principal = MakePrincipal(groupId, member); - if (null != principal) + if (principal != null) { var ex = sam.RemoveLocalGroupMember(group, principal); - if (null != ex) + if (ex != null) { WriteError(ex.MakeErrorRecord()); } @@ -278,10 +285,10 @@ private void ProcessSid(SecurityIdentifier groupSid) foreach (var member in this.Member) { LocalPrincipal principal = MakePrincipal(groupSid.ToString(), member); - if (null != principal) + if (principal != null) { var ex = sam.RemoveLocalGroupMember(groupSid, principal); - if (null != ex) + if (ex != null) { WriteError(ex.MakeErrorRecord()); } @@ -289,7 +296,7 @@ private void ProcessSid(SecurityIdentifier groupSid) } } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs index cbcef6ef48f1..4ef9da3b5992 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -9,7 +12,6 @@ using System.Diagnostics.CodeAnalysis; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -42,8 +44,10 @@ public class RemoveLocalUserCommand : Cmdlet public Microsoft.PowerShell.Commands.LocalUser[] InputObject { get { return this.inputobject;} + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalUser[] inputobject; /// @@ -61,8 +65,10 @@ public Microsoft.PowerShell.Commands.LocalUser[] InputObject public string[] Name { get { return this.name; } + set { this.name = value; } } + private string[] name; /// @@ -80,13 +86,13 @@ public string[] Name public System.Security.Principal.SecurityIdentifier[] SID { get { return this.sid; } + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier[] sid; #endregion Parameter Properties - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -96,7 +102,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -114,7 +119,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -130,7 +134,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process users requested by -Name + /// Process users requested by -Name. /// /// /// All arguments to -Name will be treated as names, @@ -156,7 +160,7 @@ private void ProcessNames() } /// - /// Process users requested by -SID + /// Process users requested by -SID. /// private void ProcessSids() { @@ -178,7 +182,7 @@ private void ProcessSids() } /// - /// Process users given through -InputObject + /// Process users given through -InputObject. /// private void ProcessUsers() { @@ -204,7 +208,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionRemoveUser); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs index 25254cf05fc4..05fd348e95e4 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -8,7 +11,6 @@ using Microsoft.PowerShell.LocalAccounts; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -40,8 +42,10 @@ public class RenameLocalGroupCommand : Cmdlet public Microsoft.PowerShell.Commands.LocalGroup InputObject { get { return this.inputobject;} + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalGroup inputobject; /// @@ -58,8 +62,10 @@ public Microsoft.PowerShell.Commands.LocalGroup InputObject public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -73,8 +79,10 @@ public string Name public string NewName { get { return this.newname;} + set { this.newname = value; } } + private string newname; /// @@ -90,12 +98,13 @@ public string NewName public System.Security.Principal.SecurityIdentifier SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier sid; #endregion Parameter Properties - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -105,7 +114,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -123,7 +131,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -139,7 +146,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process group requested by -Name + /// Process group requested by -Name. /// /// /// Arguments to -Name will be treated as names, @@ -162,7 +169,7 @@ private void ProcessName() } /// - /// Process group requested by -SID + /// Process group requested by -SID. /// private void ProcessSid() { @@ -181,7 +188,7 @@ private void ProcessSid() } /// - /// Process group given through -InputObject + /// Process group given through -InputObject. /// private void ProcessGroup() { @@ -220,7 +227,7 @@ private bool CheckShouldProcess(string groupName, string newName) return ShouldProcess(groupName, msg); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs index 4a48b659e62f..42250fc6effd 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -8,7 +11,6 @@ using Microsoft.PowerShell.LocalAccounts; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -40,8 +42,10 @@ public class RenameLocalUserCommand : Cmdlet public Microsoft.PowerShell.Commands.LocalUser InputObject { get { return this.inputobject;} + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalUser inputobject; /// @@ -58,8 +62,10 @@ public Microsoft.PowerShell.Commands.LocalUser InputObject public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -73,8 +79,10 @@ public string Name public string NewName { get { return this.newname;} + set { this.newname = value; } } + private string newname; /// @@ -90,13 +98,13 @@ public string NewName public System.Security.Principal.SecurityIdentifier SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier sid; #endregion Parameter Properties - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -106,7 +114,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -124,7 +131,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -140,7 +146,7 @@ protected override void EndProcessing() #region Private Methods /// - /// Process user requested by -Name + /// Process user requested by -Name. /// /// /// Arguments to -Name will be treated as names, @@ -163,7 +169,7 @@ private void ProcessName() } /// - /// Process user requested by -SID + /// Process user requested by -SID. /// private void ProcessSid() { @@ -182,7 +188,7 @@ private void ProcessSid() } /// - /// Process group given through -InputObject + /// Process group given through -InputObject. /// private void ProcessUser() { @@ -221,7 +227,7 @@ private bool CheckShouldProcess(string userName, string newName) return ShouldProcess(userName, msg); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs index eeaf701bffdc..8926848d7e35 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -8,7 +11,6 @@ using Microsoft.PowerShell.LocalAccounts; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -35,8 +37,10 @@ public class SetLocalGroupCommand : Cmdlet public string Description { get { return this.description;} + set { this.description = value; } } + private string description; /// @@ -53,8 +57,10 @@ public string Description public Microsoft.PowerShell.Commands.LocalGroup InputObject { get { return this.inputobject;} + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalGroup inputobject; /// @@ -71,8 +77,10 @@ public Microsoft.PowerShell.Commands.LocalGroup InputObject public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -88,13 +96,13 @@ public string Name public System.Security.Principal.SecurityIdentifier SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier sid; #endregion Parameter Properties - - #region Cmdlet Overrides /// /// BeginProcessing method. @@ -104,7 +112,6 @@ protected override void BeginProcessing() sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -148,7 +155,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -168,7 +174,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionSetGroup); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs index 4ae4e422d39a..63756347b663 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #region Using directives using System; using System.Management.Automation; @@ -8,7 +11,6 @@ using Microsoft.PowerShell.LocalAccounts; #endregion - namespace Microsoft.PowerShell.Commands { /// @@ -52,8 +54,10 @@ public class SetLocalUserCommand : PSCmdlet public System.DateTime AccountExpires { get { return this.accountexpires;} + set { this.accountexpires = value; } } + private System.DateTime accountexpires; /// @@ -64,8 +68,10 @@ public System.DateTime AccountExpires public System.Management.Automation.SwitchParameter AccountNeverExpires { get { return this.accountneverexpires;} + set { this.accountneverexpires = value; } } + private System.Management.Automation.SwitchParameter accountneverexpires; /// @@ -77,8 +83,10 @@ public System.Management.Automation.SwitchParameter AccountNeverExpires public string Description { get { return this.description;} + set { this.description = value; } } + private string description; /// @@ -91,8 +99,10 @@ public string Description public string FullName { get { return this.fullname;} + set { this.fullname = value; } } + private string fullname; /// /// The following is the definition of the input parameter "InputObject". @@ -108,8 +118,10 @@ public string FullName public Microsoft.PowerShell.Commands.LocalUser InputObject { get { return this.inputobject;} + set { this.inputobject = value; } } + private Microsoft.PowerShell.Commands.LocalUser inputobject; /// @@ -125,8 +137,10 @@ public Microsoft.PowerShell.Commands.LocalUser InputObject public string Name { get { return this.name;} + set { this.name = value; } } + private string name; /// @@ -138,8 +152,10 @@ public string Name public System.Security.SecureString Password { get { return this.password;} + set { this.password = value; } } + private System.Security.SecureString password; /// @@ -147,12 +163,14 @@ public System.Security.SecureString Password /// Specifies that the password will not expire. /// [Parameter] - public System.Boolean PasswordNeverExpires + public bool PasswordNeverExpires { get { return this.passwordneverexpires; } + set { this.passwordneverexpires = value; } } - private System.Boolean passwordneverexpires; + + private bool passwordneverexpires; /// /// The following is the definition of the input parameter "SID". @@ -167,8 +185,10 @@ public System.Boolean PasswordNeverExpires public System.Security.Principal.SecurityIdentifier SID { get { return this.sid;} + set { this.sid = value; } } + private System.Security.Principal.SecurityIdentifier sid; /// @@ -177,15 +197,15 @@ public System.Security.Principal.SecurityIdentifier SID /// account. The default value is True. /// [Parameter] - public System.Boolean UserMayChangePassword + public bool UserMayChangePassword { get { return this.usermaychangepassword;} + set { this.usermaychangepassword = value; } } - private System.Boolean usermaychangepassword; - #endregion Parameter Properties - + private bool usermaychangepassword; + #endregion Parameter Properties #region Cmdlet Overrides /// @@ -198,10 +218,10 @@ protected override void BeginProcessing() InvalidParametersException ex = new InvalidParametersException("AccountExpires", "AccountNeverExpires"); ThrowTerminatingError(ex.MakeErrorRecord()); } + sam = new Sam(); } - /// /// ProcessRecord method. /// @@ -278,7 +298,6 @@ protected override void ProcessRecord() } } - /// /// EndProcessing method. /// @@ -298,7 +317,7 @@ private bool CheckShouldProcess(string target) return ShouldProcess(target, Strings.ActionSetUser); } #endregion Private Methods - }//End Class + } -}//End namespace +} diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Exceptions.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Exceptions.cs index a9f7193efe46..48b11236bbb1 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Exceptions.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Exceptions.cs @@ -1,7 +1,11 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Management.Automation; using System.Management.Automation.SecurityAccountsManager; using System.Runtime.Serialization; + using Microsoft.PowerShell.LocalAccounts; namespace Microsoft.PowerShell.Commands @@ -61,23 +65,23 @@ internal LocalAccountsException(string message, object target, ErrorCategory err } /// - /// Compliance Constructor + /// Compliance Constructor. /// public LocalAccountsException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public LocalAccountsException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public LocalAccountsException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -121,22 +125,22 @@ public UInt32 StatusCode } /// - /// Compliance Constructor + /// Compliance Constructor. /// public InternalException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public InternalException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public InternalException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -181,22 +185,22 @@ public int NativeErrorCode } /// - /// Compliance Constructor + /// Compliance Constructor. /// public Win32InternalException() : base() {} /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public Win32InternalException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public Win32InternalException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -235,13 +239,13 @@ public InvalidPasswordException(uint errorCode) } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public InvalidPasswordException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -268,17 +272,17 @@ internal InvalidParametersException(string parameterA, string parameterB) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public InvalidParametersException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public InvalidParametersException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -296,22 +300,22 @@ internal AccessDeniedException(object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public AccessDeniedException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public AccessDeniedException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public AccessDeniedException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -329,22 +333,22 @@ internal InvalidNameException(string name, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public InvalidNameException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public InvalidNameException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public InvalidNameException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -362,22 +366,22 @@ internal NameInUseException(string name, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public NameInUseException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public NameInUseException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public NameInUseException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -396,22 +400,22 @@ internal NotFoundException(string message, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public NotFoundException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public NotFoundException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public NotFoundException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -419,7 +423,7 @@ internal NotFoundException(string message, object target) } /// - /// Exception indicating that a principal was not Found + /// Exception indicating that a principal was not Found. /// public class PrincipalNotFoundException : NotFoundException { @@ -429,22 +433,22 @@ internal PrincipalNotFoundException(string principal, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public PrincipalNotFoundException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public PrincipalNotFoundException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public PrincipalNotFoundException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -462,22 +466,22 @@ internal GroupNotFoundException(string group, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public GroupNotFoundException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public GroupNotFoundException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public GroupNotFoundException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -495,22 +499,22 @@ internal UserNotFoundException(string user, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public UserNotFoundException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public UserNotFoundException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public UserNotFoundException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -528,22 +532,22 @@ internal MemberNotFoundException(string member, string group) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public MemberNotFoundException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public MemberNotFoundException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public MemberNotFoundException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -562,22 +566,22 @@ internal ObjectExistsException(string message, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public ObjectExistsException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public ObjectExistsException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public ObjectExistsException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -595,22 +599,22 @@ internal GroupExistsException(string group, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public GroupExistsException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public GroupExistsException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public GroupExistsException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -628,22 +632,22 @@ internal UserExistsException(string user, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public UserExistsException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public UserExistsException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public UserExistsException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// @@ -661,22 +665,22 @@ internal MemberExistsException(string member, string group, object target) } /// - /// Compliance Constructor + /// Compliance Constructor. /// public MemberExistsException() : base() { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// public MemberExistsException(String message) : base(message) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// public MemberExistsException(String message, Exception ex) : base(message, ex) { } /// - /// Compliance Constructor + /// Compliance Constructor. /// /// /// diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Extensions.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Extensions.cs index 86ef63e3ef79..d492336bd6dd 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Extensions.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Extensions.cs @@ -1,4 +1,7 @@ -using System.Runtime.InteropServices; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Runtime.InteropServices; using System.Security; using System.Security.Principal; using System.Text.RegularExpressions; @@ -9,7 +12,7 @@ namespace System.Management.Automation.SecurityAccountsManager.Extensions { /// - /// Provides extension methods for the Cmdlet class + /// Provides extension methods for the Cmdlet class. /// internal static class CmdletExtensions { @@ -30,7 +33,7 @@ internal static class CmdletExtensions bool allowSidConstants = false) { if (!allowSidConstants) - if (!(s.Length > 2 && s.StartsWith("S-", StringComparison.Ordinal) && Char.IsDigit(s[2]))) + if (!(s.Length > 2 && s.StartsWith("S-", StringComparison.Ordinal) && char.IsDigit(s[2]))) return null; SecurityIdentifier sid = null; @@ -49,12 +52,12 @@ internal static class CmdletExtensions } /// - /// Provides extension methods for the PSCmdlet class + /// Provides extension methods for the PSCmdlet class. /// internal static class PSExtensions { /// - /// Determine if a given parameter was provided to the cmdlet + /// Determine if a given parameter was provided to the cmdlet. /// /// /// The object to check. diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalGroup.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalGroup.cs index 170493522fbd..25af6b87e906 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalGroup.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalGroup.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.PowerShell.LocalAccounts; @@ -14,7 +17,7 @@ public class LocalGroup : LocalPrincipal /// /// A short description of the Group. /// - public String Description { get; set; } + public string Description { get; set; } #endregion Public Properties #region Construction @@ -37,7 +40,7 @@ public LocalGroup(string name) } /// - /// Construct a new LocalGroup object that is a copy of another + /// Construct a new LocalGroup object that is a copy of another. /// /// private LocalGroup(LocalGroup other) @@ -47,7 +50,6 @@ private LocalGroup(LocalGroup other) } #endregion Construction - #region Public Methods /// /// Provides a string representation of the LocalGroup object. @@ -68,10 +70,6 @@ public override string ToString() /// public LocalGroup Clone() { - if (null == this) - { - throw new NullReferenceException(); - } return new LocalGroup(this); } #endregion Public Methods diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalPrincipal.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalPrincipal.cs index 94e5972d265c..fa7add127aed 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalPrincipal.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalPrincipal.cs @@ -1,14 +1,17 @@ -using System.Security.Principal; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Security.Principal; namespace Microsoft.PowerShell.Commands { /// - /// Defines the source of a Principal + /// Defines the source of a Principal. /// public enum PrincipalSource { /// - /// The principal source is unknown or could not be determined + /// The principal source is unknown or could not be determined. /// Unknown = 0, diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalUser.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalUser.cs index fb27679feac3..35a0059057b7 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalUser.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/LocalUser.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using Microsoft.PowerShell.LocalAccounts; @@ -52,7 +55,6 @@ public class LocalUser : LocalPrincipal /// public bool UserMayChangePassword { get; set; } - /// /// Indicates whether the user must have a password (true) or not (false). /// @@ -69,7 +71,6 @@ public class LocalUser : LocalPrincipal public DateTime? LastLogon { get; set; } #endregion Public Properties - #region Construction /// /// Initializes a new LocalUser object. @@ -134,10 +135,6 @@ public override string ToString() /// public LocalUser Clone() { - if (null == this) - { - throw new NullReferenceException(); - } return new LocalUser(this); } #endregion Public Methods diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Native.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Native.cs index 4a085d7867f2..2441c9a2ae79 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Native.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Native.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Runtime.InteropServices; using System.Text; @@ -123,7 +126,7 @@ internal struct UNICODE_STRING public UNICODE_STRING(string s) { - buffer = String.IsNullOrEmpty(s) ? String.Empty : s; + buffer = string.IsNullOrEmpty(s) ? string.Empty : s; Length = (UInt16)(2 * buffer.Length); MaximumLength = Length; } @@ -134,7 +137,7 @@ public override string ToString() // often have buffers that point to junk if Length = 0, or that // point to non-null-terminated strings, resulting in marshaled // String objects that have more characters than they should. - return Length == 0 ? String.Empty + return Length == 0 ? string.Empty : buffer.Substring(0, Length / 2); } } @@ -162,7 +165,6 @@ public void Dispose() } } - // These structures are filled in by Marshalling, so fields will be initialized // invisibly to the C# compiler, and some fields will not be used in C# code. #pragma warning disable 0649, 0169 @@ -195,7 +197,6 @@ internal static class Win32 internal const UInt32 STANDARD_RIGHTS_WRITE = READ_CONTROL; internal const UInt32 STANDARD_RIGHTS_EXECUTE = READ_CONTROL; - internal const UInt32 STANDARD_RIGHTS_ALL = 0x001F0000; internal const UInt32 SPECIFIC_RIGHTS_ALL = 0x0000FFFF; @@ -209,7 +210,6 @@ internal static class Win32 internal const UInt32 GENERIC_EXECUTE = 0x20000000; internal const UInt32 GENERIC_ALL = 0x10000000; - // These constants control the behavior of the FormatMessage Windows API function internal const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; internal const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; @@ -335,7 +335,6 @@ internal static class Win32 internal const int NERR_LastAdmin = NERR_BASE + 352; // This operation is not allowed on the last administrative account. #endregion Win32 Error Codes - #region SECURITY_DESCRIPTOR Control Flags internal const UInt16 SE_DACL_PRESENT = 0x0004; internal const UInt16 SE_SELF_RELATIVE = 0x8000; @@ -348,6 +347,7 @@ internal static class Win32 #region Win32 Functions [DllImport(PInvokeDllNames.LookupAccountSidDllName, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool LookupAccountSid(string systemName, byte[] accountSid, StringBuilder accountName, @@ -357,6 +357,7 @@ internal static class Win32 out SID_NAME_USE use); [DllImport(PInvokeDllNames.LookupAccountNameDllName, CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool LookupAccountName(string systemName, string accountName, [MarshalAs(UnmanagedType.LPArray)] @@ -366,7 +367,6 @@ internal static class Win32 ref uint domainNameLength, out SID_NAME_USE peUse); - [DllImport(PInvokeDllNames.GetSecurityDescriptorDaclDllName, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetSecurityDescriptorDacl(IntPtr pSecurityDescriptor, diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/NtStatus.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/NtStatus.cs index 59e00f0b2521..d1db20b4fe75 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/NtStatus.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/NtStatus.cs @@ -1,4 +1,6 @@ - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System.Diagnostics.CodeAnalysis; namespace System.Management.Automation.SecurityAccountsManager.Native @@ -18,7 +20,6 @@ internal static class NtStatus public const UInt32 STATUS_SEVERITY_INFORMATIONAL = 0x1; public const UInt32 STATUS_SEVERITY_ERROR = 0x3; - public const UInt32 STATUS_SUCCESS = 0x00000000; // // MessageText: @@ -28,11 +29,6 @@ internal static class NtStatus public const UInt32 STATUS_MORE_ENTRIES = 0x00000105; - - - - - ///////////////////////////////////////////////////////////////////////// // // Standard Information values @@ -430,7 +426,7 @@ internal static class NtStatus #region Public Methods /// - /// Determine if an NTSTATUS value indicates Success + /// Determine if an NTSTATUS value indicates Success. /// /// The NTSTATUS value returned from native functions. /// @@ -442,7 +438,7 @@ public static bool IsSuccess(UInt32 ntstatus) } /// - /// Determine if an NTSTATUS value indicates an Error + /// Determine if an NTSTATUS value indicates an Error. /// /// The NTSTATUS value returned from native functions. /// @@ -453,9 +449,8 @@ public static bool IsError(UInt32 ntstatus) return Severity(ntstatus) == STATUS_SEVERITY_ERROR; } - /// - /// Determine if an NTSTATUS value indicates a Warning + /// Determine if an NTSTATUS value indicates a Warning. /// /// The NTSTATUS value returned from native functions. /// @@ -480,9 +475,8 @@ public static bool IsInformational(UInt32 ntstatus) return Severity(ntstatus) == STATUS_SEVERITY_INFORMATIONAL; } - /// - /// Return the Severity part of an NTSTATUS value + /// Return the Severity part of an NTSTATUS value. /// /// The NTSTATUS value returned from native functions. /// @@ -493,9 +487,8 @@ public static uint Severity(UInt32 ntstatus) return ntstatus >> 30; } - /// - /// Return the Facility part of an NSTATUS value + /// Return the Facility part of an NSTATUS value. /// /// The NTSTATUS value returned from native functions. /// @@ -508,9 +501,8 @@ public static uint Facility(UInt32 ntstatus) return (ntstatus >> 16) & 0x0FFF; } - /// - /// Return the Code part of an NTSTATUS value + /// Return the Code part of an NTSTATUS value. /// /// The NTSTATUS value returned from native functions. /// diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/PInvokeDllNames.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/PInvokeDllNames.cs index 6a4688584f1f..026a47ca6f65 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/PInvokeDllNames.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/PInvokeDllNames.cs @@ -1,6 +1,5 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. namespace System.Management.Automation { diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Sam.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Sam.cs index b74184e1685f..cd5ee5fccabb 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Sam.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Sam.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.ComponentModel; using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Principal; -using System.ComponentModel; using Microsoft.PowerShell.Commands; using System.Management.Automation.SecurityAccountsManager.Extensions; @@ -35,7 +38,7 @@ internal enum Enabling internal class SamRidEnumeration { #region Original struct members - public String Name; + public string Name; public UInt32 RelativeId; #endregion Original struct members @@ -44,7 +47,6 @@ internal class SamRidEnumeration #endregion Additional members } - /// /// Provides methods for manipulating local Users and Groups. /// @@ -176,7 +178,6 @@ internal enum DomainAccess : uint Max = Win32.MAXIMUM_ALLOWED } - /// /// The operation under way. Used in the class. /// @@ -217,7 +218,7 @@ private class Context { public ContextOperation operation; public ContextObjectType type; - public Object target; + public object target; public string objectId; public string memberId; @@ -257,7 +258,7 @@ private class Context } /// - /// Default constructor + /// Default constructor. /// public Context() { @@ -368,7 +369,7 @@ public override string ToString() private IntPtr localDomainHandle = IntPtr.Zero; private IntPtr builtinDomainHandle = IntPtr.Zero; private Context context = null; - private string machineName = String.Empty; + private string machineName = string.Empty; #endregion Instance Data #region Construction @@ -394,7 +395,7 @@ public string StripMachineName(string name) } #region Local Groups /// - /// Retrieve a named local group + /// Retrieve a named local group. /// /// Name of the desired local group. /// @@ -416,7 +417,7 @@ internal LocalGroup GetLocalGroup(string groupName) } /// - /// Retrieve a local group by SID + /// Retrieve a local group by SID. /// /// /// A object identifying the desired group. @@ -461,7 +462,7 @@ internal LocalGroup CreateLocalGroup(LocalGroup group) } /// - /// Update a local group with new property values + /// Update a local group with new property values. /// /// /// A object representing the group to be updated. @@ -745,7 +746,7 @@ internal Exception RemoveLocalGroupMember(SecurityIdentifier groupSid, LocalPrin #region Local Users /// - /// Retrieve a named local user + /// Retrieve a named local user. /// /// Name of the desired local user. /// @@ -767,7 +768,7 @@ internal LocalUser GetLocalUser(string userName) } /// - /// Retrieve a local user by SID + /// Retrieve a local user by SID. /// /// /// A object identifying the desired user. @@ -791,7 +792,7 @@ internal LocalUser GetLocalUser(SecurityIdentifier sid) } /// - /// Create a local user + /// Create a local user. /// /// A object containing /// information about the local user to be created. @@ -855,7 +856,6 @@ internal void RemoveLocalUser(LocalUser user) RemoveUser(user.SID); } - /// /// Rename a local user. /// @@ -900,7 +900,7 @@ internal void RenameLocalUser(LocalUser user, string newName) } /// - /// Enable or disable a Local User + /// Enable or disable a Local User. /// /// /// A object identifying the user to enable or disable. @@ -920,7 +920,7 @@ internal void EnableLocalUser(SecurityIdentifier sid, Enabling enable) } /// - /// Enable or disable a Local User + /// Enable or disable a Local User. /// /// /// A object representing the user to enable or disable. @@ -1277,6 +1277,7 @@ private LocalUser CreateUser(LocalUser userInfo, System.Security.SecureString pa { SamApi.SamDeleteUser(userHandle); } + throw; } finally @@ -1289,7 +1290,7 @@ private LocalUser CreateUser(LocalUser userInfo, System.Security.SecureString pa } /// - /// Remove a group identified by SID + /// Remove a group identified by SID. /// /// /// A object identifying the @@ -1374,6 +1375,7 @@ private void RenameGroup(SecurityIdentifier sid, string newName) Marshal.DestroyStructure(buffer); Marshal.FreeHGlobal(buffer); } + if (aliasHandle != IntPtr.Zero) status = SamApi.SamCloseHandle(aliasHandle); } @@ -1617,12 +1619,12 @@ private LocalUser MakeLocalUserObject(SamRidEnumeration sre, IntPtr userHandle) FullName = allInfo.FullName.ToString(), Description = allInfo.AdminComment.ToString(), - //TODO: why is this coming up as 864000000000 (number of ticks per day)? + // TODO: why is this coming up as 864000000000 (number of ticks per day)? PasswordChangeableDate = DateTimeFromSam(allInfo.PasswordCanChange.QuadPart), PasswordExpires = DateTimeFromSam(allInfo.PasswordMustChange.QuadPart), - //TODO: why is this coming up as 0X7FFFFFFFFFFFFFFF (largest signed 64-bit, and well out of range of DateTime)? + // TODO: why is this coming up as 0X7FFFFFFFFFFFFFFF (largest signed 64-bit, and well out of range of DateTime)? AccountExpires = DateTimeFromSam(allInfo.AccountExpires.QuadPart), LastLogon = DateTimeFromSam(allInfo.LastLogon.QuadPart), PasswordLastSet = DateTimeFromSam(allInfo.PasswordLastSet.QuadPart), @@ -1763,6 +1765,7 @@ private void RenameUser(SecurityIdentifier sid, string newName) Marshal.DestroyStructure(buffer); Marshal.FreeHGlobal(buffer); } + if (userHandle != IntPtr.Zero) status = SamApi.SamCloseHandle(userHandle); } @@ -1998,6 +2001,7 @@ private void UpdateGroup(LocalGroup group, LocalGroup changed) Marshal.DestroyStructure(buffer); Marshal.FreeHGlobal(buffer); } + if (aliasHandle != IntPtr.Zero) status = SamApi.SamCloseHandle(aliasHandle); } @@ -2200,11 +2204,13 @@ private LocalGroup MakeLocalGroupObject(SamRidEnumeration sre, IntPtr aliasHandl ? sourceUser.AccountExpires.Value.ToFileTime() : 0L; } + if (setFlags.HasFlag(UserProperties.Description)) { which |= SamApi.USER_ALL_ADMINCOMMENT; info.AdminComment = new UNICODE_STRING(sourceUser.Description); } + if (setFlags.HasFlag(UserProperties.Enabled)) { which |= SamApi.USER_ALL_USERACCOUNTCONTROL; @@ -2213,6 +2219,7 @@ private LocalGroup MakeLocalGroupObject(SamRidEnumeration sre, IntPtr aliasHandl else uac |= SamApi.USER_ACCOUNT_DISABLED; } + if (setFlags.HasFlag(UserProperties.FullName)) { which |= SamApi.USER_ALL_FULLNAME; @@ -2365,6 +2372,7 @@ private RawAcl GetSamDacl(IntPtr objectHandle) if (IntPtr.Zero != securityObject) status = SamApi.SamFreeMemory(securityObject); } + return rv; } @@ -2657,6 +2665,7 @@ private SecurityIdentifier RidToSid(IntPtr domainHandle, uint rid) if (IntPtr.Zero != sidBytes) status = SamApi.SamFreeMemory(sidBytes); } + return sid; } @@ -2769,7 +2778,7 @@ private AccountInfo LookupAccountInfo(string accountName) { // Bug: 7407413 : // If accountname is in the format domain1\user1, - //then AccountName.ToString() will return domain1\domain1\user1 + // then AccountName.ToString() will return domain1\domain1\user1 // Ideally , accountname should be processed to hold only account name (without domain) // as we are keeping the domain in 'DomainName' variable. @@ -2778,6 +2787,7 @@ private AccountInfo LookupAccountInfo(string accountName) { accountName = accountName.Substring(index + 1); } + return new AccountInfo { AccountName = accountName, @@ -2818,7 +2828,7 @@ private LocalPrincipal MakeLocalPrincipalObject(AccountInfo info) switch (info.Use) { - case SID_NAME_USE.SidTypeAlias: //TODO: is this the right thing to do??? + case SID_NAME_USE.SidTypeAlias: // TODO: is this the right thing to do??? case SID_NAME_USE.SidTypeGroup: case SID_NAME_USE.SidTypeWellKnownGroup: rv.ObjectClass = Strings.ObjectClassGroup; @@ -2938,7 +2948,7 @@ private Exception MakeException(UInt32 ntStatus, Context context = null) return new UserNotFoundException(context.ObjectName, context.target); case NtStatus.STATUS_SPECIAL_GROUP: // The group specified is a special group and cannot be operated on in the requested fashion. - //case NtStatus.STATUS_SPECIAL_ALIAS: // referred to in source for SAM api, but not in ntstatus.h!!! + // case NtStatus.STATUS_SPECIAL_ALIAS: // referred to in source for SAM api, but not in ntstatus.h!!! return new InvalidOperationException(StringUtil.Format(Strings.InvalidForGroup, context.ObjectName)); @@ -2974,7 +2984,7 @@ private Exception MakeException(UInt32 ntStatus, Context context = null) case NtStatus.STATUS_PASSWORD_RESTRICTION: return new InvalidPasswordException(Native.Win32.RtlNtStatusToDosError(ntStatus)); - //TODO: do we want to handle these? + // TODO: do we want to handle these? // they appear to be returned only in functions we are not calling case NtStatus.STATUS_INVALID_SID: // member sid is corrupted case NtStatus.STATUS_INVALID_MEMBER: // member has wrong account type @@ -3125,7 +3135,7 @@ internal struct OSVERSIONINFOEX private static volatile OperatingSystem localOs; /// - /// It only contains the properties that get used in powershell + /// It only contains the properties that get used in powershell. /// internal sealed class OperatingSystem { @@ -3143,7 +3153,7 @@ internal OperatingSystem(Version version, string servicePack) } /// - /// OS version + /// OS version. /// public Version Version { @@ -3151,7 +3161,7 @@ public Version Version } /// - /// VersionString + /// VersionString. /// public string VersionString { @@ -3196,6 +3206,7 @@ private OperatingSystem GetOperatingSystem() Version ver = new Version(osviex.MajorVersion, osviex.MinorVersion, osviex.BuildNumber, (osviex.ServicePackMajor << 16) | osviex.ServicePackMinor); localOs = new OperatingSystem(ver, osviex.CSDVersion); } + return localOs; #else return Environment.OSVersion; diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/SamApi.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/SamApi.cs index e0c686ea7c7e..9768eb32d92c 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/SamApi.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/SamApi.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Collections.Generic; using System.Runtime.InteropServices; @@ -193,7 +196,7 @@ internal struct USER_ADMIN_COMMENT_INFORMATION [StructLayout(LayoutKind.Sequential)] internal struct USER_EXPIRES_INFORMATION { - //LARGE_INTEGER AccountExpires; + // LARGE_INTEGER AccountExpires; public Int64 AccountExpires; } @@ -210,7 +213,6 @@ internal struct USER_LOGON_HOURS_INFORMATION public LOGON_HOURS LogonHours; } - [StructLayout(LayoutKind.Sequential)] internal struct POLICY_PRIMARY_DOMAIN_INFO { @@ -273,7 +275,6 @@ internal static class SamApi internal const UInt32 SAM_USER_ENUMERATION_FILTER_INTERNET = 0x00000002; internal const UInt32 SAM_SERVER_LOOKUP_DOMAIN = 0x0020; - // // Bits to be used in UserAllInformation's WhichFields field (to indicate // which items were queried or set). @@ -311,7 +312,6 @@ internal static class SamApi internal const UInt32 USER_ALL_UNDEFINED_MASK = 0xC0000000; - // // Bit masks for the UserAccountControl member of the USER_ALL_INFORMATION structure // @@ -351,7 +351,6 @@ internal static class SamApi UInt32 desiredAccess, ref OBJECT_ATTRIBUTES objectAttributes); - [DllImport("samlib.dll")] internal static extern UInt32 SamRidToSid(IntPtr objectHandle, UInt32 rid, out IntPtr sid); @@ -444,7 +443,6 @@ internal static class SamApi out UInt32 grantedAccess, out UInt32 relativeId); - [DllImport("samlib.dll")] internal static extern UInt32 SamQueryInformationUser(IntPtr userHandle, USER_INFORMATION_CLASS userInformationClass, diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/StringUtil.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/StringUtil.cs index afc20f126124..c80c14be7f6d 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/StringUtil.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/StringUtil.cs @@ -1,10 +1,13 @@ -using System.Globalization; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Globalization; using System.Management.Automation.SecurityAccountsManager.Native; namespace System.Management.Automation.SecurityAccountsManager { /// - /// Contains utility functions for formatting localizable strings + /// Contains utility functions for formatting localizable strings. /// internal class StringUtil { @@ -35,6 +38,7 @@ internal static string Format(string fmt, uint p0) { return string.Format(CultureInfo.CurrentCulture, fmt, p0); } + internal static string Format(string fmt, int p0) { return string.Format(CultureInfo.CurrentCulture, fmt, p0); diff --git a/src/Microsoft.PowerShell.LocalAccounts/Microsoft.PowerShell.LocalAccounts.csproj b/src/Microsoft.PowerShell.LocalAccounts/Microsoft.PowerShell.LocalAccounts.csproj index ebd69091ebe3..6685957fae8f 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/Microsoft.PowerShell.LocalAccounts.csproj +++ b/src/Microsoft.PowerShell.LocalAccounts/Microsoft.PowerShell.LocalAccounts.csproj @@ -3,7 +3,7 @@ - PowerShell Core's Microsoft.PowerShell.LocalAccounts project + PowerShell's Microsoft.PowerShell.LocalAccounts project Microsoft.PowerShell.LocalAccounts @@ -11,20 +11,4 @@ - - $(DefineConstants);CORECLR - - - - portable - - - - $(DefineConstants);UNIX - - - - full - - diff --git a/src/Microsoft.PowerShell.MarkdownRender/CodeInlineRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/CodeInlineRenderer.cs new file mode 100644 index 000000000000..72fb64288214 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/CodeInlineRenderer.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for inline code elements. + /// + internal class CodeInlineRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, CodeInline obj) + { + renderer.Write(renderer.EscapeSequences.FormatCode(obj.Content, isInline: true)); + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/EmphasisInlineRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/EmphasisInlineRenderer.cs new file mode 100644 index 000000000000..e4ce8ab0e6f5 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/EmphasisInlineRenderer.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for bold and italics elements. + /// + internal class EmphasisInlineRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, EmphasisInline obj) + { + renderer.Write(renderer.EscapeSequences.FormatEmphasis(obj.FirstChild.ToString(), isBold: obj.DelimiterCount == 2 ? true : false)); + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/FencedCodeBlockRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/FencedCodeBlockRenderer.cs new file mode 100644 index 000000000000..36f04aca067a --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/FencedCodeBlockRenderer.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Helpers; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for code blocks with language type. + /// + internal class FencedCodeBlockRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, FencedCodeBlock obj) + { + if (obj?.Lines.Lines != null) + { + foreach (StringLine codeLine in obj.Lines.Lines) + { + if (!string.IsNullOrWhiteSpace(codeLine.ToString())) + { + // If the code block is of type YAML, then tab to right to improve readability. + // This specifically helps for parameters help content. + if (string.Equals(obj.Info, "yaml", StringComparison.OrdinalIgnoreCase)) + { + renderer.Write("\t").WriteLine(codeLine.ToString()); + } + else + { + renderer.WriteLine(renderer.EscapeSequences.FormatCode(codeLine.ToString(), isInline: false)); + } + } + } + + // Add a blank line after the code block for better readability. + renderer.WriteLine(); + } + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/HeaderBlockRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/HeaderBlockRenderer.cs new file mode 100644 index 000000000000..87dc5c0e5aab --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/HeaderBlockRenderer.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for headings. + /// + internal class HeaderBlockRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, HeadingBlock obj) + { + string headerText = obj?.Inline?.FirstChild?.ToString(); + + if (!string.IsNullOrEmpty(headerText)) + { + // Format header and then add blank line to improve readability. + switch (obj.Level) + { + case 1: + renderer.WriteLine(renderer.EscapeSequences.FormatHeader1(headerText)); + renderer.WriteLine(); + break; + + case 2: + renderer.WriteLine(renderer.EscapeSequences.FormatHeader2(headerText)); + renderer.WriteLine(); + break; + + case 3: + renderer.WriteLine(renderer.EscapeSequences.FormatHeader3(headerText)); + renderer.WriteLine(); + break; + + case 4: + renderer.WriteLine(renderer.EscapeSequences.FormatHeader4(headerText)); + renderer.WriteLine(); + break; + + case 5: + renderer.WriteLine(renderer.EscapeSequences.FormatHeader5(headerText)); + renderer.WriteLine(); + break; + + case 6: + renderer.WriteLine(renderer.EscapeSequences.FormatHeader6(headerText)); + renderer.WriteLine(); + break; + } + } + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/LeafInlineRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/LeafInlineRenderer.cs new file mode 100644 index 000000000000..7585759675ab --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/LeafInlineRenderer.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for leaf elements like plain text in paragraphs. + /// + internal class LeafInlineRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, LeafInline obj) + { + // If the next sibling is null, then this is the last line in the paragraph. + // Add new line character at the end. + // Else just write without newline at the end. + if (obj.NextSibling == null) + { + renderer.WriteLine(obj.ToString()); + } + else + { + renderer.Write(obj.ToString()); + } + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/LineBreakRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/LineBreakRenderer.cs new file mode 100644 index 000000000000..ed008b8609e9 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/LineBreakRenderer.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for line breaks. + /// + internal class LineBreakRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, LineBreakInline obj) + { + // If it is a hard line break add new line at the end. + // Else, add a space for after the last character to improve readability. + if (obj.IsHard) + { + renderer.WriteLine(); + } + else + { + renderer.Write(" "); + } + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/LinkInlineRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/LinkInlineRenderer.cs new file mode 100644 index 000000000000..677143bbff16 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/LinkInlineRenderer.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for links. + /// + internal class LinkInlineRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, LinkInline obj) + { + string text = obj.FirstChild?.ToString(); + + // Format link as image or link. + if (obj.IsImage) + { + renderer.Write(renderer.EscapeSequences.FormatImage(text)); + } + else + { + renderer.Write(renderer.EscapeSequences.FormatLink(text, obj.Url)); + } + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/ListBlockRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/ListBlockRenderer.cs new file mode 100644 index 000000000000..a4076ab04a6b --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/ListBlockRenderer.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for list blocks. + /// + internal class ListBlockRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, ListBlock obj) + { + // start index of a numbered block. + int index = 1; + + foreach (var item in obj) + { + if (item is ListItemBlock listItem) + { + if (obj.IsOrdered) + { + RenderNumberedList(renderer, listItem, index++); + } + else + { + renderer.Write(listItem); + } + } + } + + renderer.WriteLine(); + } + + private void RenderNumberedList(VT100Renderer renderer, ListItemBlock block, int index) + { + // For a numbered list, we need to make sure the index is incremented. + foreach (var line in block) + { + if (line is ParagraphBlock paragraphBlock) + { + renderer.Write(index.ToString()).Write(". ").Write(paragraphBlock.Inline); + } + } + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/ListItemBlockRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/ListItemBlockRenderer.cs new file mode 100644 index 000000000000..417ad052bcb9 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/ListItemBlockRenderer.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Threading; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for items in a list block. + /// + internal class ListItemBlockRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, ListItemBlock obj) + { + if (obj.Parent is ListBlock parent) + { + if (!parent.IsOrdered) + { + foreach (var line in obj) + { + RenderWithIndent(renderer, line, parent.BulletType, 0); + } + } + } + } + + private void RenderWithIndent(VT100Renderer renderer, MarkdownObject block, char listBullet, int indentLevel) + { + // Indent left by 2 for each level on list. + string indent = Padding(indentLevel * 2); + + if (block is ParagraphBlock paragraphBlock) + { + renderer.Write(indent).Write(listBullet).Write(" ").Write(paragraphBlock.Inline); + } + else + { + // If there is a sublist, the block is a ListBlock instead of ParagraphBlock. + if (block is ListBlock subList) + { + foreach (var subListItem in subList) + { + if (subListItem is ListItemBlock subListItemBlock) + { + foreach (var line in subListItemBlock) + { + // Increment indent level for sub list. + RenderWithIndent(renderer, line, listBullet, indentLevel + 1); + } + } + } + } + } + } + + // Typical padding is at most a screen's width, any more than that and we won't bother caching. + private const int IndentCacheMax = 120; + private static readonly string[] IndentCache = new string[IndentCacheMax]; + + internal static string Padding(int countOfSpaces) + { + if (countOfSpaces >= IndentCacheMax) + { + return new string(' ', countOfSpaces); + } + + var result = IndentCache[countOfSpaces]; + + if (result == null) + { + Interlocked.CompareExchange(ref IndentCache[countOfSpaces], new string(' ', countOfSpaces), comparand: null); + result = IndentCache[countOfSpaces]; + } + + return result; + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/MarkdownConverter.cs b/src/Microsoft.PowerShell.MarkdownRender/MarkdownConverter.cs new file mode 100644 index 000000000000..9a39a6b26ba2 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/MarkdownConverter.cs @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Type of conversion from Markdown. + /// + [Flags] + public enum MarkdownConversionType + { + /// + /// Convert to HTML. + /// + HTML = 1, + + /// + /// Convert to VT100 encoded string. + /// + VT100 = 2 + } + + /// + /// Object representing the conversion from Markdown. + /// + public class MarkdownInfo + { + /// + /// Gets the Html content after conversion. + /// + public string Html { get; internal set; } + + /// + /// Gets the VT100 encoded string after conversion. + /// + public string VT100EncodedString { get; internal set; } + + /// + /// Gets the AST of the Markdown string. + /// + public Markdig.Syntax.MarkdownDocument Tokens { get; internal set; } + } + + /// + /// Class to convert a Markdown string to VT100, HTML or AST. + /// + public sealed class MarkdownConverter + { + /// + /// Convert from Markdown string to VT100 encoded string or HTML. Returns MarkdownInfo object. + /// + /// String with Markdown content to be converted. + /// Specifies type of conversion, either VT100 or HTML. + /// Specifies the rendering options for VT100 rendering. + /// MarkdownInfo object with the converted output. + public static MarkdownInfo Convert(string markdownString, MarkdownConversionType conversionType, PSMarkdownOptionInfo optionInfo) + { + var renderInfo = new MarkdownInfo(); + var writer = new StringWriter(); + MarkdownPipeline pipeline = null; + + if (conversionType.HasFlag(MarkdownConversionType.HTML)) + { + pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build(); + var renderer = new Markdig.Renderers.HtmlRenderer(writer); + renderInfo.Html = Markdig.Markdown.Convert(markdownString, renderer, pipeline).ToString(); + } + + if (conversionType.HasFlag(MarkdownConversionType.VT100)) + { + pipeline = new MarkdownPipelineBuilder().Build(); + + // Use the VT100 renderer. + var renderer = new VT100Renderer(writer, optionInfo); + renderInfo.VT100EncodedString = Markdig.Markdown.Convert(markdownString, renderer, pipeline).ToString(); + } + + // Always have AST available. + var parsed = Markdig.Markdown.Parse(markdownString, pipeline); + renderInfo.Tokens = parsed; + + return renderInfo; + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/Microsoft.PowerShell.MarkdownRender.csproj b/src/Microsoft.PowerShell.MarkdownRender/Microsoft.PowerShell.MarkdownRender.csproj new file mode 100644 index 000000000000..8ce646c75d41 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/Microsoft.PowerShell.MarkdownRender.csproj @@ -0,0 +1,15 @@ + + + + + PowerShell's Markdown Rendering project + Microsoft.PowerShell.MarkdownRender + + + + + + + + + diff --git a/src/Microsoft.PowerShell.MarkdownRender/ParagraphBlockRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/ParagraphBlockRenderer.cs new file mode 100644 index 000000000000..bdeb1d13c61c --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/ParagraphBlockRenderer.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for paragraphs. + /// + internal class ParagraphBlockRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, ParagraphBlock obj) + { + // Call the renderer for children, leaf inline or line breaks. + renderer.WriteChildren(obj.Inline); + + // Add new line at the end of the paragraph. + renderer.WriteLine(); + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/QuoteBlockRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/QuoteBlockRenderer.cs new file mode 100644 index 000000000000..273f1c05a576 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/QuoteBlockRenderer.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Renderer for adding VT100 escape sequences for quote blocks. + /// + internal class QuoteBlockRenderer : VT100ObjectRenderer + { + protected override void Write(VT100Renderer renderer, QuoteBlock obj) + { + // Iterate through each item and add the quote character before the content. + foreach (var item in obj) + { + renderer.Write(obj.QuoteChar).Write(" ").Write(item); + } + + // Add blank line after the quote block. + renderer.WriteLine(); + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/VT100EscapeSequences.cs b/src/Microsoft.PowerShell.MarkdownRender/VT100EscapeSequences.cs new file mode 100644 index 000000000000..4b2213ab7025 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/VT100EscapeSequences.cs @@ -0,0 +1,481 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Management.Automation; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Enum to name all the properties of PSMarkdownOptionInfo. + /// + public enum MarkdownOptionInfoProperty + { + /// + /// Property name Header1. + /// + Header1, + + /// + /// Property name Header2. + /// + Header2, + + /// + /// Property name Header3. + /// + Header3, + + /// + /// Property name Header4. + /// + Header4, + + /// + /// Property name Header5. + /// + Header5, + + /// + /// Property name Header6. + /// + Header6, + + /// + /// Property name Code. + /// + Code, + + /// + /// Property name Link. + /// + Link, + + /// + /// Property name Image. + /// + Image, + + /// + /// Property name EmphasisBold. + /// + EmphasisBold, + + /// + /// Property name EmphasisItalics. + /// + EmphasisItalics + } + + /// + /// Class to represent color preference options for various Markdown elements. + /// + public sealed class PSMarkdownOptionInfo + { + private const char Esc = (char)0x1b; + private const string EndSequence = "[0m"; + + /// + /// Gets or sets current VT100 escape sequence for header 1. + /// + public string Header1 { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for header 2. + /// + public string Header2 { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for header 3. + /// + public string Header3 { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for header 4. + /// + public string Header4 { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for header 5. + /// + public string Header5 { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for header 6. + /// + public string Header6 { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for code inline and code blocks. + /// + public string Code { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for links. + /// + public string Link { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for images. + /// + public string Image { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for bold text. + /// + public string EmphasisBold { get; set; } + + /// + /// Gets or sets current VT100 escape sequence for italics text. + /// + public string EmphasisItalics { get; set; } + + /// + /// Gets or sets a value indicating whether VT100 escape sequences should be added. Default it true. + /// + public bool EnableVT100Encoding { get; set; } + + /// + /// Get the property as an rendered escape sequence. + /// This is used by formatting system for displaying. + /// + /// Name of the property to get as escape sequence. + /// Specified property name as escape sequence. + public string AsEscapeSequence(MarkdownOptionInfoProperty propertyName) + { + switch (propertyName) + { + case MarkdownOptionInfoProperty.Header1: + return string.Concat(Esc, Header1, Header1, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Header2: + return string.Concat(Esc, Header2, Header2, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Header3: + return string.Concat(Esc, Header3, Header3, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Header4: + return string.Concat(Esc, Header4, Header4, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Header5: + return string.Concat(Esc, Header5, Header5, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Header6: + return string.Concat(Esc, Header6, Header6, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Code: + return string.Concat(Esc, Code, Code, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Link: + return string.Concat(Esc, Link, Link, Esc, EndSequence); + + case MarkdownOptionInfoProperty.Image: + return string.Concat(Esc, Image, Image, Esc, EndSequence); + + case MarkdownOptionInfoProperty.EmphasisBold: + return string.Concat(Esc, EmphasisBold, EmphasisBold, Esc, EndSequence); + + case MarkdownOptionInfoProperty.EmphasisItalics: + return string.Concat(Esc, EmphasisItalics, EmphasisItalics, Esc, EndSequence); + + default: + break; + } + + return null; + } + + /// + /// Initializes a new instance of the class and sets dark as the default theme. + /// + public PSMarkdownOptionInfo() + { + SetDarkTheme(); + EnableVT100Encoding = true; + } + + private const string Header1Dark = "[7m"; + private const string Header2Dark = "[4;93m"; + private const string Header3Dark = "[4;94m"; + private const string Header4Dark = "[4;95m"; + private const string Header5Dark = "[4;96m"; + private const string Header6Dark = "[4;97m"; + private const string CodeDark = "[48;2;155;155;155;38;2;30;30;30m"; + private const string CodeMacOS = "[107;95m"; + private const string LinkDark = "[4;38;5;117m"; + private const string ImageDark = "[33m"; + private const string EmphasisBoldDark = "[1m"; + private const string EmphasisItalicsDark = "[36m"; + + private const string Header1Light = "[7m"; + private const string Header2Light = "[4;33m"; + private const string Header3Light = "[4;34m"; + private const string Header4Light = "[4;35m"; + private const string Header5Light = "[4;36m"; + private const string Header6Light = "[4;30m"; + private const string CodeLight = "[48;2;155;155;155;38;2;30;30;30m"; + private const string LinkLight = "[4;38;5;117m"; + private const string ImageLight = "[33m"; + private const string EmphasisBoldLight = "[1m"; + private const string EmphasisItalicsLight = "[36m"; + + /// + /// Set all preference for dark theme. + /// + public void SetDarkTheme() + { + Header1 = Header1Dark; + Header2 = Header2Dark; + Header3 = Header3Dark; + Header4 = Header4Dark; + Header5 = Header5Dark; + Header6 = Header6Dark; + Link = LinkDark; + Image = ImageDark; + EmphasisBold = EmphasisBoldDark; + EmphasisItalics = EmphasisItalicsDark; + SetCodeColor(isDarkTheme: true); + } + + /// + /// Set all preference for light theme. + /// + public void SetLightTheme() + { + Header1 = Header1Light; + Header2 = Header2Light; + Header3 = Header3Light; + Header4 = Header4Light; + Header5 = Header5Light; + Header6 = Header6Light; + Link = LinkLight; + Image = ImageLight; + EmphasisBold = EmphasisBoldLight; + EmphasisItalics = EmphasisItalicsLight; + SetCodeColor(isDarkTheme: false); + } + + private void SetCodeColor(bool isDarkTheme) + { + // MacOS terminal app does not support extended colors for VT100, so we special case for it. + Code = Platform.IsMacOS ? CodeMacOS : isDarkTheme ? CodeDark : CodeLight; + } + } + + /// + /// Class to represent default VT100 escape sequences. + /// + public class VT100EscapeSequences + { + private const char Esc = (char)0x1B; + private string endSequence = Esc + "[0m"; + + // For code blocks, [500@ make sure that the whole line has background color. + private const string LongBackgroundCodeBlock = "[500@"; + private PSMarkdownOptionInfo options; + + /// + /// Initializes a new instance of the class. + /// + /// PSMarkdownOptionInfo object to initialize with. + public VT100EscapeSequences(PSMarkdownOptionInfo optionInfo) + { + if (optionInfo == null) + { + throw new ArgumentNullException("optionInfo"); + } + + options = optionInfo; + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the header to format. + /// Formatted Header 1 string. + public string FormatHeader1(string headerText) + { + return FormatHeader(headerText, options.Header1); + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the header to format. + /// Formatted Header 2 string. + public string FormatHeader2(string headerText) + { + return FormatHeader(headerText, options.Header2); + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the header to format. + /// Formatted Header 3 string. + public string FormatHeader3(string headerText) + { + return FormatHeader(headerText, options.Header3); + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the header to format. + /// Formatted Header 4 string. + public string FormatHeader4(string headerText) + { + return FormatHeader(headerText, options.Header4); + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the header to format. + /// Formatted Header 5 string. + public string FormatHeader5(string headerText) + { + return FormatHeader(headerText, options.Header5); + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the header to format. + /// Formatted Header 6 string. + public string FormatHeader6(string headerText) + { + return FormatHeader(headerText, options.Header6); + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the code block to format. + /// True if it is a inline code block, false otherwise. + /// Formatted code block string. + public string FormatCode(string codeText, bool isInline) + { + bool isVT100Enabled = options.EnableVT100Encoding; + + if (isInline) + { + if (isVT100Enabled) + { + return string.Concat(Esc, options.Code, codeText, endSequence); + } + else + { + return codeText; + } + } + else + { + if (isVT100Enabled) + { + return string.Concat(Esc, options.Code, codeText, Esc, LongBackgroundCodeBlock, endSequence); + } + else + { + return codeText; + } + } + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the link to format. + /// URL of the link. + /// True url should be hidden, false otherwise. Default is true. + /// Formatted link string. + public string FormatLink(string linkText, string url, bool hideUrl = true) + { + bool isVT100Enabled = options.EnableVT100Encoding; + + if (hideUrl) + { + if (isVT100Enabled) + { + return string.Concat(Esc, options.Link, "\"", linkText, "\"", endSequence); + } + else + { + return string.Concat("\"", linkText, "\""); + } + } + else + { + if (isVT100Enabled) + { + return string.Concat("\"", linkText, "\" (", Esc, options.Link, url, endSequence, ")"); + } + else + { + return string.Concat("\"", linkText, "\" (", url, ")"); + } + } + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text to format as emphasis. + /// True if it is to be formatted as bold, false to format it as italics. + /// Formatted emphasis string. + public string FormatEmphasis(string emphasisText, bool isBold) + { + var sequence = isBold ? options.EmphasisBold : options.EmphasisItalics; + + if (options.EnableVT100Encoding) + { + return string.Concat(Esc, sequence, emphasisText, endSequence); + } + else + { + return emphasisText; + } + } + + /// + /// Class to represent default VT100 escape sequences. + /// + /// Text of the image to format. + /// Formatted image string. + public string FormatImage(string altText) + { + var text = altText; + + if (string.IsNullOrEmpty(altText)) + { + text = "Image"; + } + + if (options.EnableVT100Encoding) + { + return string.Concat(Esc, options.Image, "[", text, "]", endSequence); + } + else + { + return string.Concat("[", text, "]"); + } + } + + private string FormatHeader(string headerText, string headerEscapeSequence) + { + if (options.EnableVT100Encoding) + { + return string.Concat(Esc, headerEscapeSequence, headerText, endSequence); + } + else + { + return headerText; + } + } + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/VT100ObjectRenderer.cs b/src/Microsoft.PowerShell.MarkdownRender/VT100ObjectRenderer.cs new file mode 100644 index 000000000000..d42c85e1c458 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/VT100ObjectRenderer.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Implement the MarkdownObjectRenderer with VT100Renderer. + /// + /// The element type of the renderer. + public abstract class VT100ObjectRenderer : MarkdownObjectRenderer where T : MarkdownObject + { + } +} diff --git a/src/Microsoft.PowerShell.MarkdownRender/VT100Renderer.cs b/src/Microsoft.PowerShell.MarkdownRender/VT100Renderer.cs new file mode 100644 index 000000000000..65af4a83f801 --- /dev/null +++ b/src/Microsoft.PowerShell.MarkdownRender/VT100Renderer.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; + +using Markdig; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace Microsoft.PowerShell.MarkdownRender +{ + /// + /// Initializes an instance of the VT100 renderer. + /// + public sealed class VT100Renderer : TextRendererBase + { + /// + /// Initializes a new instance of the class. + /// + /// TextWriter to write to. + /// PSMarkdownOptionInfo object with options. + public VT100Renderer(TextWriter writer, PSMarkdownOptionInfo optionInfo) : base(writer) + { + EscapeSequences = new VT100EscapeSequences(optionInfo); + + // Add the various element renderers. + ObjectRenderers.Add(new HeaderBlockRenderer()); + ObjectRenderers.Add(new LineBreakRenderer()); + ObjectRenderers.Add(new CodeInlineRenderer()); + ObjectRenderers.Add(new FencedCodeBlockRenderer()); + ObjectRenderers.Add(new EmphasisInlineRenderer()); + ObjectRenderers.Add(new ParagraphBlockRenderer()); + ObjectRenderers.Add(new LeafInlineRenderer()); + ObjectRenderers.Add(new LinkInlineRenderer()); + ObjectRenderers.Add(new ListBlockRenderer()); + ObjectRenderers.Add(new ListItemBlockRenderer()); + ObjectRenderers.Add(new QuoteBlockRenderer()); + } + + /// + /// Gets the current escape sequences. + /// + public VT100EscapeSequences EscapeSequences { get; private set; } + } +} diff --git a/src/Microsoft.PowerShell.PSReadLine/AssemblyInfo.cs b/src/Microsoft.PowerShell.PSReadLine/AssemblyInfo.cs deleted file mode 100644 index f77c66530606..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("36053fb0-0bd0-4a1c-951c-b2ec109deca3")] diff --git a/src/Microsoft.PowerShell.PSReadLine/BasicEditing.cs b/src/Microsoft.PowerShell.PSReadLine/BasicEditing.cs deleted file mode 100644 index 377aa154cd10..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/BasicEditing.cs +++ /dev/null @@ -1,579 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Management.Automation.Runspaces; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - /// - /// Insert the key - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelfInsert(ConsoleKeyInfo? key = null, object arg = null) - { - if (!key.HasValue) - { - return; - } - - if (arg is int) - { - var count = (int)arg; - if (count <= 0) - return; - if (count > 1) - { - var toInsert = new string(key.Value.KeyChar, count); - if (_singleton._visualSelectionCommandCount > 0) - { - int start, length; - _singleton.GetRegion(out start, out length); - Replace(start, length, toInsert); - } - else - { - Insert(toInsert); - } - return; - } - } - - if (_singleton._visualSelectionCommandCount > 0) - { - int start, length; - _singleton.GetRegion(out start, out length); - Replace(start, length, new string(key.Value.KeyChar, 1)); - } - else - { - Insert(key.Value.KeyChar); - } - - } - - /// - /// Reverts all of the input to the current input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void RevertLine(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._statusIsErrorMessage) - { - // After an edit, clear the error message - _singleton.ClearStatusMessage(render: false); - } - - while (_singleton._undoEditIndex > 0) - { - _singleton._edits[_singleton._undoEditIndex - 1].Undo(); - _singleton._undoEditIndex--; - } - _singleton.Render(); - } - - /// - /// Cancel the current input, leaving the input on the screen, - /// but returns back to the host so the prompt is evaluated again. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void CancelLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.ClearStatusMessage(false); - _singleton._current = _singleton._buffer.Length; - // We want to display ^C to show the line was canceled. Instead of appending ^C - // (or (char)3), we append 2 spaces so we don't affect tokenization too much, e.g. - // changing a keyword to a command. - _singleton._buffer.Append(" "); - _singleton.ReallyRender(); - - // Now that we've rendered with this extra spaces, go back and replace the spaces - // with ^C colored in red (so it stands out.) - var coordinates = _singleton.ConvertOffsetToCoordinates(_singleton._current); - var console = _singleton._console; - var consoleBuffer = _singleton._consoleBuffer; - int i = (coordinates.Y - _singleton._initialY) * console.BufferWidth + coordinates.X; - consoleBuffer[i].UnicodeChar = '^'; - consoleBuffer[i].ForegroundColor = ConsoleColor.Red; - consoleBuffer[i].BackgroundColor = console.BackgroundColor; - consoleBuffer[i+1].UnicodeChar = 'C'; - consoleBuffer[i+1].ForegroundColor = ConsoleColor.Red; - consoleBuffer[i+1].BackgroundColor = console.BackgroundColor; - console.WriteBufferLines(consoleBuffer, ref _singleton._initialY); - - var y = coordinates.Y + 1; - _singleton.PlaceCursor(0, ref y); - _singleton._buffer.Clear(); // Clear so we don't actually run the input - _singleton._current = 0; // If Render is called, _current must be correct. - _singleton._currentHistoryIndex = _singleton._history.Count; - _singleton._inputAccepted = true; - } - - /// - /// Like ForwardKillLine - deletes text from the point to the end of the line, - /// but does not put the deleted text in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ForwardDeleteLine(ConsoleKeyInfo? key = null, object arg = null) - { - var current = _singleton._current; - var buffer = _singleton._buffer; - if (buffer.Length > 0 && current < buffer.Length) - { - int length = buffer.Length - current; - var str = buffer.ToString(current, length); - _singleton.SaveEditItem(EditItemDelete.Create(str, current)); - buffer.Remove(current, length); - _singleton.Render(); - } - } - - /// - /// Like BackwardKillLine - deletes text from the point to the start of the line, - /// but does not put the deleted text in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BackwardDeleteLine(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._current > 0) - { - _singleton._clipboard = _singleton._buffer.ToString(0, _singleton._current); - _singleton.SaveEditItem(EditItemDelete.Create(_singleton._clipboard, 0)); - _singleton._buffer.Remove(0, _singleton._current); - _singleton._current = 0; - _singleton.Render(); - } - } - - /// - /// Delete the character before the cursor. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BackwardDeleteChar(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._visualSelectionCommandCount > 0) - { - int start, length; - _singleton.GetRegion(out start, out length); - Delete(start, length); - return; - } - - if (_singleton._buffer.Length > 0 && _singleton._current > 0) - { - int qty = (arg is int) ? (int) arg : 1; - qty = Math.Min(qty, _singleton._current); - - int startDeleteIndex = _singleton._current - qty; - _singleton.SaveEditItem( - EditItemDelete.Create( - _singleton._buffer.ToString(startDeleteIndex, qty), - startDeleteIndex, - BackwardDeleteChar, - arg) - ); - _singleton.SaveToClipboard(startDeleteIndex, qty); - _singleton._buffer.Remove(startDeleteIndex, qty); - _singleton._current = startDeleteIndex; - _singleton.Render(); - } - else - { - Ding(); - } - } - - private void DeleteCharImpl(int qty, bool orExit) - { - qty = Math.Min(qty, _singleton._buffer.Length + 1 + ViEndOfLineFactor - _singleton._current); - - if (_visualSelectionCommandCount > 0) - { - int start, length; - GetRegion(out start, out length); - Delete(start, length); - return; - } - - if (_buffer.Length > 0) - { - if (_current < _buffer.Length) - { - SaveEditItem(EditItemDelete.Create(_buffer.ToString(_current, qty), _current, DeleteChar, qty)); - SaveToClipboard(_current, qty); - _buffer.Remove(_current, qty); - if (_current >= _buffer.Length) - { - _current = Math.Max(0, _buffer.Length - 1); - } - Render(); - } - } - else if (orExit) - { - throw new ExitException(); - } - } - - /// - /// Delete the character under the cursor. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void DeleteChar(ConsoleKeyInfo? key = null, object arg = null) - { - int qty = (arg is int) ? (int)arg : 1; - - _singleton.DeleteCharImpl(qty, orExit: false); - } - - /// - /// Delete the character under the cursor, or if the line is empty, exit the process - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void DeleteCharOrExit(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.DeleteCharImpl(1, orExit: true); - } - - private bool AcceptLineImpl(bool validate) - { - ParseInput(); - if (_parseErrors.Any(e => e.IncompleteInput)) - { - Insert('\n'); - return false; - } - - // If text was pasted, for performance reasons we skip rendering for some time, - // but if input is accepted, we won't have another chance to render. - // - // Also - if there was an emphasis, we want to clear that before accepting - // and that requires rendering. - bool renderNeeded = _emphasisStart >= 0 || _queuedKeys.Count > 0; - - _emphasisStart = -1; - _emphasisLength = 0; - - var insertionPoint = _current; - // Make sure cursor is at the end before writing the line - _current = _buffer.Length; - - if (renderNeeded) - { - ReallyRender(); - } - - // Only run validation if we haven't before. If we have and status line shows an error, - // treat that as a -Force and accept the input so it is added to history, and PowerShell - // can report an error as it normally does. - if (validate && !_statusIsErrorMessage) - { - var errorMessage = Validate(_ast); - if (!string.IsNullOrWhiteSpace(errorMessage)) - { - // If there are more keys, assume the user pasted with a right click and - // we should insert a newline even though validation failed. - if (_queuedKeys.Count > 0) - { - // Validation may have moved the cursor. Because there are queued - // keys, we need to move the cursor back to the correct place, and - // ignore where validation put the cursor because the queued keys - // will be inserted in the wrong place. - SetCursorPosition(insertionPoint); - Insert('\n'); - } - _statusLinePrompt = ""; - _statusBuffer.Append(errorMessage); - _statusIsErrorMessage = true; - Render(); - return false; - } - } - - if (_statusIsErrorMessage) - { - ClearStatusMessage(render: true); - } - - var coordinates = ConvertOffsetToCoordinates(_current); - var y = coordinates.Y + 1; - PlaceCursor(0, ref y); - _inputAccepted = true; - return true; - } - - class CommandValidationVisitor : AstVisitor - { - private readonly Ast _rootAst; - internal string detectedError; - - internal CommandValidationVisitor(Ast rootAst) - { - _rootAst = rootAst; - } - - public override AstVisitAction VisitCommand(CommandAst commandAst) - { - var commandName = commandAst.GetCommandName(); - if (commandName != null) - { - if (_singleton._engineIntrinsics != null) - { - var commandInfo = _singleton._engineIntrinsics.InvokeCommand.GetCommand(commandName, CommandTypes.All); - if (commandInfo == null && !_singleton.UnresolvedCommandCouldSucceed(commandName, _rootAst)) - { - _singleton._current = commandAst.CommandElements[0].Extent.EndOffset; - detectedError = string.Format(CultureInfo.CurrentCulture, PSReadLineResources.CommandNotFoundError, commandName); - return AstVisitAction.StopVisit; - } - } - - if (commandAst.CommandElements.Any(e => e is ScriptBlockExpressionAst)) - { - if (_singleton._options.CommandsToValidateScriptBlockArguments == null || - !_singleton._options.CommandsToValidateScriptBlockArguments.Contains(commandName)) - { - return AstVisitAction.SkipChildren; - } - } - } - - if (_singleton._options.CommandValidationHandler != null) - { - try - { - _singleton._options.CommandValidationHandler(commandAst); - } - catch (Exception e) - { - detectedError = e.Message; - } - } - - return !string.IsNullOrWhiteSpace(detectedError) - ? AstVisitAction.StopVisit - : AstVisitAction.Continue; - } - } - - private string Validate(Ast rootAst) - { - if (_parseErrors != null && _parseErrors.Length > 0) - { - // Move the cursor to the point of error - _current = _parseErrors[0].Extent.EndOffset; - return _parseErrors[0].Message; - } - - var validationVisitor = new CommandValidationVisitor(rootAst); - rootAst.Visit(validationVisitor); - if (!string.IsNullOrWhiteSpace(validationVisitor.detectedError)) - { - return validationVisitor.detectedError; - } - - return null; - } - - private bool UnresolvedCommandCouldSucceed(string commandName, Ast rootAst) - { - // This is a little hacky, but we check for a few things where part of the current - // command defines/imports new commands that PowerShell might not yet know about. - // There is little reason to go to great lengths at being correct here, validation - // is just a small usability tweak to avoid cluttering up history - PowerShell - // will report errors for stuff we actually let through. - - // Do we define a function matching the command name? - var fnDefns = rootAst.FindAll(ast => ast is FunctionDefinitionAst, true).OfType(); - if (fnDefns.Any(fnDefnAst => fnDefnAst.Name.Equals(commandName, StringComparison.OrdinalIgnoreCase))) - { - return true; - } - - var cmdAsts = rootAst.FindAll(ast => ast is CommandAst, true).OfType(); - foreach (var cmdAst in cmdAsts) - { - // If we dot source something, we can't in general know what is being - // dot sourced so just assume the unresolved command will work. - // If we use the invocation operator, allow that because an expression - // is being invoked and it's reasonable to just allow it. - if (cmdAst.InvocationOperator != TokenKind.Unknown) - { - return true; - } - - // Are we importing a module or being tricky with Invoke-Expression? Let those through. - var candidateCommand = cmdAst.GetCommandName(); - if (candidateCommand.Equals("Import-Module", StringComparison.OrdinalIgnoreCase) - || candidateCommand.Equals("ipmo", StringComparison.OrdinalIgnoreCase) - || candidateCommand.Equals("Invoke-Expression", StringComparison.OrdinalIgnoreCase) - || candidateCommand.Equals("iex", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - if (commandName.Length == 1) - { - switch (commandName[0]) - { - // The following are debugger commands that should be accepted if we're debugging - // because the console host will interpret these commands directly. - case 's': case 'v': case 'o': case 'c': case 'q': case 'k': case 'l': - case 'S': case 'V': case 'O': case 'C': case 'Q': case 'K': case 'L': - case '?': case 'h': case 'H': - // Ideally we would check $PSDebugContext, but it is set at function - // scope, and because we're in a module, we can't find that variable - // (arguably a PowerShell issue.) - // NestedPromptLevel is good enough though - it's rare to be in a nested. - var nestedPromptLevel = _engineIntrinsics.SessionState.PSVariable.GetValue("NestedPromptLevel"); - if (nestedPromptLevel is int) - { - return ((int)nestedPromptLevel) > 0; - } - break; - } - } - - return false; - } - - static bool StaticParameterBindingSupported(CommandInfo commandInfo) - { - var aliasInfo = commandInfo as AliasInfo; - - if (aliasInfo != null) - { - commandInfo = aliasInfo.ResolvedCommand; - } - - return (commandInfo is ExternalScriptInfo) - || (commandInfo is CmdletInfo) - || (commandInfo is FunctionInfo); - } - - /// - /// Attempt to execute the current input. If the current input is incomplete (for - /// example there is a missing closing parenthesis, bracket, or quote, then the - /// continuation prompt is displayed on the next line and PSReadline waits for - /// keys to edit the current input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void AcceptLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.AcceptLineImpl(false); - } - - /// - /// Attempt to execute the current input. If the current input is incomplete (for - /// example there is a missing closing parenthesis, bracket, or quote, then the - /// continuation prompt is displayed on the next line and PSReadline waits for - /// keys to edit the current input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ValidateAndAcceptLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.AcceptLineImpl(true); - } - - /// - /// Attempt to execute the current input. If it can be executed (like AcceptLine), - /// then recall the next item from history the next time Readline is called. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void AcceptAndGetNext(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton.AcceptLineImpl(false)) - { - if (_singleton._currentHistoryIndex < (_singleton._history.Count - 1)) - { - _singleton._getNextHistoryIndex = _singleton._currentHistoryIndex + 1; - } - else - { - Ding(); - } - } - } - - /// - /// The continuation prompt is displayed on the next line and PSReadline waits for - /// keys to edit the current input. This is useful to enter multi-line input as - /// a single command even when a single line is complete input by itself. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void AddLine(ConsoleKeyInfo? key = null, object arg = null) - { - Insert('\n'); - } - - /// - /// A new empty line is created above the current line regardless of where the cursor - /// is on the current line. The cursor moves to the beginning of the new line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void InsertLineAbove(ConsoleKeyInfo? key = null, object arg = null) - { - // Move the current position to the beginning of the current line and only the current line. - if (_singleton.LineIsMultiLine()) - { - int i = Math.Max(0, _singleton._current - 1); - for (; i > 0; i--) - { - if (_singleton._buffer[i] == '\n') - { - i += 1; - break; - } - } - - _singleton._current = i; - } - else - { - _singleton._current = 0; - } - - Insert('\n'); - PreviousLine(); - } - - /// - /// A new empty line is created below the current line regardless of where the cursor - /// is on the current line. The cursor moves to the beginning of the new line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void InsertLineBelow(ConsoleKeyInfo? key = null, object arg = null) - { - // Move the current position to the end of the current line and only the current line. - if (_singleton.LineIsMultiLine()) - { - int i = _singleton._current; - for (; i < _singleton._buffer.Length; i++) - { - if (_singleton._buffer[i] == '\n') - { - break; - } - } - - _singleton._current = i; - } - else - { - _singleton._current = _singleton._buffer.Length; - } - - Insert('\n'); - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Changes.txt b/src/Microsoft.PowerShell.PSReadLine/Changes.txt deleted file mode 100644 index 31aa77d0c267..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Changes.txt +++ /dev/null @@ -1,293 +0,0 @@ -### Version 1.2 - -New features: -* Vi editing mode - -New functions: -* InsertLineAbove - - A new empty line is created above the current line regardless of where the cursor - is on the current line. The cursor moves to the beginning of the new line. -* InsertLineBelow - - A new empty line is created below the current line regardless of where the cursor - is on the current line. The cursor moves to the beginning of the new line. - -New key bindings: -* Ctrl+Enter bound to InsertLineAbove in Windows mode -* Ctrl+Shift+Enter bound to InsertLineBelow in Windows mode - -Bug fixes: -* Home the first line of multi-line input fixed -* CaptureScreen captures colors colors correctly instead of guessing -* CaptureScreen scrolls the screen to ensure the selected line is visible -* CaptureScreen allows j/k for up/down (for the vi fans) -* Fixed uncommon syntax coloring bug with bare words that start with a variable -* Added sample handler for F7 emulation -* Fixed sample handler for Set-StrictMode error -* Improved error message when errors occur in custom handlers - -### Version 1.1 (shipped w/ Windows 10) - -Breaking change: -* Namespace PSConsoleUtilities has been renamed to Microsoft.PowerShell -* Default history file location changed to match Windows 10 - -### Version 1.0.0.13 - -New features: -* Enter now does some extra validation before accepting the input. If there are any parse - errors or a command is not found, an error message is displayed, but you can continue editing, - the erroneous line will not be added to history, and the error message will be cleared after - you make an edit. - You can press Enter a second time to force accepting the line if you choose. - - If you don't like the new behavior for Enter, you can revert to the old behavior with: - Set-PSReadlineKeyHandler -Key Enter -Function AcceptLine - -Bug fixes: -* Occasional exception with AcceptAndGetNext (Ctrl+O) followed by something other than Enter -* Event handlers that register for the engine event PowerShell.OnIdle should work now. -* ClearScreen now scrolls the screen to preserve as much output as possible -* Fix exception on error input during rendering after certain keywords like process, begin, or end. -* Fix exception after undo from menu completion -* Support CancelLine (Ctrl+C) and Abort (Ctrl+G in emacs) to cancel DigitArgument -* History recall now ignores command lines from other currently running sessions, but you can - still find command lines from those sessions when searching history. -* Color any non-whitespace prompt character when there is an error, not just non-characters -* ScrollDisplayToCursor works a little better now. - -New functions: -* ValidateAndAcceptLine - Validate the command line (by making sure there are no parse errors, commands all exist, - and possibly other sorts of validation), display an error if any errors, but don't add - the command to history and clear the error after an edit. -* DeleteCharOrExit - - emulate Ctrl+D in bash properly by exiting the process if the command line is empty -* ScrollDisplayUpLine, ScrollDisplayDownLine - Scroll the screen up or down by a line instead of by the screen - -New key bindings: -* Ctrl+D bound to DeleteCharOrExit in Emacs mode -* Ctrl+N/Ctrl+P bound to NextHistory/PreviousHistory in Emacs mode -* Ctrl+PageUp bound to ScrollDisplayUpLine -* Ctrl+PageDown bound to ScrollDisplayDownLine -* Alt+F7 bound to ClearHistory in Windows mode - -New options: -* Set-PSReadlineOption - -ErrorForegroundColor - -ErrorBackgroundColor - Colors used when ValidateAndAcceptLine reports an error - - -CommandValidationHandler - A delegate that is called from ValidateAndAcceptLine that can perform custom validation - and also fix the command line, e.g. to correct common typos. - -New cmdlet: -* Remove-PSReadlineKeyHandler - This will remove a key binding for previously bound keys. - -Breaking change: -* Demo mode removed - - Trying to bind functions EnableDemoMode or DisableDemoMode will result in an error. - -### Version 1.0.0.12 - -New features: -* Multi-line editing is now practical. Home/End go to the start/end of the current line or - start/end of the input in a reasonable way. Up/Down arrows will move across lines if the - input has multiple lines and you are not in the middle of recalling history. - -Bug fixes: -* Color the prompt character if there is an error for any non-alphanumeric character -* Fix an issue related to undo (which was commonly hit via Escape) and using history search -* Fix a bug where PowerShell events are not written to the console until PSReadline returns -* Fixed so PowerTab now works with PSReadline -* Highlight from history search is cleared before accepting a line now. -* Fixed MenuComplete so it clears the menu (which only happened on some systems) - -New functions: -* NextLine -* PreviousLine - - These functions are added for completeness, neither is particularly useful as the usual - bindings for UpArrow/DownArrow are smart enough to recall history or change lines - depending on the context. - -New key bindings: -* F8/Shift+F8 bound to HistorySearchBackward/HistorySearchForward in Windows mode - -### Version 1.0.0.11 - -Bug fixes: -* Fixed MenuComplete to actually work - -### Version 1.0.0.10 - -New features: -* Added binding Ctrl+SpaceBar to MenuComplete in Windows and Emacs modes - - If you want to old behavior of Ctrl+Spacebar, bind it to PossibleCompletions -* Added binding Alt+. (YankLastArg) to Windows mode -* Added diagnostics when an exception occurs to help reporting bugs - -Bug fixes: -* SaveHistoryPath option fixed -* Fix ShowKeyBindings to not write blank lines -* Fixed bug with undo - -### Version 1.0.0.9 - -New features: -* MenuComplete - like an interactive show completion -* Automatically save history - - at process exit - - incrementally and shared across sessions - - don't save - See parameters HistorySaveStyle and HistorySavePath to Set-PSReadlineOption -* Added sample custom binding for quickly changing directories in SamplePSReadlineProfile.ps1 - -Bug fixes: -* Items loaded from history work with RevertLine -* Recalling current line after up arrow works again - -### Version 1.0.0.8 - -New features: -* SamplePSReadlineProfile.ps1 added with examples of custom key bindings -* Word movement takes DigitArgument -* HistoryNoDuplicates now works a little differently - - Duplicates are saved (it was a dubious memory optimization anyway) - - Recall will recall the most recently executed item instead of the first -* When at the last word, NextWord/ForwardWord now move to the end of line instead - of the last character of the word. -* HistorySearchBackward/HistorySearchForward changes behavior slightly: - - use emphasis like InteractiveHistorySearch - - cursor always moves to end like PreviousHistory/NextHistory -* New api GetSelectionState to get the current selection (if any). -* New functions: - - SelectBackwardsLine - - SelectLine - - SelectAll - - CopyOrCancelLine -* New key bindings in Windows mode: - - Alt+0 through Alt+9 and Alt+-: DigitArgument - - Ctrl+R/Ctrl+S for interactive history search - -Bug fixes: -* Backspace after a failed interactive history search (Ctrl+R) caused searching - to fail if you typed anything other than backspace. - -### Version 1.0.0.7 - -New features: -* CaptureScreen - copies selected portion of screen to clipboard in text and rtf -* InvokePrompt - re-evaluate the prompt while preserving the current input -* New functions to scroll the screen w/o using the mouse: - - ScrollScreenUp - - ScrollScreenDown - - ScrollScreenTop - - ScrollScreenToCursor -* Many small bug fixes - -### Version 1.0.0.6 - -New features: -* CharacterSearch/CharacterSearchBackward -* AcceptAndGetNext (Ctrl+O in bash) -* Get-PSReadlineKeyHandler now returns unbound functions -* Get-PSReadlineKeyHandler has 2 new parameters: -Bound and -Unbound -* Set-PSReadlineKeyHandler parameter -LongDescription is now -Description - (not breaking because I left an alias) -* WhatIsKey - display binding for a key -* ShowKeyBindings - show all bound keys -* Keyboard selection of text for cut/copy/delete. New functions: - - Cut - - Copy - - KillRegion - - SelectBackwardChar - - SelectForwardChar - - SelectBackwardWord - - SelectForwardWord - - SelectNextWord - - SelectShellForwardWord - - SelectShellBackwardWord - -Breaking change: -* The properties in the output of Get-PSReadlineKeyHandler have changed. - This is unlikely to break anyone though. - -### Version 1.0.0.5 - -New features: -* Delimiter support in *Word functions -* DigitArgument (Alt-0,Alt-1,Alt-2,...,Alt-9,Alt--) to pass numeric arguments -* YankLastArg/YankNthArg to extract arguments from previous command lines -* History search is now case insensitive with an option to make it case sensitive - -Bugs fixed: -* Shift+Backspace works like Backspace -* Ctrl+R with long search lines no longer causes big problems - -Behavior change: -* Word functions now use delimiters. The previous behavior is available - via a Shell*Word function, e.g. instead of KillWord, use ShellKillWord. - -### Version 1.0.0.4 - -New features: -* Interactive history search (Ctrl+R) -* Brace matching function added (GotoBrace) -* Clear screen (Ctrl+L) - -Bugs fixed: -* When showing possible completions, truncate at newline -* Prompt before showing a large number of completions -* Undo after paste works now -* Long pause after clicking on X to close powershell is now fixed - -### Version 1.0.0.3 - -Bugs fixed: -* Removed CLR 4.5 dependency -* Fix bug where console paste didn't display everything in some cases - -### Version 1.0.0.2 - -New features: -* Add a "demo mode" that shows keys pressed -* Add ETW event source for demo mode, key logger, macro recorder etc. -* Undo/redo -* Get-PSReadlineOption cmdlet -* Make specifying key handlers for builtins simpler -* Current un-entered line is saved and recalled when cycling through history -* Support syntax coloring of member names - -Bugs fixed: -* Speed up pasting from the console -* Fix coloring of some operators -* Fix coloring in some command arguments -* Ctrl-C is handled a little better - -Breaking changes: -* CLR 4.5 is now required. -* SetBufferState is gone because it doesn't support Undo/Redo - -### Version 1.0.0.1 - -New features: -* History imported when module is loaded -* Ctrl+End/Ctrl+Home bindings emulate cmd -* Arbitrary two key chords -* Key handlers passed the invoking key and an optional argument -* Made Ding public for custom handlers - -Bugs fixed: -* Alternate keyboards now supported -* Ctrl-C now properly emulates cmd - -Breaking changes: -* MinimumHistoryCommandLength parameter removed from Set-PSReadlineOption - - Can use this instead: - Set-PSReadlineOption -AddToHistoryHandler { $args[0].Length -gt 3 } - -### Version 1.0.0.0 - -Initial release diff --git a/src/Microsoft.PowerShell.PSReadLine/Cmdlets.cs b/src/Microsoft.PowerShell.PSReadLine/Cmdlets.cs deleted file mode 100644 index 7146e28a0b94..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Cmdlets.cs +++ /dev/null @@ -1,812 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Reflection; -using System.Linq; - -namespace Microsoft.PowerShell -{ - -#pragma warning disable 1591 - - public enum TokenClassification - { - None, - Comment, - Keyword, - String, - Operator, - Variable, - Command, - Parameter, - Type, - Number, - Member, - } - - public enum EditMode - { - Windows, - Emacs, - Vi, - } - - public enum BellStyle - { - None, - Visual, - Audible - } - - #region vi - public enum ViModeStyle - { - None, - Prompt, - Cursor - } - - public enum ViMode - { - Insert, - Command - } - #endregion vi - - public enum HistorySaveStyle - { - SaveIncrementally, - SaveAtExit, - SaveNothing - } - - public class PSConsoleReadlineOptions - { -#if UNIX // TODO: why different schemes for LINUX? - public const ConsoleColor DefaultCommentForegroundColor = ConsoleColor.Magenta; - public const ConsoleColor DefaultOperatorForegroundColor = ConsoleColor.Gray; - public const ConsoleColor DefaultParameterForegroundColor = ConsoleColor.Green; -#else - public const ConsoleColor DefaultCommentForegroundColor = ConsoleColor.DarkGreen; - public const ConsoleColor DefaultOperatorForegroundColor = ConsoleColor.DarkGray; - public const ConsoleColor DefaultParameterForegroundColor = ConsoleColor.DarkGray; -#endif - public const ConsoleColor DefaultKeywordForegroundColor = ConsoleColor.Green; - public const ConsoleColor DefaultStringForegroundColor = ConsoleColor.DarkCyan; - public const ConsoleColor DefaultVariableForegroundColor = ConsoleColor.Green; - public const ConsoleColor DefaultCommandForegroundColor = ConsoleColor.Yellow; - public const ConsoleColor DefaultTypeForegroundColor = ConsoleColor.Gray; - public const ConsoleColor DefaultNumberForegroundColor = ConsoleColor.White; - public const ConsoleColor DefaultMemberForegroundColor = ConsoleColor.Gray; - public const ConsoleColor DefaultEmphasisForegroundColor = ConsoleColor.Cyan; - public const ConsoleColor DefaultErrorForegroundColor = ConsoleColor.Red; - - public const EditMode DefaultEditMode = -#if UNIX - EditMode.Emacs; -#else - EditMode.Windows; -#endif - - public const string DefaultContinuationPrompt = ">> "; - - /// - /// The maximum number of commands to store in the history. - /// - public const int DefaultMaximumHistoryCount = 4096; - - /// - /// The maximum number of items to store in the kill ring. - /// - public const int DefaultMaximumKillRingCount = 10; - - /// - /// In Emacs, when searching history, the cursor doesn't move. - /// In 4NT, the cursor moves to the end. This option allows - /// for either behavior. - /// - public const bool DefaultHistorySearchCursorMovesToEnd = false; - - /// - /// When displaying possible completions, either display - /// tooltips or display just the completions. - /// - public const bool DefaultShowToolTips = false; - - /// - /// When ringing the bell, what frequency do we use? - /// - public const int DefaultDingTone = 1221; - - public const int DefaultDingDuration = 50; - - public const int DefaultCompletionQueryItems = 100; - - // Default includes all characters PowerShell treats like a dash - em dash, en dash, horizontal bar - public const string DefaultWordDelimiters = @";:,.[]{}()/\|^&*-=+'""" + "\u2013\u2014\u2015"; - - /// - /// When ringing the bell, what should be done? - /// - public const BellStyle DefaultBellStyle = BellStyle.Audible; - - public const bool DefaultHistorySearchCaseSensitive = false; - - public const HistorySaveStyle DefaultHistorySaveStyle = HistorySaveStyle.SaveIncrementally; - - public PSConsoleReadlineOptions(string hostName) - { - ResetColors(); - EditMode = DefaultEditMode; - ContinuationPrompt = DefaultContinuationPrompt; - ContinuationPromptBackgroundColor = Console.BackgroundColor; - ContinuationPromptForegroundColor = Console.ForegroundColor; - ExtraPromptLineCount = DefaultExtraPromptLineCount; - AddToHistoryHandler = null; - HistoryNoDuplicates = DefaultHistoryNoDuplicates; - MaximumHistoryCount = DefaultMaximumHistoryCount; - MaximumKillRingCount = DefaultMaximumKillRingCount; - HistorySearchCursorMovesToEnd = DefaultHistorySearchCursorMovesToEnd; - ShowToolTips = DefaultShowToolTips; - DingDuration = DefaultDingDuration; - DingTone = DefaultDingTone; - BellStyle = DefaultBellStyle; - CompletionQueryItems = DefaultCompletionQueryItems; - WordDelimiters = DefaultWordDelimiters; - HistorySearchCaseSensitive = DefaultHistorySearchCaseSensitive; - HistorySaveStyle = DefaultHistorySaveStyle; - - string historyFileName = hostName + "_history.txt"; -#if UNIX - // PSReadline does not have access to Utils.CorePSPlatform. Must set PSReadline path separately - string historyPath = System.Environment.GetEnvironmentVariable("XDG_DATA_HOME"); - - if (!String.IsNullOrEmpty(historyPath)) - { - historyPath = System.IO.Path.Combine(historyPath, "powershell", "PSReadLine", historyFileName); - HistorySavePath = historyPath; - } - else - { - // History is data, so it goes into .local/share/powershell folder - HistorySavePath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("HOME"), - ".local", - "share", - "powershell", - "PSReadLine", - historyFileName); - } -#else - HistorySavePath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("APPDATA"), - @"Microsoft\Windows\PowerShell\PSReadline\", - historyFileName); -#endif - CommandValidationHandler = null; - CommandsToValidateScriptBlockArguments = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "ForEach-Object", "%", - "Invoke-Command", "icm", - "Measure-Command", - "New-Module", "nmo", - "Register-EngineEvent", - "Register-ObjectEvent", - "Register-WMIEvent", - "Set-PSBreakpoint", "sbp", - "Start-Job", "sajb", - "Trace-Command", "trcm", - "Use-Transaction", - "Where-Object", "?", "where", - }; - } - - public EditMode EditMode { get; set; } - - public string ContinuationPrompt { get; set; } - public ConsoleColor ContinuationPromptForegroundColor { get; set; } - public ConsoleColor ContinuationPromptBackgroundColor { get; set; } - - /// - /// Prompts are typically 1 line, but sometimes they may span lines. This - /// count is used to make sure we can display the full prompt after showing - /// ambiguous completions - /// - public int ExtraPromptLineCount { get; set; } - public const int DefaultExtraPromptLineCount = 0; - - /// - /// This handler is called before adding a command line to history. - /// The return value indicates if the command line should be added - /// to history or not. - /// - public Func AddToHistoryHandler { get; set; } - - /// - /// This handler is called from ValidateAndAcceptLine. - /// If an exception is thrown, validation fails and the error is reported. - /// - public Action CommandValidationHandler { get; set; } - - /// - /// Most commands do not accept script blocks, but for those that do, - /// we want to validate commands in the script block arguments. - /// Unfortunately, we can't know how the argument is used. In the worst - /// case, for commands like Get-ADUser, the script block actually - /// specifies a different language. - /// - /// Because we can't know ahead of time all of the commands that do - /// odd things with script blocks, we create a white-list of commands - /// that do invoke the script block - this covers the most useful cases. - /// - [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] - public HashSet CommandsToValidateScriptBlockArguments { get; set; } - - /// - /// When true, duplicates will not be added to the history. - /// - public bool HistoryNoDuplicates { get; set; } - public const bool DefaultHistoryNoDuplicates = false; - - public int MaximumHistoryCount { get; set; } - public int MaximumKillRingCount { get; set; } - public bool HistorySearchCursorMovesToEnd { get; set; } - public bool ShowToolTips { get; set; } - public int DingTone { get; set; } - public int CompletionQueryItems { get; set; } - public string WordDelimiters { get; set; } - - /// - /// When ringing the bell, how long (in ms)? - /// - public int DingDuration { get; set; } - public BellStyle BellStyle { get; set; } - - public bool HistorySearchCaseSensitive { get; set; } - internal StringComparison HistoryStringComparison - { - get { return HistorySearchCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; } - } - - #region vi - public ViModeStyle ViModeIndicator { get; set; } - #endregion vi - - /// - /// The path to the saved history. - /// - public string HistorySavePath { get; set; } - public HistorySaveStyle HistorySaveStyle { get; set; } - - public ConsoleColor DefaultTokenForegroundColor { get; set; } - public ConsoleColor CommentForegroundColor { get; set; } - public ConsoleColor KeywordForegroundColor { get; set; } - public ConsoleColor StringForegroundColor { get; set; } - public ConsoleColor OperatorForegroundColor { get; set; } - public ConsoleColor VariableForegroundColor { get; set; } - public ConsoleColor CommandForegroundColor { get; set; } - public ConsoleColor ParameterForegroundColor { get; set; } - public ConsoleColor TypeForegroundColor { get; set; } - public ConsoleColor NumberForegroundColor { get; set; } - public ConsoleColor MemberForegroundColor { get; set; } - public ConsoleColor DefaultTokenBackgroundColor { get; set; } - public ConsoleColor CommentBackgroundColor { get; set; } - public ConsoleColor KeywordBackgroundColor { get; set; } - public ConsoleColor StringBackgroundColor { get; set; } - public ConsoleColor OperatorBackgroundColor { get; set; } - public ConsoleColor VariableBackgroundColor { get; set; } - public ConsoleColor CommandBackgroundColor { get; set; } - public ConsoleColor ParameterBackgroundColor { get; set; } - public ConsoleColor TypeBackgroundColor { get; set; } - public ConsoleColor NumberBackgroundColor { get; set; } - public ConsoleColor MemberBackgroundColor { get; set; } - public ConsoleColor EmphasisForegroundColor { get; set; } - public ConsoleColor EmphasisBackgroundColor { get; set; } - public ConsoleColor ErrorForegroundColor { get; set; } - public ConsoleColor ErrorBackgroundColor { get; set; } - - internal void ResetColors() - { - DefaultTokenForegroundColor = Console.ForegroundColor; - CommentForegroundColor = DefaultCommentForegroundColor; - KeywordForegroundColor = DefaultKeywordForegroundColor; - StringForegroundColor = DefaultStringForegroundColor; - OperatorForegroundColor = DefaultOperatorForegroundColor; - VariableForegroundColor = DefaultVariableForegroundColor; - CommandForegroundColor = DefaultCommandForegroundColor; - ParameterForegroundColor = DefaultParameterForegroundColor; - TypeForegroundColor = DefaultTypeForegroundColor; - NumberForegroundColor = DefaultNumberForegroundColor; - MemberForegroundColor = DefaultNumberForegroundColor; - EmphasisForegroundColor = DefaultEmphasisForegroundColor; - ErrorForegroundColor = DefaultErrorForegroundColor; - DefaultTokenBackgroundColor = Console.BackgroundColor; - CommentBackgroundColor = Console.BackgroundColor; - KeywordBackgroundColor = Console.BackgroundColor; - StringBackgroundColor = Console.BackgroundColor; - OperatorBackgroundColor = Console.BackgroundColor; - VariableBackgroundColor = Console.BackgroundColor; - CommandBackgroundColor = Console.BackgroundColor; - ParameterBackgroundColor = Console.BackgroundColor; - TypeBackgroundColor = Console.BackgroundColor; - NumberBackgroundColor = Console.BackgroundColor; - MemberBackgroundColor = Console.BackgroundColor; - EmphasisBackgroundColor = Console.BackgroundColor; - ErrorBackgroundColor = Console.BackgroundColor; - } - - internal void SetForegroundColor(TokenClassification tokenKind, ConsoleColor color) - { - switch (tokenKind) - { - case TokenClassification.None: DefaultTokenForegroundColor = color; break; - case TokenClassification.Comment: CommentForegroundColor = color; break; - case TokenClassification.Keyword: KeywordForegroundColor = color; break; - case TokenClassification.String: StringForegroundColor = color; break; - case TokenClassification.Operator: OperatorForegroundColor = color; break; - case TokenClassification.Variable: VariableForegroundColor = color; break; - case TokenClassification.Command: CommandForegroundColor = color; break; - case TokenClassification.Parameter: ParameterForegroundColor = color; break; - case TokenClassification.Type: TypeForegroundColor = color; break; - case TokenClassification.Number: NumberForegroundColor = color; break; - case TokenClassification.Member: MemberForegroundColor = color; break; - } - } - - internal void SetBackgroundColor(TokenClassification tokenKind, ConsoleColor color) - { - switch (tokenKind) - { - case TokenClassification.None: DefaultTokenBackgroundColor = color; break; - case TokenClassification.Comment: CommentBackgroundColor = color; break; - case TokenClassification.Keyword: KeywordBackgroundColor = color; break; - case TokenClassification.String: StringBackgroundColor = color; break; - case TokenClassification.Operator: OperatorBackgroundColor = color; break; - case TokenClassification.Variable: VariableBackgroundColor = color; break; - case TokenClassification.Command: CommandBackgroundColor = color; break; - case TokenClassification.Parameter: ParameterBackgroundColor = color; break; - case TokenClassification.Type: TypeBackgroundColor = color; break; - case TokenClassification.Number: NumberBackgroundColor = color; break; - case TokenClassification.Member: MemberBackgroundColor = color; break; - } - } - } - - [Cmdlet(VerbsCommon.Get, "PSReadlineOption", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528808")] - [OutputType(typeof(PSConsoleReadlineOptions))] - public class GetPSReadlineOption : PSCmdlet - { - [ExcludeFromCodeCoverage] - protected override void EndProcessing() - { - WriteObject(PSConsoleReadLine.GetOptions()); - } - } - - [Cmdlet(VerbsCommon.Set, "PSReadlineOption", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528811")] - public class SetPSReadlineOption : PSCmdlet - { - [Parameter(ParameterSetName = "OptionsSet")] - public EditMode EditMode - { - get { return _editMode.GetValueOrDefault(); } - set { _editMode = value; } - } - internal EditMode? _editMode; - - [Parameter(ParameterSetName = "OptionsSet")] - [AllowEmptyString] - public string ContinuationPrompt { get; set; } - - [Parameter(ParameterSetName = "OptionsSet")] - public ConsoleColor ContinuationPromptForegroundColor - { - get { return _continuationPromptForegroundColor.GetValueOrDefault(); } - set { _continuationPromptForegroundColor = value; } - } - internal ConsoleColor? _continuationPromptForegroundColor; - - [Parameter(ParameterSetName = "OptionsSet")] - public ConsoleColor ContinuationPromptBackgroundColor - { - get { return _continuationPromptBackgroundColor.GetValueOrDefault(); } - set { _continuationPromptBackgroundColor = value; } - } - internal ConsoleColor? _continuationPromptBackgroundColor; - - [Parameter(ParameterSetName = "OptionsSet")] - public ConsoleColor EmphasisForegroundColor - { - get { return _emphasisForegroundColor.GetValueOrDefault(); } - set { _emphasisForegroundColor = value; } - } - internal ConsoleColor? _emphasisForegroundColor; - - [Parameter(ParameterSetName = "OptionsSet")] - public ConsoleColor EmphasisBackgroundColor - { - get { return _emphasisBackgroundColor.GetValueOrDefault(); } - set { _emphasisBackgroundColor = value; } - } - internal ConsoleColor? _emphasisBackgroundColor; - - [Parameter(ParameterSetName = "OptionsSet")] - public ConsoleColor ErrorForegroundColor - { - get { return _errorForegroundColor.GetValueOrDefault(); } - set { _errorForegroundColor = value; } - } - internal ConsoleColor? _errorForegroundColor; - - [Parameter(ParameterSetName = "OptionsSet")] - public ConsoleColor ErrorBackgroundColor - { - get { return _errorBackgroundColor.GetValueOrDefault(); } - set { _errorBackgroundColor = value; } - } - internal ConsoleColor? _errorBackgroundColor; - - [Parameter(ParameterSetName = "OptionsSet")] - public SwitchParameter HistoryNoDuplicates - { - get { return _historyNoDuplicates.GetValueOrDefault(); } - set { _historyNoDuplicates = value; } - } - internal SwitchParameter? _historyNoDuplicates; - - [Parameter(ParameterSetName = "OptionsSet")] - [AllowNull] - public Func AddToHistoryHandler - { - get { return _addToHistoryHandler; } - set - { - _addToHistoryHandler = value; - _addToHistoryHandlerSpecified = true; - } - } - private Func _addToHistoryHandler; - internal bool _addToHistoryHandlerSpecified; - - [Parameter(ParameterSetName = "OptionsSet")] - [AllowNull] - public Action CommandValidationHandler - { - get { return _commandValidationHandler; } - set - { - _commandValidationHandler = value; - _commandValidationHandlerSpecified = true; - } - } - private Action _commandValidationHandler; - internal bool _commandValidationHandlerSpecified; - - [Parameter(ParameterSetName = "OptionsSet")] - public SwitchParameter HistorySearchCursorMovesToEnd - { - get { return _historySearchCursorMovesToEnd.GetValueOrDefault(); } - set { _historySearchCursorMovesToEnd = value; } - } - internal SwitchParameter? _historySearchCursorMovesToEnd; - - [Parameter(ParameterSetName = "OptionsSet")] - public int MaximumHistoryCount - { - get { return _maximumHistoryCount.GetValueOrDefault(); } - set { _maximumHistoryCount = value; } - } - internal int? _maximumHistoryCount; - - [Parameter(ParameterSetName = "OptionsSet")] - public int MaximumKillRingCount - { - get { return _maximumKillRingCount.GetValueOrDefault(); } - set { _maximumKillRingCount = value; } - } - internal int? _maximumKillRingCount; - - [Parameter(ParameterSetName = "OptionsSet")] - public SwitchParameter ResetTokenColors - { - get { return _resetTokenColors.GetValueOrDefault(); } - set { _resetTokenColors = value; } - } - internal SwitchParameter? _resetTokenColors; - - [Parameter(ParameterSetName = "OptionsSet")] - public SwitchParameter ShowToolTips - { - get { return _showToolTips.GetValueOrDefault(); } - set { _showToolTips = value; } - } - internal SwitchParameter? _showToolTips; - - [Parameter(ParameterSetName = "OptionsSet")] - public int ExtraPromptLineCount - { - get { return _extraPromptLineCount.GetValueOrDefault(); } - set { _extraPromptLineCount = value; } - } - internal int? _extraPromptLineCount; - - [Parameter(ParameterSetName = "OptionsSet")] - public int DingTone - { - get { return _dingTone.GetValueOrDefault(); } - set { _dingTone = value; } - } - internal int? _dingTone; - - [Parameter(ParameterSetName = "OptionsSet")] - public int DingDuration - { - get { return _dingDuration.GetValueOrDefault(); } - set { _dingDuration = value; } - } - internal int? _dingDuration; - - [Parameter(ParameterSetName = "OptionsSet")] - public BellStyle BellStyle - { - get { return _bellStyle.GetValueOrDefault(); } - set { _bellStyle = value; } - } - internal BellStyle? _bellStyle; - - [Parameter(ParameterSetName = "OptionsSet")] - public int CompletionQueryItems - { - get { return _completionQueryItems.GetValueOrDefault(); } - set { _completionQueryItems = value; } - } - internal int? _completionQueryItems; - - [Parameter(ParameterSetName = "OptionsSet")] - public string WordDelimiters { get; set; } - - [Parameter(ParameterSetName = "OptionsSet")] - public SwitchParameter HistorySearchCaseSensitive - { - get { return _historySearchCaseSensitive.GetValueOrDefault(); } - set { _historySearchCaseSensitive = value; } - } - internal SwitchParameter? _historySearchCaseSensitive; - - [Parameter(ParameterSetName = "OptionsSet")] - public HistorySaveStyle HistorySaveStyle - { - get { return _historySaveStyle.GetValueOrDefault(); } - set { _historySaveStyle = value; } - } - internal HistorySaveStyle? _historySaveStyle; - - [Parameter(ParameterSetName = "OptionsSet")] - [ValidateNotNullOrEmpty] - public string HistorySavePath { get; set; } - - #region vi - [Parameter(ParameterSetName = "OptionsSet")] - public ViModeStyle ViModeIndicator - { - get { return _viModeIndicator.GetValueOrDefault(); } - set { _viModeIndicator = value; } - } - internal ViModeStyle? _viModeIndicator; - #endregion vi - - [Parameter(ParameterSetName = "ColorSet", Position = 0, Mandatory = true)] - public TokenClassification TokenKind - { - get { return _tokenKind.GetValueOrDefault(); } - set { _tokenKind = value; } - } - internal TokenClassification? _tokenKind; - - [Parameter(ParameterSetName = "ColorSet", Position = 1)] - public ConsoleColor ForegroundColor - { - get { return _foregroundColor.GetValueOrDefault(); } - set { _foregroundColor = value; } - } - internal ConsoleColor? _foregroundColor; - - [Parameter(ParameterSetName = "ColorSet", Position = 2)] - public ConsoleColor BackgroundColor - { - get { return _backgroundColor.GetValueOrDefault(); } - set { _backgroundColor = value; } - } - internal ConsoleColor? _backgroundColor; - - [ExcludeFromCodeCoverage] - protected override void EndProcessing() - { - PSConsoleReadLine.SetOptions(this); - } - } - - public class ChangePSReadlineKeyHandlerCommandBase : PSCmdlet - { - [Parameter(Position = 0, Mandatory = true)] - [Alias("Key")] - [ValidateNotNullOrEmpty] - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public string[] Chord { get; set; } - - [Parameter] - public ViMode ViMode { get; set; } - - [ExcludeFromCodeCoverage] - protected IDisposable UseRequestedDispatchTables() - { - bool inViMode = PSConsoleReadLine.GetOptions().EditMode == EditMode.Vi; - bool viModeParamPresent = MyInvocation.BoundParameters.ContainsKey("ViMode"); - - if (inViMode || viModeParamPresent) - { - if (!inViMode) - { - // "-ViMode" must have been specified explicitly. Well, okay... we can - // modify the Vi tables... but isn't that an odd thing to do from - // not-vi mode? - WriteWarning(PSReadLineResources.NotInViMode); - } - - if (ViMode == ViMode.Command) - return PSConsoleReadLine.UseViCommandModeTables(); - else // default if -ViMode not specified, invalid, or "Insert" - return PSConsoleReadLine.UseViInsertModeTables(); - } - - return null; - } - } - - [Cmdlet(VerbsCommon.Set, "PSReadlineKeyHandler", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528810")] - public class SetPSReadlineKeyHandlerCommand : ChangePSReadlineKeyHandlerCommandBase, IDynamicParameters - { - [Parameter(Position = 1, Mandatory = true, ParameterSetName = "ScriptBlock")] - [ValidateNotNull] - public ScriptBlock ScriptBlock { get; set; } - - [Parameter(ParameterSetName = "ScriptBlock")] - public string BriefDescription { get; set; } - - [Parameter(ParameterSetName = "ScriptBlock")] - [Alias("LongDescription")] // Alias to stay comptible with previous releases - public string Description { get; set; } - - private const string FunctionParameter = "Function"; - private const string FunctionParameterSet = "Function"; - - [ExcludeFromCodeCoverage] - protected override void EndProcessing() - { - using (UseRequestedDispatchTables()) - { - if (ParameterSetName.Equals(FunctionParameterSet)) - { - var function = (string)_dynamicParameters.Value[FunctionParameter].Value; - MethodInfo mi = typeof (PSConsoleReadLine).GetMethod(function, - BindingFlags.Public | BindingFlags.Static | BindingFlags.IgnoreCase); - - string functionName = mi.Name; - - var keyHandler = (Action) - mi.CreateDelegate(typeof (Action)); - - string longDescription = PSReadLineResources.ResourceManager.GetString( - functionName + "Description"); - - PSConsoleReadLine.SetKeyHandler(Chord, keyHandler, functionName, longDescription); - } - else - { - PSConsoleReadLine.SetKeyHandler(Chord, ScriptBlock, BriefDescription, Description); - } - } - } - - private readonly Lazy _dynamicParameters = - new Lazy(CreateDynamicParametersResult); - - private static RuntimeDefinedParameterDictionary CreateDynamicParametersResult() - { - var bindableFunctions = (typeof(PSConsoleReadLine).GetMethods(BindingFlags.Public | BindingFlags.Static)) - .Where(method => - { - var parameters = method.GetParameters(); - return parameters.Length == 2 - && parameters[0].ParameterType == typeof(ConsoleKeyInfo?) - && parameters[1].ParameterType == typeof(object); - }) - .Select(method => method.Name) - .OrderBy(name => name); - - var attributes = new Collection - { - new ParameterAttribute - { - Position = 1, - Mandatory = true, - ParameterSetName = FunctionParameterSet - }, - new ValidateSetAttribute(bindableFunctions.ToArray()) - }; - var parameter = new RuntimeDefinedParameter(FunctionParameter, typeof(string), attributes); - var result = new RuntimeDefinedParameterDictionary {{FunctionParameter, parameter}}; - return result; - } - - public object GetDynamicParameters() - { - return _dynamicParameters.Value; - } - } - - [Cmdlet(VerbsCommon.Get, "PSReadlineKeyHandler", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528807")] - [OutputType(typeof(KeyHandler))] - public class GetKeyHandlerCommand : PSCmdlet - { - [Parameter] - public SwitchParameter Bound - { - get { return _bound.GetValueOrDefault(); } - set { _bound = value; } - } - private SwitchParameter? _bound; - - [Parameter] - public SwitchParameter Unbound - { - get { return _unbound.GetValueOrDefault(); } - set { _unbound = value; } - } - private SwitchParameter? _unbound; - - [ExcludeFromCodeCoverage] - protected override void EndProcessing() - { - bool bound = true; - bool unbound = true; - if (_bound.HasValue && _unbound.HasValue) - { - bound = _bound.Value.IsPresent; - unbound = _unbound.Value.IsPresent; - } - else if (_bound.HasValue) - { - bound = _bound.Value.IsPresent; - unbound = false; - } - else if (_unbound.HasValue) - { - bound = false; - unbound = _unbound.Value.IsPresent; - } - WriteObject(PSConsoleReadLine.GetKeyHandlers(bound, unbound), true); - } - } - - [Cmdlet(VerbsCommon.Remove, "PSReadlineKeyHandler", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528809")] - public class RemoveKeyHandlerCommand : ChangePSReadlineKeyHandlerCommandBase - { - [ExcludeFromCodeCoverage] - protected override void EndProcessing() - { - using (UseRequestedDispatchTables()) - { - PSConsoleReadLine.RemoveKeyHandler(Chord); - } - } - } - -#pragma warning restore 1591 - -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Completion.cs b/src/Microsoft.PowerShell.PSReadLine/Completion.cs deleted file mode 100644 index aadee01d815c..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Completion.cs +++ /dev/null @@ -1,556 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Runspaces; -using System.Text; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - // Tab completion state - private int _tabCommandCount; - private CommandCompletion _tabCompletions; - private Runspace _runspace; - - // String helper for directory paths - private static string DirectorySeparatorString = System.IO.Path.DirectorySeparatorChar.ToString(); - - // Stub helper method so completion can be mocked - [ExcludeFromCodeCoverage] - CommandCompletion IPSConsoleReadLineMockableMethods.CompleteInput(string input, int cursorIndex, Hashtable options, System.Management.Automation.PowerShell powershell) - { - return CalloutUsingDefaultConsoleMode( - () => CommandCompletion.CompleteInput(input, cursorIndex, options, powershell)); - } - - /// - /// Attempt to complete the text surrounding the cursor with the next - /// available completion. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void TabCompleteNext(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.Complete(forward: true); - } - - /// - /// Attempt to complete the text surrounding the cursor with the previous - /// available completion. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void TabCompletePrevious(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.Complete(forward: false); - } - - private static bool IsSingleQuote(char c) - { - return c == '\'' || c == (char)8216 || c == (char)8217 || c == (char)8218; - } - - private static bool IsDoubleQuote(char c) - { - return c == '"' || c == (char)8220 || c == (char)8221; - } - - private static bool IsQuoted(string s) - { - if (s.Length >= 2) - { - var first = s[0]; - var last = s[s.Length - 1]; - - return ((IsSingleQuote(first) && IsSingleQuote(last)) - || - (IsDoubleQuote(first) && IsDoubleQuote(last))); - } - return false; - } - - private static string GetUnquotedText(string s, bool consistentQuoting) - { - if (!consistentQuoting && IsQuoted(s)) - { - s = s.Substring(1, s.Length - 2); - } - return s; - } - - /// - /// Attempt to perform completion on the text surrounding the cursor. - /// If there are multiple possible completions, the longest unambiguous - /// prefix is used for completion. If trying to complete the longest - /// unambiguous completion, a list of possible completions is displayed. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Complete(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.CompleteImpl(key, arg, false); - } - - /// - /// Attempt to perform completion on the text surrounding the cursor. - /// If there are multiple possible completions, the longest unambiguous - /// prefix is used for completion. If trying to complete the longest - /// unambiguous completion, a list of possible completions is displayed. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void MenuComplete(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.CompleteImpl(key, arg, true); - } - - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private void CompleteImpl(ConsoleKeyInfo? key, object arg, bool menuSelect) - { - var completions = GetCompletions(); - if (completions == null || completions.CompletionMatches.Count == 0) - return; - - if (_tabCommandCount > 0) - { - if (completions.CompletionMatches.Count == 1) - { - Ding(); - } - else - { - PossibleCompletionsImpl(completions, menuSelect); - } - return; - } - - if (completions.CompletionMatches.Count == 1) - { - // We want to add a backslash for directory completion if possible. This - // is mostly only needed if we have a single completion - if there are multiple - // completions, then we'll be showing the possible completions where it's very - // unlikely that we would add a trailing backslash. - - DoReplacementForCompletion(completions.CompletionMatches[0], completions); - return; - } - - if (menuSelect) - { - PossibleCompletionsImpl(completions, true); - return; - } - - // Find the longest unambiguous prefix. This might be the empty - // string, in which case we don't want to remove any of the users input, - // instead we'll immediately show possible completions. - // For the purposes of unambiguous prefix, we'll ignore quotes if - // some completions aren't quoted. - var firstResult = completions.CompletionMatches[0]; - int quotedCompletions = completions.CompletionMatches.Count(match => IsQuoted(match.CompletionText)); - bool consistentQuoting = - quotedCompletions == 0 || - (quotedCompletions == completions.CompletionMatches.Count && - quotedCompletions == completions.CompletionMatches.Count( - m => m.CompletionText[0] == firstResult.CompletionText[0])); - - bool ambiguous = false; - var replacementText = GetUnquotedText(firstResult.CompletionText, consistentQuoting); - foreach (var match in completions.CompletionMatches.Skip(1)) - { - var matchText = GetUnquotedText(match.CompletionText, consistentQuoting); - for (int i = 0; i < replacementText.Length; i++) - { - if (i == matchText.Length - || char.ToLowerInvariant(replacementText[i]) != char.ToLowerInvariant(matchText[i])) - { - ambiguous = true; - replacementText = replacementText.Substring(0, i); - break; - } - } - if (replacementText.Length == 0) - { - break; - } - } - - if (replacementText.Length > 0) - { - Replace(completions.ReplacementIndex, completions.ReplacementLength, replacementText); - completions.ReplacementLength = replacementText.Length; - - if (ambiguous) - { - Ding(); - } - } - else - { - // No common prefix, don't wait for a second tab, just show the possible completions - // right away. - PossibleCompletionsImpl(completions, false); - } - - _tabCommandCount += 1; - } - - private CommandCompletion GetCompletions() - { - if (_tabCommandCount == 0) - { - try - { - _tabCompletions = null; - - // Could use the overload that takes an AST as it's faster (we've already parsed the - // input for coloring) but that overload is a little more complicated in passing in the - // cursor position. - System.Management.Automation.PowerShell ps; - if (!_mockableMethods.RunspaceIsRemote(_runspace)) - { - ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); - } - else - { - ps = System.Management.Automation.PowerShell.Create(); - ps.Runspace = _runspace; - } - _tabCompletions = _mockableMethods.CompleteInput(_buffer.ToString(), _current, null, ps); - - if (_tabCompletions.CompletionMatches.Count == 0) - return null; - } - catch (Exception) - { - } - } - - return _tabCompletions; - } - - private void Complete(bool forward) - { - var completions = GetCompletions(); - if (completions == null) - return; - - completions.CurrentMatchIndex += forward ? 1 : -1; - if (completions.CurrentMatchIndex < 0) - { - completions.CurrentMatchIndex = completions.CompletionMatches.Count - 1; - } - else if (completions.CurrentMatchIndex == completions.CompletionMatches.Count) - { - completions.CurrentMatchIndex = 0; - } - - var completionResult = completions.CompletionMatches[completions.CurrentMatchIndex]; - DoReplacementForCompletion(completionResult, completions); - _tabCommandCount += 1; - } - - private void DoReplacementForCompletion(CompletionResult completionResult, CommandCompletion completions) - { - var replacementText = completionResult.CompletionText; - int cursorAdjustment = 0; - if (completionResult.ResultType == CompletionResultType.ProviderContainer) - { - replacementText = GetReplacementTextForDirectory(replacementText, ref cursorAdjustment); - } - Replace(completions.ReplacementIndex, completions.ReplacementLength, replacementText); - if (cursorAdjustment != 0) - { - _current += cursorAdjustment; - PlaceCursor(); - } - completions.ReplacementLength = replacementText.Length; - } - - private static string GetReplacementTextForDirectory(string replacementText, ref int cursorAdjustment) - { - if (!replacementText.EndsWith(DirectorySeparatorString , StringComparison.Ordinal)) - { - if (replacementText.EndsWith(String.Format("{0}\'", DirectorySeparatorString), StringComparison.Ordinal) || - replacementText.EndsWith(String.Format("{0}\"", DirectorySeparatorString), StringComparison.Ordinal)) - { - cursorAdjustment = -1; - } - else if (replacementText.EndsWith("'", StringComparison.Ordinal) || - replacementText.EndsWith("\"", StringComparison.Ordinal)) - { - var len = replacementText.Length; - replacementText = replacementText.Substring(0, len - 1) + System.IO.Path.DirectorySeparatorChar + replacementText[len - 1]; - cursorAdjustment = -1; - } - else - { - replacementText = replacementText + System.IO.Path.DirectorySeparatorChar; - } - } - return replacementText; - } - - private static void InvertSelectedCompletion(BufferChar[] buffer, int selectedItem, int menuColumnWidth, int menuRows) - { - var selectedX = selectedItem / menuRows; - var selectedY = selectedItem - (selectedX * menuRows); - var start = selectedY * _singleton._console.BufferWidth + selectedX * menuColumnWidth; - for (int i = 0; i < menuColumnWidth; i++) - { - buffer[i + start].Inverse = true; - } - } - - /// - /// Display the list of possible completions. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void PossibleCompletions(ConsoleKeyInfo? key = null, object arg = null) - { - var completions = _singleton.GetCompletions(); - _singleton.PossibleCompletionsImpl(completions, menuSelect: false); - } - - private static string HandleNewlinesForPossibleCompletions(string s) - { - s = s.Trim(); - var newlineIndex = s.IndexOfAny(new []{'\r', '\n'}); - if (newlineIndex >= 0) - { - s = s.Substring(0, newlineIndex) + "..."; - } - return s; - } - - private void PossibleCompletionsImpl(CommandCompletion completions, bool menuSelect) - { - if (completions == null || completions.CompletionMatches.Count == 0) - { - Ding(); - return; - } - - if (completions.CompletionMatches.Count >= _options.CompletionQueryItems) - { - if (!PromptYesOrNo(string.Format(CultureInfo.CurrentCulture, PSReadLineResources.DisplayAllPossibilities, completions.CompletionMatches.Count))) - { - return; - } - } - - var matches = completions.CompletionMatches; - var minColWidth = matches.Max(c => c.ListItemText.Length); - minColWidth += 2; - var menuColumnWidth = minColWidth; - - int displayRows; - var bufferWidth = _console.BufferWidth; - ConsoleBufferBuilder cb; - if (Options.ShowToolTips) - { - const string seperator = "- "; - var maxTooltipWidth = bufferWidth - minColWidth - seperator.Length; - - displayRows = matches.Count; - cb = new ConsoleBufferBuilder(displayRows * bufferWidth, _console); - for (int index = 0; index < matches.Count; index++) - { - var match = matches[index]; - var listItemText = HandleNewlinesForPossibleCompletions(match.ListItemText); - cb.Append(listItemText); - var spacesNeeded = minColWidth - listItemText.Length; - if (spacesNeeded > 0) - { - cb.Append(' ', spacesNeeded); - } - cb.Append(seperator); - var toolTip = HandleNewlinesForPossibleCompletions(match.ToolTip); - toolTip = toolTip.Length <= maxTooltipWidth - ? toolTip - : toolTip.Substring(0, maxTooltipWidth); - cb.Append(toolTip); - - // Make sure we always write out exactly 1 buffer width - spacesNeeded = (bufferWidth * (index + 1)) - cb.Length; - if (spacesNeeded > 0) - { - cb.Append(' ', spacesNeeded); - } - } - menuColumnWidth = bufferWidth; - } - else - { - var screenColumns = bufferWidth; - var displayColumns = Math.Max(1, screenColumns / minColWidth); - displayRows = (completions.CompletionMatches.Count + displayColumns - 1) / displayColumns; - cb = new ConsoleBufferBuilder(displayRows * bufferWidth, _console); - for (var row = 0; row < displayRows; row++) - { - for (var col = 0; col < displayColumns; col++) - { - var index = row + (displayRows * col); - if (index >= matches.Count) - break; - var match = matches[index]; - var item = HandleNewlinesForPossibleCompletions(match.ListItemText); - cb.Append(item); - cb.Append(' ', minColWidth - item.Length); - } - - // Make sure we always write out exactly 1 buffer width - var spacesNeeded = (bufferWidth * (row + 1)) - cb.Length; - if (spacesNeeded > 0) - { - cb.Append(' ', spacesNeeded); - } - } - } - - var menuBuffer = cb.ToArray(); - - if (menuSelect) - { - // Make sure the menu and line can appear on the screen at the same time, - // if not, we'll skip the menu. - - var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length); - var bufferLines = endBufferCoords.Y - _initialY + 1; - if ((bufferLines + displayRows) > _console.WindowHeight) - { - menuSelect = false; - } - } - - if (menuSelect) - { - RemoveEditsAfterUndo(); - var undoPoint = _edits.Count; - - int selectedItem = 0; - bool undo = false; - - DoReplacementForCompletion(matches[0], completions); - - // Recompute end of buffer coordinates as the replacement could have - // added a line. - var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length); - var menuAreaTop = endBufferCoords.Y + 1; - var previousMenuTop = menuAreaTop; - - InvertSelectedCompletion(menuBuffer, selectedItem, menuColumnWidth, displayRows); - _console.WriteBufferLines(menuBuffer, ref menuAreaTop); - - // Showing the menu may have scrolled the screen or moved the cursor, update initialY to reflect that. - _initialY -= (previousMenuTop - menuAreaTop); - PlaceCursor(); - previousMenuTop = menuAreaTop; - - int previousItem = selectedItem; - - bool processingKeys = true; - while (processingKeys) - { - var nextKey = ReadKey(); - if (nextKey == Keys.RightArrow) - { - selectedItem = Math.Min(selectedItem + displayRows, matches.Count - 1); - } - else if (nextKey == Keys.LeftArrow) - { - selectedItem = Math.Max(selectedItem - displayRows, 0); - } - else if (nextKey == Keys.DownArrow) - { - selectedItem = Math.Min(selectedItem + 1, matches.Count - 1); - } - else if (nextKey == Keys.UpArrow) - { - selectedItem = Math.Max(selectedItem - 1, 0); - } - else if (nextKey == Keys.Tab) - { - selectedItem = (selectedItem + 1) % matches.Count; - } - else if (nextKey == Keys.ShiftTab) - { - selectedItem = (selectedItem - 1) % matches.Count; - if (selectedItem < 0) - { - selectedItem += matches.Count; - } - } - else if (nextKey == Keys.CtrlG || nextKey == Keys.Escape) - { - undo = true; - processingKeys = false; - } - else - { - PrependQueuedKeys(nextKey); - processingKeys = false; - } - - if (selectedItem != previousItem) - { - DoReplacementForCompletion(matches[selectedItem], completions); - - endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length); - menuAreaTop = endBufferCoords.Y + 1; - - InvertSelectedCompletion(menuBuffer, previousItem, menuColumnWidth, displayRows); - InvertSelectedCompletion(menuBuffer, selectedItem, menuColumnWidth, displayRows); - _console.WriteBufferLines(menuBuffer, ref menuAreaTop); - previousItem = selectedItem; - - if (previousMenuTop > menuAreaTop) - { - WriteBlankLines(previousMenuTop - menuAreaTop, menuAreaTop + displayRows); - } - } - } - - WriteBlankLines(displayRows, menuAreaTop); - - var lastInsert = ((GroupedEdit)_edits[_edits.Count - 1])._groupedEditItems[1]; - Debug.Assert(lastInsert is EditItemInsertString, "The only edits possible here are pairs of Delete/Insert"); - var firstDelete = ((GroupedEdit)_edits[undoPoint])._groupedEditItems[0]; - Debug.Assert(firstDelete is EditItemDelete, "The only edits possible here are pairs of Delete/Insert"); - - var groupEditCount = _edits.Count - undoPoint; - _edits.RemoveRange(undoPoint, groupEditCount); - _undoEditIndex = undoPoint; - - if (undo) - { - // Pretend it never happened. - lastInsert.Undo(); - firstDelete.Undo(); - Render(); - } - else - { - // Leave one edit instead of possibly many to undo - SaveEditItem(GroupedEdit.Create(new List { firstDelete, lastInsert })); - } - } - else - { - var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length); - var menuAreaTop = endBufferCoords.Y + 1; - - _console.WriteBufferLines(menuBuffer, ref menuAreaTop); - _initialY = menuAreaTop + displayRows; - Render(); - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Completion.vi.cs b/src/Microsoft.PowerShell.PSReadLine/Completion.vi.cs deleted file mode 100644 index 2e5eb7458deb..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Completion.vi.cs +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Runspaces; -using System.Text; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - /// - /// Ends the current edit group, if needed, and invokes TabCompleteNext. - /// - public static void ViTabCompleteNext(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._editGroupStart >= 0) - { - _singleton._groupUndoHelper.EndGroup(); - } - TabCompleteNext(key, arg); - } - - /// - /// Ends the current edit group, if needed, and invokes TabCompletePrevious. - /// - public static void ViTabCompletePrevious(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._editGroupStart >= 0) - { - _singleton._groupUndoHelper.EndGroup(); - } - TabCompletePrevious(key, arg); - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/ConsoleBufferBuilder.cs b/src/Microsoft.PowerShell.PSReadLine/ConsoleBufferBuilder.cs deleted file mode 100644 index df5244c4f811..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/ConsoleBufferBuilder.cs +++ /dev/null @@ -1,59 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - internal class ConsoleBufferBuilder - { - private List buffer; - private IConsole _console; - - public ConsoleBufferBuilder(int capacity, IConsole console) - { - buffer = new List(capacity); - _console = console; - } - - BufferChar NewCharInfo(char c) - { - return new BufferChar - { - UnicodeChar = c, - BackgroundColor = _console.BackgroundColor, - ForegroundColor = _console.ForegroundColor - }; - } - - public void Append(string s) - { - foreach (char c in s) - { - buffer.Add(NewCharInfo(c)); - } - } - - public void Append(char c, int count) - { - while (count-- > 0) - { - buffer.Add(NewCharInfo(c)); - } - } - - public BufferChar[] ToArray() - { - return buffer.ToArray(); - } - - public int Length - { - get { return buffer.Count; } - } - } -} - diff --git a/src/Microsoft.PowerShell.PSReadLine/ConsoleKeyChordConverter.cs b/src/Microsoft.PowerShell.PSReadLine/ConsoleKeyChordConverter.cs deleted file mode 100644 index 1af6c7aecf42..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/ConsoleKeyChordConverter.cs +++ /dev/null @@ -1,341 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Runtime.InteropServices; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - /// - /// A helper class for converting strings to ConsoleKey chords. - /// - public static class ConsoleKeyChordConverter - { - /// - /// Converts a string to a sequence of ConsoleKeyInfo. - /// Sequences are separated by ','. Modifiers - /// appear before the modified key and are separated by '+'. - /// Examples: - /// Ctrl+X - /// Ctrl+D,M - /// Escape,X - /// - public static ConsoleKeyInfo[] Convert(string chord) - { - if (string.IsNullOrEmpty(chord)) - { - throw new ArgumentNullException("chord"); - } - - var tokens = chord.Split(new[] {','}); - - if (tokens.Length > 2) - { - throw new ArgumentException(PSReadLineResources.ChordWithTooManyKeys); - } - - var result = new ConsoleKeyInfo[tokens.Length]; - for (int i = 0; i < tokens.Length; i++) - { - result[i] = ConvertOneSequence(tokens[i]); - } - - return result; - } - - private static ConsoleKeyInfo ConvertOneSequence(string sequence) - { - Stack tokens = null; - ConsoleModifiers modifiers = 0; - ConsoleKey key = 0; - char keyChar = '\u0000'; - - bool valid = !String.IsNullOrEmpty(sequence); - - if (valid) - { - tokens = new Stack( - (sequence.Split(new[] {'+'}) - .Select( - part => part.ToLowerInvariant().Trim()))); - } - - while (valid && tokens.Count > 0) - { - string token = tokens.Pop(); - - // sequence was something silly like "shift++" - if (token == String.Empty) - { - valid = false; - break; - } - - // key should be first token to be popped - if (key == 0) - { - // the keyChar is this token, if not a special key like "Fxx" etc. - if (token.Length == 1) - { - keyChar = token[0]; - } - - // Enum.TryParse accepts arbitrary integers. We shouldn't, - // but single digits need to map to the correct key, e.g. - // ConsoleKey.D1 - long tokenAsLong; - if (long.TryParse(token, out tokenAsLong)) - { - if (tokenAsLong >= 0 && tokenAsLong <= 9) - { - token = "D" + token; - } - else - { - throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.UnrecognizedKey, token)); - } - } - // try simple parse for ConsoleKey enum name - valid = Enum.TryParse(token, ignoreCase: true, result: out key); - - // doesn't map to ConsoleKey so convert to virtual key from char - if (!valid && token.Length == 1) - { - string failReason; - valid = TryParseCharLiteral(token[0], ref modifiers, ref key, out failReason); - - if (!valid) - { - throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.CantTranslateKey, token[0], failReason)); - } - } - - if (!valid) - { - throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.UnrecognizedKey, token)); - } - } - else - { - // now, parse modifier(s) - ConsoleModifiers modifier; - - // courtesy translation - if (token == "ctrl") - { - token = "control"; - } - - if (Enum.TryParse(token, ignoreCase: true, result: out modifier)) - { - // modifier already set? - if ((modifiers & modifier) != 0) - { - // either found duplicate modifier token or shift state - // was already implied from char, e.g. char is "}", which is "shift+]" - throw new ArgumentException( - String.Format(CultureInfo.CurrentCulture, PSReadLineResources.InvalidModifier, modifier, key)); - } - modifiers |= modifier; - } - else - { - throw new ArgumentException( - String.Format(CultureInfo.CurrentCulture, PSReadLineResources.InvalidModifier, token, key)); - } - } - } - - if (!valid) - { - throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.InvalidSequence, sequence)); - } - - return new ConsoleKeyInfo(keyChar, key, - shift: ((modifiers & ConsoleModifiers.Shift) != 0), - alt: ((modifiers & ConsoleModifiers.Alt) != 0), - control: ((modifiers & ConsoleModifiers.Control) != 0)); - } - - private static bool TryParseCharLiteral(char literal, ref ConsoleModifiers modifiers, ref ConsoleKey key, out string failReason) - { - bool valid = false; - -#if UNIX - bool isShift; - bool isCtrl; - key = GetKeyFromCharValue(literal, out isShift, out isCtrl); - - // Failure to get a key for the char just means that the key is not - // special (in the ConsoleKey enum), so we return a default key. - // Thus this never fails. - valid = true; - failReason = null; - - if (isShift) - { - modifiers |= ConsoleModifiers.Shift; - } - if (isCtrl) - { - modifiers |= ConsoleModifiers.Control; - } - // alt is not possible to get -#else - // shift state will be in MSB - short virtualKey = NativeMethods.VkKeyScan(literal); - int hresult = Marshal.GetLastWin32Error(); - - if (virtualKey != 0) - { - // e.g. "}" = 0x01dd but "]" is 0x00dd, ergo } = shift+]. - // shift = 1, control = 2, alt = 4, hankaku = 8 (ignored) - int state = virtualKey >> 8; - - if ((state & 1) == 1) - { - modifiers |= ConsoleModifiers.Shift; - } - if ((state & 2) == 2) - { - modifiers |= ConsoleModifiers.Control; - } - if ((state & 4) == 4) - { - modifiers |= ConsoleModifiers.Alt; - } - - virtualKey &= 0xff; - - if (Enum.IsDefined(typeof (ConsoleKey), (int) virtualKey)) - { - failReason = null; - key = (ConsoleKey) virtualKey; - valid = true; - } - else - { - // haven't seen this happen yet, but possible - failReason = String.Format(CultureInfo.CurrentCulture, PSReadLineResources.UnrecognizedKey, virtualKey); - } - } - else - { - Exception e = Marshal.GetExceptionForHR(hresult); - failReason = e.Message; - } -#endif - - return valid; - } - - // this is borrowed from the CoreFX internal System.IO.StdInReader class - // https://github.com/dotnet/corefx/blob/5b2ae6aa485773cd5569f56f446698633c9ad945/src/System.Console/src/System/IO/StdInReader.cs#L222 - private static ConsoleKey GetKeyFromCharValue(char x, out bool isShift, out bool isCtrl) - { - isShift = false; - isCtrl = false; - - switch (x) - { - case '\b': - return ConsoleKey.Backspace; - - case '\t': - return ConsoleKey.Tab; - - case '\n': - return ConsoleKey.Enter; - - case (char)(0x1B): - return ConsoleKey.Escape; - - case '*': - return ConsoleKey.Multiply; - - case '+': - return ConsoleKey.Add; - - case '-': - return ConsoleKey.Subtract; - - case '/': - return ConsoleKey.Divide; - - case (char)(0x7F): - return ConsoleKey.Delete; - - case ' ': - return ConsoleKey.Spacebar; - - default: - // 1. Ctrl A to Ctrl Z. - if (x >= 1 && x <= 26) - { - isCtrl = true; - return ConsoleKey.A + x - 1; - } - - // 2. Numbers from 0 to 9. - if (x >= '0' && x <= '9') - { - return ConsoleKey.D0 + x - '0'; - } - - //3. A to Z - if (x >= 'A' && x <= 'Z') - { - isShift = true; - return ConsoleKey.A + (x - 'A'); - } - - // 4. a to z. - if (x >= 'a' && x <= 'z') - { - return ConsoleKey.A + (x - 'a'); - } - - break; - } - - return default(ConsoleKey); - } - -#if !UNIX - internal static char GetCharFromConsoleKey(ConsoleKey key, ConsoleModifiers modifiers) - { - // default for unprintables and unhandled - char keyChar = '\u0000'; - - // emulate GetKeyboardState bitmap - set high order bit for relevant modifier virtual keys - var state = new byte[256]; - state[NativeMethods.VK_SHIFT] = (byte)(((modifiers & ConsoleModifiers.Shift) != 0) ? 0x80 : 0); - state[NativeMethods.VK_CONTROL] = (byte)(((modifiers & ConsoleModifiers.Control) != 0) ? 0x80 : 0); - state[NativeMethods.VK_ALT] = (byte)(((modifiers & ConsoleModifiers.Alt) != 0) ? 0x80 : 0); - - // a ConsoleKey enum's value is a virtual key code - uint virtualKey = (uint)key; - - // get corresponding scan code - uint scanCode = NativeMethods.MapVirtualKey(virtualKey, NativeMethods.MAPVK_VK_TO_VSC); - - // get corresponding character - may be 0, 1 or 2 in length (diacritics) - var chars = new char[2]; - int charCount = NativeMethods.ToUnicode( - virtualKey, scanCode, state, chars, chars.Length, NativeMethods.MENU_IS_INACTIVE); - - // TODO: support diacritics (charCount == 2) - if (charCount == 1) - { - keyChar = chars[0]; - } - return keyChar; - } -#endif - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/ConsoleLib.cs b/src/Microsoft.PowerShell.PSReadLine/ConsoleLib.cs deleted file mode 100644 index 177f0779fa78..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/ConsoleLib.cs +++ /dev/null @@ -1,1143 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Text; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.PowerShell.Internal -{ -#pragma warning disable 1591 - - internal static class NativeMethods - { - public const uint MAPVK_VK_TO_VSC = 0x00; - public const uint MAPVK_VSC_TO_VK = 0x01; - public const uint MAPVK_VK_TO_CHAR = 0x02; - - public const byte VK_SHIFT = 0x10; - public const byte VK_CONTROL = 0x11; - public const byte VK_ALT = 0x12; - public const uint MENU_IS_ACTIVE = 0x01; - public const uint MENU_IS_INACTIVE = 0x00; // windows key - - public const uint ENABLE_PROCESSED_INPUT = 0x0001; - public const uint ENABLE_LINE_INPUT = 0x0002; - public const uint ENABLE_WINDOW_INPUT = 0x0008; - public const uint ENABLE_MOUSE_INPUT = 0x0010; - - public const int FontTypeMask = 0x06; - public const int TrueTypeFont = 0x04; - - internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // WinBase.h - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr GetStdHandle(uint handleId); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool GetConsoleMode(IntPtr hConsoleOutput, out uint dwMode); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool SetConsoleMode(IntPtr hConsoleOutput, uint dwMode); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool ScrollConsoleScreenBuffer(IntPtr hConsoleOutput, - ref SMALL_RECT lpScrollRectangle, - IntPtr lpClipRectangle, - COORD dwDestinationOrigin, - ref CHAR_INFO lpFill); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool WriteConsole(IntPtr hConsoleOutput, string lpBuffer, uint nNumberOfCharsToWrite, out uint lpNumberOfCharsWritten, IntPtr lpReserved); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool SetConsoleCtrlHandler(BreakHandler handlerRoutine, bool add); - - [DllImport("KERNEL32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool WriteConsoleOutput(IntPtr consoleOutput, CHAR_INFO[] buffer, COORD bufferSize, COORD bufferCoord, ref SMALL_RECT writeRegion); - - [DllImport("KERNEL32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool ReadConsoleOutput(IntPtr consoleOutput, [Out] CHAR_INFO[] buffer, COORD bufferSize, COORD bufferCoord, ref SMALL_RECT readRegion); - - [DllImport("user32.dll", SetLastError = true)] - public static extern uint MapVirtualKey(uint uCode, uint uMapType); - - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern int ToUnicode(uint uVirtKey, uint uScanCode, byte[] lpKeyState, - [MarshalAs(UnmanagedType.LPArray)] [Out] char[] chars, int charMaxCount, uint flags); - - [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern short VkKeyScan(char @char); - - [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - public static extern uint GetConsoleOutputCP(); - - [DllImport("User32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetConsoleWindow(); - - [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetDC(IntPtr hwnd); - - [DllImport("GDI32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool TranslateCharsetInfo(IntPtr src, out CHARSETINFO Cs, uint options); - - [DllImport("GDI32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool GetTextMetrics(IntPtr hdc, out TEXTMETRIC tm); - - [DllImport("GDI32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool GetCharWidth32(IntPtr hdc, uint first, uint last, out int width); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr CreateFile - ( - string fileName, - uint desiredAccess, - uint ShareModes, - IntPtr securityAttributes, - uint creationDisposition, - uint flagsAndAttributes, - IntPtr templateFileWin32Handle - ); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern bool GetCurrentConsoleFontEx(IntPtr consoleOutput, bool bMaximumWindow, ref CONSOLE_FONT_INFO_EX consoleFontInfo); - - [StructLayout(LayoutKind.Sequential)] - internal struct COLORREF - { - internal uint ColorDWORD; - - internal uint R - { - get { return ColorDWORD & 0xff; } - } - - internal uint G - { - get { return (ColorDWORD >> 8) & 0xff; } - } - - internal uint B - { - get { return (ColorDWORD >> 16) & 0xff; } - } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct CONSOLE_SCREEN_BUFFER_INFO_EX - { - internal int cbSize; - internal COORD dwSize; - internal COORD dwCursorPosition; - internal ushort wAttributes; - internal SMALL_RECT srWindow; - internal COORD dwMaximumWindowSize; - internal ushort wPopupAttributes; - internal bool bFullscreenSupported; - internal COLORREF Black; - internal COLORREF DarkBlue; - internal COLORREF DarkGreen; - internal COLORREF DarkCyan; - internal COLORREF DarkRed; - internal COLORREF DarkMagenta; - internal COLORREF DarkYellow; - internal COLORREF Gray; - internal COLORREF DarkGray; - internal COLORREF Blue; - internal COLORREF Green; - internal COLORREF Cyan; - internal COLORREF Red; - internal COLORREF Magenta; - internal COLORREF Yellow; - internal COLORREF White; - } - - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool GetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, - ref CONSOLE_SCREEN_BUFFER_INFO_EX csbe); - - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool SetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, - ref CONSOLE_SCREEN_BUFFER_INFO_EX csbe); - } - - public delegate bool BreakHandler(ConsoleBreakSignal ConsoleBreakSignal); - - public enum ConsoleBreakSignal : uint - { - CtrlC = 0, - CtrlBreak = 1, - Close = 2, - Logoff = 5, - Shutdown = 6, - None = 255, - } - - internal enum CHAR_INFO_Attributes : ushort - { - COMMON_LVB_LEADING_BYTE = 0x0100, - COMMON_LVB_TRAILING_BYTE = 0x0200 - } - - public enum StandardHandleId : uint - { - Error = unchecked((uint)-12), - Output = unchecked((uint)-11), - Input = unchecked((uint)-10), - } - - [Flags] - internal enum AccessQualifiers : uint - { - // From winnt.h - GenericRead = 0x80000000, - GenericWrite = 0x40000000 - } - - internal enum CreationDisposition : uint - { - // From winbase.h - CreateNew = 1, - CreateAlways = 2, - OpenExisting = 3, - OpenAlways = 4, - TruncateExisting = 5 - } - - [Flags] - internal enum ShareModes : uint - { - // From winnt.h - ShareRead = 0x00000001, - ShareWrite = 0x00000002 - } - - public struct SMALL_RECT - { - public short Left; - public short Top; - public short Right; - public short Bottom; - - [ExcludeFromCodeCoverage] - public override string ToString() - { - return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", Left, Top, Right, Bottom); - } - } - - internal struct COORD - { - public short X; - public short Y; - - [ExcludeFromCodeCoverage] - public override string ToString() - { - return String.Format(CultureInfo.InvariantCulture, "{0},{1}", X, Y); - } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct FONTSIGNATURE - { - //From public\sdk\inc\wingdi.h - - // fsUsb*: A 128-bit Unicode subset bitfield (USB) identifying up to 126 Unicode subranges - internal uint fsUsb0; - internal uint fsUsb1; - internal uint fsUsb2; - internal uint fsUsb3; - // fsCsb*: A 64-bit, code-page bitfield (CPB) that identifies a specific character set or code page. - internal uint fsCsb0; - internal uint fsCsb1; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct CHARSETINFO - { - //From public\sdk\inc\wingdi.h - internal uint ciCharset; // Character set value. - internal uint ciACP; // ANSI code-page identifier. - internal FONTSIGNATURE fs; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct TEXTMETRIC - { - //From public\sdk\inc\wingdi.h - public int tmHeight; - public int tmAscent; - public int tmDescent; - public int tmInternalLeading; - public int tmExternalLeading; - public int tmAveCharWidth; - public int tmMaxCharWidth; - public int tmWeight; - public int tmOverhang; - public int tmDigitizedAspectX; - public int tmDigitizedAspectY; - public char tmFirstChar; - public char tmLastChar; - public char tmDefaultChar; - public char tmBreakChar; - public byte tmItalic; - public byte tmUnderlined; - public byte tmStruckOut; - public byte tmPitchAndFamily; - public byte tmCharSet; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct CONSOLE_FONT_INFO_EX - { - internal int cbSize; - internal int nFont; - internal short FontWidth; - internal short FontHeight; - internal int FontFamily; - internal int FontWeight; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - internal string FontFace; - } - - public struct BufferChar - { - public char UnicodeChar; - public ConsoleColor ForegroundColor; - public ConsoleColor BackgroundColor; -#if !UNIX - public bool IsLeadByte; - public bool IsTrailByte; -#endif - public bool Inverse; - -#if !UNIX - public CHAR_INFO ToCharInfo() - { - int fg = (int) ForegroundColor; - int bg = (int) BackgroundColor; - - if (fg < 0 || fg > 0xf || bg < 0 || bg > 0xf) - throw new InvalidOperationException(); - - if (Inverse) - { - // TODO: check $host.UI.SupportsVirtualTerminal and maybe set Inverse instead (it does look weird) - fg = fg ^ 7; - bg = bg ^ 7; - } - ushort attrs = (ushort)(fg | (bg << 4)); - if (IsLeadByte) - attrs |= (ushort)CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE; - if (IsTrailByte) - attrs |= (ushort)CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE; - CHAR_INFO result = new CHAR_INFO - { - UnicodeChar = UnicodeChar, - Attributes = attrs, - }; - - return result; - } - - public static BufferChar FromCharInfo(CHAR_INFO charInfo) - { - BufferChar result = new BufferChar - { - UnicodeChar = (char) charInfo.UnicodeChar, - ForegroundColor = (ConsoleColor)(charInfo.Attributes & 0xf), - BackgroundColor = (ConsoleColor)((charInfo.Attributes & 0x00f0) >> 4), - }; - return result; - } -#endif - } - - public struct CHAR_INFO - { - public ushort UnicodeChar; - public ushort Attributes; - } - - internal static class ConsoleKeyInfoExtension - { -#if !UNIX - private static bool _toUnicodeApiAvailable = true; - - static ConsoleKeyInfoExtension() - { - try - { - var chars = new char[2]; - NativeMethods.ToUnicode(13, 28, null, chars, chars.Length, 0); - } - catch (System.EntryPointNotFoundException) - { - _toUnicodeApiAvailable = false; // api not available on NanoServer - } - } -#endif - - public static string ToGestureString(this ConsoleKeyInfo key) - { - var mods = key.Modifiers; - - var sb = new StringBuilder(); - if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) - { - sb.Append("Ctrl"); - } - if (key.Modifiers.HasFlag(ConsoleModifiers.Alt)) - { - if (sb.Length > 0) - sb.Append("+"); - sb.Append("Alt"); - } - - char c = key.KeyChar; -#if !UNIX - if (_toUnicodeApiAvailable) - { - // Windows cannot use KeyChar as some chords (like Ctrl+[) show up as control characters. - c = ConsoleKeyChordConverter.GetCharFromConsoleKey(key.Key, - (mods & ConsoleModifiers.Shift) != 0 ? ConsoleModifiers.Shift : 0); - } -#endif - - if (char.IsControl(c) || char.IsWhiteSpace(c)) - { - if (key.Modifiers.HasFlag(ConsoleModifiers.Shift)) - { - if (sb.Length > 0) - sb.Append("+"); - sb.Append("Shift"); - } - if (sb.Length > 0) - sb.Append("+"); - sb.Append(key.Key); - } - else - { - if (sb.Length > 0) - sb.Append("+"); - sb.Append(c); - } - return sb.ToString(); - } - } - -#if !UNIX - internal class ConhostConsole : IConsole - { - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - private IntPtr _hwnd = (IntPtr)0; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - private IntPtr _hDC = (IntPtr)0; - private uint _codePage; - private bool _istmInitialized = false; - private TEXTMETRIC _tm = new TEXTMETRIC(); - private bool _trueTypeInUse = false; - private static bool _getCurrentConsoleFontExApiAvailable = true; - - private readonly Lazy _outputHandle = new Lazy(() => - { - // We use CreateFile here instead of GetStdWin32Handle, as GetStdWin32Handle will return redirected handles - var handle = NativeMethods.CreateFile( - "CONOUT$", - (UInt32)(AccessQualifiers.GenericRead | AccessQualifiers.GenericWrite), - (UInt32)ShareModes.ShareWrite, - (IntPtr)0, - (UInt32)CreationDisposition.OpenExisting, - 0, - (IntPtr)0); - - if (handle == NativeMethods.INVALID_HANDLE_VALUE) - { - int err = Marshal.GetLastWin32Error(); - Win32Exception innerException = new Win32Exception(err); - throw new Exception("Failed to retrieve the input console handle.", innerException); - } - - return new SafeFileHandle(handle, true); - } - ); - - private readonly Lazy _inputHandle = new Lazy(() => - { - // We use CreateFile here instead of GetStdWin32Handle, as GetStdWin32Handle will return redirected handles - var handle = NativeMethods.CreateFile( - "CONIN$", - (UInt32)(AccessQualifiers.GenericRead | AccessQualifiers.GenericWrite), - (UInt32)ShareModes.ShareWrite, - (IntPtr)0, - (UInt32)CreationDisposition.OpenExisting, - 0, - (IntPtr)0); - - if (handle == NativeMethods.INVALID_HANDLE_VALUE) - { - int err = Marshal.GetLastWin32Error(); - Win32Exception innerException = new Win32Exception(err); - throw new Exception("Failed to retrieve the input console handle.", innerException); - } - - return new SafeFileHandle(handle, true); - }); - - public object GetConsoleInputMode() - { - uint mode; - var handle = _inputHandle.Value.DangerousGetHandle(); - NativeMethods.GetConsoleMode(handle, out mode); - return mode; - } - - public void SetConsoleInputMode(object modeObj) - { - if (modeObj is uint) - { - // Clear a couple flags so we can actually receive certain keys: - // ENABLE_PROCESSED_INPUT - enables Ctrl+C - // ENABLE_LINE_INPUT - enables Ctrl+S - // Also clear a couple flags so we don't mask the input that we ignore: - // ENABLE_MOUSE_INPUT - mouse events - // ENABLE_WINDOW_INPUT - window resize events - var mode = (uint)modeObj & - ~(NativeMethods.ENABLE_PROCESSED_INPUT | - NativeMethods.ENABLE_LINE_INPUT | - NativeMethods.ENABLE_WINDOW_INPUT | - NativeMethods.ENABLE_MOUSE_INPUT); - - var handle = _inputHandle.Value.DangerousGetHandle(); - NativeMethods.SetConsoleMode(handle, mode); - } - } - - public void RestoreConsoleInputMode(object modeObj) - { - if (modeObj is uint) - { - var handle = _inputHandle.Value.DangerousGetHandle(); - NativeMethods.SetConsoleMode(handle, (uint)modeObj); - } - } - - public ConsoleKeyInfo ReadKey() - { - return Console.ReadKey(true); - } - - public bool KeyAvailable - { - get { return Console.KeyAvailable; } - } - - public int CursorLeft - { - get { return Console.CursorLeft; } - set { Console.CursorLeft = value; } - } - - public int CursorTop - { - get { return Console.CursorTop; } - set { Console.CursorTop = value; } - } - - public int CursorSize - { - get { return Console.CursorSize; } - set { Console.CursorSize = value; } - } - - public int BufferWidth - { - get { return Console.BufferWidth; } - set { Console.BufferWidth = value; } - } - - public int BufferHeight - { - get { return Console.BufferHeight; } - set { Console.BufferHeight = value; } - } - - public int WindowWidth - { - get { return Console.WindowWidth; } - set { Console.WindowWidth = value; } - } - - public int WindowHeight - { - get { return Console.WindowHeight; } - set { Console.WindowHeight = value; } - } - - public int WindowTop - { - get { return Console.WindowTop; } - set { Console.WindowTop = value; } - } - - public ConsoleColor BackgroundColor - { - get { return Console.BackgroundColor; } - set { Console.BackgroundColor = value; } - } - - public ConsoleColor ForegroundColor - { - get { return Console.ForegroundColor; } - set { Console.ForegroundColor = value; } - } - - public void SetWindowPosition(int left, int top) - { - Console.SetWindowPosition(left, top); - } - - public void SetCursorPosition(int left, int top) - { - Console.SetCursorPosition(left, top); - } - - public void Write(string value) - { - Console.Write(value); - } - - public void WriteLine(string value) - { - Console.WriteLine(value); - } - - public void WriteBufferLines(BufferChar[] buffer, ref int top) - { - WriteBufferLines(buffer, ref top, true); - } - - public void WriteBufferLines(BufferChar[] buffer, ref int top, bool ensureBottomLineVisible) - { - int bufferWidth = Console.BufferWidth; - int bufferLineCount = buffer.Length / bufferWidth; - if ((top + bufferLineCount) > Console.BufferHeight) - { - var scrollCount = (top + bufferLineCount) - Console.BufferHeight; - ScrollBuffer(scrollCount); - top -= scrollCount; - } - - var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output); - var bufferSize = new COORD - { - X = (short) bufferWidth, - Y = (short) bufferLineCount - }; - var bufferCoord = new COORD {X = 0, Y = 0}; - var bottom = top + bufferLineCount - 1; - var writeRegion = new SMALL_RECT - { - Top = (short) top, - Left = 0, - Bottom = (short) bottom, - Right = (short) (bufferWidth - 1) - }; - NativeMethods.WriteConsoleOutput(handle, ToCharInfoBuffer(buffer), - bufferSize, bufferCoord, ref writeRegion); - - // Now make sure the bottom line is visible - if (ensureBottomLineVisible && - (bottom >= (Console.WindowTop + Console.WindowHeight))) - { - Console.CursorTop = bottom; - } - } - - public void ScrollBuffer(int lines) - { - var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output); - - var scrollRectangle = new SMALL_RECT - { - Top = (short) lines, - Left = 0, - Bottom = (short)(Console.BufferHeight - 1), - Right = (short)Console.BufferWidth - }; - var destinationOrigin = new COORD {X = 0, Y = 0}; - var fillChar = new CHAR_INFO - { - UnicodeChar = ' ', - Attributes = (ushort)((int)Console.ForegroundColor | ((int)Console.BackgroundColor << 4)) - }; - NativeMethods.ScrollConsoleScreenBuffer(handle, ref scrollRectangle, IntPtr.Zero, destinationOrigin, ref fillChar); - } - - public BufferChar[] ReadBufferLines(int top, int count) - { - var result = new CHAR_INFO[BufferWidth * count]; - var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output); - - var readBufferSize = new COORD { - X = (short)BufferWidth, - Y = (short)count}; - var readBufferCoord = new COORD {X = 0, Y = 0}; - var readRegion = new SMALL_RECT - { - Top = (short)top, - Left = 0, - Bottom = (short)(top + count), - Right = (short)(BufferWidth - 1) - }; - NativeMethods.ReadConsoleOutput(handle, result, - readBufferSize, readBufferCoord, ref readRegion); - - return ToBufferCharBuffer(result); - } - - [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", - Justification = "Then the API we pass the handle to will return an error if it is invalid. They are not exposed.")] - internal static CONSOLE_FONT_INFO_EX GetConsoleFontInfo(SafeFileHandle consoleHandle) - { - - CONSOLE_FONT_INFO_EX fontInfo = new CONSOLE_FONT_INFO_EX(); - fontInfo.cbSize = Marshal.SizeOf(fontInfo); - bool result = true; - if (_getCurrentConsoleFontExApiAvailable) - { - try - { - result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo); - } - catch (System.EntryPointNotFoundException) - { - _getCurrentConsoleFontExApiAvailable = false; // api not available on NanoServer - } - } - - if (result == false) - { - _getCurrentConsoleFontExApiAvailable = false; // api not supported on ServerCore - } - return fontInfo; - } - - public int LengthInBufferCells(char c) - { - if (!IsCJKOutputCodePage() || !_trueTypeInUse) - return 1; - - return LengthInBufferCellsFE(c); - } - - internal static bool IsAnyDBCSCharSet(uint charSet) - { - const uint SHIFTJIS_CHARSET = 128; - const uint HANGUL_CHARSET = 129; - const uint CHINESEBIG5_CHARSET = 136; - const uint GB2312_CHARSET = 134; - return charSet == SHIFTJIS_CHARSET || charSet == HANGUL_CHARSET || - charSet == CHINESEBIG5_CHARSET || charSet == GB2312_CHARSET; - } - - internal uint CodePageToCharSet() - { - CHARSETINFO csi; - const uint TCI_SRCCODEPAGE = 2; - const uint OEM_CHARSET = 255; - if (!NativeMethods.TranslateCharsetInfo((IntPtr)_codePage, out csi, TCI_SRCCODEPAGE)) - { - csi.ciCharset = OEM_CHARSET; - } - return csi.ciCharset; - } - - /// - /// Check if the output buffer code page is Japanese, Simplified Chinese, Korean, or Traditional Chinese - /// - /// true if it is CJK code page; otherwise, false. - internal bool IsCJKOutputCodePage() - { - return _codePage == 932 || // Japanese - _codePage == 936 || // Simplified Chinese - _codePage == 949 || // Korean - _codePage == 950; // Traditional Chinese - } - - internal bool IsAvailableFarEastCodePage() - { - uint charSet = CodePageToCharSet(); - return IsAnyDBCSCharSet(charSet); - } - - internal int LengthInBufferCellsFE(char c) - { - if (0x20 <= c && c <= 0x7e) - { - /* ASCII */ - return 1; - } - else if (0x3041 <= c && c <= 0x3094) - { - /* Hiragana */ - return 2; - } - else if (0x30a1 <= c && c <= 0x30f6) - { - /* Katakana */ - return 2; - } - else if (0x3105 <= c && c <= 0x312c) - { - /* Bopomofo */ - return 2; - } - else if (0x3131 <= c && c <= 0x318e) - { - /* Hangul Elements */ - return 2; - } - else if (0xac00 <= c && c <= 0xd7a3) - { - /* Korean Hangul Syllables */ - return 2; - } - else if (0xff01 <= c && c <= 0xff5e) - { - /* Fullwidth ASCII variants */ - return 2; - } - else if (0xff61 <= c && c <= 0xff9f) - { - /* Halfwidth Katakana variants */ - return 1; - } - else if ((0xffa0 <= c && c <= 0xffbe) || - (0xffc2 <= c && c <= 0xffc7) || - (0xffca <= c && c <= 0xffcf) || - (0xffd2 <= c && c <= 0xffd7) || - (0xffda <= c && c <= 0xffdc)) - { - /* Halfwidth Hangul variants */ - return 1; - } - else if (0xffe0 <= c && c <= 0xffe6) - { - /* Fullwidth symbol variants */ - return 2; - } - else if (0x4e00 <= c && c <= 0x9fa5) - { - /* Han Ideographic */ - return 2; - } - else if (0xf900 <= c && c <= 0xfa2d) - { - /* Han Compatibility Ideographs */ - return 2; - } - else - { - /* Unknown character: need to use GDI*/ - if (_hDC == (IntPtr)0) - { - _hwnd = NativeMethods.GetConsoleWindow(); - if ((IntPtr)0 == _hwnd) - { - return 1; - } - _hDC = NativeMethods.GetDC(_hwnd); - if ((IntPtr)0 == _hDC) - { - //Don't throw exception so that output can continue - return 1; - } - } - bool result = true; - if (!_istmInitialized) - { - result = NativeMethods.GetTextMetrics(_hDC, out _tm); - if (!result) - { - return 1; - } - _istmInitialized = true; - } - int width; - result = NativeMethods.GetCharWidth32(_hDC, (uint)c, (uint)c, out width); - if (!result) - { - return 1; - } - if (width >= _tm.tmMaxCharWidth) - { - return 2; - } - } - return 1; - } - - public void StartRender() - { - _codePage = NativeMethods.GetConsoleOutputCP(); - _istmInitialized = false; - var consoleHandle = _outputHandle.Value; - CONSOLE_FONT_INFO_EX fontInfo = ConhostConsole.GetConsoleFontInfo(consoleHandle); - int fontType = fontInfo.FontFamily & NativeMethods.FontTypeMask; - _trueTypeInUse = (fontType & NativeMethods.TrueTypeFont) == NativeMethods.TrueTypeFont; - } - - public void EndRender() - { - if (_hwnd != (IntPtr)0 && _hDC != (IntPtr)0) - { - NativeMethods.ReleaseDC(_hwnd, _hDC); - } - } - - private CHAR_INFO[] cachedBuffer; - private CHAR_INFO[] ToCharInfoBuffer(BufferChar[] buffer) - { - if (cachedBuffer == null || cachedBuffer.Length != buffer.Length) - { - cachedBuffer = new CHAR_INFO[buffer.Length]; - } - - for (int i = 0; i < buffer.Length; i++) - { - cachedBuffer[i] = buffer[i].ToCharInfo(); - } - - return cachedBuffer; - } - - private BufferChar[] ToBufferCharBuffer(CHAR_INFO[] buffer) - { - var result = new BufferChar[buffer.Length]; - - for (int i = 0; i < buffer.Length; i++) - { - result[i] = BufferChar.FromCharInfo(buffer[i]); - } - - return result; - } - - } - -#else - - internal class TTYConsole : IConsole - { - public object GetConsoleInputMode() - { - return Console.TreatControlCAsInput; - } - - public void SetConsoleInputMode(object modeObj) - { - Console.TreatControlCAsInput = true; - } - - public void RestoreConsoleInputMode(object modeObj) - { - if (modeObj is bool) - { - Console.TreatControlCAsInput = (bool)modeObj; - } - } - - public ConsoleKeyInfo ReadKey() - { - return Console.ReadKey(true); - } - - public bool KeyAvailable - { - get { return Console.KeyAvailable; } - } - - public int CursorLeft - { - get { return Console.CursorLeft; } - set { Console.CursorLeft = value; } - } - - public int CursorTop - { - get { return Console.CursorTop; } - set { Console.CursorTop = value; } - } - - public int CursorSize - { - get { return Console.CursorSize; } - set { Console.CursorSize = value; } - } - - public int BufferWidth - { - get { return Console.BufferWidth; } - set { Console.BufferWidth = value; } - } - - public int BufferHeight - { - get { return Console.BufferHeight; } - set { Console.BufferHeight = value; } - } - - public int WindowWidth - { - get { return Console.WindowWidth; } - set { Console.WindowWidth = value; } - } - - public int WindowHeight - { - get { return Console.WindowHeight; } - set { Console.WindowHeight = value; } - } - - public int WindowTop - { - get { return Console.WindowTop; } - set { Console.WindowTop = value; } - } - - public ConsoleColor BackgroundColor - { - get { return Console.BackgroundColor; } - set { Console.BackgroundColor = value; } - } - - public ConsoleColor ForegroundColor - { - get { return Console.ForegroundColor; } - set { Console.ForegroundColor = value; } - } - - public void SetWindowPosition(int left, int top) - { - Console.SetWindowPosition(left, top); - } - - public void SetCursorPosition(int left, int top) - { - Console.SetCursorPosition(left, top); - } - - public void Write(string value) - { - Console.Write(value); - } - - public void WriteLine(string value) - { - Console.WriteLine(value); - } - - public void WriteBufferLines(BufferChar[] buffer, ref int top) - { - WriteBufferLines(buffer, ref top, true); - } - - public void WriteBufferLines(BufferChar[] buffer, ref int top, bool ensureBottomLineVisible) - { - int bufferWidth = Console.BufferWidth; - int bufferLineCount = buffer.Length / bufferWidth; - if ((top + bufferLineCount) > Console.BufferHeight) - { - var scrollCount = (top + bufferLineCount) - Console.BufferHeight; - ScrollBuffer(scrollCount); - top -= scrollCount; - } - - ConsoleColor foregroundColor = Console.ForegroundColor; - ConsoleColor backgroundColor = Console.BackgroundColor; - - Console.SetCursorPosition(0, (top>=0) ? top : 0); - - var lastForegroundColor = (ConsoleColor)(-1); - var lastBackgroundColor = (ConsoleColor)(-1); - for (int i = 0; i < buffer.Length; ++i) - { - // TODO: use escape sequences for better perf - var nextForegroundColor = buffer[i].ForegroundColor; - var nextBackgroundColor = buffer[i].BackgroundColor; - if (nextForegroundColor != lastForegroundColor) - { - Console.ForegroundColor = lastForegroundColor = nextForegroundColor; - } - if (nextBackgroundColor != lastBackgroundColor) - { - Console.BackgroundColor = lastBackgroundColor = nextBackgroundColor; - } - - Console.Write(buffer[i].UnicodeChar); - } - - if (foregroundColor != lastForegroundColor) - { - Console.ForegroundColor = foregroundColor; - } - if (backgroundColor != lastBackgroundColor) - { - Console.BackgroundColor = backgroundColor; - } - } - - public void ScrollBuffer(int lines) - { - for (int i=0; i _edits; - public int _undoEditIndex; - public bool _saved; - public bool _fromDifferentLiveSession; - } - - // History state - private HistoryQueue _history; - private Dictionary _hashedHistory; - private int _currentHistoryIndex; - private int _getNextHistoryIndex; - private int _searchHistoryCommandCount; - private int _recallHistoryCommandCount; - private string _searchHistoryPrefix; - // When cycling through history, the current line (not yet added to history) - // is saved here so it can be restored. - private readonly HistoryItem _savedCurrentLine; - - private Mutex _historyFileMutex; - private long _historyFileLastSavedSize; - - private const string _forwardISearchPrompt = "fwd-i-search: "; - private const string _backwardISearchPrompt = "bck-i-search: "; - private const string _failedForwardISearchPrompt = "failed-fwd-i-search: "; - private const string _failedBackwardISearchPrompt = "failed-bck-i-search: "; - - private string MaybeAddToHistory(string result, List edits, int undoEditIndex, bool readingHistoryFile, bool fromDifferentSession) - { - bool addToHistory = !string.IsNullOrWhiteSpace(result) && ((Options.AddToHistoryHandler == null) || Options.AddToHistoryHandler(result)); - if (addToHistory) - { - _history.Enqueue(new HistoryItem - { - _line = result, - _edits = edits, - _undoEditIndex = undoEditIndex, - _saved = readingHistoryFile, - _fromDifferentLiveSession = fromDifferentSession, - }); - _currentHistoryIndex = _history.Count; - - if (_options.HistorySaveStyle == HistorySaveStyle.SaveIncrementally && !readingHistoryFile) - { - IncrementalHistoryWrite(); - } - } - - // Clear the saved line unless we used AcceptAndGetNext in which - // case we're really still in middle of history and might want - // to recall the saved line. - if (_getNextHistoryIndex == 0) - { - _savedCurrentLine._line = null; - _savedCurrentLine._edits = null; - _savedCurrentLine._undoEditIndex = 0; - } - return result; - } - - private string GetHistorySaveFileMutexName() - { - // Return a reasonably unique name - it's not too important as there will rarely - // be any contention. - return "PSReadlineHistoryFile_" + _options.HistorySavePath.GetHashCode(); - } - - private void IncrementalHistoryWrite() - { - var i = _currentHistoryIndex - 1; - while (i >= 0) - { - if (_history[i]._saved) - { - break; - } - i -= 1; - } - - WriteHistoryRange(i + 1, _history.Count - 1, File.AppendText); - } - - private void SaveHistoryAtExit() - { - WriteHistoryRange(0, _history.Count - 1, File.CreateText); - } - - - private int historyErrorReportedCount; - private void ReportHistoryFileError(Exception e) - { - if (historyErrorReportedCount == 2) - return; - - historyErrorReportedCount += 1; - var fgColor = Console.ForegroundColor; - var bgColor = Console.BackgroundColor; - Console.ForegroundColor = Options.ErrorForegroundColor; - Console.WriteLine(PSReadLineResources.HistoryFileErrorMessage, Options.HistorySavePath, e.Message); - if (historyErrorReportedCount == 2) - { - Console.WriteLine(PSReadLineResources.HistoryFileErrorFinalMessage); - } - Console.ForegroundColor = fgColor; - Console.BackgroundColor = bgColor; - } - - private bool WithHistoryFileMutexDo(int timeout, Action action) - { - int retryCount = 0; - do - { - try - { - if (_historyFileMutex.WaitOne(timeout)) - { - try - { - action(); - } - catch (UnauthorizedAccessException uae) - { - ReportHistoryFileError(uae); - return false; - } - catch (IOException ioe) - { - ReportHistoryFileError(ioe); - return false; - } - finally - { - _historyFileMutex.ReleaseMutex(); - } - } - } - catch (AbandonedMutexException) - { - retryCount += 1; - } - } while (retryCount > 0 && retryCount < 3); - - // No errors to report, so consider it a success even if we timed out on the mutex. - return true; - } - - private void WriteHistoryRange(int start, int end, Func fileOpener) - { - WithHistoryFileMutexDo(100, () => - { - if (!MaybeReadHistoryFile()) - return; - - bool retry = true; - retry_after_creating_directory: - try - { - using (var file = fileOpener(Options.HistorySavePath)) - { - for (var i = start; i <= end; i++) - { - _history[i]._saved = true; - var line = _history[i]._line.Replace("\n", "`\n"); - file.WriteLine(line); - } - } - var fileInfo = new FileInfo(Options.HistorySavePath); - _historyFileLastSavedSize = fileInfo.Length; - } - catch (DirectoryNotFoundException) - { - // Try making the directory, but just once - if (retry) - { - retry = false; - Directory.CreateDirectory(Path.GetDirectoryName(Options.HistorySavePath)); - goto retry_after_creating_directory; - } - } - }); - } - - private bool MaybeReadHistoryFile() - { - if (Options.HistorySaveStyle == HistorySaveStyle.SaveIncrementally) - { - return WithHistoryFileMutexDo(1000, () => - { - var fileInfo = new FileInfo(Options.HistorySavePath); - if (fileInfo.Exists && fileInfo.Length != _historyFileLastSavedSize) - { - var historyLines = new List(); - using (var fs = new FileStream(Options.HistorySavePath, FileMode.Open)) - using (var sr = new StreamReader(fs)) - { - fs.Seek(_historyFileLastSavedSize, SeekOrigin.Begin); - - while (!sr.EndOfStream) - { - historyLines.Add(sr.ReadLine()); - } - } - UpdateHistoryFromFile(historyLines, fromDifferentSession: true); - - _historyFileLastSavedSize = fileInfo.Length; - } - }); - } - - // true means no errors, not that we actually read the file - return true; - } - - private void ReadHistoryFile() - { - WithHistoryFileMutexDo(1000, () => - { - if (!File.Exists(Options.HistorySavePath)) - { - return; - } - - var historyLines = File.ReadAllLines(Options.HistorySavePath); - UpdateHistoryFromFile(historyLines, fromDifferentSession: false); - var fileInfo = new FileInfo(Options.HistorySavePath); - _historyFileLastSavedSize = fileInfo.Length; - }); - } - - void UpdateHistoryFromFile(IEnumerable historyLines, bool fromDifferentSession) - { - var sb = new StringBuilder(); - foreach (var line in historyLines) - { - if (line.EndsWith("`", StringComparison.Ordinal)) - { - sb.Append(line, 0, line.Length - 1); - sb.Append('\n'); - } - else if (sb.Length > 0) - { - sb.Append(line); - var l = sb.ToString(); - var editItems = new List {EditItemInsertString.Create(l, 0)}; - MaybeAddToHistory(l, editItems, 1, /*readingHistoryFile*/ true, fromDifferentSession); - sb.Clear(); - } - else - { - var editItems = new List {EditItemInsertString.Create(line, 0)}; - MaybeAddToHistory(line, editItems, 1, /*readingHistoryFile*/ true, fromDifferentSession); - } - } - } - - /// - /// Add a command to the history - typically used to restore - /// history from a previous session. - /// - public static void AddToHistory(string command) - { - command = command.Replace("\r\n", "\n"); - var editItems = new List {EditItemInsertString.Create(command, 0)}; - _singleton.MaybeAddToHistory(command, editItems, 1, readingHistoryFile: false, fromDifferentSession: false); - } - - /// - /// Clears history in PSReadline. This does not affect PowerShell history. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ClearHistory(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._history != null) - { - _singleton._history.Clear(); - } - _singleton._currentHistoryIndex = 0; - } - - private void UpdateFromHistory(bool moveCursor) - { - string line; - if (_currentHistoryIndex == _history.Count) - { - line = _savedCurrentLine._line; - _edits = _savedCurrentLine._edits; - _undoEditIndex = _savedCurrentLine._undoEditIndex; - } - else - { - line = _history[_currentHistoryIndex]._line; - _edits = new List(_history[_currentHistoryIndex]._edits); - _undoEditIndex = _history[_currentHistoryIndex]._undoEditIndex; - } - _buffer.Clear(); - _buffer.Append(line); - if (moveCursor) - { - _current = _options.EditMode == EditMode.Vi ? 0 : Math.Max(0, _buffer.Length + ViEndOfLineFactor); - } - else if (_current > _buffer.Length) - { - _current = Math.Max(0, _buffer.Length + ViEndOfLineFactor); - } - Render(); - } - - private void SaveCurrentLine() - { - // We're called before any history operation - so it's convenient - // to check if we need to load history from another sessions now. - MaybeReadHistoryFile(); - - if (_savedCurrentLine._line == null) - { - _savedCurrentLine._line = _buffer.ToString(); - _savedCurrentLine._edits = _edits; - _savedCurrentLine._undoEditIndex = _undoEditIndex; - } - } - - private void HistoryRecall(int direction) - { - if (_recallHistoryCommandCount == 0 && LineIsMultiLine()) - { - MoveToLine(direction); - return; - } - - if (Options.HistoryNoDuplicates && _recallHistoryCommandCount == 0) - { - _hashedHistory = new Dictionary(); - } - - int count = Math.Abs(direction); - direction = direction < 0 ? -1 : +1; - int newHistoryIndex = _currentHistoryIndex; - while (count > 0) - { - newHistoryIndex += direction; - if (newHistoryIndex < 0 || newHistoryIndex >= _history.Count) - { - break; - } - - if (_history[newHistoryIndex]._fromDifferentLiveSession) - { - continue; - } - - if (Options.HistoryNoDuplicates) - { - var line = _history[newHistoryIndex]._line; - int index; - if (!_hashedHistory.TryGetValue(line, out index)) - { - _hashedHistory.Add(line, newHistoryIndex); - --count; - } - else if (newHistoryIndex == index) - { - --count; - } - } - else - { - --count; - } - } - _recallHistoryCommandCount += 1; - if (newHistoryIndex >= 0 && newHistoryIndex <= _history.Count) - { - _currentHistoryIndex = newHistoryIndex; - UpdateFromHistory(moveCursor: true); - } - } - - /// - /// Replace the current input with the 'previous' item from PSReadline history. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void PreviousHistory(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, -1); - if (numericArg > 0) - { - numericArg = -numericArg; - } - - _singleton.SaveCurrentLine(); - _singleton.HistoryRecall(numericArg); - } - - /// - /// Replace the current input with the 'next' item from PSReadline history. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void NextHistory(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, +1); - - _singleton.SaveCurrentLine(); - _singleton.HistoryRecall(numericArg); - } - - private void HistorySearch(int direction) - { - if (_searchHistoryCommandCount == 0) - { - if (LineIsMultiLine()) - { - MoveToLine(direction); - return; - } - - _searchHistoryPrefix = _buffer.ToString(0, _current); - _emphasisStart = 0; - _emphasisLength = _current; - if (Options.HistoryNoDuplicates) - { - _hashedHistory = new Dictionary(); - } - } - _searchHistoryCommandCount += 1; - - int count = Math.Abs(direction); - direction = direction < 0 ? -1 : +1; - int newHistoryIndex = _currentHistoryIndex; - while (count > 0) - { - newHistoryIndex += direction; - if (newHistoryIndex < 0 || newHistoryIndex >= _history.Count) - { - break; - } - - if (_history[newHistoryIndex]._fromDifferentLiveSession && _searchHistoryPrefix.Length == 0) - { - continue; - } - - var line = newHistoryIndex == _history.Count ? _savedCurrentLine._line : _history[newHistoryIndex]._line; - if (line.StartsWith(_searchHistoryPrefix, Options.HistoryStringComparison)) - { - if (Options.HistoryNoDuplicates) - { - int index; - if (!_hashedHistory.TryGetValue(line, out index)) - { - _hashedHistory.Add(line, newHistoryIndex); - --count; - } - else if (index == newHistoryIndex) - { - --count; - } - } - else - { - --count; - } - } - } - - if (newHistoryIndex >= 0 && newHistoryIndex <= _history.Count) - { - _currentHistoryIndex = newHistoryIndex; - UpdateFromHistory(moveCursor: true); - } - } - - /// - /// Move to the first item in the history. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BeginningOfHistory(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.SaveCurrentLine(); - _singleton._currentHistoryIndex = 0; - _singleton.UpdateFromHistory(moveCursor: true); - } - - /// - /// Move to the last item (the current input) in the history. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void EndOfHistory(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._currentHistoryIndex = _singleton._history.Count; - _singleton.UpdateFromHistory(moveCursor: true); - } - - /// - /// Replace the current input with the 'previous' item from PSReadline history - /// that matches the characters between the start and the input and the cursor. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void HistorySearchBackward(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, -1); - if (numericArg > 0) - { - numericArg = -numericArg; - } - - _singleton.SaveCurrentLine(); - _singleton.HistorySearch(numericArg); - } - - /// - /// Replace the current input with the 'next' item from PSReadline history - /// that matches the characters between the start and the input and the cursor. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void HistorySearchForward(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, +1); - - _singleton.SaveCurrentLine(); - _singleton.HistorySearch(numericArg); - } - - private void UpdateHistoryDuringInteractiveSearch(string toMatch, int direction, ref int searchFromPoint) - { - searchFromPoint += direction; - for (; searchFromPoint >= 0 && searchFromPoint < _history.Count; searchFromPoint += direction) - { - var line = _history[searchFromPoint]._line; - var startIndex = line.IndexOf(toMatch, Options.HistoryStringComparison); - if (startIndex >= 0) - { - if (Options.HistoryNoDuplicates) - { - int index; - if (!_hashedHistory.TryGetValue(line, out index)) - { - _hashedHistory.Add(line, searchFromPoint); - } - else if (index != searchFromPoint) - { - continue; - } - } - _statusLinePrompt = direction > 0 ? _forwardISearchPrompt : _backwardISearchPrompt; - _current = startIndex; - _emphasisStart = startIndex; - _emphasisLength = toMatch.Length; - _currentHistoryIndex = searchFromPoint; - UpdateFromHistory(moveCursor: Options.HistorySearchCursorMovesToEnd); - return; - } - } - - // Make sure we're never more than 1 away from being in range so if they - // reverse direction, the first time they reverse they are back in range. - if (searchFromPoint < 0) - searchFromPoint = -1; - else if (searchFromPoint >= _history.Count) - searchFromPoint = _history.Count; - - _emphasisStart = -1; - _emphasisLength = 0; - _statusLinePrompt = direction > 0 ? _failedForwardISearchPrompt : _failedBackwardISearchPrompt; - Render(); - } - - private void InteractiveHistorySearchLoop(int direction) - { - var searchFromPoint = _currentHistoryIndex; - var searchPositions = new Stack(); - searchPositions.Push(_currentHistoryIndex); - - if (Options.HistoryNoDuplicates) - { - _hashedHistory = new Dictionary(); - } - - var toMatch = new StringBuilder(64); - while (true) - { - var key = ReadKey(); - KeyHandler handler; - _dispatchTable.TryGetValue(key, out handler); - var function = handler != null ? handler.Action : null; - if (function == ReverseSearchHistory) - { - UpdateHistoryDuringInteractiveSearch(toMatch.ToString(), -1, ref searchFromPoint); - } - else if (function == ForwardSearchHistory) - { - UpdateHistoryDuringInteractiveSearch(toMatch.ToString(), +1, ref searchFromPoint); - } - else if (function == BackwardDeleteChar || key == Keys.Backspace || key == Keys.CtrlH) - { - if (toMatch.Length > 0) - { - toMatch.Remove(toMatch.Length - 1, 1); - _statusBuffer.Remove(_statusBuffer.Length - 2, 1); - searchPositions.Pop(); - searchFromPoint = _currentHistoryIndex = searchPositions.Peek(); - UpdateFromHistory(moveCursor: Options.HistorySearchCursorMovesToEnd); - - if (_hashedHistory != null) - { - // Remove any entries with index < searchFromPoint because - // we are starting the search from this new index - we always - // want to find the latest entry that matches the search string - foreach (var pair in _hashedHistory.ToArray()) - { - if (pair.Value < searchFromPoint) - { - _hashedHistory.Remove(pair.Key); - } - } - } - - // Prompt may need to have 'failed-' removed. - var toMatchStr = toMatch.ToString(); - var startIndex = _buffer.ToString().IndexOf(toMatchStr, Options.HistoryStringComparison); - if (startIndex >= 0) - { - _statusLinePrompt = direction > 0 ? _forwardISearchPrompt : _backwardISearchPrompt; - _current = startIndex; - _emphasisStart = startIndex; - _emphasisLength = toMatch.Length; - Render(); - } - } - else - { - Ding(); - } - } - else if (key == Keys.Escape) - { - // End search - break; - } - else if (function == Abort) - { - // Abort search - EndOfHistory(); - break; - } - else if (EndInteractiveHistorySearch(key, function)) - { - PrependQueuedKeys(key); - break; - } - else - { - toMatch.Append(key.KeyChar); - _statusBuffer.Insert(_statusBuffer.Length - 1, key.KeyChar); - - var toMatchStr = toMatch.ToString(); - var startIndex = _buffer.ToString().IndexOf(toMatchStr, Options.HistoryStringComparison); - if (startIndex < 0) - { - UpdateHistoryDuringInteractiveSearch(toMatchStr, direction, ref searchFromPoint); - } - else - { - _current = startIndex; - _emphasisStart = startIndex; - _emphasisLength = toMatch.Length; - Render(); - } - searchPositions.Push(_currentHistoryIndex); - } - } - } - - private static bool EndInteractiveHistorySearch(ConsoleKeyInfo key, Action function) - { - // Keys < ' ' are control characters - if (key.KeyChar < ' ') - { - return true; - } - - if ((key.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) - { - return true; - } - - return false; - } - - private void InteractiveHistorySearch(int direction) - { - SaveCurrentLine(); - - // Add a status line that will contain the search prompt and string - _statusLinePrompt = direction > 0 ? _forwardISearchPrompt : _backwardISearchPrompt; - _statusBuffer.Append("_"); - - Render(); // Render prompt - InteractiveHistorySearchLoop(direction); - - _hashedHistory = null; - _currentHistoryIndex = _history.Count; - - _emphasisStart = -1; - _emphasisLength = 0; - - // Remove our status line, this will render - ClearStatusMessage(render: true); - } - - /// - /// Perform an incremental forward search through history - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ForwardSearchHistory(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.InteractiveHistorySearch(+1); - } - - /// - /// Perform an incremental backward search through history - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ReverseSearchHistory(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.InteractiveHistorySearch(-1); - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/HistoryQueue.cs b/src/Microsoft.PowerShell.PSReadLine/HistoryQueue.cs deleted file mode 100644 index ea6e86d485b0..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/HistoryQueue.cs +++ /dev/null @@ -1,132 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; - -namespace Microsoft.PowerShell -{ - [ExcludeFromCodeCoverage] - internal sealed class QueueDebugView - { - private readonly HistoryQueue _queue; - - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public T[] Items - { - get { return this._queue.ToArray(); } - } - - public QueueDebugView(HistoryQueue queue) - { - if (queue == null) - throw new ArgumentNullException("queue"); - this._queue = queue; - } - } - - [DebuggerDisplay("Count = {Count}")] - [DebuggerTypeProxy(typeof(QueueDebugView<>))] - internal class HistoryQueue - { - private readonly T[] _array; - private int _head; - private int _tail; - - public HistoryQueue(int capacity) - { - Debug.Assert(capacity > 0); - _array = new T[capacity]; - _head = _tail = Count = 0; - } - - public void Clear() - { - for (int i = 0; i < Count; i++) - { - this[i] = default(T); - } - _head = _tail = Count = 0; - } - - public bool Contains(T item) - { - return IndexOf(item) != -1; - } - - public int Count { get; private set; } - - public int IndexOf(T item) - { - // REVIEW: should we use case insensitive here? - var eqComparer = EqualityComparer.Default; - for (int i = 0; i < Count; i++) - { - if (eqComparer.Equals(this[i], item)) - { - return i; - } - } - - return -1; - } - - public void Enqueue(T item) - { - if (Count == _array.Length) - { - Dequeue(); - } - _array[_tail] = item; - _tail = (_tail + 1) % _array.Length; - Count += 1; - } - - public T Dequeue() - { - Debug.Assert(Count > 0); - - T obj = _array[_head]; - _array[_head] = default(T); - _head = (_head + 1) % _array.Length; - Count -= 1; - return obj; - } - - public T[] ToArray() - { - var result = new T[Count]; - if (Count > 0) - { - if (_head < _tail) - { - Array.Copy(_array, _head, result, 0, Count); - } - else - { - Array.Copy(_array, _head, result, 0, _array.Length - _head); - Array.Copy(_array, 0, result, _array.Length - _head, _tail); - } - } - return result; - } - - [ExcludeFromCodeCoverage] - public T this[int index] - { - get - { - Debug.Assert(index >= 0 && index < Count); - return _array[(_head + index) % _array.Length]; - } - set - { - Debug.Assert(index >= 0 && index < Count); - _array[(_head + index) % _array.Length] = value; - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/KeyBindings.cs b/src/Microsoft.PowerShell.PSReadLine/KeyBindings.cs deleted file mode 100644 index 05f553820951..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/KeyBindings.cs +++ /dev/null @@ -1,423 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Management.Automation; -using System.Text; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - /// - /// The class is used as the output type for the cmdlet Get-PSReadlineKeyHandler - /// - public class KeyHandler - { - /// - /// The key that is bound or unbound. - /// - public string Key { get; set; } - - /// - /// The name of the function that a key is bound to, if any. - /// - public string Function { get; set; } - - /// - /// A short description of the behavior of the function. - /// - public string Description - { - get - { - var result = _description; - if (string.IsNullOrWhiteSpace(result)) - result = PSReadLineResources.ResourceManager.GetString(Function + "Description"); - if (string.IsNullOrWhiteSpace(result)) - result = Function; - return result; - } - set { _description = value; } - } - private string _description; - } - - public partial class PSConsoleReadLine - { - class KeyHandler - { - // Each key handler will be passed 2 arguments. Most will ignore these arguments, - // but having a consistent signature greatly simplifies dispatch. Defaults - // should be included on all handlers that ignore their parameters so they - // can be called from PowerShell without passing anything. - // - // The first argument is the key that caused the action to be called - // (the second key when it's a 2 key chord). The default is null (it's nullable) - // because PowerShell can't handle default(ConsoleKeyInfo) as a default. - // Most actions will ignore this argument. - // - // The second argument is an arbitrary object. It will usually be either a number - // (e.g. as a repeat count) or a string. Most actions will ignore this argument. - public Action Action; - public string BriefDescription; - public string LongDescription - { - get - { - return _longDescription ?? - (_longDescription = - PSReadLineResources.ResourceManager.GetString(BriefDescription + "Description")); - } - set { _longDescription = value; } - } - private string _longDescription; - public ScriptBlock ScriptBlock; - } - - internal class ConsoleKeyInfoComparer : IEqualityComparer - { - public bool Equals(ConsoleKeyInfo x, ConsoleKeyInfo y) - { - // We *must not* compare the KeyChar field as its value is platform-dependent. - // We compare exactly the ConsoleKey enum field (which is platform-agnostic) - // and the modifiers. - - return x.Key == y.Key && x.Modifiers == y.Modifiers; - } - - public int GetHashCode(ConsoleKeyInfo obj) - { - // Because a comparison of two ConsoleKeyInfo objects is a comparison of the - // combination of the ConsoleKey and Modifiers, we must combine their hashes. - // Note that if the ConsoleKey is default, we must fall back to the KeyChar, - // otherwise every non-special key will compare as the same. - int h1 = obj.Key == default(ConsoleKey) - ? obj.KeyChar.GetHashCode() - : obj.Key.GetHashCode(); - int h2 = obj.Modifiers.GetHashCode(); - // This is based on Tuple.GetHashCode - return unchecked(((h1 << 5) + h1) ^ h2); - } - } - - static KeyHandler MakeKeyHandler(Action action, string briefDescription, string longDescription = null, ScriptBlock scriptBlock = null) - { - return new KeyHandler - { - Action = action, - BriefDescription = briefDescription, - LongDescription = longDescription, - ScriptBlock = scriptBlock, - }; - } - - private Dictionary _dispatchTable; - private Dictionary> _chordDispatchTable; - - /// - /// Helper to set bindings based on EditMode - /// - void SetDefaultBindings(EditMode editMode) - { - switch (editMode) - { - case EditMode.Emacs: - SetDefaultEmacsBindings(); - break; - case EditMode.Vi: - SetDefaultViBindings(); - break; - case EditMode.Windows: - SetDefaultWindowsBindings(); - break; - } - } - - void SetDefaultWindowsBindings() - { - _dispatchTable = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine") }, - { Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") }, - { Keys.CtrlEnter, MakeKeyHandler(InsertLineAbove, "InsertLineAbove") }, - { Keys.CtrlShiftEnter, MakeKeyHandler(InsertLineBelow, "InsertLineBelow") }, - { Keys.Escape, MakeKeyHandler(RevertLine, "RevertLine") }, - { Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") }, - { Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") }, - { Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") }, - { Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") }, - { Keys.ShiftLeftArrow, MakeKeyHandler(SelectBackwardChar, "SelectBackwardChar") }, - { Keys.ShiftRightArrow, MakeKeyHandler(SelectForwardChar, "SelectForwardChar") }, - { Keys.ShiftCtrlLeftArrow, MakeKeyHandler(SelectBackwardWord, "SelectBackwardWord") }, - { Keys.ShiftCtrlRightArrow, MakeKeyHandler(SelectNextWord, "SelectNextWord") }, - { Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, - { Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") }, - { Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, - { Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") }, - { Keys.ShiftHome, MakeKeyHandler(SelectBackwardsLine, "SelectBackwardsLine") }, - { Keys.ShiftEnd, MakeKeyHandler(SelectLine, "SelectLine") }, - { Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") }, - { Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, - { Keys.CtrlSpace, MakeKeyHandler(MenuComplete, "MenuComplete") }, - { Keys.Tab, MakeKeyHandler(TabCompleteNext, "TabCompleteNext") }, - { Keys.ShiftTab, MakeKeyHandler(TabCompletePrevious, "TabCompletePrevious") }, -#if !UNIX - { Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") }, -#endif - { Keys.CtrlA, MakeKeyHandler(SelectAll, "SelectAll") }, - { Keys.CtrlC, MakeKeyHandler(CopyOrCancelLine, "CopyOrCancelLine") }, - { Keys.CtrlShiftC, MakeKeyHandler(Copy, "Copy") }, - { Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") }, - { Keys.CtrlR, MakeKeyHandler(ReverseSearchHistory, "ReverseSearchHistory") }, - { Keys.CtrlS, MakeKeyHandler(ForwardSearchHistory, "ForwardSearchHistory") }, - { Keys.CtrlV, MakeKeyHandler(Paste, "Paste") }, - { Keys.CtrlX, MakeKeyHandler(Cut, "Cut") }, - { Keys.CtrlY, MakeKeyHandler(Redo, "Redo") }, - { Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") }, - { Keys.CtrlBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, - { Keys.CtrlDelete, MakeKeyHandler(KillWord, "KillWord") }, - { Keys.CtrlEnd, MakeKeyHandler(ForwardDeleteLine, "ForwardDeleteLine") }, - { Keys.CtrlHome, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") }, - { Keys.CtrlRBracket, MakeKeyHandler(GotoBrace, "GotoBrace") }, - { Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") }, - { Keys.AltPeriod, MakeKeyHandler(YankLastArg, "YankLastArg") }, - { Keys.Alt0, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt1, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt2, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt3, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt4, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt5, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt6, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt7, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt8, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt9, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.AltMinus, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.AltQuestion, MakeKeyHandler(WhatIsKey, "WhatIsKey") }, - { Keys.AltF7, MakeKeyHandler(ClearHistory, "ClearHistory") }, - { Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") }, - { Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") }, - { Keys.F8, MakeKeyHandler(HistorySearchBackward, "HistorySearchBackward") }, - { Keys.ShiftF8, MakeKeyHandler(HistorySearchForward, "HistorySearchForward") }, -#if !UNIX - { Keys.PageUp, MakeKeyHandler(ScrollDisplayUp, "ScrollDisplayUp") }, - { Keys.PageDown, MakeKeyHandler(ScrollDisplayDown, "ScrollDisplayDown") }, - { Keys.CtrlPageUp, MakeKeyHandler(ScrollDisplayUpLine, "ScrollDisplayUpLine") }, - { Keys.CtrlPageDown, MakeKeyHandler(ScrollDisplayDownLine, "ScrollDisplayDownLine") }, -#endif - }; - - _chordDispatchTable = new Dictionary>(); - } - - void SetDefaultEmacsBindings() - { - _dispatchTable = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, - { Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine") }, - { Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") }, - { Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") }, - { Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") }, - { Keys.ShiftLeftArrow, MakeKeyHandler(SelectBackwardChar, "SelectBackwardChar") }, - { Keys.ShiftRightArrow, MakeKeyHandler(SelectForwardChar, "SelectForwardChar") }, - { Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, - { Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") }, - { Keys.AltLess, MakeKeyHandler(BeginningOfHistory, "BeginningOfHistory") }, - { Keys.AltGreater, MakeKeyHandler(EndOfHistory, "EndOfHistory") }, - { Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, - { Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") }, - { Keys.ShiftHome, MakeKeyHandler(SelectBackwardsLine, "SelectBackwardsLine") }, - { Keys.ShiftEnd, MakeKeyHandler(SelectLine, "SelectLine") }, - { Keys.Escape, MakeKeyHandler(Chord, "ChordFirstKey") }, - { Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") }, - { Keys.Tab, MakeKeyHandler(Complete, "Complete") }, - { Keys.CtrlA, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, - { Keys.CtrlB, MakeKeyHandler(BackwardChar, "BackwardChar") }, - { Keys.CtrlC, MakeKeyHandler(CopyOrCancelLine, "CopyOrCancelLine") }, - { Keys.CtrlD, MakeKeyHandler(DeleteCharOrExit, "DeleteCharOrExit") }, - { Keys.CtrlE, MakeKeyHandler(EndOfLine, "EndOfLine") }, - { Keys.CtrlF, MakeKeyHandler(ForwardChar, "ForwardChar") }, - { Keys.CtrlG, MakeKeyHandler(Abort, "Abort") }, - { Keys.CtrlH, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, - { Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") }, - { Keys.CtrlK, MakeKeyHandler(KillLine, "KillLine") }, - { Keys.CtrlM, MakeKeyHandler(ValidateAndAcceptLine,"ValidateAndAcceptLine") }, - { Keys.CtrlN, MakeKeyHandler(NextHistory, "NextHistory") }, - { Keys.CtrlO, MakeKeyHandler(AcceptAndGetNext, "AcceptAndGetNext") }, - { Keys.CtrlP, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, - { Keys.CtrlR, MakeKeyHandler(ReverseSearchHistory, "ReverseSearchHistory") }, - { Keys.CtrlS, MakeKeyHandler(ForwardSearchHistory, "ForwardSearchHistory") }, - { Keys.CtrlU, MakeKeyHandler(BackwardKillLine, "BackwardKillLine") }, - { Keys.CtrlX, MakeKeyHandler(Chord, "ChordFirstKey") }, - { Keys.CtrlW, MakeKeyHandler(UnixWordRubout, "UnixWordRubout") }, - { Keys.CtrlY, MakeKeyHandler(Yank, "Yank") }, - { Keys.CtrlAt, MakeKeyHandler(SetMark, "SetMark") }, - { Keys.CtrlUnderbar, MakeKeyHandler(Undo, "Undo") }, - { Keys.CtrlRBracket, MakeKeyHandler(CharacterSearch, "CharacterSearch") }, - { Keys.AltCtrlRBracket, MakeKeyHandler(CharacterSearchBackward,"CharacterSearchBackward") }, - { Keys.Alt0, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt1, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt2, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt3, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt4, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt5, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt6, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt7, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt8, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Alt9, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.AltMinus, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.AltB, MakeKeyHandler(BackwardWord, "BackwardWord") }, - { Keys.AltShiftB, MakeKeyHandler(SelectBackwardWord, "SelectBackwardWord") }, - { Keys.AltD, MakeKeyHandler(KillWord, "KillWord") }, - { Keys.AltF, MakeKeyHandler(ForwardWord, "ForwardWord") }, - { Keys.AltShiftF, MakeKeyHandler(SelectForwardWord, "SelectForwardWord") }, - { Keys.AltR, MakeKeyHandler(RevertLine, "RevertLine") }, - { Keys.AltY, MakeKeyHandler(YankPop, "YankPop") }, - { Keys.AltBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, - { Keys.AltEquals, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") }, - { Keys.CtrlSpace, MakeKeyHandler(MenuComplete, "MenuComplete") }, - { Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") }, - { Keys.AltQuestion, MakeKeyHandler(WhatIsKey, "WhatIsKey") }, - { Keys.AltSpace, MakeKeyHandler(SetMark, "SetMark") }, // useless entry here for completeness - brings up system menu on Windows - { Keys.AltPeriod, MakeKeyHandler(YankLastArg, "YankLastArg") }, - { Keys.AltUnderbar, MakeKeyHandler(YankLastArg, "YankLastArg") }, - { Keys.AltCtrlY, MakeKeyHandler(YankNthArg, "YankNthArg") }, -#if !UNIX - { Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.PageUp, MakeKeyHandler(ScrollDisplayUp, "ScrollDisplayUp") }, - { Keys.CtrlPageUp, MakeKeyHandler(ScrollDisplayUpLine, "ScrollDisplayUpLine") }, - { Keys.PageDown, MakeKeyHandler(ScrollDisplayDown, "ScrollDisplayDown") }, - { Keys.CtrlPageDown, MakeKeyHandler(ScrollDisplayDownLine,"ScrollDisplayDownLine") }, - { Keys.CtrlHome, MakeKeyHandler(ScrollDisplayTop, "ScrollDisplayTop") }, - { Keys.CtrlEnd, MakeKeyHandler(ScrollDisplayToCursor,"ScrollDisplayToCursor") }, -#endif - }; - - _chordDispatchTable = new Dictionary>(); - - // Escape, table (meta key) - _chordDispatchTable[Keys.Escape] = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.B, MakeKeyHandler(BackwardWord, "BackwardWord") }, - { Keys.D, MakeKeyHandler(KillWord, "KillWord") }, - { Keys.F, MakeKeyHandler(ForwardWord, "ForwardWord") }, - { Keys.R, MakeKeyHandler(RevertLine, "RevertLine") }, - { Keys.Y, MakeKeyHandler(YankPop, "YankPop") }, - { Keys.CtrlY, MakeKeyHandler(YankNthArg, "YankNthArg") }, - { Keys.Backspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, - { Keys.Period, MakeKeyHandler(YankLastArg, "YankLastArg") }, - { Keys.Underbar, MakeKeyHandler(YankLastArg, "YankLastArg") }, - }; - - // Ctrl+X, table - _chordDispatchTable[Keys.CtrlX] = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.Backspace, MakeKeyHandler(BackwardKillLine, "BackwardKillLine") }, - { Keys.CtrlU, MakeKeyHandler(Undo, "Undo") }, - { Keys.CtrlX, MakeKeyHandler(ExchangePointAndMark, "ExchangePointAndMark") }, - }; - } - - /// - /// Show all bound keys - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ShowKeyBindings(ConsoleKeyInfo? key = null, object arg = null) - { - var buffer = new StringBuilder(); - buffer.AppendFormat(CultureInfo.InvariantCulture, "{0,-20} {1,-24} {2}\n", "Key", "Function", "Description"); - buffer.AppendFormat(CultureInfo.InvariantCulture, "{0,-20} {1,-24} {2}\n", "---", "--------", "-----------"); - var boundKeys = GetKeyHandlers(includeBound: true, includeUnbound: false); - var console = _singleton._console; - var maxDescriptionLength = console.WindowWidth - 20 - 24 - 2; - foreach (var boundKey in boundKeys) - { - var description = boundKey.Description; - var newline = "\n"; - if (description.Length >= maxDescriptionLength) - { - description = description.Substring(0, maxDescriptionLength - 3) + "..."; - newline = ""; - } - buffer.AppendFormat(CultureInfo.InvariantCulture, "{0,-20} {1,-24} {2}{3}", boundKey.Key, boundKey.Function, description, newline); - } - - // Don't overwrite any of the line - so move to first line after the end of our buffer. - var coords = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length); - var y = coords.Y + 1; - _singleton.PlaceCursor(0, ref y); - - console.WriteLine(buffer.ToString()); - _singleton._initialY = console.CursorTop; - _singleton.Render(); - } - - /// - /// Read a key and tell me what the key is bound to. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void WhatIsKey(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._statusLinePrompt = "what-is-key: "; - _singleton.Render(); - var toLookup = ReadKey(); - KeyHandler keyHandler; - var buffer = new StringBuilder(); - _singleton._dispatchTable.TryGetValue(toLookup, out keyHandler); - buffer.Append(toLookup.ToGestureString()); - if (keyHandler != null) - { - if (keyHandler.BriefDescription == "ChordFirstKey") - { - Dictionary secondKeyDispatchTable; - if (_singleton._chordDispatchTable.TryGetValue(toLookup, out secondKeyDispatchTable)) - { - toLookup = ReadKey(); - secondKeyDispatchTable.TryGetValue(toLookup, out keyHandler); - buffer.Append(","); - buffer.Append(toLookup.ToGestureString()); - } - } - } - buffer.Append(": "); - if (keyHandler != null) - { - buffer.Append(keyHandler.BriefDescription); - if (!string.IsNullOrWhiteSpace(keyHandler.LongDescription)) - { - buffer.Append(" - "); - buffer.Append(keyHandler.LongDescription); - } - } - else if (toLookup.KeyChar != 0) - { - buffer.Append("SelfInsert"); - buffer.Append(" - "); - buffer.Append(PSReadLineResources.SelfInsertDescription); - } - else - { - buffer.Append(PSReadLineResources.KeyIsUnbound); - } - - _singleton.ClearStatusMessage(render: false); - - // Don't overwrite any of the line - so move to first line after the end of our buffer. - var coords = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length); - var y = coords.Y + 1; - _singleton.PlaceCursor(0, ref y); - - _singleton._console.WriteLine(buffer.ToString()); - _singleton._initialY = _singleton._console.CursorTop; - _singleton.Render(); - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/KeyBindings.vi.cs b/src/Microsoft.PowerShell.PSReadLine/KeyBindings.vi.cs deleted file mode 100644 index dd9f09b633af..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/KeyBindings.vi.cs +++ /dev/null @@ -1,284 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - internal static ConsoleColor AlternateBackground(ConsoleColor bg) - { - switch (bg) - { - case ConsoleColor.Black: return ConsoleColor.DarkGray; - case ConsoleColor.Blue: return ConsoleColor.DarkBlue; - case ConsoleColor.Cyan: return ConsoleColor.DarkCyan; - case ConsoleColor.DarkBlue: return ConsoleColor.Black; - case ConsoleColor.DarkCyan: return ConsoleColor.Black; - case ConsoleColor.DarkGray: return ConsoleColor.Black; - case ConsoleColor.DarkGreen: return ConsoleColor.Black; - case ConsoleColor.DarkMagenta: return ConsoleColor.Black; - case ConsoleColor.DarkRed: return ConsoleColor.Black; - case ConsoleColor.DarkYellow: return ConsoleColor.Black; - case ConsoleColor.Gray: return ConsoleColor.White; - case ConsoleColor.Green: return ConsoleColor.DarkGreen; - case ConsoleColor.Magenta: return ConsoleColor.DarkMagenta; - case ConsoleColor.Red: return ConsoleColor.DarkRed; - case ConsoleColor.White: return ConsoleColor.Gray; - case ConsoleColor.Yellow: return ConsoleColor.DarkYellow; - default: - return ConsoleColor.Black; - } - } - - private int _normalCursorSize = 10; - - private static Dictionary _viInsKeyMap; - private static Dictionary _viCmdKeyMap; - private static Dictionary _viChordDTable; - private static Dictionary _viChordCTable; - private static Dictionary _viChordYTable; - - private static Dictionary> _viCmdChordTable; - private static Dictionary> _viInsChordTable; - - /// - /// Sets up the key bindings for vi operations. - /// - private void SetDefaultViBindings() - { - _viInsKeyMap = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine" ) }, - { Keys.CtrlD, MakeKeyHandler(ViAcceptLineOrExit, "ViAcceptLineOrExit" ) }, - { Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") }, - { Keys.Escape, MakeKeyHandler(ViCommandMode, "ViCommandMode") }, - { Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") }, - { Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") }, - { Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") }, - { Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") }, - { Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, - { Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") }, - { Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, - { Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") }, - { Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") }, - { Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, - { Keys.CtrlSpace, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") }, - { Keys.Tab, MakeKeyHandler(ViTabCompleteNext, "ViTabCompleteNext") }, - { Keys.ShiftTab, MakeKeyHandler(ViTabCompletePrevious, "ViTabCompletePrevious") }, - { Keys.CtrlV, MakeKeyHandler(Paste, "Paste") }, -#if !UNIX - { Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") }, -#endif - { Keys.CtrlC, MakeKeyHandler(CancelLine, "CancelLine") }, - { Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") }, - { Keys.CtrlY, MakeKeyHandler(Redo, "Redo") }, - { Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") }, - { Keys.CtrlBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, - { Keys.CtrlDelete, MakeKeyHandler(KillWord, "KillWord") }, - { Keys.CtrlEnd, MakeKeyHandler(ForwardDeleteLine, "ForwardDeleteLine") }, - { Keys.CtrlHome, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") }, - { Keys.CtrlRBracket, MakeKeyHandler(GotoBrace, "GotoBrace") }, - { Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") }, - { Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward,"CharacterSearchBackward") }, - { Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") } - }; - _viCmdKeyMap = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.Enter, MakeKeyHandler(ViAcceptLine, "ViAcceptLine") }, - { Keys.CtrlD, MakeKeyHandler(ViAcceptLineOrExit, "ViAcceptLineOrExit") }, - { Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") }, - { Keys.Escape, MakeKeyHandler(Ding, "Ignore") }, - { Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") }, - { Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") }, - { Keys.Space, MakeKeyHandler(ForwardChar, "ForwardChar") }, - { Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") }, - { Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") }, - { Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, - { Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") }, - { Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") }, - { Keys.End, MakeKeyHandler(MoveToEndOfLine, "MoveToEndOfLine") }, - { Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") }, - { Keys.Backspace, MakeKeyHandler(BackwardChar, "BackwardChar") }, - { Keys.CtrlSpace, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") }, - { Keys.Tab, MakeKeyHandler(TabCompleteNext, "TabCompleteNext") }, - { Keys.ShiftTab, MakeKeyHandler(TabCompletePrevious, "TabCompletePrevious") }, - { Keys.CtrlV, MakeKeyHandler(Paste, "Paste") }, -#if !UNIX - { Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") }, - { Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") }, -#endif - { Keys.CtrlC, MakeKeyHandler(CancelLine, "CancelLine") }, - { Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") }, - { Keys.CtrlT, MakeKeyHandler(SwapCharacters, "SwapCharacters") }, - { Keys.CtrlU, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") }, - { Keys.CtrlW, MakeKeyHandler(BackwardDeleteWord, "BackwardDeleteWord") }, - { Keys.CtrlY, MakeKeyHandler(Redo, "Redo") }, - { Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") }, - { Keys.CtrlBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") }, - { Keys.CtrlDelete, MakeKeyHandler(KillWord, "KillWord") }, - { Keys.CtrlEnd, MakeKeyHandler(ForwardDeleteLine, "ForwardDeleteLine") }, - { Keys.CtrlHome, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") }, - { Keys.CtrlRBracket, MakeKeyHandler(GotoBrace, "GotoBrace") }, - { Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") }, - { Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") }, - { Keys.A, MakeKeyHandler(ViInsertWithAppend, "ViInsertWithAppend") }, - { Keys.B, MakeKeyHandler(ViBackwardWord, "ViBackwardWord") }, - { Keys.C, MakeKeyHandler(ViChord, "ChordFirstKey") }, - { Keys.D, MakeKeyHandler(ViChord, "ChordFirstKey") }, - { Keys.E, MakeKeyHandler(NextWordEnd, "NextWordEnd") }, - { Keys.F, MakeKeyHandler(SearchChar, "SearchChar") }, - { Keys.G, MakeKeyHandler(Ding, "Ignore") }, - { Keys.H, MakeKeyHandler(BackwardChar, "BackwardChar") }, - { Keys.I, MakeKeyHandler(ViInsertMode, "ViInsertMode") }, - { Keys.J, MakeKeyHandler(NextHistory, "NextHistory") }, - { Keys.K, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, - { Keys.L, MakeKeyHandler(ForwardChar, "ForwardChar") }, - { Keys.M, MakeKeyHandler(Ding, "Ignore") }, - { Keys.N, MakeKeyHandler(RepeatSearch, "RepeatSearch") }, - { Keys.O, MakeKeyHandler(ViAppendLine, "ViAppendLine") }, - { Keys.P, MakeKeyHandler(PasteAfter, "PasteAfter") }, - { Keys.Q, MakeKeyHandler(Ding, "Ignore") }, - { Keys.R, MakeKeyHandler(ReplaceCharInPlace, "ReplaceCharInPlace") }, - { Keys.S, MakeKeyHandler(ViInsertWithDelete, "ViInsertWithDelete") }, - { Keys.T, MakeKeyHandler(SearchCharWithBackoff,"SearchCharWithBackoff") }, - { Keys.U, MakeKeyHandler(Undo, "Undo") }, - { Keys.V, MakeKeyHandler(ViEditVisually, "ViEditVisually") }, - { Keys.W, MakeKeyHandler(ViNextWord, "ViNextWord") }, - { Keys.X, MakeKeyHandler(DeleteChar, "DeleteChar") }, - { Keys.Y, MakeKeyHandler(ViChord, "ChordFirstKey") }, - { Keys.Z, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucA, MakeKeyHandler(ViInsertAtEnd, "ViInsertAtEnd") }, - { Keys.ucB, MakeKeyHandler(ViBackwardGlob, "ViBackwardGlob") }, - { Keys.ucC, MakeKeyHandler(ViReplaceToEnd, "ViReplaceToEnd") }, - { Keys.ucD, MakeKeyHandler(DeleteToEnd, "DeleteToEnd") }, - { Keys.ucE, MakeKeyHandler(ViEndOfGlob, "ViEndOfGlob") }, - { Keys.ucF, MakeKeyHandler(SearchCharBackward, "SearchCharBackward") }, - { Keys.ucG, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucH, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucI, MakeKeyHandler(ViInsertAtBegining, "ViInsertAtBegining") }, - { Keys.ucJ, MakeKeyHandler(ViJoinLines, "ViJoinLines") }, - { Keys.ucK, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucL, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucM, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucN, MakeKeyHandler(RepeatSearchBackward, "RepeatSearchBackward") }, - { Keys.ucO, MakeKeyHandler(ViInsertLine, "ViInsertLine") }, - { Keys.ucP, MakeKeyHandler(PasteBefore, "PasteBefore") }, - { Keys.ucQ, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucR, MakeKeyHandler(ViReplaceUntilEsc, "ViReplaceUntilEsc") }, - { Keys.ucS, MakeKeyHandler(ViReplaceLine, "ViReplaceLine") }, - { Keys.ucT, MakeKeyHandler(SearchCharBackwardWithBackoff, "SearchCharBackwardWithBackoff") }, - { Keys.ucU, MakeKeyHandler(UndoAll, "UndoAll") }, - { Keys.ucV, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucW, MakeKeyHandler(ViNextGlob, "ViNextGlob") }, - { Keys.ucX, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") }, - { Keys.ucY, MakeKeyHandler(Ding, "Ignore") }, - { Keys.ucZ, MakeKeyHandler(Ding, "Ignore") }, - { Keys._0, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._1, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._2, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._3, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._4, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._5, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._6, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._7, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._8, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys._9, MakeKeyHandler(DigitArgument, "DigitArgument") }, - { Keys.Dollar, MakeKeyHandler(MoveToEndOfLine, "MoveToEndOfLine") }, - { Keys.Percent, MakeKeyHandler(ViGotoBrace, "ViGotoBrace") }, - { Keys.Pound, MakeKeyHandler(PrependAndAccept, "PrependAndAccept") }, - { Keys.Pipe, MakeKeyHandler(GotoColumn, "GotoColumn") }, - { Keys.Uphat, MakeKeyHandler(GotoFirstNonBlankOfLine, "GotoFirstNonBlankOfLine") }, - { Keys.Tilde, MakeKeyHandler(InvertCase, "InvertCase") }, - { Keys.Slash, MakeKeyHandler(ViSearchHistoryBackward, "SearchBackward") }, - { Keys.CtrlR, MakeKeyHandler(SearchCharBackward, "SearchCharBackward") }, - { Keys.Question, MakeKeyHandler(SearchForward, "SearchForward") }, - { Keys.CtrlS, MakeKeyHandler(SearchForward, "SearchForward") }, - { Keys.Plus, MakeKeyHandler(NextHistory, "NextHistory") }, - { Keys.Minus, MakeKeyHandler(PreviousHistory, "PreviousHistory") }, - { Keys.Period, MakeKeyHandler(RepeatLastCommand, "RepeatLastCommand") }, - { Keys.Semicolon, MakeKeyHandler(RepeatLastCharSearch, "RepeatLastCharSearch") }, - { Keys.Comma, MakeKeyHandler(RepeatLastCharSearchBackwards, "RepeatLastCharSearchBackwards") } - }; - - _viChordDTable = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.D, MakeKeyHandler( DeleteLine, "DeleteLine") }, - { Keys.Dollar, MakeKeyHandler( DeleteToEnd, "DeleteToEnd") }, - { Keys.B, MakeKeyHandler( BackwardDeleteWord, "BackwardDeleteWord") }, - { Keys.ucB, MakeKeyHandler( ViBackwardDeleteGlob, "ViBackwardDeleteGlob") }, - { Keys.W, MakeKeyHandler( DeleteWord, "DeleteWord") }, - { Keys.ucW, MakeKeyHandler( ViDeleteGlob, "ViDeleteGlob") }, - { Keys.E, MakeKeyHandler( DeleteEndOfWord, "DeleteEndOfWord") }, - { Keys.ucE, MakeKeyHandler( ViDeleteEndOfGlob, "ViDeleteEndOfGlob") }, - { Keys.H, MakeKeyHandler( BackwardDeleteChar, "BackwardDeleteChar") }, - { Keys.L, MakeKeyHandler( DeleteChar, "DeleteChar") }, - { Keys.Space, MakeKeyHandler( DeleteChar, "DeleteChar") }, - { Keys._0, MakeKeyHandler( BackwardDeleteLine, "BackwardDeleteLine") }, - { Keys.Uphat, MakeKeyHandler( DeleteLineToFirstChar, "DeleteLineToFirstChar") }, - { Keys.Percent, MakeKeyHandler( ViDeleteBrace, "DeleteBrace") }, - { Keys.F, MakeKeyHandler( ViDeleteToChar, "ViDeleteToChar") }, - { Keys.ucF, MakeKeyHandler( ViDeleteToCharBackward, "ViDeleteToCharBackward") }, - { Keys.T, MakeKeyHandler( ViDeleteToBeforeChar, "ViDeleteToBeforeChar") }, - { Keys.ucT, MakeKeyHandler( ViDeleteToBeforeCharBackward, "ViDeleteToBeforeCharBackward") }, - }; - - _viChordCTable = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.C, MakeKeyHandler( ViReplaceLine, "ViReplaceLine") }, - { Keys.Dollar, MakeKeyHandler( ViReplaceToEnd, "ViReplaceToEnd") }, - { Keys.B, MakeKeyHandler( ViBackwardReplaceWord, "ViBackwardReplaceWord") }, - { Keys.ucB, MakeKeyHandler( ViBackwardReplaceGlob, "ViBackwardReplaceGlob") }, - { Keys.W, MakeKeyHandler( ViReplaceWord, "ViReplaceWord") }, - { Keys.ucW, MakeKeyHandler( ViReplaceGlob, "ViReplaceGlob") }, - { Keys.E, MakeKeyHandler( ViReplaceEndOfWord, "ViReplaceEndOfWord") }, - { Keys.ucE, MakeKeyHandler( ViReplaceEndOfGlob, "ViReplaceEndOfGlob") }, - { Keys.H, MakeKeyHandler( BackwardReplaceChar, "BackwardReplaceChar") }, - { Keys.L, MakeKeyHandler( ReplaceChar, "ReplaceChar") }, - { Keys.Space, MakeKeyHandler( ReplaceChar, "ReplaceChar") }, - { Keys._0, MakeKeyHandler( ViBackwardReplaceLine, "ViBackwardReplaceLine") }, - { Keys.Uphat, MakeKeyHandler( ViBackwardReplaceLineToFirstChar, "ViBackwardReplaceLineToFirstChar") }, - { Keys.Percent, MakeKeyHandler( ViReplaceBrace, "ViReplaceBrace") }, - { Keys.F, MakeKeyHandler( ViReplaceToChar, "ViReplaceToChar") }, - { Keys.ucF, MakeKeyHandler( ViReplaceToCharBackward, "ViReplaceToCharBackward") }, - { Keys.T, MakeKeyHandler( ViReplaceToBeforeChar, "ViReplaceToBeforeChar") }, - { Keys.ucT, MakeKeyHandler( ViReplaceToBeforeCharBackward, "ViReplaceToBeforeCharBackward") }, - }; - - _viChordYTable = new Dictionary(new ConsoleKeyInfoComparer()) - { - { Keys.Y, MakeKeyHandler( ViYankLine, "ViYankLine") }, - { Keys.Dollar, MakeKeyHandler( ViYankToEndOfLine, "ViYankToEndOfLine") }, - { Keys.B, MakeKeyHandler( ViYankPreviousWord, "ViYankPreviousWord") }, - { Keys.ucB, MakeKeyHandler( ViYankPreviousGlob, "ViYankPreviousGlob") }, - { Keys.W, MakeKeyHandler( ViYankNextWord, "ViYankNextWord") }, - { Keys.ucW, MakeKeyHandler( ViYankNextGlob, "ViYankNextGlob") }, - { Keys.E, MakeKeyHandler( ViYankEndOfWord, "ViYankEndOfWord") }, - { Keys.ucE, MakeKeyHandler( ViYankEndOfGlob, "ViYankEndOfGlob") }, - { Keys.H, MakeKeyHandler( ViYankLeft, "ViYankLeft") }, - { Keys.L, MakeKeyHandler( ViYankRight, "ViYankRight") }, - { Keys.Space, MakeKeyHandler( ViYankRight, "ViYankRight") }, - { Keys._0, MakeKeyHandler( ViYankBeginningOfLine, "ViYankBeginningOfLine") }, - { Keys.Uphat, MakeKeyHandler( ViYankToFirstChar, "ViYankToFirstChar") }, - { Keys.Percent, MakeKeyHandler( ViYankPercent, "ViYankPercent") }, - }; - - _viCmdChordTable = new Dictionary>(); - _viInsChordTable = new Dictionary>(); - - _dispatchTable = _viInsKeyMap; - _chordDispatchTable = _viInsChordTable; - _viCmdChordTable[Keys.D] = _viChordDTable; - _viCmdChordTable[Keys.C] = _viChordCTable; - _viCmdChordTable[Keys.Y] = _viChordYTable; - - _normalCursorSize = _console.CursorSize; - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Keys.cs b/src/Microsoft.PowerShell.PSReadLine/Keys.cs deleted file mode 100644 index df66e6baae5b..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Keys.cs +++ /dev/null @@ -1,299 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; - -namespace Microsoft.PowerShell -{ - internal static class Keys - { - public static ConsoleKeyInfo A = new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false); - public static ConsoleKeyInfo B = new ConsoleKeyInfo('b', ConsoleKey.B, false, false, false); - public static ConsoleKeyInfo C = new ConsoleKeyInfo('c', ConsoleKey.C, false, false, false); - public static ConsoleKeyInfo D = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false); - public static ConsoleKeyInfo E = new ConsoleKeyInfo('e', ConsoleKey.E, false, false, false); - public static ConsoleKeyInfo F = new ConsoleKeyInfo('f', ConsoleKey.F, false, false, false); - public static ConsoleKeyInfo G = new ConsoleKeyInfo('g', ConsoleKey.G, false, false, false); - public static ConsoleKeyInfo H = new ConsoleKeyInfo('h', ConsoleKey.H, false, false, false); - public static ConsoleKeyInfo I = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false); - public static ConsoleKeyInfo J = new ConsoleKeyInfo('j', ConsoleKey.J, false, false, false); - public static ConsoleKeyInfo K = new ConsoleKeyInfo('k', ConsoleKey.K, false, false, false); - public static ConsoleKeyInfo L = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false); - public static ConsoleKeyInfo M = new ConsoleKeyInfo('m', ConsoleKey.M, false, false, false); - public static ConsoleKeyInfo N = new ConsoleKeyInfo('n', ConsoleKey.N, false, false, false); - public static ConsoleKeyInfo O = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false); - public static ConsoleKeyInfo P = new ConsoleKeyInfo('p', ConsoleKey.P, false, false, false); - public static ConsoleKeyInfo Q = new ConsoleKeyInfo('q', ConsoleKey.Q, false, false, false); - public static ConsoleKeyInfo R = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false); - public static ConsoleKeyInfo S = new ConsoleKeyInfo('s', ConsoleKey.S, false, false, false); - public static ConsoleKeyInfo T = new ConsoleKeyInfo('t', ConsoleKey.T, false, false, false); - public static ConsoleKeyInfo U = new ConsoleKeyInfo('u', ConsoleKey.U, false, false, false); - public static ConsoleKeyInfo V = new ConsoleKeyInfo('v', ConsoleKey.V, false, false, false); - public static ConsoleKeyInfo W = new ConsoleKeyInfo('w', ConsoleKey.W, false, false, false); - public static ConsoleKeyInfo X = new ConsoleKeyInfo('x', ConsoleKey.X, false, false, false); - public static ConsoleKeyInfo Y = new ConsoleKeyInfo('y', ConsoleKey.Y, false, false, false); - public static ConsoleKeyInfo Z = new ConsoleKeyInfo('z', ConsoleKey.Z, false, false, false); - public static ConsoleKeyInfo ucA = new ConsoleKeyInfo('A', ConsoleKey.A, true, false, false); - public static ConsoleKeyInfo ucB = new ConsoleKeyInfo('B', ConsoleKey.B, true, false, false); - public static ConsoleKeyInfo ucC = new ConsoleKeyInfo('C', ConsoleKey.C, true, false, false); - public static ConsoleKeyInfo ucD = new ConsoleKeyInfo('D', ConsoleKey.D, true, false, false); - public static ConsoleKeyInfo ucE = new ConsoleKeyInfo('E', ConsoleKey.E, true, false, false); - public static ConsoleKeyInfo ucF = new ConsoleKeyInfo('F', ConsoleKey.F, true, false, false); - public static ConsoleKeyInfo ucG = new ConsoleKeyInfo('G', ConsoleKey.G, true, false, false); - public static ConsoleKeyInfo ucH = new ConsoleKeyInfo('H', ConsoleKey.H, true, false, false); - public static ConsoleKeyInfo ucI = new ConsoleKeyInfo('I', ConsoleKey.I, true, false, false); - public static ConsoleKeyInfo ucJ = new ConsoleKeyInfo('J', ConsoleKey.J, true, false, false); - public static ConsoleKeyInfo ucK = new ConsoleKeyInfo('K', ConsoleKey.K, true, false, false); - public static ConsoleKeyInfo ucL = new ConsoleKeyInfo('L', ConsoleKey.L, true, false, false); - public static ConsoleKeyInfo ucM = new ConsoleKeyInfo('M', ConsoleKey.M, true, false, false); - public static ConsoleKeyInfo ucN = new ConsoleKeyInfo('N', ConsoleKey.N, true, false, false); - public static ConsoleKeyInfo ucO = new ConsoleKeyInfo('O', ConsoleKey.O, true, false, false); - public static ConsoleKeyInfo ucP = new ConsoleKeyInfo('P', ConsoleKey.P, true, false, false); - public static ConsoleKeyInfo ucQ = new ConsoleKeyInfo('Q', ConsoleKey.Q, true, false, false); - public static ConsoleKeyInfo ucR = new ConsoleKeyInfo('R', ConsoleKey.R, true, false, false); - public static ConsoleKeyInfo ucS = new ConsoleKeyInfo('S', ConsoleKey.S, true, false, false); - public static ConsoleKeyInfo ucT = new ConsoleKeyInfo('T', ConsoleKey.T, true, false, false); - public static ConsoleKeyInfo ucU = new ConsoleKeyInfo('U', ConsoleKey.U, true, false, false); - public static ConsoleKeyInfo ucV = new ConsoleKeyInfo('V', ConsoleKey.V, true, false, false); - public static ConsoleKeyInfo ucW = new ConsoleKeyInfo('W', ConsoleKey.W, true, false, false); - public static ConsoleKeyInfo ucX = new ConsoleKeyInfo('X', ConsoleKey.X, true, false, false); - public static ConsoleKeyInfo ucY = new ConsoleKeyInfo('Y', ConsoleKey.Y, true, false, false); - public static ConsoleKeyInfo ucZ = new ConsoleKeyInfo('Z', ConsoleKey.Z, true, false, false); - - public static ConsoleKeyInfo _0 = new ConsoleKeyInfo('0', ConsoleKey.D0, false, false, false); - public static ConsoleKeyInfo _1 = new ConsoleKeyInfo('1', ConsoleKey.D1, false, false, false); - public static ConsoleKeyInfo _2 = new ConsoleKeyInfo('2', ConsoleKey.D2, false, false, false); - public static ConsoleKeyInfo _3 = new ConsoleKeyInfo('3', ConsoleKey.D3, false, false, false); - public static ConsoleKeyInfo _4 = new ConsoleKeyInfo('4', ConsoleKey.D4, false, false, false); - public static ConsoleKeyInfo _5 = new ConsoleKeyInfo('5', ConsoleKey.D5, false, false, false); - public static ConsoleKeyInfo _6 = new ConsoleKeyInfo('6', ConsoleKey.D6, false, false, false); - public static ConsoleKeyInfo _7 = new ConsoleKeyInfo('7', ConsoleKey.D7, false, false, false); - public static ConsoleKeyInfo _8 = new ConsoleKeyInfo('8', ConsoleKey.D8, false, false, false); - public static ConsoleKeyInfo _9 = new ConsoleKeyInfo('9', ConsoleKey.D9, false, false, false); - - public static ConsoleKeyInfo RParen = new ConsoleKeyInfo(')', ConsoleKey.D0, true, false, false); - public static ConsoleKeyInfo Bang = new ConsoleKeyInfo('!', ConsoleKey.D1, true, false, false); - public static ConsoleKeyInfo At = new ConsoleKeyInfo('@', ConsoleKey.D2, true, false, false); - public static ConsoleKeyInfo Pound = new ConsoleKeyInfo('#', ConsoleKey.D3, true, false, false); - public static ConsoleKeyInfo Dollar = new ConsoleKeyInfo('$', ConsoleKey.D4, true, false, false); - public static ConsoleKeyInfo Percent = new ConsoleKeyInfo('%', ConsoleKey.D5, true, false, false); - public static ConsoleKeyInfo Uphat = new ConsoleKeyInfo('^', ConsoleKey.D6, true, false, false); - public static ConsoleKeyInfo Ampersand = new ConsoleKeyInfo('&', ConsoleKey.D7, true, false, false); - public static ConsoleKeyInfo Star = new ConsoleKeyInfo('*', ConsoleKey.D8, true, false, false); - public static ConsoleKeyInfo LParen = new ConsoleKeyInfo('(', ConsoleKey.D9, true, false, false); - - public static ConsoleKeyInfo Colon = new ConsoleKeyInfo(':', ConsoleKey.Oem1, true, false, false); - public static ConsoleKeyInfo Semicolon = new ConsoleKeyInfo(';', ConsoleKey.Oem1, false, false, false); - public static ConsoleKeyInfo Question = new ConsoleKeyInfo('?', ConsoleKey.Oem2, true, false, false); - public static ConsoleKeyInfo Slash = new ConsoleKeyInfo('/', ConsoleKey.Oem2, false, false, false); - public static ConsoleKeyInfo Tilde = new ConsoleKeyInfo('~', ConsoleKey.Oem3, true, false, false); - public static ConsoleKeyInfo Backtick = new ConsoleKeyInfo('`', ConsoleKey.Oem3, false, false, false); - public static ConsoleKeyInfo LCurly = new ConsoleKeyInfo('{', ConsoleKey.Oem4, true, false, false); - public static ConsoleKeyInfo LBracket = new ConsoleKeyInfo('[', ConsoleKey.Oem4, false, false, false); - public static ConsoleKeyInfo Pipe = new ConsoleKeyInfo('|', ConsoleKey.Oem5, true, false, false); - public static ConsoleKeyInfo Backslash = new ConsoleKeyInfo('\\', ConsoleKey.Oem5, false, false, false); - public static ConsoleKeyInfo RCurly = new ConsoleKeyInfo('}', ConsoleKey.Oem6, true, false, false); - public static ConsoleKeyInfo RBracket = new ConsoleKeyInfo(']', ConsoleKey.Oem6, false, false, false); - public static ConsoleKeyInfo SQuote = new ConsoleKeyInfo('\'', ConsoleKey.Oem7, false, false, false); - public static ConsoleKeyInfo DQuote = new ConsoleKeyInfo('"', ConsoleKey.Oem7, true, false, false); - public static ConsoleKeyInfo LessThan = new ConsoleKeyInfo('<', ConsoleKey.OemComma, true, false, false); - public static ConsoleKeyInfo Comma = new ConsoleKeyInfo(',', ConsoleKey.OemComma, false, false, false); - public static ConsoleKeyInfo GreaterThan = new ConsoleKeyInfo('>', ConsoleKey.OemPeriod, true, false, false); - public static ConsoleKeyInfo Period = new ConsoleKeyInfo('.', ConsoleKey.OemPeriod, false, false, false); - public static ConsoleKeyInfo Underbar = new ConsoleKeyInfo('_', ConsoleKey.OemMinus, true, false, false); - public static ConsoleKeyInfo Minus = new ConsoleKeyInfo('-', ConsoleKey.OemMinus, false, false, false); - public static ConsoleKeyInfo AltMinus = new ConsoleKeyInfo('-', ConsoleKey.OemMinus, false, true, false); - public static ConsoleKeyInfo Plus = new ConsoleKeyInfo('+', ConsoleKey.OemPlus, true, false, false); - new - public static ConsoleKeyInfo Equals = new ConsoleKeyInfo('=', ConsoleKey.OemPlus, false, false, false); - - public static ConsoleKeyInfo CtrlAt = new ConsoleKeyInfo((char)0, ConsoleKey.D2, true, false, true); - public static ConsoleKeyInfo AltUnderbar = new ConsoleKeyInfo('_', ConsoleKey.OemMinus, true, true, false); - public static ConsoleKeyInfo CtrlUnderbar = new ConsoleKeyInfo((char)31, ConsoleKey.OemMinus, true, false, true); - public static ConsoleKeyInfo AltEquals = new ConsoleKeyInfo('=', ConsoleKey.OemPlus, false, true, false); - public static ConsoleKeyInfo Space = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false); - // Useless because it's caught by the console to bring up the system menu. - public static ConsoleKeyInfo AltSpace = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, true, false); - public static ConsoleKeyInfo CtrlSpace = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, true); - public static ConsoleKeyInfo AltLess = new ConsoleKeyInfo('<', ConsoleKey.OemComma, true, true, false); - public static ConsoleKeyInfo AltGreater = new ConsoleKeyInfo('>', ConsoleKey.OemPeriod, true, true, false); - public static ConsoleKeyInfo CtrlRBracket = new ConsoleKeyInfo((char)29, ConsoleKey.Oem6, false, false, true); - public static ConsoleKeyInfo AltCtrlRBracket = new ConsoleKeyInfo((char)0, ConsoleKey.Oem6, false, true, true); - public static ConsoleKeyInfo AltPeriod = new ConsoleKeyInfo('.', ConsoleKey.OemPeriod, false, true, false); - public static ConsoleKeyInfo CtrlAltQuestion = new ConsoleKeyInfo((char)0, ConsoleKey.Oem2, true, true, true); - public static ConsoleKeyInfo AltQuestion = new ConsoleKeyInfo('?', ConsoleKey.Oem2, true, true, false); - - public static ConsoleKeyInfo Alt0 = new ConsoleKeyInfo('0', ConsoleKey.D0, false, true, false); - public static ConsoleKeyInfo Alt1 = new ConsoleKeyInfo('1', ConsoleKey.D1, false, true, false); - public static ConsoleKeyInfo Alt2 = new ConsoleKeyInfo('2', ConsoleKey.D2, false, true, false); - public static ConsoleKeyInfo Alt3 = new ConsoleKeyInfo('3', ConsoleKey.D3, false, true, false); - public static ConsoleKeyInfo Alt4 = new ConsoleKeyInfo('4', ConsoleKey.D4, false, true, false); - public static ConsoleKeyInfo Alt5 = new ConsoleKeyInfo('5', ConsoleKey.D5, false, true, false); - public static ConsoleKeyInfo Alt6 = new ConsoleKeyInfo('6', ConsoleKey.D6, false, true, false); - public static ConsoleKeyInfo Alt7 = new ConsoleKeyInfo('7', ConsoleKey.D7, false, true, false); - public static ConsoleKeyInfo Alt8 = new ConsoleKeyInfo('8', ConsoleKey.D8, false, true, false); - public static ConsoleKeyInfo Alt9 = new ConsoleKeyInfo('9', ConsoleKey.D9, false, true, false); - - public static ConsoleKeyInfo AltA = new ConsoleKeyInfo((char)97, ConsoleKey.A, false, true, false); - public static ConsoleKeyInfo AltB = new ConsoleKeyInfo((char)98, ConsoleKey.B, false, true, false); - public static ConsoleKeyInfo AltC = new ConsoleKeyInfo((char)99, ConsoleKey.C, false, true, false); - public static ConsoleKeyInfo AltD = new ConsoleKeyInfo((char)100, ConsoleKey.D, false, true, false); - public static ConsoleKeyInfo AltE = new ConsoleKeyInfo((char)101, ConsoleKey.E, false, true, false); - public static ConsoleKeyInfo AltF = new ConsoleKeyInfo((char)102, ConsoleKey.F, false, true, false); - public static ConsoleKeyInfo AltG = new ConsoleKeyInfo((char)103, ConsoleKey.G, false, true, false); - public static ConsoleKeyInfo AltH = new ConsoleKeyInfo((char)104, ConsoleKey.H, false, true, false); - public static ConsoleKeyInfo AltI = new ConsoleKeyInfo((char)105, ConsoleKey.I, false, true, false); - public static ConsoleKeyInfo AltJ = new ConsoleKeyInfo((char)106, ConsoleKey.J, false, true, false); - public static ConsoleKeyInfo AltK = new ConsoleKeyInfo((char)107, ConsoleKey.K, false, true, false); - public static ConsoleKeyInfo AltL = new ConsoleKeyInfo((char)108, ConsoleKey.L, false, true, false); - public static ConsoleKeyInfo AltM = new ConsoleKeyInfo((char)109, ConsoleKey.M, false, true, false); - public static ConsoleKeyInfo AltN = new ConsoleKeyInfo((char)110, ConsoleKey.N, false, true, false); - public static ConsoleKeyInfo AltO = new ConsoleKeyInfo((char)111, ConsoleKey.O, false, true, false); - public static ConsoleKeyInfo AltP = new ConsoleKeyInfo((char)112, ConsoleKey.P, false, true, false); - public static ConsoleKeyInfo AltQ = new ConsoleKeyInfo((char)113, ConsoleKey.Q, false, true, false); - public static ConsoleKeyInfo AltR = new ConsoleKeyInfo((char)114, ConsoleKey.R, false, true, false); - public static ConsoleKeyInfo AltS = new ConsoleKeyInfo((char)115, ConsoleKey.S, false, true, false); - public static ConsoleKeyInfo AltT = new ConsoleKeyInfo((char)116, ConsoleKey.T, false, true, false); - public static ConsoleKeyInfo AltU = new ConsoleKeyInfo((char)117, ConsoleKey.U, false, true, false); - public static ConsoleKeyInfo AltV = new ConsoleKeyInfo((char)118, ConsoleKey.V, false, true, false); - public static ConsoleKeyInfo AltW = new ConsoleKeyInfo((char)119, ConsoleKey.W, false, true, false); - public static ConsoleKeyInfo AltX = new ConsoleKeyInfo((char)120, ConsoleKey.X, false, true, false); - public static ConsoleKeyInfo AltY = new ConsoleKeyInfo((char)121, ConsoleKey.Y, false, true, false); - public static ConsoleKeyInfo AltZ = new ConsoleKeyInfo((char)122, ConsoleKey.Z, false, true, false); - - public static ConsoleKeyInfo CtrlA = new ConsoleKeyInfo((char)1, ConsoleKey.A, false, false, true); - public static ConsoleKeyInfo CtrlB = new ConsoleKeyInfo((char)2, ConsoleKey.B, false, false, true); - public static ConsoleKeyInfo CtrlC = new ConsoleKeyInfo((char)3, ConsoleKey.C, false, false, true); - public static ConsoleKeyInfo CtrlD = new ConsoleKeyInfo((char)4, ConsoleKey.D, false, false, true); - public static ConsoleKeyInfo CtrlE = new ConsoleKeyInfo((char)5, ConsoleKey.E, false, false, true); - public static ConsoleKeyInfo CtrlF = new ConsoleKeyInfo((char)6, ConsoleKey.F, false, false, true); - public static ConsoleKeyInfo CtrlG = new ConsoleKeyInfo((char)7, ConsoleKey.G, false, false, true); - public static ConsoleKeyInfo CtrlH = new ConsoleKeyInfo((char)8, ConsoleKey.H, false, false, true); - public static ConsoleKeyInfo CtrlI = new ConsoleKeyInfo((char)9, ConsoleKey.I, false, false, true); - public static ConsoleKeyInfo CtrlJ = new ConsoleKeyInfo((char)10, ConsoleKey.J, false, false, true); - public static ConsoleKeyInfo CtrlK = new ConsoleKeyInfo((char)11, ConsoleKey.K, false, false, true); - public static ConsoleKeyInfo CtrlL = new ConsoleKeyInfo((char)12, ConsoleKey.L, false, false, true); - public static ConsoleKeyInfo CtrlM = new ConsoleKeyInfo((char)13, ConsoleKey.M, false, false, true); - public static ConsoleKeyInfo CtrlN = new ConsoleKeyInfo((char)14, ConsoleKey.N, false, false, true); - public static ConsoleKeyInfo CtrlO = new ConsoleKeyInfo((char)15, ConsoleKey.O, false, false, true); - public static ConsoleKeyInfo CtrlP = new ConsoleKeyInfo((char)16, ConsoleKey.P, false, false, true); - public static ConsoleKeyInfo CtrlQ = new ConsoleKeyInfo((char)17, ConsoleKey.Q, false, false, true); - public static ConsoleKeyInfo CtrlR = new ConsoleKeyInfo((char)18, ConsoleKey.R, false, false, true); - public static ConsoleKeyInfo CtrlS = new ConsoleKeyInfo((char)19, ConsoleKey.S, false, false, true); - public static ConsoleKeyInfo CtrlT = new ConsoleKeyInfo((char)20, ConsoleKey.T, false, false, true); - public static ConsoleKeyInfo CtrlU = new ConsoleKeyInfo((char)21, ConsoleKey.U, false, false, true); - public static ConsoleKeyInfo CtrlV = new ConsoleKeyInfo((char)22, ConsoleKey.V, false, false, true); - public static ConsoleKeyInfo CtrlW = new ConsoleKeyInfo((char)23, ConsoleKey.W, false, false, true); - public static ConsoleKeyInfo CtrlX = new ConsoleKeyInfo((char)24, ConsoleKey.X, false, false, true); - public static ConsoleKeyInfo CtrlY = new ConsoleKeyInfo((char)25, ConsoleKey.Y, false, false, true); - public static ConsoleKeyInfo CtrlZ = new ConsoleKeyInfo((char)26, ConsoleKey.Z, false, false, true); - - public static ConsoleKeyInfo CtrlShiftC = new ConsoleKeyInfo((char)3, ConsoleKey.C, true, false, true); - - public static ConsoleKeyInfo AltShiftB = new ConsoleKeyInfo('B', ConsoleKey.B, true, true, false); - public static ConsoleKeyInfo AltShiftF = new ConsoleKeyInfo('F', ConsoleKey.F, true, true, false); - - public static ConsoleKeyInfo AltCtrlY = new ConsoleKeyInfo((char)0, ConsoleKey.Y, false, true, true); - - public static ConsoleKeyInfo Backspace = new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false); - public static ConsoleKeyInfo CtrlBackspace = new ConsoleKeyInfo((char)0x7f, ConsoleKey.Backspace, false, false, true); - public static ConsoleKeyInfo AltBackspace = new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, true, false); - public static ConsoleKeyInfo Delete = new ConsoleKeyInfo((char)0, ConsoleKey.Delete, false, false, false); - public static ConsoleKeyInfo CtrlDelete = new ConsoleKeyInfo((char)0, ConsoleKey.Delete, false, false, true); - public static ConsoleKeyInfo DownArrow = new ConsoleKeyInfo((char)0, ConsoleKey.DownArrow, false, false, false); - public static ConsoleKeyInfo End = new ConsoleKeyInfo((char)0, ConsoleKey.End, false, false, false); - public static ConsoleKeyInfo CtrlEnd = new ConsoleKeyInfo((char)0, ConsoleKey.End, false, false, true); - public static ConsoleKeyInfo ShiftEnd = new ConsoleKeyInfo((char)0, ConsoleKey.End, true, false, false); - public static ConsoleKeyInfo Enter = new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false); - public static ConsoleKeyInfo Escape = new ConsoleKeyInfo((char)27, ConsoleKey.Escape, false, false, false); - public static ConsoleKeyInfo Home = new ConsoleKeyInfo((char)0, ConsoleKey.Home, false, false, false); - public static ConsoleKeyInfo CtrlHome = new ConsoleKeyInfo((char)0, ConsoleKey.Home, false, false, true); - public static ConsoleKeyInfo ShiftHome = new ConsoleKeyInfo((char)0, ConsoleKey.Home, true, false, false); - public static ConsoleKeyInfo LeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, false, false, false); - public static ConsoleKeyInfo RightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, false, false, false); - public static ConsoleKeyInfo Tab = new ConsoleKeyInfo((char)9, ConsoleKey.Tab, false, false, false); - public static ConsoleKeyInfo UpArrow = new ConsoleKeyInfo((char)0, ConsoleKey.UpArrow, false, false, false); - public static ConsoleKeyInfo PageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, false, false, false); - public static ConsoleKeyInfo PageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, false, false, false); - public static ConsoleKeyInfo ShiftPageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, true, false, false); - public static ConsoleKeyInfo ShiftPageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, true, false, false); - public static ConsoleKeyInfo CtrlPageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, false, false, true); - public static ConsoleKeyInfo CtrlPageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, false, false, true); - public static ConsoleKeyInfo AltPageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, false, true, false); - public static ConsoleKeyInfo AltPageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, false, true, false); - - public static ConsoleKeyInfo ShiftLeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, true, false, false); - public static ConsoleKeyInfo ShiftRightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, true, false, false); - public static ConsoleKeyInfo CtrlLeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, false, false, true); - public static ConsoleKeyInfo CtrlRightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, false, false, true); - public static ConsoleKeyInfo ShiftCtrlLeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, true, false, true); - public static ConsoleKeyInfo ShiftCtrlRightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, true, false, true); - - public static ConsoleKeyInfo ShiftTab = new ConsoleKeyInfo((char)9, ConsoleKey.Tab, true, false, false); - - public static ConsoleKeyInfo CtrlEnter = new ConsoleKeyInfo((char)10, ConsoleKey.Enter, false, false, true); - public static ConsoleKeyInfo CtrlShiftEnter = new ConsoleKeyInfo((char)0, ConsoleKey.Enter, true, false, true); - public static ConsoleKeyInfo ShiftEnter = new ConsoleKeyInfo((char)13, ConsoleKey.Enter, true, false, false); - - public static ConsoleKeyInfo F1 = new ConsoleKeyInfo((char)0, ConsoleKey.F1, false, false, false); - public static ConsoleKeyInfo F2 = new ConsoleKeyInfo((char)0, ConsoleKey.F2, false, false, false); - public static ConsoleKeyInfo F3 = new ConsoleKeyInfo((char)0, ConsoleKey.F3, false, false, false); - public static ConsoleKeyInfo F4 = new ConsoleKeyInfo((char)0, ConsoleKey.F4, false, false, false); - public static ConsoleKeyInfo F5 = new ConsoleKeyInfo((char)0, ConsoleKey.F5, false, false, false); - public static ConsoleKeyInfo F6 = new ConsoleKeyInfo((char)0, ConsoleKey.F6, false, false, false); - public static ConsoleKeyInfo F7 = new ConsoleKeyInfo((char)0, ConsoleKey.F7, false, false, false); - public static ConsoleKeyInfo F8 = new ConsoleKeyInfo((char)0, ConsoleKey.F8, false, false, false); - public static ConsoleKeyInfo F9 = new ConsoleKeyInfo((char)0, ConsoleKey.F9, false, false, false); - public static ConsoleKeyInfo Fl0 = new ConsoleKeyInfo((char)0, ConsoleKey.F10, false, false, false); - public static ConsoleKeyInfo F11 = new ConsoleKeyInfo((char)0, ConsoleKey.F11, false, false, false); - public static ConsoleKeyInfo F12 = new ConsoleKeyInfo((char)0, ConsoleKey.F12, false, false, false); - public static ConsoleKeyInfo F13 = new ConsoleKeyInfo((char)0, ConsoleKey.F13, false, false, false); - public static ConsoleKeyInfo F14 = new ConsoleKeyInfo((char)0, ConsoleKey.F14, false, false, false); - public static ConsoleKeyInfo F15 = new ConsoleKeyInfo((char)0, ConsoleKey.F15, false, false, false); - public static ConsoleKeyInfo F16 = new ConsoleKeyInfo((char)0, ConsoleKey.F16, false, false, false); - public static ConsoleKeyInfo F17 = new ConsoleKeyInfo((char)0, ConsoleKey.F17, false, false, false); - public static ConsoleKeyInfo F18 = new ConsoleKeyInfo((char)0, ConsoleKey.F18, false, false, false); - public static ConsoleKeyInfo F19 = new ConsoleKeyInfo((char)0, ConsoleKey.F19, false, false, false); - public static ConsoleKeyInfo F20 = new ConsoleKeyInfo((char)0, ConsoleKey.F20, false, false, false); - public static ConsoleKeyInfo F21 = new ConsoleKeyInfo((char)0, ConsoleKey.F21, false, false, false); - public static ConsoleKeyInfo F22 = new ConsoleKeyInfo((char)0, ConsoleKey.F22, false, false, false); - public static ConsoleKeyInfo F23 = new ConsoleKeyInfo((char)0, ConsoleKey.F23, false, false, false); - public static ConsoleKeyInfo F24 = new ConsoleKeyInfo((char)0, ConsoleKey.F24, false, false, false); - - public static ConsoleKeyInfo AltF1 = new ConsoleKeyInfo((char)0, ConsoleKey.F1, false, true, false); - public static ConsoleKeyInfo AltF2 = new ConsoleKeyInfo((char)0, ConsoleKey.F2, false, true, false); - public static ConsoleKeyInfo AltF3 = new ConsoleKeyInfo((char)0, ConsoleKey.F3, false, true, false); - public static ConsoleKeyInfo AltF4 = new ConsoleKeyInfo((char)0, ConsoleKey.F4, false, true, false); - public static ConsoleKeyInfo AltF5 = new ConsoleKeyInfo((char)0, ConsoleKey.F5, false, true, false); - public static ConsoleKeyInfo AltF6 = new ConsoleKeyInfo((char)0, ConsoleKey.F6, false, true, false); - public static ConsoleKeyInfo AltF7 = new ConsoleKeyInfo((char)0, ConsoleKey.F7, false, true, false); - public static ConsoleKeyInfo AltF8 = new ConsoleKeyInfo((char)0, ConsoleKey.F8, false, true, false); - public static ConsoleKeyInfo AltF9 = new ConsoleKeyInfo((char)0, ConsoleKey.F9, false, true, false); - public static ConsoleKeyInfo AltFl0 = new ConsoleKeyInfo((char)0, ConsoleKey.F10, false, true, false); - public static ConsoleKeyInfo AltF11 = new ConsoleKeyInfo((char)0, ConsoleKey.F11, false, true, false); - public static ConsoleKeyInfo AltF12 = new ConsoleKeyInfo((char)0, ConsoleKey.F12, false, true, false); - public static ConsoleKeyInfo AltF13 = new ConsoleKeyInfo((char)0, ConsoleKey.F13, false, true, false); - public static ConsoleKeyInfo AltF14 = new ConsoleKeyInfo((char)0, ConsoleKey.F14, false, true, false); - public static ConsoleKeyInfo AltF15 = new ConsoleKeyInfo((char)0, ConsoleKey.F15, false, true, false); - public static ConsoleKeyInfo AltF16 = new ConsoleKeyInfo((char)0, ConsoleKey.F16, false, true, false); - public static ConsoleKeyInfo AltF17 = new ConsoleKeyInfo((char)0, ConsoleKey.F17, false, true, false); - public static ConsoleKeyInfo AltF18 = new ConsoleKeyInfo((char)0, ConsoleKey.F18, false, true, false); - public static ConsoleKeyInfo AltF19 = new ConsoleKeyInfo((char)0, ConsoleKey.F19, false, true, false); - public static ConsoleKeyInfo AltF20 = new ConsoleKeyInfo((char)0, ConsoleKey.F20, false, true, false); - public static ConsoleKeyInfo AltF21 = new ConsoleKeyInfo((char)0, ConsoleKey.F21, false, true, false); - public static ConsoleKeyInfo AltF22 = new ConsoleKeyInfo((char)0, ConsoleKey.F22, false, true, false); - public static ConsoleKeyInfo AltF23 = new ConsoleKeyInfo((char)0, ConsoleKey.F23, false, true, false); - public static ConsoleKeyInfo AltF24 = new ConsoleKeyInfo((char)0, ConsoleKey.F24, false, true, false); - - public static ConsoleKeyInfo ShiftF3 = new ConsoleKeyInfo((char)0, ConsoleKey.F3, true, false, false); - public static ConsoleKeyInfo ShiftF8 = new ConsoleKeyInfo((char)0, ConsoleKey.F8, true, false, false); - - // Keys to ignore -#if !UNIX - public static ConsoleKeyInfo VolumeUp = new ConsoleKeyInfo((char)0, /*ConsoleKey.VolumeUp*/(ConsoleKey)175, false, false, false); - public static ConsoleKeyInfo VolumeDown = new ConsoleKeyInfo((char)0, /*ConsoleKey.VolumeDown*/(ConsoleKey)174, false, false, false); - public static ConsoleKeyInfo VolumeMute = new ConsoleKeyInfo((char)0, /*ConsoleKey.VolumeMute*/(ConsoleKey)173, false, false, false); -#endif - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/KillYank.cs b/src/Microsoft.PowerShell.PSReadLine/KillYank.cs deleted file mode 100644 index b06be4cc9284..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/KillYank.cs +++ /dev/null @@ -1,565 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation.Language; -#if !CORECLR // TODO: clipboard -using System.Windows.Forms; -#endif - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - // Yank/Kill state - private List _killRing; - private int _killIndex; - private int _killCommandCount; - private int _yankCommandCount; - private int _yankStartPoint; - private int _yankLastArgCommandCount; - class YankLastArgState - { - internal int argument; - internal int historyIndex; - internal int historyIncrement; - internal int startPoint = -1; - } - private YankLastArgState _yankLastArgState; - private int _visualSelectionCommandCount; - - /// - /// Mark the current location of the cursor for use in a subsequent editing command. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SetMark(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._mark = _singleton._current; - } - - /// - /// The cursor is placed at the location of the mark and the mark is moved - /// to the location of the cursor. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ExchangePointAndMark(ConsoleKeyInfo? key = null, object arg = null) - { - var tmp = _singleton._mark; - _singleton._mark = _singleton._current; - _singleton._current = tmp; - _singleton.PlaceCursor(); - } - - /// - /// The contents of the kill ring are cleared. - /// - public static void ClearKillRing() - { - if (_singleton._killRing != null) - { - _singleton._killRing.Clear(); - } - _singleton._killIndex = -1; // So first add indexes 0. - } - - private void Kill(int start, int length, bool prepend) - { - if (length > 0) - { - var killText = _buffer.ToString(start, length); - SaveEditItem(EditItemDelete.Create(killText, start)); - _buffer.Remove(start, length); - _current = start; - Render(); - if (_killCommandCount > 0) - { - if (prepend) - { - _killRing[_killIndex] = killText + _killRing[_killIndex]; - } - else - { - _killRing[_killIndex] += killText; - } - } - else - { - if (_killRing.Count < Options.MaximumKillRingCount) - { - _killRing.Add(killText); - _killIndex = _killRing.Count - 1; - } - else - { - _killIndex += 1; - if (_killIndex == _killRing.Count) - { - _killIndex = 0; - } - _killRing[_killIndex] = killText; - } - } - } - _killCommandCount += 1; - } - - /// - /// Clear the input from the cursor to the end of the input. The cleared text is placed - /// in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void KillLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.Kill(_singleton._current, _singleton._buffer.Length - _singleton._current, false); - } - - /// - /// Clear the input from the start of the input to the cursor. The cleared text is placed - /// in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BackwardKillLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.Kill(0, _singleton._current, true); - } - - /// - /// Clear the input from the cursor to the end of the current word. If the cursor - /// is between words, the input is cleared from the cursor to the end of the next word. - /// The cleared text is placed in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void KillWord(ConsoleKeyInfo? key = null, object arg = null) - { - int i = _singleton.FindForwardWordPoint(_singleton.Options.WordDelimiters); - _singleton.Kill(_singleton._current, i - _singleton._current, false); - } - - /// - /// Clear the input from the cursor to the end of the current word. If the cursor - /// is between words, the input is cleared from the cursor to the end of the next word. - /// The cleared text is placed in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ShellKillWord(ConsoleKeyInfo? key = null, object arg = null) - { - var token = _singleton.FindToken(_singleton._current, FindTokenMode.CurrentOrNext); - var end = (token.Kind == TokenKind.EndOfInput) - ? _singleton._buffer.Length - : token.Extent.EndOffset; - _singleton.Kill(_singleton._current, end - _singleton._current, false); - } - - /// - /// Clear the input from the start of the current word to the cursor. If the cursor - /// is between words, the input is cleared from the start of the previous word to the - /// cursor. The cleared text is placed in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BackwardKillWord(ConsoleKeyInfo? key = null, object arg = null) - { - int i = _singleton.FindBackwardWordPoint(_singleton.Options.WordDelimiters); - _singleton.Kill(i, _singleton._current - i, true); - } - - /// - /// Clear the input from the start of the current word to the cursor. If the cursor - /// is between words, the input is cleared from the start of the previous word to the - /// cursor. The cleared text is placed in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void UnixWordRubout(ConsoleKeyInfo? key = null, object arg = null) - { - int i = _singleton.FindBackwardWordPoint(""); - _singleton.Kill(i, _singleton._current - i, true); - } - - /// - /// Clear the input from the start of the current word to the cursor. If the cursor - /// is between words, the input is cleared from the start of the previous word to the - /// cursor. The cleared text is placed in the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ShellBackwardKillWord(ConsoleKeyInfo? key = null, object arg = null) - { - var token = _singleton.FindToken(_singleton._current, FindTokenMode.Previous); - var start = token == null - ? 0 - : token.Extent.StartOffset; - _singleton.Kill(start, _singleton._current - start, true); - } - - /// - /// Kill the text between the cursor and the mark. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void KillRegion(ConsoleKeyInfo? key = null, object arg = null) - { - int start, length; - _singleton.GetRegion(out start, out length); - _singleton.Kill(start, length, true); - } - - private void YankImpl() - { - if (_killRing.Count == 0) - return; - - // Starting a yank session, yank the last thing killed and - // remember where we started. - _mark = _yankStartPoint = _current; - Insert(_killRing[_killIndex]); - - _yankCommandCount += 1; - } - - /// - /// Add the most recently killed text to the input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Yank(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.YankImpl(); - } - - private void YankPopImpl() - { - if (_yankCommandCount == 0) - return; - - _killIndex -= 1; - if (_killIndex < 0) - { - _killIndex = _killRing.Count - 1; - } - var yankText = _killRing[_killIndex]; - Replace(_yankStartPoint, _current - _yankStartPoint, yankText); - _yankCommandCount += 1; - } - - /// - /// If the previous operation was Yank or YankPop, replace the previously yanked - /// text with the next killed text from the kill ring. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void YankPop(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.YankPopImpl(); - } - - void YankArgImpl(YankLastArgState yankLastArgState) - { - if (yankLastArgState.historyIndex < 0 || yankLastArgState.historyIndex >= _history.Count) - { - Ding(); - return; - } - - Token[] tokens; - ParseError[] errors; - var buffer = _history[yankLastArgState.historyIndex]; - Parser.ParseInput(buffer._line, out tokens, out errors); - - int arg = (yankLastArgState.argument < 0) - ? tokens.Length + yankLastArgState.argument - 1 - : yankLastArgState.argument; - if (arg < 0 || arg >= tokens.Length) - { - Ding(); - return; - } - - var argText = tokens[arg].Text; - if (yankLastArgState.startPoint < 0) - { - yankLastArgState.startPoint = _current; - Insert(argText); - } - else - { - Replace(yankLastArgState.startPoint, _current - yankLastArgState.startPoint, argText); - } - } - - /// - /// Yank the first argument (after the command) from the previous history line. - /// With an argument, yank the nth argument (starting from 0), if the argument - /// is negative, start from the last argument. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void YankNthArg(ConsoleKeyInfo? key = null, object arg = null) - { - var yankLastArgState = new YankLastArgState - { - argument = (arg is int) ? (int)arg : 1, - historyIndex = _singleton._currentHistoryIndex - 1, - }; - _singleton.YankArgImpl(yankLastArgState); - } - - /// - /// Yank the last argument from the previous history line. With an argument, - /// the first time it is invoked, behaves just like YankNthArg. If invoked - /// multiple times, instead it iterates through history and arg sets the direction - /// (negative reverses the direction.) - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void YankLastArg(ConsoleKeyInfo? key = null, object arg = null) - { - if (arg != null && !(arg is int)) - { - Ding(); - return; - } - - _singleton._yankLastArgCommandCount += 1; - - if (_singleton._yankLastArgCommandCount == 1) - { - _singleton._yankLastArgState = new YankLastArgState - { - argument = (arg != null) ? (int)arg : -1, - historyIncrement = -1, - historyIndex = _singleton._currentHistoryIndex - 1 - }; - - _singleton.YankArgImpl(_singleton._yankLastArgState); - return; - } - - var yankLastArgState = _singleton._yankLastArgState; - - if (arg != null) - { - if ((int)arg < 0) - { - yankLastArgState.historyIncrement = -yankLastArgState.historyIncrement; - } - } - - yankLastArgState.historyIndex += yankLastArgState.historyIncrement; - - // Don't increment more than 1 out of range so it's quick to get back to being in range. - if (yankLastArgState.historyIndex < 0) - { - Ding(); - yankLastArgState.historyIndex = 0; - } - else if (yankLastArgState.historyIndex >= _singleton._history.Count) - { - Ding(); - yankLastArgState.historyIndex = _singleton._history.Count - 1; - } - else - { - _singleton.YankArgImpl(yankLastArgState); - } - } - - private void VisualSelectionCommon(Action action) - { - if (_singleton._visualSelectionCommandCount == 0) - { - SetMark(); - } - _singleton._visualSelectionCommandCount += 1; - action(); - _singleton.Render(); - } - - /// - /// Adjust the current selection to include the previous character - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectBackwardChar(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => BackwardChar(key, arg)); - } - - /// - /// Adjust the current selection to include the next character - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectForwardChar(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => ForwardChar(key, arg)); - } - - /// - /// Adjust the current selection to include the previous word - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectBackwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => BackwardWord(key, arg)); - } - - /// - /// Adjust the current selection to include the next word - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectNextWord(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => NextWord(key, arg)); - } - - /// - /// Adjust the current selection to include the next word using ForwardWord - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectForwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => ForwardWord(key, arg)); - } - - /// - /// Adjust the current selection to include the next word using ShellForwardWord - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectShellForwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => ShellForwardWord(key, arg)); - } - - /// - /// Adjust the current selection to include the next word using ShellNextWord - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectShellNextWord(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => ShellNextWord(key, arg)); - } - - /// - /// Adjust the current selection to include the previous word using ShellBackwardWord - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectShellBackwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => ShellBackwardWord(key, arg)); - } - - /// - /// Select the entire line - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectAll(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._visualSelectionCommandCount += 1; - _singleton._mark = 0; - _singleton._current = _singleton._buffer.Length; - _singleton.Render(); - } - - /// - /// Adjust the current selection to include from the cursor to the end of the line - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => EndOfLine(key, arg)); - } - - /// - /// Adjust the current selection to include from the cursor to the start of the line - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void SelectBackwardsLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.VisualSelectionCommon(() => BeginningOfLine(key, arg)); - } - - /// - /// Paste text from the system clipboard. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Paste(ConsoleKeyInfo? key = null, object arg = null) - { -#if !CORECLR // TODO: clipboard - string textToPaste = null; - ExecuteOnSTAThread(() => { - if (Clipboard.ContainsText()) - { - textToPaste = Clipboard.GetText(); - } - }); - - if (textToPaste != null) - { - textToPaste = textToPaste.Replace("\r", ""); - if (_singleton._visualSelectionCommandCount > 0) - { - int start, length; - _singleton.GetRegion(out start, out length); - Replace(start, length, textToPaste); - } - else - { - Insert(textToPaste); - } - } -#endif - } - - /// - /// Copy selected region to the system clipboard. If no region is selected, copy the whole line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Copy(ConsoleKeyInfo? key = null, object arg = null) - { -#if !CORECLR // TODO: clipboard - string textToSet; - if (_singleton._visualSelectionCommandCount > 0) - { - int start, length; - _singleton.GetRegion(out start, out length); - textToSet = _singleton._buffer.ToString(start, length); - } - else - { - textToSet = _singleton._buffer.ToString(); - } - if (!string.IsNullOrEmpty(textToSet)) - { - ExecuteOnSTAThread(() => Clipboard.SetText(textToSet)); - } -#endif - } - - /// - /// If text is selected, copy to the clipboard, otherwise cancel the line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void CopyOrCancelLine(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._visualSelectionCommandCount > 0) - { - Copy(key, arg); - } - else - { - CancelLine(key, arg); - } - } - - /// - /// Delete selected region placing deleted text in the system clipboard. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Cut(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._visualSelectionCommandCount > 0) - { - int start, length; - _singleton.GetRegion(out start, out length); -#if !CORECLR // TODO: clipboard - ExecuteOnSTAThread(() => Clipboard.SetText(_singleton._buffer.ToString(start, length))); -#endif - Delete(start, length); - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/License.txt b/src/Microsoft.PowerShell.PSReadLine/License.txt deleted file mode 100644 index 6e21fbbafe2d..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/License.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013, Jason Shirk -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/Microsoft.PowerShell.PSReadLine/Microsoft.PowerShell.PSReadLine.csproj b/src/Microsoft.PowerShell.PSReadLine/Microsoft.PowerShell.PSReadLine.csproj deleted file mode 100644 index cd14d6c2faa9..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Microsoft.PowerShell.PSReadLine.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - PowerShell Core's Microsoft.PowerShell.PSReadLine project - Microsoft.PowerShell.PSReadLine - - - - - - - - $(DefineConstants);CORECLR - - - - portable - - - - $(DefineConstants);UNIX - - - - full - - - diff --git a/src/Microsoft.PowerShell.PSReadLine/Movement.cs b/src/Microsoft.PowerShell.PSReadLine/Movement.cs deleted file mode 100644 index b309b3245b54..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Movement.cs +++ /dev/null @@ -1,550 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation.Language; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private int _moveToLineCommandCount; - private int _moveToLineDesiredColumn; - - /// - /// If the input has multiple lines, move to the end of the current line, - /// or if already at the end of the line, move to the end of the input. - /// If the input has a single line, move to the end of the input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void EndOfLine(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton.LineIsMultiLine()) - { - int i = _singleton._current; - for (; i < _singleton._buffer.Length; i++) - { - if (_singleton._buffer[i] == '\n') - { - break; - } - } - - _singleton._current = (i == _singleton._current) ? _singleton._buffer.Length : i; - } - else - { - _singleton._current = _singleton._buffer.Length; - } - _singleton.PlaceCursor(); - } - - /// - /// If the input has multiple lines, move to the start of the current line, - /// or if already at the start of the line, move to the start of the input. - /// If the input has a single line, move to the start of the input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BeginningOfLine(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton.LineIsMultiLine()) - { - int i = Math.Max(0, _singleton._current - 1); - for (; i > 0; i--) - { - if (_singleton._buffer[i] == '\n') - { - i += 1; - break; - } - } - - _singleton._current = (i == _singleton._current) ? 0 : i; - } - else - { - _singleton._current = 0; - } - _singleton.PlaceCursor(); - } - - /// - /// Move the cursor one character to the right. This may move the cursor to the next - /// line of multi-line input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ForwardChar(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (TryGetArgAsInt(arg, out numericArg, 1)) - { - SetCursorPosition(_singleton._current + numericArg); - } - } - - /// - /// Move the cursor one character to the left. This may move the cursor to the previous - /// line of multi-line input. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BackwardChar(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (TryGetArgAsInt(arg, out numericArg, 1)) - { - SetCursorPosition(_singleton._current - numericArg); - } - } - - private void MoveToLine(int numericArg) - { - const int endOfLine = int.MaxValue; - - _moveToLineCommandCount += 1; - var coords = ConvertOffsetToCoordinates(_current); - if (_moveToLineCommandCount == 1) - { - _moveToLineDesiredColumn = - (_current == _buffer.Length || _buffer[_current] == '\n') - ? endOfLine - : coords.X; - } - - var topLine = _initialY + Options.ExtraPromptLineCount; - - var newY = coords.Y + numericArg; - coords.Y = (short)Math.Max(newY, topLine); - if (_moveToLineDesiredColumn != endOfLine) - { - coords.X = (short)_moveToLineDesiredColumn; - } - - var newCurrent = ConvertLineAndColumnToOffset(coords); - if (newCurrent != -1) - { - _current = newCurrent; - if (_moveToLineDesiredColumn == endOfLine) - { - while (_current < _buffer.Length && _buffer[_current] != '\n') - { - _current += 1; - } - } - PlaceCursor(); - } - } - - /// - /// Move the cursor to the previous line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void PreviousLine(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (TryGetArgAsInt(arg, out numericArg, 1)) - { - _singleton.MoveToLine(-numericArg); - } - } - - /// - /// Move the cursor to the next line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void NextLine(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (TryGetArgAsInt(arg, out numericArg, 1)) - { - _singleton.MoveToLine(numericArg); - } - } - - /// - /// Move the cursor forward to the start of the next word. - /// Word boundaries are defined by a configurable set of characters. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void NextWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - BackwardWord(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - int i = _singleton.FindNextWordPoint(_singleton.Options.WordDelimiters); - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - /// - /// Move the cursor forward to the end of the current word, or if between words, - /// to the end of the next word. Word boundaries are defined by PowerShell tokens. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ShellNextWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - ShellBackwardWord(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - var token = _singleton.FindToken(_singleton._current, FindTokenMode.Next); - - Debug.Assert(token != null, "We'll always find EOF"); - - _singleton._current = token.Kind == TokenKind.EndOfInput - ? _singleton._buffer.Length - : token.Extent.StartOffset; - _singleton.PlaceCursor(); - } - } - - /// - /// Move the cursor forward to the end of the current word, or if between words, - /// to the end of the next word. Word boundaries are defined by a configurable - /// set of characters. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ForwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - BackwardWord(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - int i = _singleton.FindForwardWordPoint(_singleton.Options.WordDelimiters); - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - /// - /// Move the cursor forward to the start of the next word. - /// Word boundaries are defined by PowerShell tokens. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ShellForwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - ShellBackwardWord(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - var token = _singleton.FindToken(_singleton._current, FindTokenMode.CurrentOrNext); - - Debug.Assert(token != null, "We'll always find EOF"); - - _singleton._current = token.Kind == TokenKind.EndOfInput - ? _singleton._buffer.Length - : token.Extent.EndOffset; - _singleton.PlaceCursor(); - } - } - - private static bool CheckIsBound(Action action) - { - foreach (var entry in _singleton._dispatchTable) - { - if (entry.Value.Action == action) - return true; - } - return false; - } - - /// - /// Move the cursor back to the start of the current word, or if between words, - /// the start of the previous word. Word boundaries are defined by a configurable - /// set of characters. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void BackwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - if (CheckIsBound(ForwardWord)) - { - ForwardWord(key, -numericArg); - } - else - { - NextWord(key, -numericArg); - } - return; - } - - while (numericArg-- > 0) - { - int i = _singleton.FindBackwardWordPoint(_singleton.Options.WordDelimiters); - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - /// - /// Move the cursor back to the start of the current word, or if between words, - /// the start of the previous word. Word boundaries are defined by PowerShell tokens. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ShellBackwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - if (CheckIsBound(ShellForwardWord)) - { - ShellForwardWord(key, -numericArg); - } - else - { - ShellNextWord(key, -numericArg); - } - return; - } - - while (numericArg-- > 0) - { - var token = _singleton.FindToken(_singleton._current, FindTokenMode.Previous); - - _singleton._current = (token != null) ? token.Extent.StartOffset : 0; - _singleton.PlaceCursor(); - } - } - - /// - /// Go to the matching brace, paren, or square bracket - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void GotoBrace(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._current >= _singleton._buffer.Length) - { - Ding(); - return; - } - - _singleton.MaybeParseInput(); - - Token token = null; - var index = 0; - for (; index < _singleton._tokens.Length; index++) - { - token = _singleton._tokens[index]; - if (token.Extent.StartOffset == _singleton._current) - break; - } - - TokenKind toMatch; - int direction; - switch (token.Kind) - { - case TokenKind.LParen: toMatch = TokenKind.RParen; direction = 1; break; - case TokenKind.LCurly: toMatch = TokenKind.RCurly; direction = 1; break; - case TokenKind.LBracket: toMatch = TokenKind.RBracket; direction = 1; break; - - case TokenKind.RParen: toMatch = TokenKind.LParen; direction = -1; break; - case TokenKind.RCurly: toMatch = TokenKind.LCurly; direction = -1; break; - case TokenKind.RBracket: toMatch = TokenKind.LBracket; direction = -1; break; - - default: - // Nothing to match (don't match inside strings/comments) - Ding(); - return; - } - - var matchCount = 0; - var limit = (direction > 0) ? _singleton._tokens.Length - 1 : -1; - for (; index != limit; index += direction) - { - var t = _singleton._tokens[index]; - if (t.Kind == token.Kind) - { - matchCount++; - } - else if (t.Kind == toMatch) - { - matchCount--; - if (matchCount == 0) - { - _singleton._current = t.Extent.StartOffset; - _singleton.PlaceCursor(); - return; - } - } - } - Ding(); - } - - /// - /// Clear the screen and draw the current line at the top of the screen. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ClearScreen(ConsoleKeyInfo? key = null, object arg = null) - { - var console = _singleton._console; -#if UNIX // TODO: this is not correct, it should only scroll - console.Clear(); - _singleton._initialY = 0; - _singleton.Render(); -#else - if (_singleton._initialY + console.WindowHeight > console.BufferHeight) - { - var scrollCount = _singleton._initialY - console.WindowTop; - console.ScrollBuffer(scrollCount); - _singleton._initialY -= scrollCount; - console.SetCursorPosition(console.CursorLeft, console.CursorTop - scrollCount); - } - else - { - console.SetWindowPosition(0, _singleton._initialY); - } -#endif - } - - // Try to convert the arg to a char, return 0 for failure - private static char TryGetArgAsChar(object arg) - { - if (arg is char) - { - return (char)arg; - } - - var s = arg as string; - if (s != null && s.Length == 1) - { - return s[0]; - } - - return (char)0; - } - - /// - /// Read a character and search forward for the next occurence of that character. - /// If an argument is specified, search forward (or backward if negative) for the - /// nth occurence. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void CharacterSearch(ConsoleKeyInfo? key = null, object arg = null) - { - int occurence = (arg is int) ? (int)arg : 1; - if (occurence < 0) - { - CharacterSearchBackward(key, -occurence); - return; - } - - char toFind = TryGetArgAsChar(arg); - if (toFind == (char)0) - { - // Should we prompt? - toFind = ReadKey().KeyChar; - } - for (int i = _singleton._current + 1; i < _singleton._buffer.Length; i++) - { - if (_singleton._buffer[i] == toFind) - { - occurence -= 1; - if (occurence == 0) - { - _singleton._current = i; - _singleton.PlaceCursor(); - break; - } - } - } - if (occurence > 0) - { - Ding(); - } - } - - /// - /// Read a character and search backward for the next occurence of that character. - /// If an argument is specified, search backward (or forward if negative) for the - /// nth occurence. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void CharacterSearchBackward(ConsoleKeyInfo? key = null, object arg = null) - { - int occurence = (arg is int) ? (int)arg : 1; - if (occurence < 0) - { - CharacterSearch(key, -occurence); - return; - } - - char toFind = TryGetArgAsChar(arg); - if (toFind == (char)0) - { - // Should we prompt? - toFind = ReadKey().KeyChar; - } - for (int i = _singleton._current - 1; i >= 0; i--) - { - if (_singleton._buffer[i] == toFind) - { - occurence -= 1; - if (occurence == 0) - { - _singleton._current = i; - _singleton.PlaceCursor(); - return; - } - } - } - Ding(); - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Movement.vi.cs b/src/Microsoft.PowerShell.PSReadLine/Movement.vi.cs deleted file mode 100644 index 7c1c8a7bf21a..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Movement.vi.cs +++ /dev/null @@ -1,326 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - /// - /// Move the cursor forward to the start of the next word. - /// Word boundaries are defined by a configurable set of characters. - /// - public static void ViNextWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - ViBackwardWord(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - int i = _singleton.ViFindNextWordPoint(_singleton.Options.WordDelimiters); - if (i >= _singleton._buffer.Length) - { - i += ViEndOfLineFactor; - } - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - /// - /// Move the cursor back to the start of the current word, or if between words, - /// the start of the previous word. Word boundaries are defined by a configurable - /// set of characters. - /// - public static void ViBackwardWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - ViNextWord(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - int i = _singleton.ViFindPreviousWordPoint(_singleton.Options.WordDelimiters); - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - /// - /// Moves the cursor back to the beginning of the previous word, using only white space as delimiters. - /// - public static void ViBackwardGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int i = _singleton._current; - while (numericArg-- > 0) - { - i = _singleton.ViFindPreviousGlob(i - 1); - } - _singleton._current = i; - _singleton.PlaceCursor(); - } - - /// - /// Moves to the next word, using only white space as a word delimiter. - /// - private static void ViNextGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int i = _singleton._current; - while (numericArg-- > 0) - { - i = _singleton.ViFindNextGlob(i); - } - - _singleton._current = Math.Min(i, _singleton._buffer.Length - 1); - _singleton.PlaceCursor(); - } - - private static void ViEndOfGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - ViEndOfPreviousGlob(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - int i = _singleton.ViFindEndOfGlob(); - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - private static void ViEndOfPreviousGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - if (numericArg < 0) - { - ViEndOfGlob(key, -numericArg); - return; - } - - while (numericArg-- > 0) - { - int i = _singleton.ViFindEndOfPreviousGlob(); - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - /// - /// Returns 0 if the cursor is allowed to go past the last character in the line, -1 otherwise. - /// - /// - private static int ViEndOfLineFactor - { - get - { - if (_singleton._dispatchTable == _viCmdKeyMap) - { - return -1; - } - return 0; - } - } - - /// - /// Move the cursor to the end of the input. - /// - public static void MoveToEndOfLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._current = Math.Max(0, _singleton._buffer.Length + ViEndOfLineFactor); - _singleton.PlaceCursor(); - } - - /// - /// Move the cursor forward to the end of the current word, or if between words, - /// to the end of the next word. Word boundaries are defined by a configurable - /// set of characters. - /// - public static void NextWordEnd(ConsoleKeyInfo? key = null, object arg = null) - { - int qty = (arg is int) ? (int)arg : 1; - for (; qty > 0 && _singleton._current < _singleton._buffer.Length - 1; qty--) - { - int i = _singleton.ViFindNextWordEnd(_singleton.Options.WordDelimiters); - _singleton._current = i; - _singleton.PlaceCursor(); - } - } - - /// - /// Move to the column indicated by arg. - /// - public static void GotoColumn(ConsoleKeyInfo? key = null, object arg = null) - { - int col = (arg is int) ? (int) arg : -1; - if (col < 0 ) { - Ding(); - return; - } - - if (col < _singleton._buffer.Length + ViEndOfLineFactor) - { - _singleton._current = Math.Min(col, _singleton._buffer.Length) - 1; - } - else - { - _singleton._current = _singleton._buffer.Length + ViEndOfLineFactor; - Ding(); - } - _singleton.PlaceCursor(); - } - - /// - /// Move the cursor to the first non-blank character in the line. - /// - public static void GotoFirstNonBlankOfLine(ConsoleKeyInfo? key = null, object arg = null) - { - for (int i = 0; i < _singleton._buffer.Length; i++) - { - if (!Char.IsWhiteSpace(_singleton._buffer[i])) - { - _singleton._current = i; - _singleton.PlaceCursor(); - return; - } - } - } - - /// - /// Similar to , but is character based instead of token based. - /// - public static void ViGotoBrace(ConsoleKeyInfo? key = null, object arg = null) - { - int i = _singleton.ViFindBrace(_singleton._current); - if (i == _singleton._current) - { - Ding(); - return; - } - _singleton._current = i; - _singleton.PlaceCursor(); - } - - private int ViFindBrace(int i) - { - switch (_buffer[i]) - { - case '{': - return ViFindForward(i, '}', withoutPassing: '{'); - case '[': - return ViFindForward(i, ']', withoutPassing: '['); - case '(': - return ViFindForward(i, ')', withoutPassing: '('); - case '}': - return ViFindBackward(i, '{', withoutPassing: '}'); - case ']': - return ViFindBackward(i, '[', withoutPassing: ']'); - case ')': - return ViFindBackward(i, '(', withoutPassing: ')'); - default: - return i; - } - } - - private int ViFindBackward(int start, char target, char withoutPassing) - { - if (start == 0) - { - return start; - } - int i = start - 1; - int withoutPassingCount = 0; - while (i != 0 && !(_buffer[i] == target && withoutPassingCount == 0)) - { - if (_buffer[i] == withoutPassing) - { - withoutPassingCount++; - } - if (_buffer[i] == target) - { - withoutPassingCount--; - } - i--; - } - if (_buffer[i] == target && withoutPassingCount == 0) - { - return i; - } - return start; - } - - private int ViFindForward(int start, char target, char withoutPassing) - { - if (IsAtEndOfLine(start)) - { - return start; - } - int i = start + 1; - int withoutPassingCount = 0; - while (!IsAtEndOfLine(i) && !(_buffer[i] == target && withoutPassingCount == 0)) - { - if (_buffer[i] == withoutPassing) - { - withoutPassingCount++; - } - if (_buffer[i] == target) - { - withoutPassingCount--; - } - i++; - } - if (_buffer[i] == target && withoutPassingCount == 0) - { - return i; - } - return start; - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Options.cs b/src/Microsoft.PowerShell.PSReadLine/Options.cs deleted file mode 100644 index 63b440f145a1..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Options.cs +++ /dev/null @@ -1,403 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation; -using System.Reflection; -using System.Threading; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private readonly PSConsoleReadlineOptions _options; - private PSConsoleReadlineOptions Options - { - get { return _options; } - } - - private void SetOptionsInternal(SetPSReadlineOption options) - { - if (options.ContinuationPrompt != null) - { - Options.ContinuationPrompt = options.ContinuationPrompt; - } - if (options._continuationPromptForegroundColor.HasValue) - { - Options.ContinuationPromptForegroundColor = options.ContinuationPromptForegroundColor; - } - if (options._continuationPromptBackgroundColor.HasValue) - { - Options.ContinuationPromptBackgroundColor = options.ContinuationPromptBackgroundColor; - } - if (options._emphasisBackgroundColor.HasValue) - { - Options.EmphasisBackgroundColor = options.EmphasisBackgroundColor; - } - if (options._emphasisForegroundColor.HasValue) - { - Options.EmphasisForegroundColor = options.EmphasisForegroundColor; - } - if (options._errorBackgroundColor.HasValue) - { - Options.ErrorBackgroundColor = options.ErrorBackgroundColor; - } - if (options._errorForegroundColor.HasValue) - { - Options.ErrorForegroundColor = options.ErrorForegroundColor; - } - if (options._historyNoDuplicates.HasValue) - { - Options.HistoryNoDuplicates = options.HistoryNoDuplicates; - } - if (options._historySearchCursorMovesToEnd.HasValue) - { - Options.HistorySearchCursorMovesToEnd = options.HistorySearchCursorMovesToEnd; - } - if (options._addToHistoryHandlerSpecified) - { - Options.AddToHistoryHandler = options.AddToHistoryHandler; - } - if (options._commandValidationHandlerSpecified) - { - Options.CommandValidationHandler = options.CommandValidationHandler; - } - if (options._maximumHistoryCount.HasValue) - { - Options.MaximumHistoryCount = options.MaximumHistoryCount; - if (_history != null) - { - var newHistory = new HistoryQueue(Options.MaximumHistoryCount); - while (_history.Count > Options.MaximumHistoryCount) - { - _history.Dequeue(); - } - while (_history.Count > 0) - { - newHistory.Enqueue(_history.Dequeue()); - } - _history = newHistory; - _currentHistoryIndex = _history.Count; - } - } - if (options._maximumKillRingCount.HasValue) - { - Options.MaximumKillRingCount = options.MaximumKillRingCount; - // TODO - make _killRing smaller - } - if (options._editMode.HasValue) - { - Options.EditMode = options.EditMode; - - // Switching/resetting modes - clear out chord dispatch table - _chordDispatchTable.Clear(); - - SetDefaultBindings(Options.EditMode); - } - if (options._showToolTips.HasValue) - { - Options.ShowToolTips = options.ShowToolTips; - } - if (options._extraPromptLineCount.HasValue) - { - Options.ExtraPromptLineCount = options.ExtraPromptLineCount; - } - if (options._dingTone.HasValue) - { - Options.DingTone = options.DingTone; - } - if (options._dingDuration.HasValue) - { - Options.DingDuration = options.DingDuration; - } - if (options._bellStyle.HasValue) - { - Options.BellStyle = options.BellStyle; - } - if (options._completionQueryItems.HasValue) - { - Options.CompletionQueryItems = options.CompletionQueryItems; - } - if (options.WordDelimiters != null) - { - Options.WordDelimiters = options.WordDelimiters; - } - if (options._historySearchCaseSensitive.HasValue) - { - Options.HistorySearchCaseSensitive = options.HistorySearchCaseSensitive; - } - if (options._historySaveStyle.HasValue) - { - Options.HistorySaveStyle = options.HistorySaveStyle; - } - #region vi - if (options._viModeIndicator.HasValue) - { - Options.ViModeIndicator = options.ViModeIndicator; - } - #endregion - if (options.HistorySavePath != null) - { - Options.HistorySavePath = options.HistorySavePath; - if (_historyFileMutex != null) - { - _historyFileMutex.Dispose(); - } - _historyFileMutex = new Mutex(false, GetHistorySaveFileMutexName()); - _historyFileLastSavedSize = 0; - } - if (options.ResetTokenColors) - { - Options.ResetColors(); - } - if (options._tokenKind.HasValue) - { - if (options._foregroundColor.HasValue) - { - Options.SetForegroundColor(options.TokenKind, options.ForegroundColor); - } - if (options._backgroundColor.HasValue) - { - Options.SetBackgroundColor(options.TokenKind, options.BackgroundColor); - } - } - } - - private void SetKeyHandlerInternal(string[] keys, Action handler, string briefDescription, string longDescription, ScriptBlock scriptBlock) - { - foreach (var key in keys) - { - var chord = ConsoleKeyChordConverter.Convert(key); - if (chord.Length == 1) - { - _dispatchTable[chord[0]] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock); - } - else - { - _dispatchTable[chord[0]] = MakeKeyHandler(Chord, "ChordFirstKey"); - Dictionary secondDispatchTable; - if (!_chordDispatchTable.TryGetValue(chord[0], out secondDispatchTable)) - { - secondDispatchTable = new Dictionary(); - _chordDispatchTable[chord[0]] = secondDispatchTable; - } - secondDispatchTable[chord[1]] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock); - } - } - } - - private void RemoveKeyHandlerInternal(string[] keys) - { - foreach (var key in keys) - { - var chord = ConsoleKeyChordConverter.Convert(key); - if (chord.Length == 1) - { - _dispatchTable.Remove(chord[0]); - } - else - { - Dictionary secondDispatchTable; - if (_chordDispatchTable.TryGetValue(chord[0], out secondDispatchTable)) - { - secondDispatchTable.Remove(chord[1]); - if (secondDispatchTable.Count == 0) - { - _dispatchTable.Remove(chord[0]); - } - } - } - } - } - - /// - /// Helper function for the Set-PSReadlineOption cmdlet. - /// - public static void SetOptions(SetPSReadlineOption options) - { - _singleton.SetOptionsInternal(options); - } - - /// - /// Helper function for the Get-PSReadlineOption cmdlet. - /// - public static PSConsoleReadlineOptions GetOptions() - { - // Should we copy? It doesn't matter much, everything can be tweaked from - // the cmdlet anyway. - return _singleton._options; - } - - class CustomHandlerException : Exception - { - internal CustomHandlerException(Exception innerException) - : base("", innerException) - { - } - } - - /// - /// Helper function for the Set-PSReadlineKeyHandler cmdlet. - /// - public static void SetKeyHandler(string[] key, ScriptBlock scriptBlock, string briefDescription, string longDescription) - { - Action handler = (k, arg) => - { - try - { - scriptBlock.Invoke(k, arg); - } - catch (Exception e) - { - throw new CustomHandlerException(e); - } - }; - - _singleton.SetKeyHandlerInternal(key, handler, briefDescription, longDescription, scriptBlock); - } - - /// - /// Helper function for the Set-PSReadlineKeyHandler cmdlet. - /// - [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] - public static void SetKeyHandler(string[] key, Action handler, string briefDescription, string longDescription) - { - _singleton.SetKeyHandlerInternal(key, handler, briefDescription, longDescription, null); - } - - /// - /// Helper function for the Remove-PSReadlineKeyHandler cmdlet. - /// - /// - public static void RemoveKeyHandler(string[] key) - { - _singleton.RemoveKeyHandlerInternal(key); - } - - /// - /// Helper function for the Get-PSReadlineKeyHandler cmdlet. - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static IEnumerable GetKeyHandlers(bool includeBound = true, bool includeUnbound = false) - { - var boundFunctions = new HashSet(StringComparer.OrdinalIgnoreCase); - - foreach (var entry in _singleton._dispatchTable) - { - if (entry.Value.BriefDescription == "Ignore" - || entry.Value.BriefDescription == "ChordFirstKey") - { - continue; - } - boundFunctions.Add(entry.Value.BriefDescription); - if (includeBound) - { - yield return new Microsoft.PowerShell.KeyHandler - { - Key = entry.Key.ToGestureString(), - Function = entry.Value.BriefDescription, - Description = entry.Value.LongDescription, - }; - } - } - - // Added to support vi command mode mappings - if (_singleton._options.EditMode == EditMode.Vi) - { - foreach (var entry in _viCmdKeyMap) - { - if (entry.Value.BriefDescription == "Ignore" - || entry.Value.BriefDescription == "ChordFirstKey") - { - continue; - } - boundFunctions.Add(entry.Value.BriefDescription); - if (includeBound) - { - yield return new Microsoft.PowerShell.KeyHandler - { - Key = "<" + entry.Key.ToGestureString() + ">", - Function = entry.Value.BriefDescription, - Description = entry.Value.LongDescription, - }; - } - } - } - - foreach( var entry in _singleton._chordDispatchTable ) - { - foreach( var secondEntry in entry.Value ) - { - boundFunctions.Add( secondEntry.Value.BriefDescription ); - if (includeBound) - { - yield return new Microsoft.PowerShell.KeyHandler - { - Key = entry.Key.ToGestureString() + "," + secondEntry.Key.ToGestureString(), - Function = secondEntry.Value.BriefDescription, - Description = secondEntry.Value.LongDescription, - }; - } - } - } - - // Added to support vi command mode chorded mappings - if (_singleton._options.EditMode == EditMode.Vi) - { - foreach (var entry in _viCmdChordTable) - { - foreach (var secondEntry in entry.Value) - { - if (secondEntry.Value.BriefDescription == "Ignore") - { - continue; - } - boundFunctions.Add(secondEntry.Value.BriefDescription); - if (includeBound) - { - yield return new Microsoft.PowerShell.KeyHandler - { - Key = "<" + entry.Key.ToGestureString() + "," + secondEntry.Key.ToGestureString() + ">", - Function = secondEntry.Value.BriefDescription, - Description = secondEntry.Value.LongDescription - }; - } - } - } - } - - if (includeUnbound) - { - // SelfInsert isn't really unbound, but we don't want UI to show it that way - boundFunctions.Add("SelfInsert"); - - var methods = typeof (PSConsoleReadLine).GetMethods(BindingFlags.Public | BindingFlags.Static); - foreach (var method in methods) - { - var parameters = method.GetParameters(); - if (parameters.Length != 2 || - parameters[0].ParameterType != typeof (ConsoleKeyInfo?) || - parameters[1].ParameterType != typeof (object)) - { - continue; - } - - if (!boundFunctions.Contains(method.Name)) - { - yield return new Microsoft.PowerShell.KeyHandler - { - Key = "Unbound", - Function = method.Name, - Description = null, - }; - } - } - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/PSReadLine.psd1 b/src/Microsoft.PowerShell.PSReadLine/PSReadLine.psd1 deleted file mode 100644 index a634495d19d2..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/PSReadLine.psd1 +++ /dev/null @@ -1,17 +0,0 @@ -@{ -RootModule = 'PSReadLine.psm1' -NestedModules = @("Microsoft.PowerShell.PSReadLine.dll") -ModuleVersion = '1.2' -GUID = '5714753b-2afd-4492-a5fd-01d9e2cff8b5' -Author = 'Microsoft Corporation' -CompanyName = 'Microsoft Corporation' -Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.' -Description = 'Great command line editing in the PowerShell console host' -PowerShellVersion = '3.0' -DotNetFrameworkVersion = '4.0' -CLRVersion = '4.0' -FunctionsToExport = 'PSConsoleHostReadline' -CmdletsToExport = 'Get-PSReadlineKeyHandler','Set-PSReadlineKeyHandler','Remove-PSReadlineKeyHandler', - 'Get-PSReadlineOption','Set-PSReadlineOption' -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855966' -} diff --git a/src/Microsoft.PowerShell.PSReadLine/PSReadLine.psm1 b/src/Microsoft.PowerShell.PSReadLine/PSReadLine.psm1 deleted file mode 100644 index 4f2bf37fe896..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/PSReadLine.psm1 +++ /dev/null @@ -1,5 +0,0 @@ -function PSConsoleHostReadline -{ - Microsoft.PowerShell.Core\Set-StrictMode -Off - [Microsoft.PowerShell.PSConsoleReadLine]::ReadLine($host.Runspace, $ExecutionContext) -} diff --git a/src/Microsoft.PowerShell.PSReadLine/PSReadLineResources.Designer.cs b/src/Microsoft.PowerShell.PSReadLine/PSReadLineResources.Designer.cs deleted file mode 100644 index c96e5f059dab..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/PSReadLineResources.Designer.cs +++ /dev/null @@ -1,1839 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.PowerShell { - using System; - using System.Reflection; - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class PSReadLineResources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal PSReadLineResources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.PowerShell.PSReadLine.PSReadLineResources", typeof(PSReadLineResources).GetTypeInfo().Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Abort the current operation, e.g. incremental history search. - /// - internal static string AbortDescription { - get { - return ResourceManager.GetString("AbortDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accept the current line and recall the next line from history after the current line finishes executing. - /// - internal static string AcceptAndGetNextDescription { - get { - return ResourceManager.GetString("AcceptAndGetNextDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accept the input or move to the next line if input is missing a closing token.. - /// - internal static string AcceptLineDescription { - get { - return ResourceManager.GetString("AcceptLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the next line without attempting to execute the input. - /// - internal static string AddLineDescription { - get { - return ResourceManager.GetString("AddLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor back one character. - /// - internal static string BackwardCharDescription { - get { - return ResourceManager.GetString("BackwardCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete the character before the cursor. - /// - internal static string BackwardDeleteCharDescription { - get { - return ResourceManager.GetString("BackwardDeleteCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete text from the cursor to the start of the line. - /// - internal static string BackwardDeleteLineDescription { - get { - return ResourceManager.GetString("BackwardDeleteLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete the previous word in the line.. - /// - internal static string BackwardDeleteWordDescription { - get { - return ResourceManager.GetString("BackwardDeleteWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the text from the cursor to the beginning of the line to the kill ring. - /// - internal static string BackwardKillLineDescription { - get { - return ResourceManager.GetString("BackwardKillLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the text from the start of the current or previous word to the cursor to the kill ring. - /// - internal static string BackwardKillWordDescription { - get { - return ResourceManager.GetString("BackwardKillWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replaces the character in front of the cursor.. - /// - internal static string BackwardReplaceCharDescription { - get { - return ResourceManager.GetString("BackwardReplaceCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the beginning of the current or previous word. - /// - internal static string BackwardWordDescription { - get { - return ResourceManager.GetString("BackwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to the first item in the history. - /// - internal static string BeginningOfHistoryDescription { - get { - return ResourceManager.GetString("BeginningOfHistoryDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the beginning of the line. - /// - internal static string BeginningOfLineDescription { - get { - return ResourceManager.GetString("BeginningOfLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Abort editing the current line and re-evaluate the prompt. - /// - internal static string CancelLineDescription { - get { - return ResourceManager.GetString("CancelLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to translate '{0}' to virtual key code: {1}.. - /// - internal static string CantTranslateKey { - get { - return ResourceManager.GetString("CantTranslateKey", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Allows you to select multiple lines from the console using Shift+UpArrow/DownArrow and copy the selected lines to clipboard by pressing Enter.. - /// - internal static string CaptureScreenDescription { - get { - return ResourceManager.GetString("CaptureScreenDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Read a character and move the cursor to the previous occurence of that character. - /// - internal static string CharacterSearchBackwardDescription { - get { - return ResourceManager.GetString("CharacterSearchBackwardDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Read a character and move the cursor to the next occurence of that character. - /// - internal static string CharacterSearchDescription { - get { - return ResourceManager.GetString("CharacterSearchDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Chord can have at most two keys.. - /// - internal static string ChordWithTooManyKeys { - get { - return ResourceManager.GetString("ChordWithTooManyKeys", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove all items from the command line history (not PowerShell history). - /// - internal static string ClearHistoryDescription { - get { - return ResourceManager.GetString("ClearHistoryDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove all items from the kill ring. - /// - internal static string ClearKillRingDescription { - get { - return ResourceManager.GetString("ClearKillRingDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Clear the screen and redraw the current line at the top of the screen. - /// - internal static string ClearScreenDescription { - get { - return ResourceManager.GetString("ClearScreenDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Command '{0}' cannot be found.. - /// - internal static string CommandNotFoundError { - get { - return ResourceManager.GetString("CommandNotFoundError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Complete the input if there is a single completion, otherwise complete the input with common prefix for all completions. Show possible completions if pressed a second time.. - /// - internal static string CompleteDescription { - get { - return ResourceManager.GetString("CompleteDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Copy selected region to the system clipboard. If no region is selected, copy the whole line. - /// - internal static string CopyDescription { - get { - return ResourceManager.GetString("CopyDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Either copy selected text to the clipboard, or if no text is selected, cancel editing the line with CancelLine.. - /// - internal static string CopyOrCancelLineDescription { - get { - return ResourceManager.GetString("CopyOrCancelLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete selected region placing deleted text in the system clipboard. - /// - internal static string CutDescription { - get { - return ResourceManager.GetString("CutDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes all characters between the cursor and the matching brace.. - /// - internal static string DeleteBraceDescription { - get { - return ResourceManager.GetString("DeleteBraceDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete the character under the cursor. - /// - internal static string DeleteCharDescription { - get { - return ResourceManager.GetString("DeleteCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete the character under the cursor, or if the line is empty, exit the process.. - /// - internal static string DeleteCharOrExitDescription { - get { - return ResourceManager.GetString("DeleteCharOrExitDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete to the end of the current word, as delimited by white space and common delimiters.. - /// - internal static string DeleteEndOfWordDescription { - get { - return ResourceManager.GetString("DeleteEndOfWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes the current line.. - /// - internal static string DeleteLineDescription { - get { - return ResourceManager.GetString("DeleteLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes all of the line except for leading whitespace.. - /// - internal static string DeleteLineToFirstCharDescription { - get { - return ResourceManager.GetString("DeleteLineToFirstCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes from the cursor to the end of the line.. - /// - internal static string DeleteToEndDescription { - get { - return ResourceManager.GetString("DeleteToEndDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes from the cursor to the end of the current word.. - /// - internal static string DeleteToEndOfWordDescription { - get { - return ResourceManager.GetString("DeleteToEndOfWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes the current word.. - /// - internal static string DeleteWordDescription { - get { - return ResourceManager.GetString("DeleteWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Start or accumulate a numeric argument to other functions. - /// - internal static string DigitArgumentDescription { - get { - return ResourceManager.GetString("DigitArgumentDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Display all {0} possibilities? (y or n) _. - /// - internal static string DisplayAllPossibilities { - get { - return ResourceManager.GetString("DisplayAllPossibilities", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to String is not used in the UI. - /// - internal static string EmacsCtrlXDescription { - get { - return ResourceManager.GetString("EmacsCtrlXDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to String is not used in the UI. - /// - internal static string EmacsMetaDescription { - get { - return ResourceManager.GetString("EmacsMetaDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to the last item (the current input) in the history. - /// - internal static string EndOfHistoryDescription { - get { - return ResourceManager.GetString("EndOfHistoryDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the end of the line. - /// - internal static string EndOfLineDescription { - get { - return ResourceManager.GetString("EndOfLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mark the location of the cursor and move the cursor to the position of the previous mark. - /// - internal static string ExchangePointAndMarkDescription { - get { - return ResourceManager.GetString("ExchangePointAndMarkDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor forward one character. - /// - internal static string ForwardCharDescription { - get { - return ResourceManager.GetString("ForwardCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete text from the cursor to the end of the line. - /// - internal static string ForwardDeleteLineDescription { - get { - return ResourceManager.GetString("ForwardDeleteLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search history forward interactively. - /// - internal static string ForwardSearchHistoryDescription { - get { - return ResourceManager.GetString("ForwardSearchHistoryDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor forward to the end of the current word, or if between words, to the end of the next word. . - /// - internal static string ForwardWordDescription { - get { - return ResourceManager.GetString("ForwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Go to matching brace. - /// - internal static string GotoBraceDescription { - get { - return ResourceManager.GetString("GotoBraceDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Moves the cursor to the prescribed column.. - /// - internal static string GotoColumnDescription { - get { - return ResourceManager.GetString("GotoColumnDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Positions the cursor at the first non-blank character.. - /// - internal static string GotoFirstNonBlankOfLineDescription { - get { - return ResourceManager.GetString("GotoFirstNonBlankOfLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This error will not be reported again in this session. Consider using a different path with: - /// Set-PSReadlineOption -HistorySavePath <Path> - ///Or not saving history with: - /// Set-PSReadlineOption -HistorySaveStyle SaveNothing. - /// - internal static string HistoryFileErrorFinalMessage { - get { - return ResourceManager.GetString("HistoryFileErrorFinalMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error reading or writing history file '{0}': {1}. - /// - internal static string HistoryFileErrorMessage { - get { - return ResourceManager.GetString("HistoryFileErrorMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search for the previous item in the history that starts with the current input - like PreviousHistory if the input is empty. - /// - internal static string HistorySearchBackwardDescription { - get { - return ResourceManager.GetString("HistorySearchBackwardDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search for the next item in the history that starts with the current input - like NextHistory if the input is empty. - /// - internal static string HistorySearchForwardDescription { - get { - return ResourceManager.GetString("HistorySearchForwardDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to String is not used in the UI. - /// - internal static string IgnoreDescription { - get { - return ResourceManager.GetString("IgnoreDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete the current character and insert the next character.. - /// - internal static string InsertCharacterDescription { - get { - return ResourceManager.GetString("InsertCharacterDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Inserts a new empty line above the current line without attempting to execute the input. - /// - internal static string InsertLineAboveDescription { - get { - return ResourceManager.GetString("InsertLineAboveDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Inserts a new empty line below the current line without attempting to execute the input. - /// - internal static string InsertLineBelowDescription { - get { - return ResourceManager.GetString("InsertLineBelowDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Duplicate or invalid modifier token '{0}' for key '{1}'.. - /// - internal static string InvalidModifier { - get { - return ResourceManager.GetString("InvalidModifier", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid sequence '{0}'.. - /// - internal static string InvalidSequence { - get { - return ResourceManager.GetString("InvalidSequence", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Inverts the case of the current character and advances the cursor.. - /// - internal static string InvertCaseDescription { - get { - return ResourceManager.GetString("InvertCaseDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Erases the current prompt and calls the prompt function to redisplay the prompt. - /// - internal static string InvokePromptDescription { - get { - return ResourceManager.GetString("InvokePromptDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Key is unbound. - /// - internal static string KeyIsUnbound { - get { - return ResourceManager.GetString("KeyIsUnbound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the text from the cursor to the end of the input to the kill ring. - /// - internal static string KillLineDescription { - get { - return ResourceManager.GetString("KillLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Kill the text between the cursor and the mark. - /// - internal static string KillRegionDescription { - get { - return ResourceManager.GetString("KillRegionDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the text from the cursor to the end of the current or next word to the kill ring. - /// - internal static string KillWordDescription { - get { - return ResourceManager.GetString("KillWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Complete the input if there is a single completion, otherwise complete the input by selecting from a menu of possible completions.. - /// - internal static string MenuCompleteDescription { - get { - return ResourceManager.GetString("MenuCompleteDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to the end of the line.. - /// - internal static string MoveToEndOfLineDescription { - get { - return ResourceManager.GetString("MoveToEndOfLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the input with the next item in the history. - /// - internal static string NextHistoryDescription { - get { - return ResourceManager.GetString("NextHistoryDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the next line if the input has multiple lines.. - /// - internal static string NextLineDescription { - get { - return ResourceManager.GetString("NextLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor forward to the start of the next word. - /// - internal static string NextWordDescription { - get { - return ResourceManager.GetString("NextWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Moves the cursor forward to the end of the next word.. - /// - internal static string NextWordEndDescription { - get { - return ResourceManager.GetString("NextWordEndDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The -ViMode parameter was used, but the current EditMode is not Vi.. - /// - internal static string NotInViMode { - get { - return ResourceManager.GetString("NotInViMode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to - ///Oops, something went wrong. Please report this bug with the details below. - ///Report on GitHub: https://github.com/lzybkr/PSReadLine/issues/new. - /// - internal static string OopsAnErrorMessage1 { - get { - return ResourceManager.GetString("OopsAnErrorMessage1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ----------------------------------------------------------------------- - ///Last {0} Keys: - ///{1} - /// - ///Exception: - ///{2} - ///-----------------------------------------------------------------------. - /// - internal static string OopsAnErrorMessage2 { - get { - return ResourceManager.GetString("OopsAnErrorMessage2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An exception occurred in custom key handler, see $error for more information: {0}. - /// - internal static string OopsCustomHandlerException { - get { - return ResourceManager.GetString("OopsCustomHandlerException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Write the contents of the local clipboard after the cursor.. - /// - internal static string PasteAfterDescription { - get { - return ResourceManager.GetString("PasteAfterDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Write the contents of the local clipboard before the cursor.. - /// - internal static string PasteBeforeDescription { - get { - return ResourceManager.GetString("PasteBeforeDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Paste text from the system clipboard. - /// - internal static string PasteDescription { - get { - return ResourceManager.GetString("PasteDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Display the possible completions without changing the input. - /// - internal static string PossibleCompletionsDescription { - get { - return ResourceManager.GetString("PossibleCompletionsDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Inserts the entered character at the beginning and accepts the line.. - /// - internal static string PrependAndAcceptDescription { - get { - return ResourceManager.GetString("PrependAndAcceptDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the input with the previous item in the history. - /// - internal static string PreviousHistoryDescription { - get { - return ResourceManager.GetString("PreviousHistoryDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the previous line if the input has multiple lines.. - /// - internal static string PreviousLineDescription { - get { - return ResourceManager.GetString("PreviousLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Redo an undo. - /// - internal static string RedoDescription { - get { - return ResourceManager.GetString("RedoDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Repeat the last recorded character search in the opposite direction.. - /// - internal static string RepeatLastCharSearchBackwardsDescription { - get { - return ResourceManager.GetString("RepeatLastCharSearchBackwardsDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Repeat the last recorded character search.. - /// - internal static string RepeatLastCharSearchDescription { - get { - return ResourceManager.GetString("RepeatLastCharSearchDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Repeats the last modification command.. - /// - internal static string RepeatLastCommandDescription { - get { - return ResourceManager.GetString("RepeatLastCommandDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Repeats the last search.. - /// - internal static string RepeatLastSearchDescription { - get { - return ResourceManager.GetString("RepeatLastSearchDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Repeat the last search, but in the opposite direction.. - /// - internal static string RepeatSearchBackwardDescription { - get { - return ResourceManager.GetString("RepeatSearchBackwardDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Repeat the last search.. - /// - internal static string RepeatSearchDescription { - get { - return ResourceManager.GetString("RepeatSearchDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the current character with the next set of characters typed.. - /// - internal static string ReplaceCharDescription { - get { - return ResourceManager.GetString("ReplaceCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the current character with only one character.. - /// - internal static string ReplaceCharInPlaceDescription { - get { - return ResourceManager.GetString("ReplaceCharInPlaceDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to length is too big. - /// - internal static string ReplacementLengthTooBig { - get { - return ResourceManager.GetString("ReplacementLengthTooBig", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search history backwards interactively. - /// - internal static string ReverseSearchHistoryDescription { - get { - return ResourceManager.GetString("ReverseSearchHistoryDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Equivalent to undo all edits (clears the line except lines imported from history). - /// - internal static string RevertLineDescription { - get { - return ResourceManager.GetString("RevertLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Scroll the display down one screen. - /// - internal static string ScrollDisplayDownDescription { - get { - return ResourceManager.GetString("ScrollDisplayDownDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Scroll the display down one line. - /// - internal static string ScrollDisplayDownLineDescription { - get { - return ResourceManager.GetString("ScrollDisplayDownLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Scroll the display to the cursor. - /// - internal static string ScrollDisplayToCursorDescription { - get { - return ResourceManager.GetString("ScrollDisplayToCursorDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Scroll the display to the top. - /// - internal static string ScrollDisplayTopDescription { - get { - return ResourceManager.GetString("ScrollDisplayTopDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Scroll the display up one screen. - /// - internal static string ScrollDisplayUpDescription { - get { - return ResourceManager.GetString("ScrollDisplayUpDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Scroll the display up one line. - /// - internal static string ScrollDisplayUpLineDescription { - get { - return ResourceManager.GetString("ScrollDisplayUpLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Searches backward for the prescribed character.. - /// - internal static string SearchBackwardCharDescription { - get { - return ResourceManager.GetString("SearchBackwardCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to the previous occurrence of the specified character.. - /// - internal static string SearchCharBackwardDescription { - get { - return ResourceManager.GetString("SearchCharBackwardDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to the previous occurrence of the specified character and then forward one character.. - /// - internal static string SearchCharBackwardWithBackoffDescription { - get { - return ResourceManager.GetString("SearchCharBackwardWithBackoffDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to the next occurrence of the specified character.. - /// - internal static string SearchCharDescription { - get { - return ResourceManager.GetString("SearchCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move to he next occurrence of the specified character and then back one character.. - /// - internal static string SearchCharWithBackoffDescription { - get { - return ResourceManager.GetString("SearchCharWithBackoffDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Searches for the prescribed character in the prescribed direction.. - /// - internal static string SearchDescription { - get { - return ResourceManager.GetString("SearchDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Prompts for a search string and initiates a search upon AcceptLine.. - /// - internal static string SearchForwardDescription { - get { - return ResourceManager.GetString("SearchForwardDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select the entire line. Moves the cursor to the end of the line. - /// - internal static string SelectAllDescription { - get { - return ResourceManager.GetString("SelectAllDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the previous character. - /// - internal static string SelectBackwardCharDescription { - get { - return ResourceManager.GetString("SelectBackwardCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include from the cursor to the end of the line. - /// - internal static string SelectBackwardsLineDescription { - get { - return ResourceManager.GetString("SelectBackwardsLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the previous word. - /// - internal static string SelectBackwardWordDescription { - get { - return ResourceManager.GetString("SelectBackwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the next character. - /// - internal static string SelectForwardCharDescription { - get { - return ResourceManager.GetString("SelectForwardCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the next word using ForwardWord. - /// - internal static string SelectForwardWordDescription { - get { - return ResourceManager.GetString("SelectForwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include from the cursor to the start of the line. - /// - internal static string SelectLineDescription { - get { - return ResourceManager.GetString("SelectLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the next word. - /// - internal static string SelectNextWordDescription { - get { - return ResourceManager.GetString("SelectNextWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the previous word using ShellBackwardWord. - /// - internal static string SelectShellBackwardWordDescription { - get { - return ResourceManager.GetString("SelectShellBackwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the next word using ShellForwardWord. - /// - internal static string SelectShellForwardWordDescription { - get { - return ResourceManager.GetString("SelectShellForwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Adjust the current selection to include the next word using ShellNextWord. - /// - internal static string SelectShellNextWordDescription { - get { - return ResourceManager.GetString("SelectShellNextWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Insert the key typed. - /// - internal static string SelfInsertDescription { - get { - return ResourceManager.GetString("SelfInsertDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Mark the location of the cursor. - /// - internal static string SetMarkDescription { - get { - return ResourceManager.GetString("SetMarkDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the text from the cursor to the start of the current or previous token to the kill ring. - /// - internal static string ShellBackwardKillWordDescription { - get { - return ResourceManager.GetString("ShellBackwardKillWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the beginning of the current or previous token or start of the line. - /// - internal static string ShellBackwardWordDescription { - get { - return ResourceManager.GetString("ShellBackwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the beginning of the next token or end of line. - /// - internal static string ShellForwardWordDescription { - get { - return ResourceManager.GetString("ShellForwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the text from the cursor to the end of the current or next token to the kill ring. - /// - internal static string ShellKillWordDescription { - get { - return ResourceManager.GetString("ShellKillWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the end of the current token. - /// - internal static string ShellNextWordDescription { - get { - return ResourceManager.GetString("ShellNextWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show all key bindings. - /// - internal static string ShowKeyBindingsDescription { - get { - return ResourceManager.GetString("ShowKeyBindingsDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to 'start' cannot be less than zero or greater than the length of the buffer. - /// - internal static string StartOutOfRange { - get { - return ResourceManager.GetString("StartOutOfRange", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Swap the current character with the character before it.. - /// - internal static string SwapCharactersDescription { - get { - return ResourceManager.GetString("SwapCharactersDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Complete the input using the next completion. - /// - internal static string TabCompleteNextDescription { - get { - return ResourceManager.GetString("TabCompleteNextDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Complete the input using the previous completion. - /// - internal static string TabCompletePreviousDescription { - get { - return ResourceManager.GetString("TabCompletePreviousDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Undoes all commands for this line.. - /// - internal static string UndoAllDescription { - get { - return ResourceManager.GetString("UndoAllDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Undo a previous edit. - /// - internal static string UndoDescription { - get { - return ResourceManager.GetString("UndoDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the text from the cursor to the start of the current or previous whitespace delimited word to the kill ring. - /// - internal static string UnixWordRuboutDescription { - get { - return ResourceManager.GetString("UnixWordRuboutDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unrecognized key '{0}'. Please use a character literal or a well-known key name from the System.ConsoleKey enumeration.. - /// - internal static string UnrecognizedKey { - get { - return ResourceManager.GetString("UnrecognizedKey", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accept the input or move to the next line if input is missing a closing token. - ///If there are other parse errors, unresolved commands, or incorrect parameters, show the error and continue editing.. - /// - internal static string ValidateAndAcceptLineDescription { - get { - return ResourceManager.GetString("ValidateAndAcceptLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accept the line and switch to Vi's insert mode.. - /// - internal static string ViAcceptLineDescription { - get { - return ResourceManager.GetString("ViAcceptLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to If the line is empty, exit, otherwise accept the line as input.. - /// - internal static string ViAcceptLineOrExitDescription { - get { - return ResourceManager.GetString("ViAcceptLineOrExitDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Switches to insert mode after positioning the cursor past the end of the line.. - /// - internal static string ViAppendAtEndDescription { - get { - return ResourceManager.GetString("ViAppendAtEndDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Appends a new multi-line edit mode line to the current line.. - /// - internal static string ViAppendLineDescription { - get { - return ResourceManager.GetString("ViAppendLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete backward to the beginning of the previous word, as delimited by white space.. - /// - internal static string ViBackwardDeleteGlobDescription { - get { - return ResourceManager.GetString("ViBackwardDeleteGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the beginning of the previous word, as delimited by white space.. - /// - internal static string ViBackwardGlobDescription { - get { - return ResourceManager.GetString("ViBackwardGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete backward to the beginning of the previous word, as delimited by white space, and enter insert mode.. - /// - internal static string ViBackwardReplaceGlobDescription { - get { - return ResourceManager.GetString("ViBackwardReplaceGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replaces the line left of the cursor and all of the way to the beginning.. - /// - internal static string ViBackwardReplaceLineDescription { - get { - return ResourceManager.GetString("ViBackwardReplaceLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replaces the line left of the cursor and all but one character to the beginning of the line.. - /// - internal static string ViBackwardReplaceLineToFirstCharDescription { - get { - return ResourceManager.GetString("ViBackwardReplaceLineToFirstCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the previous word.. - /// - internal static string ViBackwardReplaceWordDescription { - get { - return ResourceManager.GetString("ViBackwardReplaceWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete backward to the beginning of the previous word, as delimited by white space and common delimiters, and enter insert mode.. - /// - internal static string ViBackwardWordDescription { - get { - return ResourceManager.GetString("ViBackwardWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Switch to VI's command mode.. - /// - internal static string ViCommandModeDescription { - get { - return ResourceManager.GetString("ViCommandModeDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes all characters between the cursor position and the matching brace.. - /// - internal static string ViDeleteBraceDescription { - get { - return ResourceManager.GetString("ViDeleteBraceDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete to the end of this word, as delimited by white space.. - /// - internal static string ViDeleteEndOfGlobDescription { - get { - return ResourceManager.GetString("ViDeleteEndOfGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete the current word, as delimited by white space.. - /// - internal static string ViDeleteGlobDescription { - get { - return ResourceManager.GetString("ViDeleteGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Handles the processing of a number argument after the first key of a chord.. - /// - internal static string ViDigitArgumentInChordDescription { - get { - return ResourceManager.GetString("ViDigitArgumentInChordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invokes the console compatible editor specified by $env:VISUAL or $env:$EDITOR on the current command line.. - /// - internal static string ViEditVisuallyDescription { - get { - return ResourceManager.GetString("ViEditVisuallyDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the end this word, as delimited by white space.. - /// - internal static string ViEndOfGlobDescription { - get { - return ResourceManager.GetString("ViEndOfGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exit the shell.. - /// - internal static string ViExitDescription { - get { - return ResourceManager.GetString("ViExitDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the matching brace.. - /// - internal static string ViGotoBraceDescription { - get { - return ResourceManager.GetString("ViGotoBraceDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Moves the cursor to the beginning of the line and switches to insert mode.. - /// - internal static string ViInsertAtBeginningDescription { - get { - return ResourceManager.GetString("ViInsertAtBeginingDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Moves the cursor to the end of the line and switches to insert mode.. - /// - internal static string ViInsertAtEndDescription { - get { - return ResourceManager.GetString("ViInsertAtEndDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Inserts a new multi-line edit mode line in front of the current line.. - /// - internal static string ViInsertLineDescription { - get { - return ResourceManager.GetString("ViInsertLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Switches to insert mode.. - /// - internal static string ViInsertModeDescription { - get { - return ResourceManager.GetString("ViInsertModeDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Switch to insert mode, appending at the current line position.. - /// - internal static string ViInsertWithAppendDescription { - get { - return ResourceManager.GetString("ViInsertWithAppendDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deletes the current character and switches to insert mode.. - /// - internal static string ViInsertWithDeleteDescription { - get { - return ResourceManager.GetString("ViInsertWithDeleteDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Joins the current multi-line edit mode line with the next.. - /// - internal static string ViJoinLinesDescription { - get { - return ResourceManager.GetString("ViJoinLinesDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the beginning of the next word, as delimited by white space.. - /// - internal static string ViNextGlobDescription { - get { - return ResourceManager.GetString("ViNextGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Move the cursor to the beginning of the next word, as delimited by white space and common delimiters.. - /// - internal static string ViNextWordDescription { - get { - return ResourceManager.GetString("ViNextWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace all characters between the current brace character and it's matching partner.. - /// - internal static string ViReplaceBraceDescription { - get { - return ResourceManager.GetString("ViReplaceBraceDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete to the end of the word, as delimited by white space, and enter insert mode.. - /// - internal static string ViReplaceEndOfGlobDescription { - get { - return ResourceManager.GetString("ViReplaceEndOfGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete to the end of the word, as delimited by white space and common delimiters, and enter insert mode.. - /// - internal static string ViReplaceEndOfWordDescription { - get { - return ResourceManager.GetString("ViReplaceEndOfWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Delete to the beginning of the next word, as delimited by white space, and enter insert mode.. - /// - internal static string ViReplaceGlobDescription { - get { - return ResourceManager.GetString("ViReplaceGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Repace the current line with the next set of characters typed.. - /// - internal static string ViReplaceLineDescription { - get { - return ResourceManager.GetString("ViReplaceLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the characters from the cursor position to the end of the line.. - /// - internal static string ViReplaceToEndDescription { - get { - return ResourceManager.GetString("ViReplaceToEndDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the current character until an escape is entered or the line is accepted.. - /// - internal static string ViReplaceUntilEscDescription { - get { - return ResourceManager.GetString("ViReplaceUntilEscDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the current word.. - /// - internal static string ViReplaceWordDescription { - get { - return ResourceManager.GetString("ViReplaceWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Starts a new search backward in the history.. - /// - internal static string ViSearchHistoryBackwardDescription { - get { - return ResourceManager.GetString("ViSearchHistoryBackwardDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invokes TabCompleteNext after doing some vi-specific clean up.. - /// - internal static string ViTabCompleteNextDescription { - get { - return ResourceManager.GetString("ViTabCompleteNextDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invokes TabCompletePrevious after doing some vi-specific clean up.. - /// - internal static string ViTabCompletePreviousDescription { - get { - return ResourceManager.GetString("ViTabCompletePreviousDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Transposes the current character with the next character in the line.. - /// - internal static string ViTransposeCharsDescription { - get { - return ResourceManager.GetString("ViTransposeCharsDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place the characters before the cursor into the local clipboard.. - /// - internal static string ViYankBeginningOfLineDescription { - get { - return ResourceManager.GetString("ViYankBeginningOfLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place the characters from the cursor to the end of the next white space delimited word into the local clipboard.. - /// - internal static string ViYankEndOfGlobDescription { - get { - return ResourceManager.GetString("ViYankEndOfGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place the characters from the cursor to the end of the next word, as delimited by white space and common delimiters, into the local clipboard.. - /// - internal static string ViYankEndOfWordDescription { - get { - return ResourceManager.GetString("ViYankEndOfWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place the character to the left of the cursor into the local clipboard.. - /// - internal static string ViYankLeftDescription { - get { - return ResourceManager.GetString("ViYankLeftDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters in the current line into the local clipboard.. - /// - internal static string ViYankLineDescription { - get { - return ResourceManager.GetString("ViYankLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters from the cursor to the end of the word, as delimited by white space, into the local clipboard.. - /// - internal static string ViYankNextGlobDescription { - get { - return ResourceManager.GetString("ViYankNextGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters from the cursor to the end of the word, as delimited by white space and common delimiters, into the local clipboard.. - /// - internal static string ViYankNextWordDescription { - get { - return ResourceManager.GetString("ViYankNextWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters between the matching brace and the cursor into the local clipboard.. - /// - internal static string ViYankPercentDescription { - get { - return ResourceManager.GetString("ViYankPercentDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters from before the cursor to the beginning of the previous word, as delimited by white space, into the local clipboard.. - /// - internal static string ViYankPreviousGlobDescription { - get { - return ResourceManager.GetString("ViYankPreviousGlobDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters from before the cursor to the beginning of the previous word, as delimited by white space and common delimiters, into the local clipboard.. - /// - internal static string ViYankPreviousWordDescription { - get { - return ResourceManager.GetString("ViYankPreviousWordDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place the character at the cursor into the local clipboard.. - /// - internal static string ViYankRightDescription { - get { - return ResourceManager.GetString("ViYankRightDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters at and after the cursor into the local clipboard.. - /// - internal static string ViYankToEndOfLineDescription { - get { - return ResourceManager.GetString("ViYankToEndOfLineDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Place all characters before the cursor and to the 1st non-white space character into the local clipboard.. - /// - internal static string ViYankToFirstCharDescription { - get { - return ResourceManager.GetString("ViYankToFirstCharDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show the key binding for the next chord entered. - /// - internal static string WhatIsKeyDescription { - get { - return ResourceManager.GetString("WhatIsKeyDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Copy the text from the current kill ring position to the input. - /// - internal static string YankDescription { - get { - return ResourceManager.GetString("YankDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Copy the text of the last argument to the input. - /// - internal static string YankLastArgDescription { - get { - return ResourceManager.GetString("YankLastArgDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Copy the text of the first argument to the input. - /// - internal static string YankNthArgDescription { - get { - return ResourceManager.GetString("YankNthArgDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replace the previously yanked text with the text from the next kill ring position. - /// - internal static string YankPopDescription { - get { - return ResourceManager.GetString("YankPopDescription", resourceCulture); - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/PSReadLineResources.resx b/src/Microsoft.PowerShell.PSReadLine/PSReadLineResources.resx deleted file mode 100644 index b8d156511231..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/PSReadLineResources.resx +++ /dev/null @@ -1,720 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Accept the input or move to the next line if input is missing a closing token. - - - Move the cursor to the next line without attempting to execute the input - - - Move the cursor back one character - - - Delete the character before the cursor - - - Delete text from the cursor to the start of the line - - - Move the text from the cursor to the beginning of the line to the kill ring - - - Move to the first item in the history - - - Move the cursor to the beginning of the line - - - Abort editing the current line and re-evaluate the prompt - - - Remove all items from the kill ring - - - Remove all items from the command line history (not PowerShell history) - - - Complete the input if there is a single completion, otherwise complete the input with common prefix for all completions. Show possible completions if pressed a second time. - - - Delete the character under the cursor - - - Move the cursor to the beginning of the current or previous token or start of the line - - - String is not used in the UI - - - String is not used in the UI - - - Move to the last item (the current input) in the history - - - Move the cursor to the end of the line - - - Mark the location of the cursor and move the cursor to the position of the previous mark - - - Move the cursor forward one character - - - Delete text from the cursor to the end of the line - - - Move the cursor to the beginning of the next token or end of line - - - Search for the previous item in the history that starts with the current input - like PreviousHistory if the input is empty - - - Search for the next item in the history that starts with the current input - like NextHistory if the input is empty - - - String is not used in the UI - - - Move the text from the cursor to the start of the current or previous token to the kill ring - - - Move the text from the cursor to the end of the input to the kill ring - - - Move the text from the cursor to the end of the current or next token to the kill ring - - - Replace the input with the next item in the history - - - Paste text from the system clipboard - - - Display the possible completions without changing the input - - - Replace the input with the previous item in the history - - - Redo an undo - - - Equivalent to undo all edits (clears the line except lines imported from history) - - - Mark the location of the cursor - - - Complete the input using the next completion - - - Complete the input using the previous completion - - - Undo a previous edit - - - Copy the text from the current kill ring position to the input - - - Replace the previously yanked text with the text from the next kill ring position - - - 'start' cannot be less than zero or greater than the length of the buffer - - - length is too big - - - Display all {0} possibilities? (y or n) _ - - - Clear the screen and redraw the current line at the top of the screen - - - Go to matching brace - - - Abort the current operation, e.g. incremental history search - - - Search history forward interactively - - - Search history backwards interactively - - - Move the text from the start of the current or previous word to the cursor to the kill ring - - - Move the cursor to the beginning of the current or previous word - - - Move the cursor forward to the end of the current word, or if between words, to the end of the next word. - - - Move the text from the cursor to the end of the current or next word to the kill ring - - - Move the cursor forward to the start of the next word - - - Move the text from the cursor to the start of the current or previous whitespace delimited word to the kill ring - - - Read a character and move the cursor to the previous occurence of that character - - - Read a character and move the cursor to the next occurence of that character - - - Start or accumulate a numeric argument to other functions - - - Copy the text of the last argument to the input - - - Copy the text of the first argument to the input - - - Accept the current line and recall the next line from history after the current line finishes executing - - - Key is unbound - - - Insert the key typed - - - Show all key bindings - - - Show the key binding for the next chord entered - - - Copy selected region to the system clipboard. If no region is selected, copy the whole line - - - Delete selected region placing deleted text in the system clipboard - - - Kill the text between the cursor and the mark - - - Adjust the current selection to include the previous character - - - Adjust the current selection to include the previous word - - - Adjust the current selection to include the next character - - - Adjust the current selection to include the next word using ForwardWord - - - Adjust the current selection to include the next word - - - Adjust the current selection to include the previous word using ShellBackwardWord - - - Adjust the current selection to include the next word using ShellForwardWord - - - Allows you to select multiple lines from the console using Shift+UpArrow/DownArrow and copy the selected lines to clipboard by pressing Enter. - - - Erases the current prompt and calls the prompt function to redisplay the prompt - - - Scroll the display down one screen - - - Scroll the display down one line - - - Scroll the display to the cursor - - - Scroll the display to the top - - - Scroll the display up one screen - - - Scroll the display up one line - - - Adjust the current selection to include the next word using ShellNextWord - - - Move the cursor to the end of the current token - - - Adjust the current selection to include from the cursor to the end of the line - - - Adjust the current selection to include from the cursor to the start of the line - - - Select the entire line. Moves the cursor to the end of the line - - - Either copy selected text to the clipboard, or if no text is selected, cancel editing the line with CancelLine. - - - Complete the input if there is a single completion, otherwise complete the input by selecting from a menu of possible completions. - - - -Oops, something went wrong. Please report this bug with the details below. -Report on GitHub: https://github.com/lzybkr/PSReadLine/issues/new - - - ----------------------------------------------------------------------- -Last {0} Keys: -{1} - -Exception: -{2} ------------------------------------------------------------------------ - - - Move the cursor to the next line if the input has multiple lines. - - - Move the cursor to the previous line if the input has multiple lines. - - - Command '{0}' cannot be found. - - - Accept the input or move to the next line if input is missing a closing token. -If there are other parse errors, unresolved commands, or incorrect parameters, show the error and continue editing. - - - Delete the character under the cursor, or if the line is empty, exit the process. - - - Unable to translate '{0}' to virtual key code: {1}. - - - Chord can have at most two keys. - - - Duplicate or invalid modifier token '{0}' for key '{1}'. - - - Invalid sequence '{0}'. - - - Unrecognized key '{0}'. Please use a character literal or a well-known key name from the System.ConsoleKey enumeration. - - - Accept the line and switch to Vi's insert mode. - - - Delete the previous word in the line. - - - Switch to VI's command mode. - - - Move to the end of the line. - - - Switch to insert mode, appending at the current line position. - - - Swap the current character with the character before it. - - - Repeats the last search. - - - Searches backward for the prescribed character. - - - Searches for the prescribed character in the prescribed direction. - - - Switches to insert mode after positioning the cursor past the end of the line. - - - Deletes all of the line except for leading whitespace. - - - Replaces the character in front of the cursor. - - - Replaces the line left of the cursor and all of the way to the beginning. - - - Replaces the line left of the cursor and all but one character to the beginning of the line. - - - Inserts the entered character at the beginning and accepts the line. - - - Deletes all characters between the cursor and the matching brace. - - - Deletes the current line. - - - Deletes from the cursor to the end of the line. - - - Deletes from the cursor to the end of the current word. - - - Deletes the current word. - - - Positions the cursor at the first non-blank character. - - - Moves the cursor forward to the end of the next word. - - - Moves the cursor to the prescribed column. - - - Switches to insert mode. - - - Moves the cursor to the beginning of the line and switches to insert mode. - - - Moves the cursor to the end of the line and switches to insert mode. - - - Deletes the current character and switches to insert mode. - - - Inverts the case of the current character and advances the cursor. - - - Repeats the last modification command. - - - Repeat the last search, but in the opposite direction. - - - Repeat the last search. - - - Replace all characters between the current brace character and it's matching partner. - - - Replace the current character with the next set of characters typed. - - - Replace the current character with only one character. - - - Repace the current line with the next set of characters typed. - - - Replace the characters from the cursor position to the end of the line. - - - Replace the current character until an escape is entered or the line is accepted. - - - Replace the current word. - - - Delete the current character and insert the next character. - - - Starts a new search backward in the history. - - - Transposes the current character with the next character in the line. - - - Undoes all commands for this line. - - - Prompts for a search string and initiates a search upon AcceptLine. - - - Repeat the last recorded character search in the opposite direction. - - - Repeat the last recorded character search. - - - Move to the previous occurrence of the specified character. - - - Move to the previous occurrence of the specified character and then forward one character. - - - Move to the next occurrence of the specified character. - - - Move to he next occurrence of the specified character and then back one character. - - - Replace the previous word. - - - Delete backward to the beginning of the previous word, as delimited by white space and common delimiters, and enter insert mode. - - - Write the contents of the local clipboard after the cursor. - - - Move the cursor to the beginning of the next word, as delimited by white space and common delimiters. - - - Move the cursor to the beginning of the previous word, as delimited by white space. - - - Move the cursor to the end this word, as delimited by white space. - - - Write the contents of the local clipboard before the cursor. - - - Move the cursor to the beginning of the next word, as delimited by white space. - - - Move the cursor to the matching brace. - - - Delete backward to the beginning of the previous word, as delimited by white space. - - - Delete the current word, as delimited by white space. - - - Delete to the end of the current word, as delimited by white space and common delimiters. - - - Delete to the end of this word, as delimited by white space. - - - Delete backward to the beginning of the previous word, as delimited by white space, and enter insert mode. - - - Delete to the beginning of the next word, as delimited by white space, and enter insert mode. - - - Delete to the end of the word, as delimited by white space and common delimiters, and enter insert mode. - - - Delete to the end of the word, as delimited by white space, and enter insert mode. - - - Place all characters in the current line into the local clipboard. - - - Place all characters at and after the cursor into the local clipboard. - - - Place all characters from before the cursor to the beginning of the previous word, as delimited by white space and common delimiters, into the local clipboard. - - - Place all characters from before the cursor to the beginning of the previous word, as delimited by white space, into the local clipboard. - - - Place all characters from the cursor to the end of the word, as delimited by white space and common delimiters, into the local clipboard. - - - Place all characters from the cursor to the end of the word, as delimited by white space, into the local clipboard. - - - Place the characters from the cursor to the end of the next word, as delimited by white space and common delimiters, into the local clipboard. - - - Place the characters from the cursor to the end of the next white space delimited word into the local clipboard. - - - Place the character to the left of the cursor into the local clipboard. - - - Place the character at the cursor into the local clipboard. - - - Place the characters before the cursor into the local clipboard. - - - Place all characters before the cursor and to the 1st non-white space character into the local clipboard. - - - Place all characters between the matching brace and the cursor into the local clipboard. - - - Deletes all characters between the cursor position and the matching brace. - - - If the line is empty, exit, otherwise accept the line as input. - - - Handles the processing of a number argument after the first key of a chord. - - - Exit the shell. - - - Invokes TabCompleteNext after doing some vi-specific clean up. - - - Invokes TabCompletePrevious after doing some vi-specific clean up. - - - Invokes the console compatible editor specified by $env:VISUAL or $env:$EDITOR on the current command line. - - - Appends a new multi-line edit mode line to the current line. - - - Inserts a new multi-line edit mode line in front of the current line. - - - Joins the current multi-line edit mode line with the next. - - - The -ViMode parameter was used, but the current EditMode is not Vi. - - - Inserts a new empty line above the current line without attempting to execute the input - - - Inserts a new empty line below the current line without attempting to execute the input - - - Error reading or writing history file '{0}': {1} - - - This error will not be reported again in this session. Consider using a different path with: - Set-PSReadlineOption -HistorySavePath <Path> -Or not saving history with: - Set-PSReadlineOption -HistorySaveStyle SaveNothing - - - An exception occurred in custom key handler, see $error for more information: {0} - - diff --git a/src/Microsoft.PowerShell.PSReadLine/PublicAPI.cs b/src/Microsoft.PowerShell.PSReadLine/PublicAPI.cs deleted file mode 100644 index 2db274ec43bc..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/PublicAPI.cs +++ /dev/null @@ -1,250 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Management.Automation.Runspaces; - - -namespace Microsoft.PowerShell -{ - namespace Internal - { -#pragma warning disable 1591 - - [SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - public interface IPSConsoleReadLineMockableMethods - { - void Ding(); - CommandCompletion CompleteInput(string input, int cursorIndex, Hashtable options, System.Management.Automation.PowerShell powershell); - bool RunspaceIsRemote(Runspace runspace); - - } - - [SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")] - public interface IConsole - { - object GetConsoleInputMode(); - void SetConsoleInputMode(object mode); - void RestoreConsoleInputMode(object mode); - ConsoleKeyInfo ReadKey(); - bool KeyAvailable { get; } - int CursorLeft { get; set; } - int CursorTop { get; set;} - int CursorSize { get; set; } - int BufferWidth { get; set; } - int BufferHeight { get; set;} - int WindowWidth { get; set; } - int WindowHeight { get; set; } - int WindowTop { get; set; } - ConsoleColor BackgroundColor { get; set; } - ConsoleColor ForegroundColor { get; set; } - void SetWindowPosition(int left, int top); - void SetCursorPosition(int left, int top); - void WriteLine(string s); - void Write(string s); - void WriteBufferLines(BufferChar[] buffer, ref int top); - void WriteBufferLines(BufferChar[] buffer, ref int top, bool ensureBottomLineVisible); - void ScrollBuffer(int lines); - BufferChar[] ReadBufferLines(int top, int count); - - void StartRender(); - int LengthInBufferCells(char c); - void EndRender(); -#if UNIX - void Clear(); -#endif - } - -#pragma warning restore 1591 - } - - /// - public partial class PSConsoleReadLine - { - /// - /// Insert a character at the current position. Supports undo. - /// - /// Character to insert - public static void Insert(char c) - { - _singleton.SaveEditItem(EditItemInsertChar.Create(c, _singleton._current)); - - // Use Append if possible because Insert at end makes StringBuilder quite slow. - if (_singleton._current == _singleton._buffer.Length) - { - _singleton._buffer.Append(c); - } - else - { - _singleton._buffer.Insert(_singleton._current, c); - } - _singleton._current += 1; - _singleton.Render(); - } - - /// - /// Insert a string at the current position. Supports undo. - /// - /// String to insert - public static void Insert(string s) - { - _singleton.SaveEditItem(EditItemInsertString.Create(s, _singleton._current)); - - // Use Append if possible because Insert at end makes StringBuilder quite slow. - if (_singleton._current == _singleton._buffer.Length) - { - _singleton._buffer.Append(s); - } - else - { - _singleton._buffer.Insert(_singleton._current, s); - } - _singleton._current += s.Length; - _singleton.Render(); - } - - /// - /// Delete some text at the given position. Supports undo. - /// - /// The start position to delete - /// The length to delete - public static void Delete(int start, int length) - { - Replace(start, length, null); - } - - /// - /// Replace some text at the given position. Supports undo. - /// - /// The start position to replace - /// The length to replace - /// The replacement text - /// The action that initiated the replace (used for undo) - /// The argument to the action that initiated the replace (used for undo) - public static void Replace(int start, int length, string replacement, Action instigator = null, object instigatorArg = null) - { - if (start < 0 || start > _singleton._buffer.Length) - { - throw new ArgumentException(PSReadLineResources.StartOutOfRange, "start"); - } - if (length > (_singleton._buffer.Length - start)) - { - throw new ArgumentException(PSReadLineResources.ReplacementLengthTooBig, "length"); - } - - bool useEditGroup = (_singleton._editGroupStart == -1); - - if (useEditGroup) - { - _singleton.StartEditGroup(); - } - - var str = _singleton._buffer.ToString(start, length); - _singleton.SaveEditItem(EditItemDelete.Create(str, start)); - _singleton._buffer.Remove(start, length); - if (replacement != null) - { - _singleton.SaveEditItem(EditItemInsertString.Create(replacement, start)); - _singleton._buffer.Insert(start, replacement); - _singleton._current = start + replacement.Length; - } - else - { - _singleton._current = start; - } - - if (useEditGroup) - { - _singleton.EndEditGroup(instigator, instigatorArg); // Instigator is needed for VI undo - _singleton.Render(); - } - } - - /// - /// Get the state of the buffer - the current input and the position of the cursor - /// - public static void GetBufferState(out string input, out int cursor) - { - input = _singleton._buffer.ToString(); - cursor = _singleton._current; - } - - /// - /// Get the state of the buffer - the ast, tokens, errors, and position of the cursor - /// - public static void GetBufferState(out Ast ast, out Token[] tokens, out ParseError[] parseErrors, out int cursor) - { - _singleton.ParseInput(); - ast = _singleton._ast; - tokens = _singleton._tokens; - parseErrors = _singleton._parseErrors; - cursor = _singleton._current; - } - - /// - /// Get the selection state of the buffer - /// - /// The start of the current selection or -1 if nothing is selected. - /// The length of the current selection or -1 if nothing is selected. - public static void GetSelectionState(out int start, out int length) - { - if (_singleton._visualSelectionCommandCount == 0) - { - start = -1; - length = -1; - } - else - { - _singleton.GetRegion(out start, out length); - } - } - - /// - /// Set the position of the cursor. - /// - public static void SetCursorPosition(int cursor) - { - if (cursor > _singleton._buffer.Length + ViEndOfLineFactor) - { - cursor = _singleton._buffer.Length + ViEndOfLineFactor; - } - if (cursor < 0) - { - cursor = 0; - } - - _singleton._current = cursor; - _singleton.PlaceCursor(); - } - - /// - /// A helper method when your function expects an optional int argument (e.g. from DigitArgument) - /// If there is not argument (it's null), returns true and sets numericArg to defaultNumericArg. - /// Dings and returns false if the argument is not an int (no conversion is attempted) - /// Otherwise returns true, and numericArg has the result. - /// - public static bool TryGetArgAsInt(object arg, out int numericArg, int defaultNumericArg) - { - if (arg == null) - { - numericArg = defaultNumericArg; - return true; - } - - if (arg is int) - { - numericArg = (int)arg; - return true; - } - - Ding(); - numericArg = 0; - return false; - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/ReadLine.cs b/src/Microsoft.PowerShell.PSReadLine/ReadLine.cs deleted file mode 100644 index 0aede96f9214..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/ReadLine.cs +++ /dev/null @@ -1,957 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Management.Automation.Runspaces; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using Microsoft.PowerShell.Commands; -using Microsoft.PowerShell.Internal; - -[module: SuppressMessage("Microsoft.Design", "CA1014:MarkAssembliesWithClsCompliant")] - -namespace Microsoft.PowerShell -{ - [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors")] - [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] - class ExitException : Exception { } - - public partial class PSConsoleReadLine : IPSConsoleReadLineMockableMethods - { - private static readonly PSConsoleReadLine _singleton = new PSConsoleReadLine(); - - private bool _delayedOneTimeInitCompleted; - - private IPSConsoleReadLineMockableMethods _mockableMethods; - private IConsole _console; - - private EngineIntrinsics _engineIntrinsics; -#if !UNIX - private static GCHandle _breakHandlerGcHandle; -#endif - private Thread _readKeyThread; - private AutoResetEvent _readKeyWaitHandle; - private AutoResetEvent _keyReadWaitHandle; - private ManualResetEvent _closingWaitHandle; - private WaitHandle[] _threadProcWaitHandles; - private WaitHandle[] _requestKeyWaitHandles; - private object _savedConsoleInputMode; - - private readonly StringBuilder _buffer; - private readonly StringBuilder _statusBuffer; - private bool _statusIsErrorMessage; - private string _statusLinePrompt; - private List _edits; - private int _editGroupStart; - private int _undoEditIndex; - private int _mark; - private bool _inputAccepted; - private readonly Queue _queuedKeys; - private Stopwatch _lastRenderTime; - private static Stopwatch _readkeyStopwatch = new Stopwatch(); - - // Save a fixed # of keys so we can reconstruct a repro after a crash - private readonly static HistoryQueue _lastNKeys = new HistoryQueue(200); - - // Tokens etc. - private Token[] _tokens; - private Ast _ast; - private ParseError[] _parseErrors; - - bool IPSConsoleReadLineMockableMethods.RunspaceIsRemote(Runspace runspace) - { - return runspace != null && runspace.ConnectionInfo != null; - } - - private void ReadOneOrMoreKeys() - { - _readkeyStopwatch.Restart(); - while (_console.KeyAvailable) - { - var key = _console.ReadKey(); - _lastNKeys.Enqueue(key); - _queuedKeys.Enqueue(key); - if (_readkeyStopwatch.ElapsedMilliseconds > 2) - { - // Don't spend too long in this loop if there are lots of queued keys - break; - } - } - - if (_queuedKeys.Count == 0) - { - var key = _console.ReadKey(); - _lastNKeys.Enqueue(key); - _queuedKeys.Enqueue(key); - } - } - - private void ReadKeyThreadProc() - { - while (true) - { - // Wait until ReadKey tells us to read a key (or it's time to exit). - int handleId = WaitHandle.WaitAny(_singleton._threadProcWaitHandles); - if (handleId == 1) // It was the _closingWaitHandle that was signaled. - break; - - ReadOneOrMoreKeys(); - - // One or more keys were read - let ReadKey know we're done. - _keyReadWaitHandle.Set(); - } - } - - private static ConsoleKeyInfo ReadKey() - { - // Reading a key is handled on a different thread. During process shutdown, - // PowerShell will wait in it's ConsoleCtrlHandler until the pipeline has completed. - // If we're running, we're most likely blocked waiting for user input. - // This is a problem for two reasons. First, exiting takes a long time (5 seconds - // on Win8) because PowerShell is waiting forever, but the OS will forcibly terminate - // the console. Also - if there are any event handlers for the engine event - // PowerShell.Exiting, those handlers won't get a chance to run. - // - // By waiting for a key on a different thread, our pipeline execution thread - // (the thread Readline is called from) avoid being blocked in code that can't - // be unblocked and instead blocks on events we control. - - // First, set an event so the thread to read a key actually attempts to read a key. - _singleton._readKeyWaitHandle.Set(); - - int handleId; - System.Management.Automation.PowerShell ps = null; - - try - { - while (true) - { - // Next, wait for one of three things: - // - a key is pressed - // - the console is exiting - // - 300ms - to process events if we're idle - - handleId = WaitHandle.WaitAny(_singleton._requestKeyWaitHandles, 300); - if (handleId != WaitHandle.WaitTimeout) - break; - if (_singleton._engineIntrinsics == null) - continue; - - // If we timed out, check for event subscribers (which is just - // a hint that there might be an event waiting to be processed.) - var eventSubscribers = _singleton._engineIntrinsics.Events.Subscribers; - if (eventSubscribers.Count > 0) - { - bool runPipelineForEventProcessing = false; - foreach (var sub in eventSubscribers) - { - if (sub.SourceIdentifier.Equals("PowerShell.OnIdle", StringComparison.OrdinalIgnoreCase)) - { - // There is an OnIdle event. We're idle because we timed out. Normally - // PowerShell generates this event, but PowerShell assumes the engine is not - // idle because it called PSConsoleHostReadline which isn't returning. - // So we generate the event instead. - _singleton._engineIntrinsics.Events.GenerateEvent("PowerShell.OnIdle", null, null, null); - runPipelineForEventProcessing = true; - break; - } - - // If there are any event subscribers that have an action (which might - // write to the console) and have a source object (i.e. aren't engine - // events), run a tiny useless bit of PowerShell so that the events - // can be processed. - if (sub.Action != null && sub.SourceObject != null) - { - runPipelineForEventProcessing = true; - break; - } - } - - if (runPipelineForEventProcessing) - { - if (ps == null) - { - ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); - ps.AddScript("0"); - } - - // To detect output during possible event processing, see if the cursor moved - // and rerender if so. - var console = _singleton._console; - var y = console.CursorTop; - ps.Invoke(); - if (y != console.CursorTop) - { - _singleton._initialY = console.CursorTop; - _singleton.Render(); - } - } - } - } - } - finally - { - if (ps != null) { ps.Dispose(); } - } - - if (handleId == 1) - { - // The console is exiting - throw an exception to unwind the stack to the point - // where we can return from ReadLine. - if (_singleton.Options.HistorySaveStyle == HistorySaveStyle.SaveAtExit) - { - _singleton.SaveHistoryAtExit(); - } - _singleton._historyFileMutex.Dispose(); - - throw new OperationCanceledException(); - } - - var key = _singleton._queuedKeys.Dequeue(); - return key; - } - - private void PrependQueuedKeys(ConsoleKeyInfo key) - { - if (_queuedKeys.Count > 0) - { - // This should almost never happen so being inefficient is fine. - var list = new List(_queuedKeys); - _queuedKeys.Clear(); - _queuedKeys.Enqueue(key); - list.ForEach(k => _queuedKeys.Enqueue(k)); - } - else - { - _queuedKeys.Enqueue(key); - } - } - - private bool BreakHandler(ConsoleBreakSignal signal) - { - if (signal == ConsoleBreakSignal.Close || signal == ConsoleBreakSignal.Shutdown) - { - // Set the event so ReadKey throws an exception to unwind. - _closingWaitHandle.Set(); - } - - return false; - } - - /// - /// Entry point - called from the PowerShell function PSConsoleHostReadline - /// after the prompt has been displayed. - /// - /// The complete command line. - public static string ReadLine(Runspace runspace, EngineIntrinsics engineIntrinsics) - { - var console = _singleton._console; - - // If either stdin or stdout is redirected, PSReadline doesn't really work, so throw - // and let PowerShell call Console.ReadLine or do whatever else it decides to do. - if (Console.IsInputRedirected || Console.IsOutputRedirected) - { - throw new NotSupportedException(); - } - - _singleton._savedConsoleInputMode = _singleton._console.GetConsoleInputMode(); - bool firstTime = true; - while (true) - { - try - { - _singleton._console.SetConsoleInputMode(_singleton._savedConsoleInputMode); - - if (firstTime) - { - firstTime = false; - _singleton.Initialize(runspace, engineIntrinsics); - } - - return _singleton.InputLoop(); - } - catch (OperationCanceledException) - { - // Console is exiting - return value isn't too critical - null or 'exit' could work equally well. - return ""; - } - catch (ExitException) - { - return "exit"; - } - catch (CustomHandlerException e) - { - var oldColor = console.ForegroundColor; - console.ForegroundColor = ConsoleColor.Red; - console.WriteLine( - string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsCustomHandlerException, e.InnerException.Message)); - console.ForegroundColor = oldColor; - - var lineBeforeCrash = _singleton._buffer.ToString(); - _singleton.Initialize(runspace, _singleton._engineIntrinsics); - InvokePrompt(); - Insert(lineBeforeCrash); - } - catch (Exception e) - { - // If we're running tests, just throw. - if (_singleton._mockableMethods != _singleton) - { - throw; - } - - while (e.InnerException != null) - { - e = e.InnerException; - } - var oldColor = console.ForegroundColor; - console.ForegroundColor = ConsoleColor.Red; - console.WriteLine(PSReadLineResources.OopsAnErrorMessage1); - console.ForegroundColor = oldColor; - var sb = new StringBuilder(); - for (int i = 0; i < _lastNKeys.Count; i++) - { - sb.Append(' '); - sb.Append(_lastNKeys[i].ToGestureString()); - - KeyHandler handler; - if (_singleton._dispatchTable.TryGetValue(_lastNKeys[i], out handler) && - "AcceptLine".Equals(handler.BriefDescription, StringComparison.OrdinalIgnoreCase)) - { - // Make it a little easier to see the keys - sb.Append('\n'); - } - } - - console.WriteLine(string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsAnErrorMessage2, _lastNKeys.Count, sb, e)); - var lineBeforeCrash = _singleton._buffer.ToString(); - _singleton.Initialize(runspace, _singleton._engineIntrinsics); - InvokePrompt(); - Insert(lineBeforeCrash); - } - finally - { - _singleton._console.RestoreConsoleInputMode(_singleton._savedConsoleInputMode); - } - } - } - - private string InputLoop() - { - ProcessViVisualEditing(); - - while (true) - { - var killCommandCount = _killCommandCount; - var yankCommandCount = _yankCommandCount; - var tabCommandCount = _tabCommandCount; - var searchHistoryCommandCount = _searchHistoryCommandCount; - var recallHistoryCommandCount = _recallHistoryCommandCount; - var yankLastArgCommandCount = _yankLastArgCommandCount; - var visualSelectionCommandCount = _visualSelectionCommandCount; - var movingAtEndOfLineCount = _moveToLineCommandCount; - - var key = ReadKey(); - ProcessOneKey(key, _dispatchTable, ignoreIfNoAction: false, arg: null); - if (_inputAccepted) - { - return MaybeAddToHistory(_buffer.ToString(), _edits, _undoEditIndex, readingHistoryFile: false, fromDifferentSession: false); - } - - if (killCommandCount == _killCommandCount) - { - // Reset kill command count if it didn't change - _killCommandCount = 0; - } - if (yankCommandCount == _yankCommandCount) - { - // Reset yank command count if it didn't change - _yankCommandCount = 0; - } - if (yankLastArgCommandCount == _yankLastArgCommandCount) - { - // Reset yank last arg command count if it didn't change - _yankLastArgCommandCount = 0; - _yankLastArgState = null; - } - if (tabCommandCount == _tabCommandCount) - { - // Reset tab command count if it didn't change - _tabCommandCount = 0; - _tabCompletions = null; - } - if (searchHistoryCommandCount == _searchHistoryCommandCount) - { - if (_searchHistoryCommandCount > 0) - { - _emphasisStart = -1; - _emphasisLength = 0; - Render(); - _currentHistoryIndex = _history.Count; - } - _searchHistoryCommandCount = 0; - _searchHistoryPrefix = null; - } - if (recallHistoryCommandCount == _recallHistoryCommandCount) - { - if (_recallHistoryCommandCount > 0) - { - _currentHistoryIndex = _history.Count; - } - _recallHistoryCommandCount = 0; - } - if (searchHistoryCommandCount == _searchHistoryCommandCount && - recallHistoryCommandCount == _recallHistoryCommandCount) - { - _hashedHistory = null; - } - if (visualSelectionCommandCount == _visualSelectionCommandCount && _visualSelectionCommandCount > 0) - { - _visualSelectionCommandCount = 0; - Render(); // Clears the visual selection - } - if (movingAtEndOfLineCount == _moveToLineCommandCount) - { - _moveToLineCommandCount = 0; - } - } - } - - T CalloutUsingDefaultConsoleMode(Func func) - { - var currentMode = _console.GetConsoleInputMode(); - try - { - _console.RestoreConsoleInputMode(_savedConsoleInputMode); - return func(); - } - finally - { - _console.RestoreConsoleInputMode(currentMode); - } - } - - void CalloutUsingDefaultConsoleMode(Action action) - { - CalloutUsingDefaultConsoleMode(() => { action(); return null; }); - } - - void ProcessOneKey(ConsoleKeyInfo key, Dictionary dispatchTable, bool ignoreIfNoAction, object arg) - { - KeyHandler handler; - - if (!dispatchTable.TryGetValue(key, out handler)) - { - // If we see a control character where Ctrl wasn't used but shift was, treat that like - // shift hadn't be pressed. This cleanly allows Shift+Backspace without adding a key binding. - if (key.KeyChar > 0 && char.IsControl(key.KeyChar) && key.Modifiers == ConsoleModifiers.Shift) - { - key = new ConsoleKeyInfo(key.KeyChar, key.Key, false, false, false); - dispatchTable.TryGetValue(key, out handler); - } - } - - if (handler != null) - { - if (handler.ScriptBlock != null) - { - CalloutUsingDefaultConsoleMode(() => handler.Action(key, arg)); - } - else - { - handler.Action(key, arg); - } - } - else if (!ignoreIfNoAction && key.KeyChar != 0) - { - SelfInsert(key, arg); - } - } - - private PSConsoleReadLine() - { - _mockableMethods = this; -#if UNIX - _console = new TTYConsole(); -#else - _console = new ConhostConsole(); -#endif - - _buffer = new StringBuilder(8 * 1024); - _statusBuffer = new StringBuilder(256); - _savedCurrentLine = new HistoryItem(); - _queuedKeys = new Queue(); - - string hostName = null; - // This works mostly by luck - we're not doing anything to guarantee the constructor for our - // singleton is called on a thread with a runspace, but it is happening by coincidence. - using (var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)) - { - try - { - ps.AddCommand("Get-Variable").AddParameter("Name", "host").AddParameter("ValueOnly"); - var results = ps.Invoke(); - dynamic host = results.Count == 1 ? results[0] : null; - if (host != null) - { - hostName = host.Name as string; - } - } - catch - { - } - } - if (hostName == null) - { - hostName = "PSReadline"; - } - _options = new PSConsoleReadlineOptions(hostName); - SetDefaultBindings(_options.EditMode); - } - - private void Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics) - { - _engineIntrinsics = engineIntrinsics; - _runspace = runspace; - - if (!_delayedOneTimeInitCompleted) - { - DelayedOneTimeInitialize(); - _delayedOneTimeInitCompleted = true; - } - - _buffer.Clear(); - _edits = new List(); - _undoEditIndex = 0; - _editGroupStart = -1; - _current = 0; - _mark = 0; - _emphasisStart = -1; - _emphasisLength = 0; - _tokens = null; - _parseErrors = null; - _inputAccepted = false; - _initialX = _console.CursorLeft; - _initialY = _console.CursorTop - Options.ExtraPromptLineCount; - _initialBackgroundColor = _console.BackgroundColor; - _initialForegroundColor = _console.ForegroundColor; - _space = new BufferChar - { - UnicodeChar = ' ', - BackgroundColor = _initialBackgroundColor, - ForegroundColor = _initialForegroundColor - }; - _bufferWidth = _console.BufferWidth; - _killCommandCount = 0; - _yankCommandCount = 0; - _yankLastArgCommandCount = 0; - _tabCommandCount = 0; - _visualSelectionCommandCount = 0; - _statusIsErrorMessage = false; - - -#if UNIX // TODO: not necessary if ReadBufferLines worked, or if rendering worked on spans instead of complete lines - string newPrompt = GetPrompt(); - int index = newPrompt.LastIndexOf('\n'); - if (index != -1) - { - // The prompt text could be a multi-line string, and in such case - // we only want the part of it that is shown on the input line. - newPrompt = newPrompt.Substring(index + 1); - } - var bufferLineCount = (newPrompt.Length) / (_console.BufferWidth) + 1; - _consoleBuffer = ReadBufferLines(_initialY, bufferLineCount); - - for (int i=0; i 0) - { - _currentHistoryIndex = _getNextHistoryIndex; - UpdateFromHistory(moveCursor: true); - _getNextHistoryIndex = 0; - if (_searchHistoryCommandCount > 0) - { - _searchHistoryPrefix = ""; - if (Options.HistoryNoDuplicates) - { - _hashedHistory = new Dictionary(); - } - } - } - else - { - _searchHistoryCommandCount = 0; - } - } - - private void DelayedOneTimeInitialize() - { - // Delayed initialization is needed so that options can be set - // after the constuctor but have an affect before the user starts - // editing their first command line. For example, if the user - // specifies a custom history save file, we don't want to try reading - // from the default one. - - if (_engineIntrinsics != null) - { - var historyCountVar = _engineIntrinsics.SessionState.PSVariable.Get("MaximumHistoryCount"); - if (historyCountVar != null && historyCountVar.Value is int) - { - _options.MaximumHistoryCount = (int)historyCountVar.Value; - } - } - -#if UNIX - _historyFileMutex = new Mutex(false); -#else - _historyFileMutex = new Mutex(false, GetHistorySaveFileMutexName()); -#endif - - _history = new HistoryQueue(Options.MaximumHistoryCount); - _currentHistoryIndex = 0; - - bool readHistoryFile = true; - try - { - if (_options.HistorySaveStyle == HistorySaveStyle.SaveNothing && Runspace.DefaultRunspace != null) - { - using (var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)) - { - ps.AddCommand("Microsoft.PowerShell.Core\\Get-History"); - foreach (var historyInfo in ps.Invoke()) - { - AddToHistory(historyInfo.CommandLine); - } - readHistoryFile = false; - } - } - } - catch - { - } - - if (readHistoryFile) - { - ReadHistoryFile(); - } - - _killIndex = -1; // So first add indexes 0. - _killRing = new List(Options.MaximumKillRingCount); - -#if !UNIX - _breakHandlerGcHandle = GCHandle.Alloc(new BreakHandler(_singleton.BreakHandler)); - NativeMethods.SetConsoleCtrlHandler((BreakHandler)_breakHandlerGcHandle.Target, true); -#endif - _singleton._readKeyWaitHandle = new AutoResetEvent(false); - _singleton._keyReadWaitHandle = new AutoResetEvent(false); - _singleton._closingWaitHandle = new ManualResetEvent(false); - _singleton._requestKeyWaitHandles = new WaitHandle[] {_singleton._keyReadWaitHandle, _singleton._closingWaitHandle}; - _singleton._threadProcWaitHandles = new WaitHandle[] {_singleton._readKeyWaitHandle, _singleton._closingWaitHandle}; - -#if !CORECLR - // This is for a "being hosted in an alternate appdomain scenario" (the - // DomainUnload event is not raised for the default appdomain). It allows us - // to exit cleanly when the appdomain is unloaded but the process is not going - // away. - if (!AppDomain.CurrentDomain.IsDefaultAppDomain()) - { - AppDomain.CurrentDomain.DomainUnload += (x, y) => - { - _singleton._closingWaitHandle.Set(); - _singleton._readKeyThread.Join(); // may need to wait for history to be written - }; - } -#endif - - _singleton._readKeyThread = new Thread(_singleton.ReadKeyThreadProc) {IsBackground = true}; - _singleton._readKeyThread.Start(); - } - - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void Chord(ConsoleKeyInfo? key = null, object arg = null) - { - if (!key.HasValue) - { - throw new ArgumentNullException("key"); - } - - Dictionary secondKeyDispatchTable; - if (_singleton._chordDispatchTable.TryGetValue(key.Value, out secondKeyDispatchTable)) - { - var secondKey = ReadKey(); - _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg); - } - } - - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void Ignore(ConsoleKeyInfo? key = null, object arg = null) - { - } - - private static void ExecuteOnSTAThread(Action action) - { -#if CORECLR - action(); -#else - if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) - { - action(); - return; - } - - Exception exception = null; - var thread = new Thread(() => - { - try - { - action(); - } - catch (Exception e) - { - exception = e; - } - }); - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - thread.Join(); - - if (exception != null) - { - throw exception; - } -#endif - } - - #region Miscellaneous bindable functions - - /// - /// Abort current action, e.g. incremental history search - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Abort(ConsoleKeyInfo? key = null, object arg = null) - { - } - - /// - /// Start a new digit argument to pass to other functions - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void DigitArgument(ConsoleKeyInfo? key = null, object arg = null) - { - if (!key.HasValue || char.IsControl(key.Value.KeyChar)) - { - Ding(); - return; - } - - if (_singleton._options.EditMode == EditMode.Vi && key.Value.KeyChar == '0') - { - BeginningOfLine(); - return; - } - - bool sawDigit = false; - _singleton._statusLinePrompt = "digit-argument: "; - var argBuffer = _singleton._statusBuffer; - argBuffer.Append(key.Value.KeyChar); - if (key.Value.KeyChar == '-') - { - argBuffer.Append('1'); - } - else - { - sawDigit = true; - } - - _singleton.Render(); // Render prompt - while (true) - { - var nextKey = ReadKey(); - KeyHandler handler; - if (_singleton._dispatchTable.TryGetValue(nextKey, out handler)) - { - if (handler.Action == DigitArgument) - { - if (nextKey.KeyChar == '-') - { - if (argBuffer[0] == '-') - { - argBuffer.Remove(0, 1); - } - else - { - argBuffer.Insert(0, '-'); - } - _singleton.Render(); // Render prompt - continue; - } - - if (nextKey.KeyChar >= '0' && nextKey.KeyChar <= '9') - { - if (!sawDigit && argBuffer.Length > 0) - { - // Buffer is either '-1' or '1' from one or more Alt+- keys - // but no digits yet. Remove the '1'. - argBuffer.Length -= 1; - } - sawDigit = true; - argBuffer.Append(nextKey.KeyChar); - _singleton.Render(); // Render prompt - continue; - } - } - else if (handler.Action == Abort || - handler.Action == CancelLine || - handler.Action == CopyOrCancelLine) - { - break; - } - } - - int intArg; - if (int.TryParse(argBuffer.ToString(), out intArg)) - { - _singleton.ProcessOneKey(nextKey, _singleton._dispatchTable, ignoreIfNoAction: false, arg: intArg); - } - else - { - Ding(); - } - break; - } - - // Remove our status line - argBuffer.Clear(); - _singleton.ClearStatusMessage(render: true); - } - - - /// - /// Erases the current prompt and calls the prompt function to redisplay - /// the prompt. Useful for custom key handlers that change state, e.g. - /// change the current directory. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void InvokePrompt(ConsoleKeyInfo? key = null, object arg = null) - { - var currentBuffer = _singleton._buffer.ToString(); - var currentPos = _singleton._current; - _singleton._buffer.Clear(); - _singleton._current = 0; - for (int i = 0; i < _singleton._consoleBuffer.Length; i++) - { - _singleton._consoleBuffer[i].UnicodeChar = ' '; - _singleton._consoleBuffer[i].ForegroundColor = _singleton._console.ForegroundColor; - _singleton._consoleBuffer[i].BackgroundColor = _singleton._console.BackgroundColor; - } - _singleton.Render(); - _singleton._console.CursorLeft = 0; - _singleton._console.CursorTop = _singleton._initialY - _singleton.Options.ExtraPromptLineCount; - - string newPrompt = GetPrompt(); - _singleton._console.Write(newPrompt); - - _singleton._initialX = _singleton._console.CursorLeft; - _singleton._consoleBuffer = ReadBufferLines(_singleton._initialY, 1 + _singleton.Options.ExtraPromptLineCount); -#if UNIX // TODO: ReadBufferLines only needed for extra line, but doesn't work on Linux - for (int i=0; i - /// Gets the current prompt as possibly defined by the user through the - /// prompt function, and returns a default prompt if no other is - /// available. Also handles remote prompts. - /// - public static string GetPrompt() - { - string newPrompt; - var runspaceIsRemote = _singleton._mockableMethods.RunspaceIsRemote(_singleton._runspace); - - if ((_singleton._runspace.Debugger != null) && _singleton._runspace.Debugger.InBreakpoint) - { - // Run prompt command in debugger API to ensure it is run correctly on the runspace. - // This handles remote runspace debugging and nested debugger scenarios. - PSDataCollection results = new PSDataCollection(); - var command = new PSCommand(); - command.AddCommand(PromptCommand); - _singleton._runspace.Debugger.ProcessCommand( - command, - results); - - newPrompt = (results.Count == 1) ? (results[0].BaseObject as string) : DefaultPrompt; - } - else - { - System.Management.Automation.PowerShell ps; - if (!runspaceIsRemote) - { - ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); - } - else - { - ps = System.Management.Automation.PowerShell.Create(); - ps.Runspace = _singleton._runspace; - } - using (ps) - { - ps.AddCommand(PromptCommand); - var result = ps.Invoke(); - newPrompt = result.Count == 1 ? result[0] : DefaultPrompt; - } - } - - if (string.IsNullOrEmpty(newPrompt)) - { - newPrompt = DefaultPrompt; - } - - if (runspaceIsRemote) - { - var connectionInfo = _singleton._runspace.ConnectionInfo; - if (!string.IsNullOrEmpty(connectionInfo.ComputerName)) - { - newPrompt = string.Format(CultureInfo.InvariantCulture, "[{0}]: {1}", connectionInfo.ComputerName, newPrompt); - } - } - - return newPrompt; - } - - #endregion Miscellaneous bindable functions - - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/ReadLine.vi.cs b/src/Microsoft.PowerShell.PSReadLine/ReadLine.vi.cs deleted file mode 100644 index 304663f06a41..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/ReadLine.vi.cs +++ /dev/null @@ -1,1247 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - /// - /// Remembers last history search direction. - /// - private bool _searchHistoryBackward = true; - - private class ViCharacterSearcher - { - private char searchChar = '\0'; - private bool wasBackward = false; - private bool wasBackoff = false; - - public static ViCharacterSearcher instance = new ViCharacterSearcher(); - - public static bool IsRepeatable - { - get { return instance.searchChar != '\0'; } - } - - public static char SearchChar - { - get { return instance.searchChar; } - } - - public static bool WasBackward - { - get { return instance.wasBackward; } - } - - public static bool WasBackoff - { - get { return instance.wasBackoff; } - } - - public static void Set(char theChar, bool isBackward = false, bool isBackoff = false) - { - instance.searchChar = theChar; - instance.wasBackward = isBackward; - instance.wasBackoff = isBackoff; - } - - - public static void Search(char keyChar, object arg, bool backoff) - { - int qty = (arg is int) ? (int) arg : 1; - - for (int i = _singleton._current + 1; i < _singleton._buffer.Length; i++) - { - if (_singleton._buffer[i] == keyChar) - { - qty -= 1; - if (qty == 0) - { - _singleton._current = backoff ? i - 1 : i; - _singleton.PlaceCursor(); - return; - } - } - } - Ding(); - } - - public static bool SearchDelete(char keyChar, object arg, bool backoff, Action instigator) - { - int qty = (arg is int) ? (int) arg : 1; - - for (int i = _singleton._current + 1; i < _singleton._buffer.Length; i++) - { - if (_singleton._buffer[i] == keyChar) - { - qty -= 1; - if (qty == 0) - { - DeleteToEndPoint(arg, backoff ? i : i + 1, instigator); - return true; - } - } - } - Ding(); - return false; - } - - public static void SearchBackward(char keyChar, object arg, bool backoff) - { - Set(keyChar, isBackward: true, isBackoff: backoff); - int qty = (arg is int) ? (int) arg : 1; - - for (int i = _singleton._current - 1; i >= 0; i--) - { - if (_singleton._buffer[i] == keyChar) - { - qty -= 1; - if (qty == 0) - { - _singleton._current = backoff ? i + 1 : i; - _singleton.PlaceCursor(); - return; - } - } - } - Ding(); - } - - public static bool SearchBackwardDelete(char keyChar, object arg, bool backoff, Action instigator) - { - Set(keyChar, isBackward: true, isBackoff: backoff); - int qty = (arg is int) ? (int) arg : 1; - - for (int i = _singleton._current - 1; i >= 0; i--) - { - if (_singleton._buffer[i] == keyChar) - { - qty -= 1; - if (qty == 0) - { - DeleteBackwardToEndPoint(arg, backoff ? i + 1 : i, instigator); - return true; - } - } - } - Ding(); - return false; - } - } - - /// - /// Repeat the last recorded character search. - /// - public static void RepeatLastCharSearch(ConsoleKeyInfo? key = null, object arg = null) - { - if (!ViCharacterSearcher.IsRepeatable) - { - Ding(); - return; - } - - if (ViCharacterSearcher.WasBackward) - { - ViCharacterSearcher.SearchBackward(ViCharacterSearcher.SearchChar, null, ViCharacterSearcher.WasBackoff); - } - else - { - ViCharacterSearcher.Search(ViCharacterSearcher.SearchChar, null, ViCharacterSearcher.WasBackoff); - } - } - - /// - /// Repeat the last recorded character search, but in the opposite direction. - /// - public static void RepeatLastCharSearchBackwards(ConsoleKeyInfo? key = null, object arg = null) - { - if (!ViCharacterSearcher.IsRepeatable) - { - Ding(); - return; - } - - if (ViCharacterSearcher.WasBackward) - { - ViCharacterSearcher.Search(ViCharacterSearcher.SearchChar, null, ViCharacterSearcher.WasBackoff); - } - else - { - ViCharacterSearcher.SearchBackward(ViCharacterSearcher.SearchChar, null, ViCharacterSearcher.WasBackoff); - } - } - - /// - /// Read the next character and then find it, going forward, and then back off a character. - /// This is for 't' functionality. - /// - public static void SearchChar(ConsoleKeyInfo? key = null, object arg = null) - { - char keyChar = ReadKey().KeyChar; - ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: false); - ViCharacterSearcher.Search(keyChar, arg, backoff: false); - } - - /// - /// Read the next character and then find it, going backward, and then back off a character. - /// This is for 'T' functionality. - /// - public static void SearchCharBackward(ConsoleKeyInfo? key = null, object arg = null) - { - char keyChar = ReadKey().KeyChar; - ViCharacterSearcher.Set(keyChar, isBackward: true, isBackoff: false); - ViCharacterSearcher.SearchBackward(keyChar, arg, backoff: false); - } - - /// - /// Read the next character and then find it, going forward, and then back off a character. - /// This is for 't' functionality. - /// - public static void SearchCharWithBackoff(ConsoleKeyInfo? key = null, object arg = null) - { - char keyChar = ReadKey().KeyChar; - ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: true); - ViCharacterSearcher.Search(keyChar, arg, backoff: true); - } - - /// - /// Read the next character and then find it, going backward, and then back off a character. - /// This is for 'T' functionality. - /// - public static void SearchCharBackwardWithBackoff(ConsoleKeyInfo? key = null, object arg = null) - { - char keyChar = ReadKey().KeyChar; - ViCharacterSearcher.Set(keyChar, isBackward: true, isBackoff: true); - ViCharacterSearcher.SearchBackward(keyChar, arg, backoff: true); - } - - /// - /// Exits the shell. - /// - public static void ViExit(ConsoleKeyInfo? key = null, object arg = null) - { - throw new ExitException(); - } - - /// - /// Delete to the end of the line. - /// - public static void DeleteToEnd(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._current >= _singleton._buffer.Length) - { - Ding(); - return; - } - - _singleton._clipboard = _singleton._buffer.ToString(_singleton._current, _singleton._buffer.Length - _singleton._current); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - _singleton._current, - DeleteToEnd, - arg - )); - _singleton._buffer.Remove(_singleton._current, _singleton._buffer.Length - _singleton._current); - _singleton._current = Math.Max(0, _singleton._buffer.Length - 1); - _singleton.Render(); - } - - /// - /// Delete the next word. - /// - public static void DeleteWord(ConsoleKeyInfo? key = null, object arg = null) - { - int qty = (arg is int) ? (int)arg : 1; - int endPoint = _singleton._current; - for (int i = 0; i < qty; i++) - { - endPoint = _singleton.ViFindNextWordPoint(endPoint, _singleton.Options.WordDelimiters); - } - - if (endPoint <= _singleton._current) - { - Ding(); - return; - } - - DeleteToEndPoint(arg, endPoint, DeleteWord); - } - - private static void DeleteToEndPoint(object arg, int endPoint, Action instigator) - { - _singleton.SaveToClipboard(_singleton._current, endPoint - _singleton._current); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - _singleton._current, - instigator, - arg - )); - _singleton._buffer.Remove(_singleton._current, endPoint - _singleton._current); - if (_singleton._current >= _singleton._buffer.Length) - { - _singleton._current = Math.Max(0, _singleton._buffer.Length - 1); - } - _singleton.Render(); - } - - private static void DeleteBackwardToEndPoint(object arg, int endPoint, Action instigator) - { - int deleteLength = _singleton._current - endPoint + 1; - - _singleton.SaveToClipboard(endPoint, deleteLength); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - endPoint, - instigator, - arg - )); - _singleton._buffer.Remove(endPoint, deleteLength); - _singleton._current = endPoint; - _singleton.Render(); - } - - /// - /// Delete the next glob (white space delimited word). - /// - public static void ViDeleteGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int qty = (arg is int) ? (int)arg : 1; - int endPoint = _singleton._current; - while (qty-- > 0) - { - endPoint = _singleton.ViFindNextGlob(endPoint); - } - int length = endPoint - _singleton._current; - - _singleton.SaveToClipboard(_singleton._current, length); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - _singleton._current, - ViDeleteGlob, - arg - )); - _singleton._buffer.Remove(_singleton._current, length); - if (_singleton._current >= _singleton._buffer.Length) - { - _singleton._current = Math.Max(0, _singleton._buffer.Length - 1); - } - _singleton.Render(); - } - - /// - /// Delete to the end of the word. - /// - public static void DeleteEndOfWord(ConsoleKeyInfo? key = null, object arg = null) - { - int qty = (arg is int) ? (int)arg : 1; - int endPoint = _singleton._current; - for (int i = 0; i < qty; i++) - { - endPoint = _singleton.ViFindNextWordEnd(endPoint, _singleton.Options.WordDelimiters); - } - - if (endPoint <= _singleton._current) - { - Ding(); - return; - } - _singleton.SaveToClipboard(_singleton._current, 1 + endPoint - _singleton._current); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - _singleton._current, - DeleteEndOfWord, - arg - )); - _singleton._buffer.Remove(_singleton._current, 1 + endPoint - _singleton._current); - if (_singleton._current >= _singleton._buffer.Length) - { - _singleton._current = Math.Max(0,_singleton._buffer.Length - 1); - } - _singleton.Render(); - } - - /// - /// Delete to the end of the word. - /// - public static void ViDeleteEndOfGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int qty = (arg is int) ? (int)arg : 1; - int endPoint = _singleton._current; - for (int i = 0; i < qty; i++) - { - endPoint = _singleton.ViFindGlobEnd(endPoint); - } - - _singleton.SaveToClipboard(_singleton._current, 1 + endPoint - _singleton._current); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - _singleton._current, - ViDeleteEndOfGlob, - arg - )); - _singleton._buffer.Remove(_singleton._current, 1 + endPoint - _singleton._current); - if (_singleton._current >= _singleton._buffer.Length) - { - _singleton._current = Math.Max(0, _singleton._buffer.Length - 1); - } - _singleton.Render(); - } - - /// - /// Deletes until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViDeleteToChar(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViDeleteToChar(keyChar, key, arg); - } - - private static void ViDeleteToChar(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: false); - ViCharacterSearcher.SearchDelete(keyChar, arg, backoff: false, instigator: (_key, _arg) => ViDeleteToChar(keyChar, _key, _arg)); - } - - /// - /// Deletes until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViDeleteToCharBackward(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViDeleteToCharBack(keyChar, key, arg); - } - - private static void ViDeleteToCharBack(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - ViCharacterSearcher.SearchBackwardDelete(keyChar, arg, backoff: false, instigator: (_key, _arg) => ViDeleteToCharBack(keyChar, _key, _arg)); - } - - /// - /// Deletes until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViDeleteToBeforeChar(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViDeleteToBeforeChar(keyChar, key, arg); - } - - private static void ViDeleteToBeforeChar(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: true); - ViCharacterSearcher.SearchDelete(keyChar, arg, backoff: true, instigator: (_key, _arg) => ViDeleteToBeforeChar(keyChar, _key, _arg)); - } - - /// - /// Deletes until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViDeleteToBeforeCharBackward(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViDeleteToBeforeCharBack(keyChar, key, arg); - } - - private static void ViDeleteToBeforeCharBack(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - ViCharacterSearcher.Set(keyChar, isBackward: true, isBackoff: true); - ViCharacterSearcher.SearchBackwardDelete(keyChar, arg, backoff: true, instigator: (_key, _arg) => ViDeleteToBeforeCharBack(keyChar, _key, _arg)); - } - - /// - /// Ring the bell. - /// - private static void Ding(ConsoleKeyInfo? key = null, object arg = null) - { - Ding(); - } - - /// - /// Switch the current operating mode from Vi-Insert to Vi-Command. - /// - public static void ViCommandMode(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._editGroupStart >= 0) - { - _singleton._groupUndoHelper.EndGroup(); - } - _singleton._dispatchTable = _viCmdKeyMap; - _singleton._chordDispatchTable = _viCmdChordTable; - BackwardChar(); - _singleton.PlaceCursor(); - _singleton.ViIndicateCommandMode(); - } - - /// - /// Switch to Insert mode. - /// - public static void ViInsertMode(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._dispatchTable = _viInsKeyMap; - _singleton._chordDispatchTable = _viInsChordTable; - _singleton.ViIndicateInsertMode(); - } - - /// - /// Temporarily swap in Vi-Command dispatch tables. Used for setting handlers. - /// - internal static IDisposable UseViCommandModeTables() - { - var oldDispatchTable = _singleton._dispatchTable; - var oldChordDispatchTable = _singleton._chordDispatchTable; - - _singleton._dispatchTable = _viCmdKeyMap; - _singleton._chordDispatchTable = _viCmdChordTable; - - return new Disposable( () => - { - _singleton._dispatchTable = oldDispatchTable; - _singleton._chordDispatchTable = oldChordDispatchTable; - } ); - } - - /// - /// Temporarily swap in Vi-Insert dispatch tables. Used for setting handlers. - /// - internal static IDisposable UseViInsertModeTables() - { - var oldDispatchTable = _singleton._dispatchTable; - var oldChordDispatchTable = _singleton._chordDispatchTable; - - _singleton._dispatchTable = _viInsKeyMap; - _singleton._chordDispatchTable = _viInsChordTable; - - return new Disposable( () => - { - _singleton._dispatchTable = oldDispatchTable; - _singleton._chordDispatchTable = oldChordDispatchTable; - } ); - } - - private void ViIndicateCommandMode() - { - if (_options.ViModeIndicator == ViModeStyle.Cursor) - { - _console.CursorSize = _normalCursorSize < 50 ? 100 : 25; - } - else if (_options.ViModeIndicator == ViModeStyle.Prompt) - { - ConsoleColor savedBackground = _console.BackgroundColor; - _console.BackgroundColor = AlternateBackground(_console.BackgroundColor); - InvokePrompt(); - _console.BackgroundColor = savedBackground; - } - } - - private void ViIndicateInsertMode() - { - if (_options.ViModeIndicator == ViModeStyle.Cursor) - { - _console.CursorSize = _normalCursorSize; - } - else if (_options.ViModeIndicator == ViModeStyle.Prompt) - { - InvokePrompt(); - } - } - - /// - /// Switch to Insert mode and position the cursor at the beginning of the line. - /// - public static void ViInsertAtBegining(ConsoleKeyInfo? key = null, object arg = null) - { - ViInsertMode(key, arg); - BeginningOfLine(key, arg); - } - - /// - /// Switch to Insert mode and position the cursor at the end of the line. - /// - public static void - ViInsertAtEnd(ConsoleKeyInfo? key = null, object arg = null) - { - ViInsertMode(key, arg); - EndOfLine(key, arg); - } - - /// - /// Append from the current line position. - /// - public static void ViInsertWithAppend(ConsoleKeyInfo? key = null, object arg = null) - { - ViInsertMode(key, arg); - ForwardChar(key, arg); - } - - /// - /// Delete the current character and switch to Insert mode. - /// - public static void ViInsertWithDelete(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._groupUndoHelper.StartGroup(ViInsertWithDelete, arg); - DeleteChar(key, arg); - ViInsertMode(key, arg); - } - - /// - /// Accept the line and switch to Insert mode. - /// - public static void ViAcceptLine(ConsoleKeyInfo? key = null, object arg = null) - { - ViInsertMode(key, arg); - AcceptLine(key, arg); - } - - /// - /// Prepend a '#' and accept the line. - /// - public static void PrependAndAccept(ConsoleKeyInfo? key = null, object arg = null) - { - BeginningOfLine(key, arg); - SelfInsert(key, arg); - ViAcceptLine(key, arg); - } - - /// - /// Invert the case of the current character and move to the next one. - /// - public static void InvertCase(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._current >= _singleton._buffer.Length) - { - Ding(); - return; - } - - int qty = (arg is int) ? (int) arg : 1; - - for (; qty > 0 && _singleton._current < _singleton._buffer.Length; qty--) - { - char c = _singleton._buffer[_singleton._current]; - if (Char.IsLetter(c)) - { - char newChar = Char.IsUpper(c) ? Char.ToLower(c) : char.ToUpper(c); - EditItem delEditItem = EditItemDelete.Create(c.ToString(), _singleton._current); - EditItem insEditItem = EditItemInsertChar.Create(newChar, _singleton._current); - _singleton.SaveEditItem(GroupedEdit.Create(new List - { - delEditItem, - insEditItem - }, - InvertCase, - arg - )); - - _singleton._buffer[_singleton._current] = newChar; - } - _singleton._current = Math.Min(_singleton._current + 1, _singleton._buffer.Length); - _singleton.PlaceCursor(); - } - _singleton.Render(); - } - - /// - /// Swap the current character and the one before it. - /// - public static void SwapCharacters(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._current <= 0 || _singleton._current >= _singleton._buffer.Length) - { - Ding(); - return; - } - - char current = _singleton._buffer[_singleton._current]; - char previous = _singleton._buffer[_singleton._current - 1]; - - _singleton.StartEditGroup(); - _singleton.SaveEditItem(EditItemDelete.Create(_singleton._buffer.ToString(_singleton._current - 1, 2), _singleton._current - 1)); - _singleton.SaveEditItem(EditItemInsertChar.Create(current, _singleton._current - 1)); - _singleton.SaveEditItem(EditItemInsertChar.Create(previous, _singleton._current)); - _singleton.EndEditGroup(); - - _singleton._buffer[_singleton._current] = previous; - _singleton._buffer[_singleton._current - 1] = current; - _singleton._current = Math.Min(_singleton._current + 1, _singleton._buffer.Length - 1); - _singleton.PlaceCursor(); - _singleton.Render(); - } - - /// - /// Deletes text from the cursor to the first non-blank character of the line, - /// - public static void DeleteLineToFirstChar(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._current > 0) - { - int i = 0; - for (; i < _singleton._current; i++) - { - if (!Char.IsWhiteSpace(_singleton._buffer[i])) - { - break; - } - } - - _singleton.SaveToClipboard(i, _singleton._current - i); - _singleton.SaveEditItem(EditItemDelete.Create(_singleton._clipboard, i, DeleteLineToFirstChar)); - - _singleton._buffer.Remove(i, _singleton._current - i); - _singleton._current = i; - _singleton.Render(); - } - else - { - Ding(); - } - } - - /// - /// Deletes the current line, enabling undo. - /// - public static void DeleteLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._clipboard = _singleton._buffer.ToString(); - _singleton.SaveEditItem(EditItemDelete.Create(_singleton._clipboard, 0)); - _singleton._current = 0; - _singleton._buffer.Remove(0, _singleton._buffer.Length); - _singleton.Render(); - } - - /// - /// Deletes the previous word. - /// - public static void BackwardDeleteWord(ConsoleKeyInfo? key = null, object arg = null) - { - int qty = (arg is int) ? (int) arg : 1; - int deletePoint = _singleton._current; - for (int i = 0; i < qty; i++) - { - deletePoint = _singleton.ViFindPreviousWordPoint(deletePoint, _singleton.Options.WordDelimiters); - } - if (deletePoint == _singleton._current) - { - Ding(); - return; - } - _singleton._clipboard = _singleton._buffer.ToString(deletePoint, _singleton._current - deletePoint); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - deletePoint, - BackwardDeleteWord, - arg - )); - _singleton._buffer.Remove(deletePoint, _singleton._current - deletePoint); - _singleton._current = deletePoint; - _singleton.Render(); - } - - /// - /// Deletes the previous word, using only white space as the word delimiter. - /// - public static void ViBackwardDeleteGlob(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._current == 0) - { - Ding(); - return; - } - int qty = (arg is int) ? (int)arg : 1; - int deletePoint = _singleton._current; - for (int i = 0; i < qty && deletePoint > 0; i++) - { - deletePoint = _singleton.ViFindPreviousGlob(deletePoint - 1); - } - if (deletePoint == _singleton._current) - { - Ding(); - return; - } - _singleton._clipboard = _singleton._buffer.ToString(deletePoint, _singleton._current - deletePoint); - _singleton.SaveEditItem(EditItemDelete.Create( - _singleton._clipboard, - deletePoint, - BackwardDeleteWord, - arg - )); - _singleton._buffer.Remove(deletePoint, _singleton._current - deletePoint); - _singleton._current = deletePoint; - _singleton.Render(); - } - - /// - /// Find the matching brace, paren, or square bracket and delete all contents within, including the brace. - /// - public static void ViDeleteBrace(ConsoleKeyInfo? key = null, object arg = null) - { - int newCursor = _singleton.ViFindBrace(_singleton._current); - - if (_singleton._current < newCursor) - { - DeleteRange(_singleton._current, newCursor, ViDeleteBrace); - } - else if (newCursor < _singleton._current) - { - DeleteRange(newCursor, _singleton._current, ViDeleteBrace); - } - else - { - Ding(); - } - } - - /// - /// Delete all characters included in the supplied range. - /// - /// Index of where to begin the delete. - /// Index of where to end the delete. - /// Action that generated this request, used for repeat command ('.'). - private static void DeleteRange(int first, int last, Action action) - { - int length = last - first + 1; - - _singleton.SaveToClipboard(first, length); - _singleton.SaveEditItem(EditItemDelete.Create(_singleton._clipboard, first, action)); - _singleton._current = first; - _singleton._buffer.Remove(first, length); - _singleton.Render(); - } - - - /// - /// Prompts for a search string and initiates search upon AcceptLine. - /// - public static void ViSearchHistoryBackward(ConsoleKeyInfo? key = null, object arg = null) - { - if (!key.HasValue || char.IsControl(key.Value.KeyChar)) - { - Ding(); - return; - } - - _singleton.StartSearch(backward: true); - } - - /// - /// Prompts for a search string and initiates search upon AcceptLine. - /// - public static void SearchForward(ConsoleKeyInfo? key = null, object arg = null) - { - if (!key.HasValue || char.IsControl(key.Value.KeyChar)) - { - Ding(); - return; - } - - _singleton.StartSearch(backward: false); - } - - /// - /// Repeat the last search in the same direction as before. - /// - public static void RepeatSearch(ConsoleKeyInfo? key = null, object arg = null) - { - if (string.IsNullOrEmpty(_singleton._searchHistoryPrefix)) - { - Ding(); - return; - } - - _singleton.HistorySearch(); - } - - /// - /// Repeat the last search in the same direction as before. - /// - public static void RepeatSearchBackward(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._searchHistoryBackward = !_singleton._searchHistoryBackward; - RepeatSearch(); - _singleton._searchHistoryBackward = !_singleton._searchHistoryBackward; - } - - /// - /// Prompts for a string for history searching. - /// - /// True for searching backward in the history. - private void StartSearch(bool backward) - { - _statusLinePrompt = "find: "; - var argBuffer = _statusBuffer; - Render(); // Render prompt - - while (true) - { - var nextKey = ReadKey(); - if (nextKey.Key == Keys.Enter.Key || nextKey.Key == Keys.Tab.Key) - { - _searchHistoryPrefix = argBuffer.ToString(); - _searchHistoryBackward = backward; - HistorySearch(); - break; - } - if (nextKey.Key == Keys.Escape.Key) - { - break; - } - if (nextKey.Key == Keys.Backspace.Key) - { - if (argBuffer.Length > 0) - { - argBuffer.Remove(argBuffer.Length - 1, 1); - Render(); // Render prompt - continue; - } - break; - } - argBuffer.Append(nextKey.KeyChar); - Render(); // Render prompt - } - - // Remove our status line - argBuffer.Clear(); - _statusLinePrompt = null; - Render(); // Render prompt - } - - /// - /// Searches line history. - /// - private void HistorySearch() - { - _searchHistoryCommandCount++; - - int incr = _searchHistoryBackward ? -1 : +1; - for (int i = _currentHistoryIndex + incr; i >= 0 && i < _history.Count; i += incr) - { - if (Options.HistoryStringComparison.HasFlag(StringComparison.OrdinalIgnoreCase)) - { - if (_history[i]._line.ToLower().Contains(_searchHistoryPrefix.ToLower())) - { - _currentHistoryIndex = i; - UpdateFromHistory(moveCursor: Options.HistorySearchCursorMovesToEnd); - return; - } - } - else - { - if (_history[i]._line.Contains(_searchHistoryPrefix)) - { - _currentHistoryIndex = i; - UpdateFromHistory(moveCursor: Options.HistorySearchCursorMovesToEnd); - return; - } - } - } - - Ding(); - } - - /// - /// Repeat the last text modification. - /// - public static void RepeatLastCommand(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._undoEditIndex > 0) - { - EditItem editItem = _singleton._edits[_singleton._undoEditIndex - 1]; - if (editItem._instigator != null) - { - editItem._instigator(key, editItem._instigatorArg); - return; - } - } - Ding(); - } - - /// - /// Chords in vi needs special handling because a numeric argument can be input between the 1st and 2nd key. - /// - /// - /// - private static void ViChord(ConsoleKeyInfo? key = null, object arg = null) - { - if (!key.HasValue) - { - throw new ArgumentNullException("key"); - } - if (arg != null) - { - Chord(key, arg); - return; - } - - Dictionary secondKeyDispatchTable; - if (_singleton._chordDispatchTable.TryGetValue(key.Value, out secondKeyDispatchTable)) - { - //if (_singleton._demoMode) - //{ - // // Render so the first key of the chord appears in the demo window - // _singleton.Render(); - //} - var secondKey = ReadKey(); - KeyHandler handler; - if (secondKeyDispatchTable.TryGetValue(secondKey, out handler)) - { - _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg); - } - else if (!IsNumberic(secondKey)) - { - _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg); - } - else - { - var argBuffer = _singleton._statusBuffer; - argBuffer.Clear(); - _singleton._statusLinePrompt = "digit-argument: "; - while (IsNumberic(secondKey)) - { - argBuffer.Append(secondKey.KeyChar); - _singleton.Render(); - secondKey = ReadKey(); - } - int numericArg = int.Parse(argBuffer.ToString()); - if (secondKeyDispatchTable.TryGetValue(secondKey, out handler)) - { - _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: numericArg); - } - else - { - Ding(); - } - argBuffer.Clear(); - _singleton.ClearStatusMessage(render: true); - } - } - } - - private static bool IsNumberic(ConsoleKeyInfo key) - { - return char.IsNumber(key.KeyChar); - } - - /// - /// Start a new digit argument to pass to other functions while in one of vi's chords. - /// - public static void ViDigitArgumentInChord(ConsoleKeyInfo? key = null, object arg = null) - { - if (!key.HasValue || char.IsControl(key.Value.KeyChar)) - { - Ding(); - return; - } - - #region VI special case - if (_singleton._options.EditMode == EditMode.Vi && key.Value.KeyChar == '0') - { - BeginningOfLine(); - return; - } - #endregion VI special case - - bool sawDigit = false; - _singleton._statusLinePrompt = "digit-argument: "; - var argBuffer = _singleton._statusBuffer; - argBuffer.Append(key.Value.KeyChar); - if (key.Value.KeyChar == '-') - { - argBuffer.Append('1'); - } - else - { - sawDigit = true; - } - - _singleton.Render(); // Render prompt - while (true) - { - var nextKey = ReadKey(); - KeyHandler handler; - if (_singleton._dispatchTable.TryGetValue(nextKey, out handler) && handler.Action == DigitArgument) - { - if (nextKey.KeyChar == '-') - { - if (argBuffer[0] == '-') - { - argBuffer.Remove(0, 1); - } - else - { - argBuffer.Insert(0, '-'); - } - _singleton.Render(); // Render prompt - continue; - } - - if (nextKey.KeyChar >= '0' && nextKey.KeyChar <= '9') - { - if (!sawDigit && argBuffer.Length > 0) - { - // Buffer is either '-1' or '1' from one or more Alt+- keys - // but no digits yet. Remove the '1'. - argBuffer.Length -= 1; - } - sawDigit = true; - argBuffer.Append(nextKey.KeyChar); - _singleton.Render(); // Render prompt - continue; - } - } - - int intArg; - if (int.TryParse(argBuffer.ToString(), out intArg)) - { - _singleton.ProcessOneKey(nextKey, _singleton._dispatchTable, ignoreIfNoAction: false, arg: intArg); - } - else - { - Ding(); - } - break; - } - } - - /// - /// Like DeleteCharOrExit in Emacs mode, but accepts the line instead of deleting a character. - /// - public static void ViAcceptLineOrExit(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._buffer.Length > 0) - { - _singleton.AcceptLineImpl(false); - } - else - { - ViExit(key, arg); - } - } - - /// - /// A new line is inserted above the current line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ViInsertLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._groupUndoHelper.StartGroup(ViInsertLine, arg); - _singleton.MoveToBeginningOfPhrase(); - _singleton._buffer.Insert(_singleton._current, '\n'); - //_singleton._current = Math.Max(0, _singleton._current - 1); - _singleton.SaveEditItem(EditItemInsertChar.Create( '\n', _singleton._current)); - _singleton.Render(); - ViInsertMode(); - } - - private void MoveToBeginningOfPhrase() - { - while (!IsAtBeginningOfPhrase()) - { - _current--; - } - } - - private bool IsAtBeginningOfPhrase() - { - if (_current == 0) - { - return true; - } - if (_buffer[_current - 1] == '\n') - { - return true; - } - return false; - } - - /// - /// A new line is inserted below the current line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ViAppendLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._groupUndoHelper.StartGroup(ViInsertLine, arg); - _singleton.MoveToEndOfPhrase(); - int insertPoint = 0; - if (_singleton.IsAtEndOfLine(_singleton._current)) - { - insertPoint = _singleton._buffer.Length; - _singleton._buffer.Append('\n'); - _singleton._current = insertPoint; - } - else - { - insertPoint = _singleton._current + 1; - _singleton._buffer.Insert(insertPoint, '\n'); - } - _singleton.SaveEditItem(EditItemInsertChar.Create('\n', insertPoint)); - _singleton.Render(); - ViInsertWithAppend(); - } - - private void MoveToEndOfPhrase() - { - while (!IsAtEndOfPhrase()) - { - _current++; - } - } - - private bool IsAtEndOfPhrase() - { - if (_buffer.Length == 0 || _current == _buffer.Length + ViEndOfLineFactor) - { - return true; - } - if (_buffer[_current] == '\n') - { - return true; - } - return false; - } - - /// - /// Joins 2 lines. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ViJoinLines(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.MoveToEndOfPhrase(); - if (_singleton.IsAtEndOfLine(_singleton._current)) - { - Ding(); - } - else - { - _singleton._buffer[_singleton._current] = ' '; - _singleton._groupUndoHelper.StartGroup(ViJoinLines, arg); - _singleton.SaveEditItem(EditItemDelete.Create("\n", _singleton._current)); - _singleton.SaveEditItem(EditItemInsertChar.Create(' ', _singleton._current)); - _singleton._groupUndoHelper.EndGroup(); - _singleton.Render(); - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Render.cs b/src/Microsoft.PowerShell.PSReadLine/Render.cs deleted file mode 100644 index 632fdeb9cc32..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Render.cs +++ /dev/null @@ -1,815 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Management.Automation.Language; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { -#if UNIX - private const ConsoleColor UnknownColor = (ConsoleColor) (-1); -#endif - private BufferChar[] _consoleBuffer; - private int _initialX; - private int _initialY; - private int _bufferWidth; - private ConsoleColor _initialBackgroundColor; - private ConsoleColor _initialForegroundColor; - private BufferChar _space; - private int _current; - private int _emphasisStart; - private int _emphasisLength; - - private class SavedTokenState - { - internal Token[] Tokens { get; set; } - internal int Index { get; set; } - internal ConsoleColor BackgroundColor { get; set; } - internal ConsoleColor ForegroundColor { get; set; } - } - - private void MaybeParseInput() - { - if (_tokens == null) - { - ParseInput(); - } - } - - private string ParseInput() - { - var text = _buffer.ToString(); - _ast = Parser.ParseInput(text, out _tokens, out _parseErrors); - return text; - } - - private void ClearStatusMessage(bool render) - { - _statusBuffer.Clear(); - _statusLinePrompt = null; - _statusIsErrorMessage = false; - if (render) - { - Render(); - } - } - - private void Render() - { - // If there are a bunch of keys queued up, skip rendering if we've rendered - // recently. - if (_queuedKeys.Count > 10 && (_lastRenderTime.ElapsedMilliseconds < 50)) - { - // We won't render, but most likely the tokens will be different, so make - // sure we don't use old tokens. - _tokens = null; - _ast = null; - return; - } - - ReallyRender(); - } - - [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")] - private void ReallyRender() - { - var text = ParseInput(); - - int statusLineCount = GetStatusLineCount(); - int j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount); - var backgroundColor = _initialBackgroundColor; - var foregroundColor = _initialForegroundColor; - bool afterLastToken = false; - int totalBytes = j; - int bufferWidth = _console.BufferWidth; - - var tokenStack = new Stack(); - tokenStack.Push(new SavedTokenState - { - Tokens = _tokens, - Index = 0, - BackgroundColor = _initialBackgroundColor, - ForegroundColor = _initialForegroundColor - }); - - int bufferLineCount; - - try - { - _console.StartRender(); - bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount; - if (_consoleBuffer.Length != bufferLineCount * bufferWidth) - { - var newBuffer = new BufferChar[bufferLineCount * bufferWidth]; - Array.Copy(_consoleBuffer, newBuffer, _initialX + (Options.ExtraPromptLineCount * _bufferWidth)); - if (_consoleBuffer.Length > bufferLineCount * bufferWidth) - { - int consoleBufferOffset = ConvertOffsetToConsoleBufferOffset(text.Length, _initialX + (Options.ExtraPromptLineCount * _bufferWidth)); - // Need to erase the extra lines that we won't draw again - for (int i = consoleBufferOffset; i < _consoleBuffer.Length; i++) - { - _consoleBuffer[i] = _space; - } - _console.WriteBufferLines(_consoleBuffer, ref _initialY); - } - _consoleBuffer = newBuffer; - } - - for (int i = 0; i < text.Length; i++) - { - totalBytes = totalBytes % bufferWidth; - if (!afterLastToken) - { - // Figure out the color of the character - if it's in a token, - // use the tokens color otherwise use the initial color. - var state = tokenStack.Peek(); - var token = state.Tokens[state.Index]; - - if (i == token.Extent.EndOffset) - { - if (token == state.Tokens[state.Tokens.Length - 1]) - { - tokenStack.Pop(); - if (tokenStack.Count == 0) - { - afterLastToken = true; - token = null; - foregroundColor = _initialForegroundColor; - backgroundColor = _initialBackgroundColor; - } - else - { - state = tokenStack.Peek(); - } - } - - if (!afterLastToken) - { - foregroundColor = state.ForegroundColor; - backgroundColor = state.BackgroundColor; - token = state.Tokens[++state.Index]; - } - } - - if (!afterLastToken && i == token.Extent.StartOffset) - { - GetTokenColors(token, out foregroundColor, out backgroundColor); - - var stringToken = token as StringExpandableToken; - if (stringToken != null) - { - // We might have nested tokens. - if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any()) - { - var tokens = new Token[stringToken.NestedTokens.Count + 1]; - stringToken.NestedTokens.CopyTo(tokens, 0); - // NestedTokens doesn't have an "EOS" token, so we use - // the string literal token for that purpose. - tokens[tokens.Length - 1] = stringToken; - - tokenStack.Push(new SavedTokenState - { - Tokens = tokens, - Index = 0, - BackgroundColor = backgroundColor, - ForegroundColor = foregroundColor - }); - - if (i == tokens[0].Extent.StartOffset) - { - GetTokenColors(tokens[0], out foregroundColor, out backgroundColor); - } - } - } - } - } - - var charToRender = text[i]; - if (charToRender == '\n') - { - while ((j % bufferWidth) != 0) - { - _consoleBuffer[j++] = _space; - } - - for (int k = 0; k < Options.ContinuationPrompt.Length; k++, j++) - { - _consoleBuffer[j].UnicodeChar = Options.ContinuationPrompt[k]; - _consoleBuffer[j].ForegroundColor = Options.ContinuationPromptForegroundColor; - _consoleBuffer[j].BackgroundColor = Options.ContinuationPromptBackgroundColor; - } - } - else - { - int size = LengthInBufferCells(charToRender); - totalBytes += size; - - //if there is no enough space for the character at the edge, fill in spaces at the end and - //put the character to next line. - int filling = totalBytes > bufferWidth ? (totalBytes - bufferWidth) % size : 0; - for (int f = 0; f < filling; f++) - { - _consoleBuffer[j++] = _space; - totalBytes++; - } - - if (char.IsControl(charToRender)) - { - _consoleBuffer[j].UnicodeChar = '^'; - MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); - _consoleBuffer[j].UnicodeChar = (char)('@' + charToRender); - MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); - - } -#if !UNIX - else if (size > 1) - { - _consoleBuffer[j].UnicodeChar = charToRender; - _consoleBuffer[j].IsLeadByte = true; - MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); - _consoleBuffer[j].UnicodeChar = charToRender; - _consoleBuffer[j].IsTrailByte = true; - MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); - } -#endif - else - { - _consoleBuffer[j].UnicodeChar = charToRender; - MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); - } - } - } - } - finally - { - _console.EndRender(); - } - - for (; j < (_consoleBuffer.Length - (statusLineCount * _bufferWidth)); j++) - { - _consoleBuffer[j] = _space; - } - - if (_statusLinePrompt != null) - { - foregroundColor = _statusIsErrorMessage ? Options.ErrorForegroundColor : _console.ForegroundColor; - backgroundColor = _statusIsErrorMessage ? Options.ErrorBackgroundColor : _console.BackgroundColor; - - for (int i = 0; i < _statusLinePrompt.Length; i++, j++) - { - _consoleBuffer[j].UnicodeChar = _statusLinePrompt[i]; - _consoleBuffer[j].ForegroundColor = foregroundColor; - _consoleBuffer[j].BackgroundColor = backgroundColor; - } - for (int i = 0; i < _statusBuffer.Length; i++, j++) - { - _consoleBuffer[j].UnicodeChar = _statusBuffer[i]; - _consoleBuffer[j].ForegroundColor = foregroundColor; - _consoleBuffer[j].BackgroundColor = backgroundColor; - } - - for (; j < _consoleBuffer.Length; j++) - { - _consoleBuffer[j] = _space; - } - } - - bool rendered = false; - if (_parseErrors.Length > 0) - { - int promptChar = _initialX - 1 + (_bufferWidth * Options.ExtraPromptLineCount); - - while (promptChar >= 0) - { - var c = _consoleBuffer[promptChar].UnicodeChar; - if (char.IsWhiteSpace(c)) - { - promptChar -= 1; - continue; - } - - ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor; - _consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red; - _console.WriteBufferLines(_consoleBuffer, ref _initialY); - rendered = true; - _consoleBuffer[promptChar].ForegroundColor = prevColor; - break; - } - } - - if (!rendered) - { - _console.WriteBufferLines(_consoleBuffer, ref _initialY); - } - - PlaceCursor(); - - if ((_initialY + bufferLineCount) > (_console.WindowTop + _console.WindowHeight)) - { -#if !UNIX // TODO: verify this isn't necessary for LINUX - _console.WindowTop = _initialY + bufferLineCount - _console.WindowHeight; -#endif - } - - _lastRenderTime.Restart(); - } - - private int LengthInBufferCells(char c) - { - int length = Char.IsControl(c) ? 1 : 0; - if (c < 256) - { - return length + 1; - } - return _console.LengthInBufferCells(c); - } - - private static void WriteBlankLines(int count, int top) - { - var console = _singleton._console; - var blanks = new BufferChar[count * console.BufferWidth]; - for (int i = 0; i < blanks.Length; i++) - { - blanks[i].BackgroundColor = console.BackgroundColor; - blanks[i].ForegroundColor = console.ForegroundColor; - blanks[i].UnicodeChar = ' '; - } - console.WriteBufferLines(blanks, ref top); - } - - private static BufferChar[] ReadBufferLines(int top, int count) - { - return _singleton._console.ReadBufferLines(top, count); - } - - private void GetTokenColors(Token token, out ConsoleColor foregroundColor, out ConsoleColor backgroundColor) - { - switch (token.Kind) - { - case TokenKind.Comment: - foregroundColor = _options.CommentForegroundColor; - backgroundColor = _options.CommentBackgroundColor; - return; - - case TokenKind.Parameter: - foregroundColor = _options.ParameterForegroundColor; - backgroundColor = _options.ParameterBackgroundColor; - return; - - case TokenKind.Variable: - case TokenKind.SplattedVariable: - foregroundColor = _options.VariableForegroundColor; - backgroundColor = _options.VariableBackgroundColor; - return; - - case TokenKind.StringExpandable: - case TokenKind.StringLiteral: - case TokenKind.HereStringExpandable: - case TokenKind.HereStringLiteral: - foregroundColor = _options.StringForegroundColor; - backgroundColor = _options.StringBackgroundColor; - return; - - case TokenKind.Number: - foregroundColor = _options.NumberForegroundColor; - backgroundColor = _options.NumberBackgroundColor; - return; - } - - if ((token.TokenFlags & TokenFlags.CommandName) != 0) - { - foregroundColor = _options.CommandForegroundColor; - backgroundColor = _options.CommandBackgroundColor; - return; - } - - if ((token.TokenFlags & TokenFlags.Keyword) != 0) - { - foregroundColor = _options.KeywordForegroundColor; - backgroundColor = _options.KeywordBackgroundColor; - return; - } - - if ((token.TokenFlags & (TokenFlags.BinaryOperator | TokenFlags.UnaryOperator | TokenFlags.AssignmentOperator)) != 0) - { - foregroundColor = _options.OperatorForegroundColor; - backgroundColor = _options.OperatorBackgroundColor; - return; - } - - if ((token.TokenFlags & TokenFlags.TypeName) != 0) - { - foregroundColor = _options.TypeForegroundColor; - backgroundColor = _options.TypeBackgroundColor; - return; - } - - if ((token.TokenFlags & TokenFlags.MemberName) != 0) - { - foregroundColor = _options.MemberForegroundColor; - backgroundColor = _options.MemberBackgroundColor; - return; - } - - foregroundColor = _options.DefaultTokenForegroundColor; - backgroundColor = _options.DefaultTokenBackgroundColor; - } - - private void GetRegion(out int start, out int length) - { - if (_mark < _current) - { - start = _mark; - length = _current - start; - } - else - { - start = _current; - length = _mark - start; - } - } - - private bool InRegion(int i) - { - int start, end; - if (_mark > _current) - { - start = _current; - end = _mark; - } - else - { - start = _mark; - end = _current; - } - return i >= start && i < end; - } - - private void MaybeEmphasize(ref BufferChar charInfo, int i, ConsoleColor foregroundColor, ConsoleColor backgroundColor) - { - if (i >= _emphasisStart && i < (_emphasisStart + _emphasisLength)) - { - backgroundColor = _options.EmphasisBackgroundColor; - foregroundColor = _options.EmphasisForegroundColor; - } - else if (_visualSelectionCommandCount > 0 && InRegion(i)) - { - // We can't quite emulate real console selection because it inverts - // based on actual screen colors, our palette is limited. The choice - // to invert only the lower 3 bits to change the color is somewhat - // but looks best with the 2 default color schemes - starting PowerShell - // from it's shortcut or from a cmd shortcut. -#if UNIX // TODO: set Inverse attribute and let render choose what to do. - ConsoleColor tempColor = (foregroundColor == UnknownColor) ? ConsoleColor.White : foregroundColor; - foregroundColor = (backgroundColor == UnknownColor) ? ConsoleColor.Black : backgroundColor; - backgroundColor = tempColor; -#else - foregroundColor = (ConsoleColor)((int)foregroundColor ^ 7); - backgroundColor = (ConsoleColor)((int)backgroundColor ^ 7); -#endif - } - - charInfo.ForegroundColor = foregroundColor; - charInfo.BackgroundColor = backgroundColor; - } - - private void PlaceCursor(int x, ref int y) - { - int statusLineCount = GetStatusLineCount(); - if ((y + statusLineCount) >= _console.BufferHeight) - { - _console.ScrollBuffer((y + statusLineCount) - _console.BufferHeight + 1); - y = _console.BufferHeight - 1; - } - _console.SetCursorPosition(x, y); - } - - private void PlaceCursor() - { - var coordinates = ConvertOffsetToCoordinates(_current); - int y = coordinates.Y; - PlaceCursor(coordinates.X, ref y); - } - - private COORD ConvertOffsetToCoordinates(int offset) - { - int x = _initialX; - int y = _initialY + Options.ExtraPromptLineCount; - - int bufferWidth = _console.BufferWidth; - var continuationPromptLength = Options.ContinuationPrompt.Length; - - for (int i = 0; i < offset; i++) - { - char c = _buffer[i]; - if (c == '\n') - { - y += 1; - x = continuationPromptLength; - } - else - { - int size = LengthInBufferCells(c); - x += size; - // Wrap? No prompt when wrapping - if (x >= bufferWidth) - { - int offsize = x - bufferWidth; - if (offsize % size == 0) - { - x -= bufferWidth; - } - else - { - x = size; - } - y += 1; - } - } - } - - //if the next character has bigger size than the remain space on this line, - //the cursor goes to next line where the next character is. - if (_buffer.Length > offset) - { - int size = LengthInBufferCells(_buffer[offset]); - // next one is Wrapped to next line - if (x + size > bufferWidth && (x + size - bufferWidth) % size != 0) - { - x = 0; - y++; - } - } - - return new COORD {X = (short)x, Y = (short)y}; - } - - private int ConvertOffsetToConsoleBufferOffset(int offset, int startIndex) - { - int j = startIndex; - for (int i = 0; i < offset; i++) - { - var c = _buffer[i]; - if (c == '\n') - { - for (int k = 0; k < Options.ContinuationPrompt.Length; k++) - { - j++; - } - } - else if (LengthInBufferCells(c) > 1) - { - j += 2; - } - else - { - j++; - } - } - return j; - } - - private int ConvertLineAndColumnToOffset(COORD coord) - { - int offset; - int x = _initialX; - int y = _initialY + Options.ExtraPromptLineCount; - - int bufferWidth = _console.BufferWidth; - var continuationPromptLength = Options.ContinuationPrompt.Length; - for (offset = 0; offset < _buffer.Length; offset++) - { - // If we are on the correct line, return when we find - // the correct column - if (coord.Y == y && coord.X <= x) - { - return offset; - } - char c = _buffer[offset]; - if (c == '\n') - { - // If we are about to move off of the correct line, - // the line was shorter than the column we wanted so return. - if (coord.Y == y) - { - return offset; - } - y += 1; - x = continuationPromptLength; - } - else - { - int size = LengthInBufferCells(c); - x += size; - // Wrap? No prompt when wrapping - if (x >= bufferWidth) - { - int offsize = x - bufferWidth; - if (offsize % size == 0) - { - x -= bufferWidth; - } - else - { - x = size; - } - y += 1; - } - } - } - - // Return -1 if y is out of range, otherwise the last line was shorter - // than we wanted, but still in range so just return the last offset. - return (coord.Y == y) ? offset : -1; - } - - private bool LineIsMultiLine() - { - for (int i = 0; i < _buffer.Length; i++) - { - if (_buffer[i] == '\n') - return true; - } - return false; - } - - private int GetStatusLineCount() - { - if (_statusLinePrompt == null) - return 0; - - return (_statusLinePrompt.Length + _statusBuffer.Length) / _console.BufferWidth + 1; - } - - [ExcludeFromCodeCoverage] - void IPSConsoleReadLineMockableMethods.Ding() - { - switch (Options.BellStyle) - { - case BellStyle.None: - break; - case BellStyle.Audible: -#if UNIX - Console.Beep(); -#else - Console.Beep(Options.DingTone, Options.DingDuration); -#endif - break; - case BellStyle.Visual: - // TODO: flash prompt? command line? - break; - } - } - - /// - /// Notify the user based on their preference for notification. - /// - public static void Ding() - { - _singleton._mockableMethods.Ding(); - } - - private bool PromptYesOrNo(string s) - { - _statusLinePrompt = s; - Render(); - - var key = ReadKey(); - - _statusLinePrompt = null; - Render(); - return key.Key == ConsoleKey.Y; - } - -#region Screen scrolling - -#if !UNIX - /// - /// Scroll the display up one screen. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ScrollDisplayUp(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, +1); - var console = _singleton._console; - var newTop = console.WindowTop - (numericArg * console.WindowHeight); - if (newTop < 0) - { - newTop = 0; - } - console.SetWindowPosition(0, newTop); - } - - /// - /// Scroll the display up one line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ScrollDisplayUpLine(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, +1); - var console = _singleton._console; - var newTop = console.WindowTop - numericArg; - if (newTop < 0) - { - newTop = 0; - } - console.SetWindowPosition(0, newTop); - } - - /// - /// Scroll the display down one screen. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ScrollDisplayDown(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, +1); - var console = _singleton._console; - var newTop = console.WindowTop + (numericArg * console.WindowHeight); - if (newTop > (console.BufferHeight - console.WindowHeight)) - { - newTop = (console.BufferHeight - console.WindowHeight); - } - console.SetWindowPosition(0, newTop); - } - - /// - /// Scroll the display down one line. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ScrollDisplayDownLine(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - TryGetArgAsInt(arg, out numericArg, +1); - var console = _singleton._console; - var newTop = console.WindowTop + numericArg; - if (newTop > (console.BufferHeight - console.WindowHeight)) - { - newTop = (console.BufferHeight - console.WindowHeight); - } - console.SetWindowPosition(0, newTop); - } - - /// - /// Scroll the display to the top. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ScrollDisplayTop(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._console.SetWindowPosition(0, 0); - } - - /// - /// Scroll the display to the cursor. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void ScrollDisplayToCursor(ConsoleKeyInfo? key = null, object arg = null) - { - // Ideally, we'll put the last input line at the bottom of the window - var coordinates = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length); - - var console = _singleton._console; - var newTop = coordinates.Y - console.WindowHeight + 1; - - // If the cursor is already visible, and we're on the first - // page-worth of the buffer, then just scroll to the top (we can't - // scroll to before the beginning of the buffer). - // - // Note that we don't want to just return, because the window may - // have been scrolled way past the end of the content, so we really - // do need to set the new window top to 0 to bring it back into - // view. - if (newTop < 0) - { - newTop = 0; - } - - // But if the cursor won't be visible, make sure it is. - if (newTop > console.CursorTop) - { - // Add 10 for some extra context instead of putting the - // cursor on the bottom line. - newTop = console.CursorTop - console.WindowHeight + 10; - } - - // But we can't go past the end of the buffer. - if (newTop > (console.BufferHeight - console.WindowHeight)) - { - newTop = (console.BufferHeight - console.WindowHeight); - } - console.SetWindowPosition(0, newTop); - } - -#endif -#endregion Screen scrolling - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Replace.vi.cs b/src/Microsoft.PowerShell.PSReadLine/Replace.vi.cs deleted file mode 100644 index c4960e5b7032..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Replace.vi.cs +++ /dev/null @@ -1,350 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private static void ViReplaceUntilEsc(ConsoleKeyInfo? key, object arg) - { - if (_singleton._current >= _singleton._buffer.Length) - { - Ding(); - return; - } - - int startingCursor = _singleton._current; - int maxDeleteLength = _singleton._buffer.Length - _singleton._current; - StringBuilder deletedStr = new StringBuilder(); - - ConsoleKeyInfo nextKey = ReadKey(); - while (nextKey.Key != ConsoleKey.Escape && nextKey.Key != ConsoleKey.Enter) - { - if (nextKey.Key != ConsoleKey.Backspace && nextKey.KeyChar != '\u0000') - { - if (_singleton._current >= _singleton._buffer.Length) - { - _singleton._buffer.Append(nextKey.KeyChar); - } - else - { - deletedStr.Append(_singleton._buffer[_singleton._current]); - _singleton._buffer[_singleton._current] = nextKey.KeyChar; - } - _singleton._current++; - _singleton.Render(); - } - if (nextKey.Key == ConsoleKey.Backspace) - { - if (_singleton._current == startingCursor) - { - Ding(); - } - else - { - if (deletedStr.Length == _singleton._current - startingCursor) - { - _singleton._buffer[_singleton._current - 1] = deletedStr[deletedStr.Length - 1]; - deletedStr.Remove(deletedStr.Length - 1, 1); - } - else - { - _singleton._buffer.Remove(_singleton._current - 1, 1); - } - _singleton._current--; - _singleton.Render(); - } - } - nextKey = ReadKey(); - } - - if (_singleton._current > startingCursor) - { - _singleton.StartEditGroup(); - string insStr = _singleton._buffer.ToString(startingCursor, _singleton._current - startingCursor); - _singleton.SaveEditItem(EditItemDelete.Create(deletedStr.ToString(), startingCursor)); - _singleton.SaveEditItem(EditItemInsertString.Create(insStr, startingCursor)); - _singleton.EndEditGroup(); - } - - if (nextKey.Key == ConsoleKey.Enter) - { - ViAcceptLine(nextKey); - } - } - - private static void ViReplaceBrace(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViReplaceBrace, arg); - ViDeleteBrace(key, arg); - ViInsertMode(key, arg); - } - - private static void ViBackwardReplaceLineToFirstChar(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViBackwardReplaceLineToFirstChar, arg); - DeleteLineToFirstChar(key, arg); - ViInsertMode(key, arg); - } - - private static void ViBackwardReplaceLine(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViBackwardReplaceLine, arg); - BackwardDeleteLine(key, arg); - ViInsertMode(key, arg); - } - - private static void BackwardReplaceChar(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(BackwardReplaceChar, arg); - BackwardDeleteChar(key, arg); - ViInsertMode(key, arg); - } - - private static void ViBackwardReplaceWord(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViBackwardReplaceWord, arg); - BackwardDeleteWord(key, arg); - ViInsertMode(key, arg); - } - - private static void ViBackwardReplaceGlob(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViBackwardReplaceGlob, arg); - ViBackwardDeleteGlob(key, arg); - ViInsertMode(key, arg); - } - - private static void ViReplaceToEnd(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViReplaceToEnd, arg); - DeleteToEnd(key, arg); - _singleton._current = Math.Min(_singleton._buffer.Length, _singleton._current + 1); - _singleton.PlaceCursor(); - ViInsertMode(key, arg); - } - - private static void ViReplaceLine(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViReplaceLine, arg); - DeleteLine(key, arg); - ViInsertMode(key, arg); - } - - private static void ViReplaceWord(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViReplaceWord, arg); - _singleton._lastWordDelimiter = char.MinValue; - _singleton._shouldAppend = false; - DeleteWord(key, arg); - if (_singleton._current < _singleton._buffer.Length - 1) - { - if (char.IsWhiteSpace(_singleton._lastWordDelimiter)) - { - Insert(_singleton._lastWordDelimiter); - _singleton._current--; - } - _singleton._lastWordDelimiter = char.MinValue; - _singleton.PlaceCursor(); - } - if (_singleton._current == _singleton._buffer.Length - 1 - && !_singleton.IsDelimiter(_singleton._lastWordDelimiter, _singleton.Options.WordDelimiters) - && _singleton._shouldAppend) - { - ViInsertWithAppend(key, arg); - } - else - { - ViInsertMode(key, arg); - } - } - - private static void ViReplaceGlob(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViReplaceGlob, arg); - ViDeleteGlob(key, arg); - if (_singleton._current < _singleton._buffer.Length - 1) - { - Insert(' '); - _singleton._current--; - _singleton.PlaceCursor(); - } - if (_singleton._current == _singleton._buffer.Length - 1) - { - ViInsertWithAppend(key, arg); - } - else - { - ViInsertMode(key, arg); - } - } - - private static void ViReplaceEndOfWord(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViReplaceEndOfWord, arg); - DeleteEndOfWord(key, arg); - if (_singleton._current == _singleton._buffer.Length - 1) - { - ViInsertWithAppend(key, arg); - } - else - { - ViInsertMode(key, arg); - } - } - - private static void ViReplaceEndOfGlob(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ViReplaceEndOfGlob, arg); - ViDeleteEndOfGlob(key, arg); - if (_singleton._current == _singleton._buffer.Length - 1) - { - ViInsertWithAppend(key, arg); - } - else - { - ViInsertMode(key, arg); - } - } - - private static void ReplaceChar(ConsoleKeyInfo? key, object arg) - { - _singleton._groupUndoHelper.StartGroup(ReplaceChar, arg); - DeleteChar(key, arg); - ViInsertMode(key, arg); - } - - /// - /// Replaces the current character with the next character typed. - /// - private static void ReplaceCharInPlace(ConsoleKeyInfo? key, object arg) - { - ConsoleKeyInfo nextKey = ReadKey(); - if (_singleton._buffer.Length > 0 && nextKey.KeyChar > 0 && nextKey.Key != ConsoleKey.Escape && nextKey.Key != ConsoleKey.Enter) - { - _singleton.StartEditGroup(); - _singleton.SaveEditItem(EditItemDelete.Create(_singleton._buffer[_singleton._current].ToString(), _singleton._current)); - _singleton.SaveEditItem(EditItemInsertString.Create(nextKey.KeyChar.ToString(), _singleton._current)); - _singleton.EndEditGroup(); - - _singleton._buffer[_singleton._current] = nextKey.KeyChar; - _singleton.Render(); - } - else - { - Ding(); - } - } - - /// - /// Deletes until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViReplaceToChar(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViReplaceToChar(keyChar, key, arg); - } - - private static void ViReplaceToChar(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - bool shouldAppend = _singleton._current > 0; - - _singleton._groupUndoHelper.StartGroup(ReplaceChar, arg); - ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: false); - if (ViCharacterSearcher.SearchDelete(keyChar, arg, backoff: false, instigator: (_key, _arg) => ViReplaceToChar(keyChar, _key, _arg))) - { - if (shouldAppend) - { - ViInsertWithAppend(key, arg); - } - else - { - ViInsertMode(key, arg); - } - } - } - - /// - /// Replaces until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViReplaceToCharBackward(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViReplaceToCharBack(keyChar, key, arg); - } - - private static void ViReplaceToCharBack(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._groupUndoHelper.StartGroup(ReplaceChar, arg); - if (ViCharacterSearcher.SearchBackwardDelete(keyChar, arg, backoff: false, instigator: (_key, _arg) => ViReplaceToCharBack(keyChar, _key, _arg))) - { - ViInsertMode(key, arg); - } - } - - /// - /// Replaces until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViReplaceToBeforeChar(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViReplaceToBeforeChar(keyChar, key, arg); - } - - private static void ViReplaceToBeforeChar(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._groupUndoHelper.StartGroup(ReplaceChar, arg); - ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: true); - if (ViCharacterSearcher.SearchDelete(keyChar, arg, backoff: true, instigator: (_key, _arg) => ViReplaceToBeforeChar(keyChar, _key, _arg))) - { - ViInsertMode(key, arg); - } - } - - /// - /// Replaces until given character - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - private static void ViReplaceToBeforeCharBackward(ConsoleKeyInfo? key = null, object arg = null) - { - var keyChar = ReadKey().KeyChar; - ViReplaceToBeforeCharBack(keyChar, key, arg); - } - - private static void ViReplaceToBeforeCharBack(char keyChar, ConsoleKeyInfo? key = null, object arg = null) - { - _singleton._groupUndoHelper.StartGroup(ReplaceChar, arg); - if (ViCharacterSearcher.SearchBackwardDelete(keyChar, arg, backoff: true, instigator: (_key, _arg) => ViReplaceToBeforeCharBack(keyChar, _key, _arg))) - { - ViInsertMode(key, arg); - } - } - - - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/SamplePSReadlineProfile.ps1 b/src/Microsoft.PowerShell.PSReadLine/SamplePSReadlineProfile.ps1 deleted file mode 100644 index cfde8a0c8179..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/SamplePSReadlineProfile.ps1 +++ /dev/null @@ -1,491 +0,0 @@ - -# This is an example profile for PSReadline. -# -# This is roughly what I use so there is some emphasis on emacs bindings, -# but most of these bindings make sense in Windows mode as well. - -Import-Module PSReadLine - -Set-PSReadLineOption -EditMode Emacs - -# Searching for commands with up/down arrow is really handy. The -# option "moves to end" is useful if you want the cursor at the end -# of the line while cycling through history like it does w/o searching, -# without that option, the cursor will remain at the position it was -# when you used up arrow, which can be useful if you forget the exact -# string you started the search on. -Set-PSReadLineOption -HistorySearchCursorMovesToEnd -Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward -Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward - -# This key handler shows the entire or filtered history using Out-GridView. The -# typed text is used as the substring pattern for filtering. A selected command -# is inserted to the command line without invoking. Multiple command selection -# is supported, e.g. selected by Ctrl + Click. -Set-PSReadlineKeyHandler -Key F7 ` - -BriefDescription History ` - -LongDescription 'Show command history' ` - -ScriptBlock { - $pattern = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$pattern, [ref]$null) - if ($pattern) - { - $pattern = [regex]::Escape($pattern) - } - - $history = [System.Collections.ArrayList]@( - $last = '' - $lines = '' - foreach ($line in [System.IO.File]::ReadLines((Get-PSReadlineOption).HistorySavePath)) - { - if ($line.EndsWith('`')) - { - $line = $line.Substring(0, $line.Length - 1) - $lines = if ($lines) - { - "$lines`n$line" - } - else - { - $line - } - continue - } - - if ($lines) - { - $line = "$lines`n$line" - $lines = '' - } - - if (($line -cne $last) -and (!$pattern -or ($line -match $pattern))) - { - $last = $line - $line - } - } - ) - $history.Reverse() - - $command = $history | Out-GridView -Title History -PassThru - if ($command) - { - [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() - [Microsoft.PowerShell.PSConsoleReadLine]::Insert(($command -join "`n")) - } -} - -# This is an example of a macro that you might use to execute a command. -# This will add the command to history. -Set-PSReadlineKeyHandler -Key Ctrl+B ` - -BriefDescription BuildCurrentDirectory ` - -LongDescription "Build the current directory" ` - -ScriptBlock { - [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() - [Microsoft.PowerShell.PSConsoleReadLine]::Insert("msbuild") - [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() -} - -# In Emacs mode - Tab acts like in bash, but the Windows style completion -# is still useful sometimes, so bind some keys so we can do both -Set-PSReadlineKeyHandler -Key Ctrl+Q -Function TabCompleteNext -Set-PSReadlineKeyHandler -Key Ctrl+Shift+Q -Function TabCompletePrevious - -# Clipboard interaction is bound by default in Windows mode, but not Emacs mode. -Set-PSReadlineKeyHandler -Key Shift+Ctrl+C -Function Copy -Set-PSReadlineKeyHandler -Key Ctrl+V -Function Paste - -# CaptureScreen is good for blog posts or email showing a transaction -# of what you did when asking for help or demonstrating a technique. -Set-PSReadlineKeyHandler -Chord 'Ctrl+D,Ctrl+C' -Function CaptureScreen - -# The built-in word movement uses character delimiters, but token based word -# movement is also very useful - these are the bindings you'd use if you -# prefer the token based movements bound to the normal emacs word movement -# key bindings. -Set-PSReadlineKeyHandler -Key Alt+D -Function ShellKillWord -Set-PSReadlineKeyHandler -Key Alt+Backspace -Function ShellBackwardKillWord -Set-PSReadlineKeyHandler -Key Alt+B -Function ShellBackwardWord -Set-PSReadlineKeyHandler -Key Alt+F -Function ShellForwardWord -Set-PSReadlineKeyHandler -Key Shift+Alt+B -Function SelectShellBackwardWord -Set-PSReadlineKeyHandler -Key Shift+Alt+F -Function SelectShellForwardWord - -#region Smart Insert/Delete - -# The next four key handlers are designed to make entering matched quotes -# parens, and braces a nicer experience. I'd like to include functions -# in the module that do this, but this implementation still isn't as smart -# as ReSharper, so I'm just providing it as a sample. - -Set-PSReadlineKeyHandler -Key '"',"'" ` - -BriefDescription SmartInsertQuote ` - -LongDescription "Insert paired quotes if not already on a quote" ` - -ScriptBlock { - param($key, $arg) - - $line = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - - if ($line[$cursor] -eq $key.KeyChar) { - # Just move the cursor - [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) - } - else { - # Insert matching quotes, move cursor to be in between the quotes - [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)" * 2) - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor - 1) - } -} - -Set-PSReadlineKeyHandler -Key '(','{','[' ` - -BriefDescription InsertPairedBraces ` - -LongDescription "Insert matching braces" ` - -ScriptBlock { - param($key, $arg) - - $closeChar = switch ($key.KeyChar) - { - <#case#> '(' { [char]')'; break } - <#case#> '{' { [char]'}'; break } - <#case#> '[' { [char]']'; break } - } - - [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)$closeChar") - $line = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor - 1) -} - -Set-PSReadlineKeyHandler -Key ')',']','}' ` - -BriefDescription SmartCloseBraces ` - -LongDescription "Insert closing brace or skip" ` - -ScriptBlock { - param($key, $arg) - - $line = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - - if ($line[$cursor] -eq $key.KeyChar) - { - [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) - } - else - { - [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)") - } -} - -Set-PSReadlineKeyHandler -Key Backspace ` - -BriefDescription SmartBackspace ` - -LongDescription "Delete previous character or matching quotes/parens/braces" ` - -ScriptBlock { - param($key, $arg) - - $line = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - - if ($cursor -gt 0) - { - $toMatch = $null - if ($cursor -lt $line.Length) - { - switch ($line[$cursor]) - { - <#case#> '"' { $toMatch = '"'; break } - <#case#> "'" { $toMatch = "'"; break } - <#case#> ')' { $toMatch = '('; break } - <#case#> ']' { $toMatch = '['; break } - <#case#> '}' { $toMatch = '{'; break } - } - } - - if ($null -ne $toMatch -and $line[$cursor-1] -eq $toMatch) - { - [Microsoft.PowerShell.PSConsoleReadLine]::Delete($cursor - 1, 2) - } - else - { - [Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar($key, $arg) - } - } -} - -#endregion Smart Insert/Delete - -# Sometimes you enter a command but realize you forgot to do something else first. -# This binding will let you save that command in the history so you can recall it, -# but it doesn't actually execute. It also clears the line with RevertLine so the -# undo stack is reset - though redo will still reconstruct the command line. -Set-PSReadlineKeyHandler -Key Alt+w ` - -BriefDescription SaveInHistory ` - -LongDescription "Save current line in history but do not execute" ` - -ScriptBlock { - param($key, $arg) - - $line = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - [Microsoft.PowerShell.PSConsoleReadLine]::AddToHistory($line) - [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() -} - -# Insert text from the clipboard as a here string -Set-PSReadlineKeyHandler -Key Ctrl+Shift+v ` - -BriefDescription PasteAsHereString ` - -LongDescription "Paste the clipboard text as a here string" ` - -ScriptBlock { - param($key, $arg) - - Add-Type -Assembly PresentationCore - if ([System.Windows.Clipboard]::ContainsText()) - { - # Get clipboard text - remove trailing spaces, convert \r\n to \n, and remove the final \n. - $text = ([System.Windows.Clipboard]::GetText() -replace "\p{Zs}*`r?`n","`n").TrimEnd() - [Microsoft.PowerShell.PSConsoleReadLine]::Insert("@'`n$text`n'@") - } - else - { - [Microsoft.PowerShell.PSConsoleReadLine]::Ding() - } -} - -# Sometimes you want to get a property of invoke a member on what you've entered so far -# but you need parens to do that. This binding will help by putting parens around the current selection, -# or if nothing is selected, the whole line. -Set-PSReadlineKeyHandler -Key 'Alt+(' ` - -BriefDescription ParenthesizeSelection ` - -LongDescription "Put parenthesis around the selection or entire line and move the cursor to after the closing parenthesis" ` - -ScriptBlock { - param($key, $arg) - - $selectionStart = $null - $selectionLength = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength) - - $line = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - if ($selectionStart -ne -1) - { - [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, '(' + $line.SubString($selectionStart, $selectionLength) + ')') - [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) - } - else - { - [Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $line.Length, '(' + $line + ')') - [Microsoft.PowerShell.PSConsoleReadLine]::EndOfLine() - } -} - -# Each time you press Alt+', this key handler will change the token -# under or before the cursor. It will cycle through single quotes, double quotes, or -# no quotes each time it is invoked. -Set-PSReadlineKeyHandler -Key "Alt+'" ` - -BriefDescription ToggleQuoteArgument ` - -LongDescription "Toggle quotes on the argument under the cursor" ` - -ScriptBlock { - param($key, $arg) - - $ast = $null - $tokens = $null - $errors = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor) - - $tokenToChange = $null - foreach ($token in $tokens) - { - $extent = $token.Extent - if ($extent.StartOffset -le $cursor -and $extent.EndOffset -ge $cursor) - { - $tokenToChange = $token - - # If the cursor is at the end (it's really 1 past the end) of the previous token, - # we only want to change the previous token if there is no token under the cursor - if ($extent.EndOffset -eq $cursor -and $foreach.MoveNext()) - { - $nextToken = $foreach.Current - if ($nextToken.Extent.StartOffset -eq $cursor) - { - $tokenToChange = $nextToken - } - } - break - } - } - - if ($null -ne $tokenToChange) - { - $extent = $tokenToChange.Extent - $tokenText = $extent.Text - if ($tokenText[0] -eq '"' -and $tokenText[-1] -eq '"') - { - # Switch to no quotes - $replacement = $tokenText.Substring(1, $tokenText.Length - 2) - } - elseif ($tokenText[0] -eq "'" -and $tokenText[-1] -eq "'") - { - # Switch to double quotes - $replacement = '"' + $tokenText.Substring(1, $tokenText.Length - 2) + '"' - } - else - { - # Add single quotes - $replacement = "'" + $tokenText + "'" - } - - [Microsoft.PowerShell.PSConsoleReadLine]::Replace( - $extent.StartOffset, - $tokenText.Length, - $replacement) - } -} - -# This example will replace any aliases on the command line with the resolved commands. -Set-PSReadlineKeyHandler -Key "Alt+%" ` - -BriefDescription ExpandAliases ` - -LongDescription "Replace all aliases with the full command" ` - -ScriptBlock { - param($key, $arg) - - $ast = $null - $tokens = $null - $errors = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor) - - $startAdjustment = 0 - foreach ($token in $tokens) - { - if ($token.TokenFlags -band [System.Management.Automation.Language.TokenFlags]::CommandName) - { - $alias = $ExecutionContext.InvokeCommand.GetCommand($token.Extent.Text, 'Alias') - if ($null -ne $alias) - { - $resolvedCommand = $alias.ResolvedCommandName - if ($null -ne $resolvedCommand) - { - $extent = $token.Extent - $length = $extent.EndOffset - $extent.StartOffset - [Microsoft.PowerShell.PSConsoleReadLine]::Replace( - $extent.StartOffset + $startAdjustment, - $length, - $resolvedCommand) - - # Our copy of the tokens won't have been updated, so we need to - # adjust by the difference in length - $startAdjustment += ($resolvedCommand.Length - $length) - } - } - } - } -} - -# F1 for help on the command line - naturally -Set-PSReadlineKeyHandler -Key F1 ` - -BriefDescription CommandHelp ` - -LongDescription "Open the help window for the current command" ` - -ScriptBlock { - param($key, $arg) - - $ast = $null - $tokens = $null - $errors = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor) - - $commandAst = $ast.FindAll( { - $node = $args[0] - $node -is [System.Management.Automation.Language.CommandAst] -and - $node.Extent.StartOffset -le $cursor -and - $node.Extent.EndOffset -ge $cursor - }, $true) | Select-Object -Last 1 - - if ($null -ne $commandAst) - { - $commandName = $commandAst.GetCommandName() - if ($null -ne $commandName) - { - $command = $ExecutionContext.InvokeCommand.GetCommand($commandName, 'All') - if ($command -is [System.Management.Automation.AliasInfo]) - { - $commandName = $command.ResolvedCommandName - } - - if ($null -ne $commandName) - { - Get-Help $commandName -ShowWindow - } - } - } -} - - -# -# Ctrl+Shift+j then type a key to mark the current directory. -# Ctrj+j then the same key will change back to that directory without -# needing to type cd and won't change the command line. - -# -$global:PSReadlineMarks = @{} - -Set-PSReadlineKeyHandler -Key Ctrl+Shift+j ` - -BriefDescription MarkDirectory ` - -LongDescription "Mark the current directory" ` - -ScriptBlock { - param($key, $arg) - - $key = [Console]::ReadKey($true) - $global:PSReadlineMarks[$key.KeyChar] = $pwd -} - -Set-PSReadlineKeyHandler -Key Ctrl+j ` - -BriefDescription JumpDirectory ` - -LongDescription "Goto the marked directory" ` - -ScriptBlock { - param($key, $arg) - - $key = [Console]::ReadKey() - $dir = $global:PSReadlineMarks[$key.KeyChar] - if ($dir) - { - cd $dir - [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() - } -} - -Set-PSReadlineKeyHandler -Key Alt+j ` - -BriefDescription ShowDirectoryMarks ` - -LongDescription "Show the currently marked directories" ` - -ScriptBlock { - param($key, $arg) - - $global:PSReadlineMarks.GetEnumerator() | ForEach-Object { - [PSCustomObject]@{Key = $_.Key; Dir = $_.Value} } | - Format-Table -AutoSize | Out-Host - - [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() -} - -Set-PSReadlineOption -CommandValidationHandler { - param([System.Management.Automation.Language.CommandAst]$CommandAst) - - switch ($CommandAst.GetCommandName()) - { - 'git' { - $gitCmd = $CommandAst.CommandElements[1].Extent - switch ($gitCmd.Text) - { - 'cmt' { - [Microsoft.PowerShell.PSConsoleReadLine]::Replace( - $gitCmd.StartOffset, $gitCmd.EndOffset - $gitCmd.StartOffset, 'commit') - } - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/ScreenCapture.cs b/src/Microsoft.PowerShell.PSReadLine/ScreenCapture.cs deleted file mode 100644 index 4404c4866b46..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/ScreenCapture.cs +++ /dev/null @@ -1,309 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -#if !UNIX -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Microsoft.PowerShell.Internal; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private static void InvertLines(int start, int count) - { - var buffer = ReadBufferLines(start, count); - for (int i = 0; i < buffer.Length; i++) - { - buffer[i].ForegroundColor = (ConsoleColor)((int)buffer[i].ForegroundColor ^ 7); - buffer[i].BackgroundColor = (ConsoleColor)((int)buffer[i].BackgroundColor ^ 7); - } - _singleton._console.WriteBufferLines(buffer, ref start, false); - } - - /// - /// Start interactive screen capture - up/down arrows select lines, enter copies - /// selected text to clipboard as text and html - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void CaptureScreen(ConsoleKeyInfo? key = null, object arg = null) - { - int selectionTop = _singleton._console.CursorTop; - int selectionHeight = 1; - int currentY = selectionTop; - Internal.IConsole console = _singleton._console; - - // We'll keep the current selection line (currentY) at least 4 lines - // away from the top or bottom of the window. - const int margin = 5; - Func tooCloseToTop = () => { return (currentY - console.WindowTop) < margin; }; - Func tooCloseToBottom = () => { return ((console.WindowTop + console.WindowHeight) - currentY) < margin; }; - - // Current lines starts out selected - InvertLines(selectionTop, selectionHeight); - bool done = false; - while (!done) - { - var k = ReadKey(); - switch (k.Key) - { - case ConsoleKey.K: - case ConsoleKey.UpArrow: - if (tooCloseToTop()) - ScrollDisplayUpLine(); - - if (currentY > 0) - { - currentY -= 1; - if ((k.Modifiers & ConsoleModifiers.Shift) == ConsoleModifiers.Shift) - { - if (currentY < selectionTop) - { - // Extend selection up, only invert newly selected line. - InvertLines(currentY, 1); - selectionTop = currentY; - selectionHeight += 1; - } - else if (currentY >= selectionTop) - { - // Selection shortend 1 line, invert unselected line. - InvertLines(currentY + 1, 1); - selectionHeight -= 1; - } - break; - } - goto updateSelectionCommon; - } - break; - - case ConsoleKey.J: - case ConsoleKey.DownArrow: - if (tooCloseToBottom()) - ScrollDisplayDownLine(); - - if (currentY < (console.BufferHeight - 1)) - { - currentY += 1; - if ((k.Modifiers & ConsoleModifiers.Shift) == ConsoleModifiers.Shift) - { - if (currentY == (selectionTop + selectionHeight)) - { - // Extend selection down, only invert newly selected line. - InvertLines(selectionTop + selectionHeight, 1); - selectionHeight += 1; - } - else if (currentY == (selectionTop + 1)) - { - // Selection shortend 1 line, invert unselected line. - InvertLines(selectionTop, 1); - selectionTop = currentY; - selectionHeight -= 1; - } - break; - } - goto updateSelectionCommon; - } - break; - - updateSelectionCommon: - // Shift not pressed - unselect current selection - InvertLines(selectionTop, selectionHeight); - selectionTop = currentY; - selectionHeight = 1; - InvertLines(selectionTop, selectionHeight); - break; - - case ConsoleKey.Enter: - InvertLines(selectionTop, selectionHeight); - DumpScreenToClipboard(selectionTop, selectionHeight); - ScrollDisplayToCursor(); - return; - - case ConsoleKey.Escape: - done = true; - continue; - - case ConsoleKey.C: - case ConsoleKey.G: - if (k.Modifiers == ConsoleModifiers.Control) - { - done = true; - continue; - } - Ding(); - break; - default: - Ding(); - break; - } - } - InvertLines(selectionTop, selectionHeight); - ScrollDisplayToCursor(); - } - - private const string CmdColorTable = @" -\red0\green0\blue0; -\red0\green0\blue128; -\red0\green128\blue0; -\red0\green128\blue128; -\red128\green0\blue0; -\red128\green0\blue128; -\red128\green128\blue0; -\red192\green192\blue192; -\red128\green128\blue128; -\red0\green0\blue255; -\red0\green255\blue0; -\red0\green255\blue255; -\red255\green0\blue0; -\red255\green0\blue255; -\red255\green255\blue0; -\red255\green255\blue255; -"; - - private const string PowerShellColorTable = @" -\red1\green36\blue86; -\red0\green0\blue128; -\red0\green128\blue0; -\red0\green128\blue128; -\red128\green0\blue0; -\red1\green36\blue86; -\red238\green237\blue240; -\red192\green192\blue192; -\red128\green128\blue128; -\red0\green0\blue255; -\red0\green255\blue0; -\red0\green255\blue255; -\red255\green0\blue0; -\red255\green0\blue255; -\red255\green255\blue0; -\red255\green255\blue255; -"; - - private static string GetRTFColorFromColorRef(NativeMethods.COLORREF colorref) - { - return string.Concat("\\red", colorref.R.ToString("D"), - "\\green", colorref.G.ToString("D"), - "\\blue", colorref.B.ToString("D"), ";"); - } - - private static string GetColorTable() - { - var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output); - var csbe = new NativeMethods.CONSOLE_SCREEN_BUFFER_INFO_EX - { - cbSize = Marshal.SizeOf() - }; - if (NativeMethods.GetConsoleScreenBufferInfoEx(handle, ref csbe)) - { - return GetRTFColorFromColorRef(csbe.Black) + - GetRTFColorFromColorRef(csbe.DarkBlue) + - GetRTFColorFromColorRef(csbe.DarkGreen) + - GetRTFColorFromColorRef(csbe.DarkCyan) + - GetRTFColorFromColorRef(csbe.DarkRed) + - GetRTFColorFromColorRef(csbe.DarkMagenta) + - GetRTFColorFromColorRef(csbe.DarkYellow) + - GetRTFColorFromColorRef(csbe.Gray) + - GetRTFColorFromColorRef(csbe.DarkGray) + - GetRTFColorFromColorRef(csbe.Blue) + - GetRTFColorFromColorRef(csbe.Green) + - GetRTFColorFromColorRef(csbe.Cyan) + - GetRTFColorFromColorRef(csbe.Red) + - GetRTFColorFromColorRef(csbe.Magenta) + - GetRTFColorFromColorRef(csbe.Yellow) + - GetRTFColorFromColorRef(csbe.White); - } - - // A bit of a hack if the above failed - assume PowerShell's color scheme if the - // background color is Magenta, otherwise we assume the default scheme. - return _singleton._console.BackgroundColor == ConsoleColor.DarkMagenta - ? PowerShellColorTable - : CmdColorTable; - } - - private static void DumpScreenToClipboard(int top, int count) - { - var buffer = ReadBufferLines(top, count); - var bufferWidth = _singleton._console.BufferWidth; - - var textBuffer = new StringBuilder(buffer.Length + count); - - var rtfBuffer = new StringBuilder(); - rtfBuffer.Append(@"{\rtf\ansi{\fonttbl{\f0 Consolas;}}"); - - var colorTable = GetColorTable(); - rtfBuffer.AppendFormat(@"{{\colortbl;{0}}}{1}", colorTable, Environment.NewLine); - rtfBuffer.Append(@"\f0 \fs18 "); - - var charInfo = buffer[0]; - var fgColor = (int)charInfo.ForegroundColor; - var bgColor = (int)charInfo.BackgroundColor; - rtfBuffer.AppendFormat(@"{{\cf{0}\chshdng0\chcbpat{1} ", fgColor + 1, bgColor + 1); - for (int i = 0; i < count; i++) - { - var spaces = 0; - var rtfSpaces = 0; - for (int j = 0; j < bufferWidth; j++) - { - charInfo = buffer[i * bufferWidth + j]; - if ((int)charInfo.ForegroundColor != fgColor || (int)charInfo.BackgroundColor != bgColor) - { - if (rtfSpaces > 0) - { - rtfBuffer.Append(' ', rtfSpaces); - rtfSpaces = 0; - } - fgColor = (int)charInfo.ForegroundColor; - bgColor = (int)charInfo.BackgroundColor; - rtfBuffer.AppendFormat(@"}}{{\cf{0}\chshdng0\chcbpat{1} ", fgColor + 1, bgColor + 1); - } - - var c = (char)charInfo.UnicodeChar; - if (c == ' ') - { - // Trailing spaces are skipped, we'll add them back if we find a non-space - // before the end of line - ++spaces; - ++rtfSpaces; - } - else - { - if (spaces > 0) - { - textBuffer.Append(' ', spaces); - spaces = 0; - } - if (rtfSpaces > 0) - { - rtfBuffer.Append(' ', rtfSpaces); - rtfSpaces = 0; - } - - textBuffer.Append(c); - switch (c) - { - case '\\': rtfBuffer.Append(@"\\"); break; - case '\t': rtfBuffer.Append(@"\tab"); break; - case '{': rtfBuffer.Append(@"\{"); break; - case '}': rtfBuffer.Append(@"\}"); break; - default: rtfBuffer.Append(c); break; - } - } - } - rtfBuffer.AppendFormat(@"\shading0 \cbpat{0} \par{1}", bgColor + 1, Environment.NewLine); - textBuffer.Append(Environment.NewLine); - } - rtfBuffer.Append("}}"); - -#if !CORECLR // TODO: break dependency on Window.Forms w/ p/invokes to clipboard directly, for now, just silently skip the copy. - var dataObject = new System.Windows.Forms.DataObject(); - dataObject.SetData(System.Windows.Forms.DataFormats.Text, textBuffer.ToString()); - dataObject.SetData(System.Windows.Forms.DataFormats.Rtf, rtfBuffer.ToString()); - ExecuteOnSTAThread(() => System.Windows.Forms.Clipboard.SetDataObject(dataObject, copy: true)); -#endif - } - } -} -#endif diff --git a/src/Microsoft.PowerShell.PSReadLine/UndoRedo.cs b/src/Microsoft.PowerShell.PSReadLine/UndoRedo.cs deleted file mode 100644 index e25aa8ad85f6..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/UndoRedo.cs +++ /dev/null @@ -1,242 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private void RemoveEditsAfterUndo() - { - // If there is some sort of edit after an undo, forget - // any edit items that were undone. - int removeCount = _edits.Count - _undoEditIndex; - if (removeCount > 0) - { - _edits.RemoveRange(_undoEditIndex, removeCount); - if (_editGroupStart >= 0) - { - // Adjust the edit group start if we are started a group. - _editGroupStart -= removeCount; - } - } - } - - private void SaveEditItem(EditItem editItem) - { - if (_statusIsErrorMessage) - { - // After an edit, clear the error message - ClearStatusMessage(render: true); - } - - RemoveEditsAfterUndo(); - - _edits.Add(editItem); - _undoEditIndex = _edits.Count; - } - - private void StartEditGroup() - { - if (_editGroupStart != -1) - { - // Nesting not supported. - throw new InvalidOperationException(); - } - - RemoveEditsAfterUndo(); - _editGroupStart = _edits.Count; - } - - private void EndEditGroup(Action instigator = null, object instigatorArg = null) - { - var groupEditCount = _edits.Count - _editGroupStart; - var groupedEditItems = _edits.GetRange(_editGroupStart, groupEditCount); - _edits.RemoveRange(_editGroupStart, groupEditCount); - SaveEditItem(GroupedEdit.Create(groupedEditItems, instigator, instigatorArg)); - _editGroupStart = -1; - } - - /// - /// Undo a previous edit. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Undo(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._undoEditIndex > 0) - { - if (_singleton._statusIsErrorMessage) - { - // After an edit, clear the error message - _singleton.ClearStatusMessage(render: false); - } - _singleton._edits[_singleton._undoEditIndex - 1].Undo(); - _singleton._undoEditIndex--; - if (_singleton._options.EditMode == EditMode.Vi && _singleton._current >= _singleton._buffer.Length) - { - _singleton._current = Math.Max(0, _singleton._buffer.Length - 1); - } - _singleton.Render(); - } - else - { - Ding(); - } - } - - /// - /// Undo an undo. - /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] - public static void Redo(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._undoEditIndex < _singleton._edits.Count) - { - _singleton._edits[_singleton._undoEditIndex].Redo(); - _singleton._undoEditIndex++; - _singleton.Render(); - } - else - { - Ding(); - } - } - - abstract class EditItem - { - public Action _instigator = null; - public object _instigatorArg = null; - - public abstract void Undo(); - public abstract void Redo(); - } - - [DebuggerDisplay("Insert '{_insertedCharacter}' ({_insertStartPosition})")] - class EditItemInsertChar : EditItem - { - // The character inserted is not needed for undo, only for redo - private char _insertedCharacter; - private int _insertStartPosition; - - public static EditItem Create(char character, int position) - { - return new EditItemInsertChar - { - _insertedCharacter = character, - _insertStartPosition = position - }; - } - - public override void Undo() - { - Debug.Assert(_singleton._buffer[_insertStartPosition] == _insertedCharacter, "Character to undo is not what it should be"); - _singleton._buffer.Remove(_insertStartPosition, 1); - _singleton._current = _insertStartPosition; - } - - public override void Redo() - { - _singleton._buffer.Insert(_insertStartPosition, _insertedCharacter); - _singleton._current++; - } - } - - [DebuggerDisplay("Insert '{_insertedString}' ({_insertStartPosition})")] - class EditItemInsertString : EditItem - { - // The string inserted tells us the length to delete on undo. - // The contents of the string are only needed for redo. - private string _insertedString; - private int _insertStartPosition; - - public static EditItem Create(string str, int position) - { - return new EditItemInsertString - { - _insertedString = str, - _insertStartPosition = position - }; - } - - public override void Undo() - { - Debug.Assert(_singleton._buffer.ToString(_insertStartPosition, _insertedString.Length).Equals(_insertedString), - "Character to undo is not what it should be"); - _singleton._buffer.Remove(_insertStartPosition, _insertedString.Length); - _singleton._current = _insertStartPosition; - } - - public override void Redo() - { - _singleton._buffer.Insert(_insertStartPosition, _insertedString); - _singleton._current += _insertedString.Length; - } - } - - [DebuggerDisplay("Delete '{_deletedString}' ({_deleteStartPosition})")] - class EditItemDelete : EditItem - { - private string _deletedString; - private int _deleteStartPosition; - - public static EditItem Create(string str, int position, Action instigator = null, object instigatorArg = null) - { - return new EditItemDelete - { - _deletedString = str, - _deleteStartPosition = position, - _instigator = instigator, - _instigatorArg = instigatorArg - }; - } - - public override void Undo() - { - _singleton._buffer.Insert(_deleteStartPosition, _deletedString); - _singleton._current = _deleteStartPosition + _deletedString.Length; - } - - public override void Redo() - { - _singleton._buffer.Remove(_deleteStartPosition, _deletedString.Length); - _singleton._current = _deleteStartPosition; - } - } - - class GroupedEdit : EditItem - { - internal List _groupedEditItems; - - public static EditItem Create(List groupedEditItems, Action instigator = null, object instigatorArg = null) - { - return new GroupedEdit - { - _groupedEditItems = groupedEditItems, - _instigator = instigator, - _instigatorArg = instigatorArg - }; - } - - public override void Undo() - { - for (int i = _groupedEditItems.Count - 1; i >= 0; i--) - { - _groupedEditItems[i].Undo(); - } - } - - public override void Redo() - { - foreach (var editItem in _groupedEditItems) - { - editItem.Redo(); - } - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/UndoRedo.vi.cs b/src/Microsoft.PowerShell.PSReadLine/UndoRedo.vi.cs deleted file mode 100644 index ed0d127f028a..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/UndoRedo.vi.cs +++ /dev/null @@ -1,70 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private class GroupUndoHelper - { - public Action _instigator = null; - public object _instigatorArg = null; - - public GroupUndoHelper() - { - _instigator = null; - _instigatorArg = null; - } - - public void StartGroup(Action instigator, object instigatorArg) - { - _instigator = instigator; - _instigatorArg = instigatorArg; - _singleton.StartEditGroup(); - } - - public void Clear() - { - _instigator = null; - _instigatorArg = null; - } - - public void EndGroup() - { - if (_singleton._editGroupStart >= 0) - { - _singleton.EndEditGroup(_instigator, _instigatorArg); - } - Clear(); - } - } - private GroupUndoHelper _groupUndoHelper = new GroupUndoHelper(); - - /// - /// Undo all previous edits for line. - /// - public static void UndoAll(ConsoleKeyInfo? key = null, object arg = null) - { - if (_singleton._undoEditIndex > 0) - { - while (_singleton._undoEditIndex > 0) - { - _singleton._edits[_singleton._undoEditIndex - 1].Undo(); - _singleton._undoEditIndex--; - } - _singleton.Render(); - } - else - { - Ding(); - } - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/VisualEditing.vi.cs b/src/Microsoft.PowerShell.PSReadLine/VisualEditing.vi.cs deleted file mode 100644 index b93a6f36b4ac..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/VisualEditing.vi.cs +++ /dev/null @@ -1,111 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private string _visualEditTemporaryFilename = null; - private Func _savedAddToHistoryHandler = null; - - /// - /// Edit the command line in a text editor specified by $env:EDITOR or $env:VISUAL - /// - public static void ViEditVisually(ConsoleKeyInfo? key = null, object arg = null) - { - string editorOfChoice = GetPreferredEditor(); - if (string.IsNullOrWhiteSpace(editorOfChoice)) - { - Ding(); - return; - } - - _singleton._visualEditTemporaryFilename = GetTemporaryPowerShellFile(); - using (FileStream fs = File.OpenWrite(_singleton._visualEditTemporaryFilename)) - { - using (TextWriter tw = new StreamWriter(fs)) - { - tw.Write(_singleton._buffer.ToString()); - } - } - - _singleton._savedAddToHistoryHandler = _singleton.Options.AddToHistoryHandler; - _singleton.Options.AddToHistoryHandler = ((string s) => - { - return false; - }); - - _singleton._buffer.Clear(); - _singleton._current = 0; - _singleton.Render(); - _singleton._buffer.Append(editorOfChoice + " \'" + _singleton._visualEditTemporaryFilename + "\'"); - AcceptLine(); - } - - private static string GetTemporaryPowerShellFile() - { - string filename; - do - { - filename = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".ps1"); - } while (File.Exists(filename) || Directory.Exists(filename)); - - return filename; - } - - private void ProcessViVisualEditing() - { - if (_visualEditTemporaryFilename == null) - { - return; - } - - Options.AddToHistoryHandler = _savedAddToHistoryHandler; - _savedAddToHistoryHandler = null; - - string editedCommand = null; - using (TextReader tr = File.OpenText(_visualEditTemporaryFilename)) - { - editedCommand = tr.ReadToEnd(); - } - File.Delete(_visualEditTemporaryFilename); - _visualEditTemporaryFilename = null; - - if (!string.IsNullOrWhiteSpace(editedCommand)) - { - while (editedCommand.Length > 0 && char.IsWhiteSpace(editedCommand[editedCommand.Length - 1])) - { - editedCommand = editedCommand.Substring(0, editedCommand.Length - 1); - } - editedCommand = editedCommand.Replace(Environment.NewLine, "\n"); - _buffer.Clear(); - _buffer.Append(editedCommand); - _current = _buffer.Length - 1; - Render(); - //_queuedKeys.Enqueue(Keys.Enter); - } - } - - private static string GetPreferredEditor() - { - string[] names = {"VISUAL", "EDITOR"}; - foreach (string name in names) - { - string editor = Environment.GetEnvironmentVariable(name); - if (!string.IsNullOrWhiteSpace(editor)) - { - return editor; - } - } - - return null; - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Words.cs b/src/Microsoft.PowerShell.PSReadLine/Words.cs deleted file mode 100644 index fe8f3c8ecc96..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Words.cs +++ /dev/null @@ -1,204 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System.Collections.Generic; -using System.Management.Automation.Language; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private enum FindTokenMode - { - CurrentOrNext, - Next, - Previous, - } - - static bool OffsetWithinToken(int offset, Token token) - { - return offset < token.Extent.EndOffset && offset >= token.Extent.StartOffset; - } - - private Token FindNestedToken(int offset, IList tokens, FindTokenMode mode) - { - Token token = null; - bool foundNestedToken = false; - int i; - for (i = tokens.Count - 1; i >= 0; i--) - { - if (OffsetWithinToken(offset, tokens[i])) - { - token = tokens[i]; - var strToken = token as StringExpandableToken; - if (strToken != null && strToken.NestedTokens != null) - { - var nestedToken = FindNestedToken(offset, strToken.NestedTokens, mode); - if (nestedToken != null) - { - token = nestedToken; - foundNestedToken = true; - } - } - break; - } - if (offset >= tokens[i].Extent.EndOffset) - { - break; - } - } - - switch (mode) - { - case FindTokenMode.CurrentOrNext: - if (token == null && (i + 1) < tokens.Count) - { - token = tokens[i + 1]; - } - break; - case FindTokenMode.Next: - if (!foundNestedToken) - { - // If there is no next token, return null (happens with nested - // tokens where there is no EOF/EOS token). - token = ((i + 1) < tokens.Count) ? tokens[i + 1] : null; - } - break; - case FindTokenMode.Previous: - if (token == null) - { - if (i >= 0) - { - token = tokens[i]; - } - } - else if (offset == token.Extent.StartOffset) - { - token = i > 0 ? tokens[i - 1] : null; - } - break; - } - - return token; - } - - private Token FindToken(int current, FindTokenMode mode) - { - MaybeParseInput(); - return FindNestedToken(current, _tokens, mode); - } - - private bool InWord(int index, string wordDelimiters) - { - char c = _buffer[index]; - return !char.IsWhiteSpace(c) && wordDelimiters.IndexOf(c) < 0; - } - - /// - /// Find the end of the current/next word as defined by wordDelimiters and whitespace. - /// - private int FindForwardWordPoint(string wordDelimiters) - { - int i = _current; - if (i == _buffer.Length) - { - return i; - } - - if (!InWord(i, wordDelimiters)) - { - // Scan to end of current non-word region - while (i < _buffer.Length) - { - if (InWord(i, wordDelimiters)) - { - break; - } - i += 1; - } - } - while (i < _buffer.Length) - { - if (!InWord(i, wordDelimiters)) - { - break; - } - i += 1; - } - return i; - } - - /// - /// Find the start of the next word. - /// - private int FindNextWordPoint(string wordDelimiters) - { - int i = _singleton._current; - if (i == _singleton._buffer.Length) - { - return i; - } - - if (InWord(i, wordDelimiters)) - { - // Scan to end of current word region - while (i < _singleton._buffer.Length) - { - if (!InWord(i, wordDelimiters)) - { - break; - } - i += 1; - } - } - - while (i < _singleton._buffer.Length) - { - if (InWord(i, wordDelimiters)) - { - break; - } - i += 1; - } - return i; - } - - /// - /// Find the beginning of the previous word. - /// - private int FindBackwardWordPoint(string wordDelimiters) - { - int i = _current - 1; - if (i < 0) - { - return 0; - } - - if (!InWord(i, wordDelimiters)) - { - // Scan backwards until we are at the end of the previous word. - while (i > 0) - { - if (InWord(i, wordDelimiters)) - { - break; - } - i -= 1; - } - } - while (i > 0) - { - if (!InWord(i, wordDelimiters)) - { - i += 1; - break; - } - i -= 1; - } - return i; - } - - - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/Words.vi.cs b/src/Microsoft.PowerShell.PSReadLine/Words.vi.cs deleted file mode 100644 index 219499737c05..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/Words.vi.cs +++ /dev/null @@ -1,488 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System.Collections.Generic; -using System.Management.Automation.Language; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private char _lastWordDelimiter = char.MinValue; - private bool _shouldAppend = false; - - /// - /// Returns the position of the beginning of the next word as delimited by white space and delimiters. - /// - private int ViFindNextWordPoint(string wordDelimiters) - { - return ViFindNextWordPoint(_current, wordDelimiters); - } - - /// - /// Returns the position of the beginning of the next word as delimited by white space and delimiters. - /// - private int ViFindNextWordPoint(int i, string wordDelimiters) - { - if (IsAtEndOfLine(i)) - { - return i; - } - if (InWord(i, wordDelimiters)) - { - return ViFindNextWordFromWord(i, wordDelimiters); - } - if (IsDelimiter(i, wordDelimiters)) - { - return ViFindNextWordFromDelimiter(i, wordDelimiters); - } - return ViFindNextWordFromWhiteSpace(i, wordDelimiters); - } - - private int ViFindNextWordFromWhiteSpace(int i, string wordDelimiters) - { - while (!IsAtEndOfLine(i) && IsWhiteSpace(i)) - { - i++; - } - return i; - } - - private int ViFindNextWordFromDelimiter(int i, string wordDelimiters) - { - while (!IsAtEndOfLine(i) && IsDelimiter(i, wordDelimiters)) - { - i++; - } - if (IsAtEndOfLine(i)) - { - if (IsDelimiter(i, wordDelimiters)) - { - _shouldAppend = true; - return i + 1; - } - return i; - } - while (!IsAtEndOfLine(i) && IsWhiteSpace(i)) - { - i++; - } - return i; - } - - private bool IsAtEndOfLine(int i) - { - return i >= (_buffer.Length - 1); - } - - private bool IsPastEndOfLine(int i) - { - return i > (_buffer.Length - 1); - } - - private int ViFindNextWordFromWord(int i, string wordDelimiters) - { - while (!IsAtEndOfLine(i) && InWord(i, wordDelimiters)) - { - i++; - } - if (IsAtEndOfLine(i) && InWord(i, wordDelimiters)) - { - _shouldAppend = true; - return i + 1; - } - if (IsDelimiter(i, wordDelimiters)) - { - _lastWordDelimiter = _buffer[i]; - return i; - } - while (!IsAtEndOfLine(i) && IsWhiteSpace(i)) - { - i++; - } - if (IsAtEndOfLine(i) && !InWord(i, wordDelimiters)) - { - return i + 1; - } - _lastWordDelimiter = _buffer[i-1]; - return i; - } - - /// - /// Returns true of the character at the given position is white space. - /// - private bool IsWhiteSpace(int i) - { - return char.IsWhiteSpace(_buffer[i]); - } - - /// - /// Returns the beginning of the current/next word as defined by wordDelimiters and whitespace. - /// - private int ViFindPreviousWordPoint(string wordDelimiters) - { - return ViFindPreviousWordPoint(_current, wordDelimiters); - } - - /// - /// Returns the beginning of the current/next word as defined by wordDelimiters and whitespace. - /// - /// Current cursor location. - /// Characters used to delimit words. - /// Location of the beginning of the previous word. - private int ViFindPreviousWordPoint(int i, string wordDelimiters) - { - if (i == 0) - { - return i; - } - - if (IsWhiteSpace(i)) - { - return FindPreviousWordFromWhiteSpace(i, wordDelimiters); - } - else if (InWord(i, wordDelimiters)) - { - return FindPreviousWordFromWord(i, wordDelimiters); - } - return FindPreviousWordFromDelimiter(i, wordDelimiters); - } - - /// - /// Knowing that you're starting with a word, find the previous start of the next word. - /// - private int FindPreviousWordFromWord(int i, string wordDelimiters) - { - i--; - if (InWord(i, wordDelimiters)) - { - while (i > 0 && InWord(i, wordDelimiters)) - { - i--; - } - if (i == 0 && InWord(i, wordDelimiters)) - { - return i; - } - return i + 1; - } - if (IsWhiteSpace(i)) - { - while (i > 0 && IsWhiteSpace(i)) - { - i--; - } - if (i == 0) - { - return i; - } - if (InWord(i, wordDelimiters) && InWord(i-1, wordDelimiters)) - { - return FindPreviousWordFromWord(i, wordDelimiters); - } - if (IsDelimiter(i - 1, wordDelimiters)) - { - FindPreviousWordFromDelimiter(i, wordDelimiters); - } - return i; - } - while (i > 0 && IsDelimiter(i, wordDelimiters)) - { - i--; - } - if (i == 0 && IsDelimiter(i, wordDelimiters)) - { - return i; - } - return i + 1; - } - - /// - /// Returns true if the cursor is on a word delimiter - /// - private bool IsDelimiter(int i, string wordDelimiters) - { - return wordDelimiters.IndexOf(_buffer[i]) >= 0; - } - - /// - /// Returns true if is in the set of . - /// - private bool IsDelimiter(char c, string wordDelimiters) - { - foreach (char delimiter in wordDelimiters) - { - if (c == delimiter) - { - return true; - } - } - return false; - } - - /// - /// Returns the cursor position of the beginning of the previous word when starting on a delimiter - /// - private int FindPreviousWordFromDelimiter(int i, string wordDelimiters) - { - i--; - if (IsDelimiter(i, wordDelimiters)) - { - while (i > 0 && IsDelimiter(i, wordDelimiters)) - { - i--; - } - if (i == 0 && !IsDelimiter(i, wordDelimiters)) - { - return i + 1; - } - if (!IsWhiteSpace(i)) - { - return i + 1; - } - return i; - } - return ViFindPreviousWordPoint(i, wordDelimiters); - } - - - /// - /// Returns the cursor position of the beginning of the previous word when starting on white space - /// - private int FindPreviousWordFromWhiteSpace(int i, string wordDelimiters) - { - while (IsWhiteSpace(i) && i > 0) - { - i--; - } - int j = i - 1; - if (j < 0 || !InWord(i, wordDelimiters) || char.IsWhiteSpace(_buffer[j])) - { - return i; - } - return (ViFindPreviousWordPoint(i, wordDelimiters)); - } - - /// - /// Returns the cursor position of the previous word, ignoring all delimiters other what white space - /// - private int ViFindPreviousGlob() - { - int i = _current; - if (i == 0) - { - return 0; - } - i--; - - return ViFindPreviousGlob(i); - } - - /// - /// Returns the cursor position of the previous word from i, ignoring all delimiters other what white space - /// - private int ViFindPreviousGlob(int i) - { - if (i <= 0) - { - return 0; - } - - if (!IsWhiteSpace(i)) - { - while (i > 0 && !IsWhiteSpace(i)) - { - i--; - } - if (!IsWhiteSpace(i)) - { - return i; - } - return i + 1; - } - while (i > 0 && IsWhiteSpace(i)) - { - i--; - } - if (i == 0) - { - return i; - } - return ViFindPreviousGlob(i); - } - - /// - /// Finds the next work, using only white space as the word delimiter. - /// - private int ViFindNextGlob() - { - int i = _current; - return ViFindNextGlob(i); - } - - private int ViFindNextGlob(int i) - { - if (i >= _buffer.Length) - { - return i; - } - while (!IsAtEndOfLine(i) && !IsWhiteSpace(i)) - { - i++; - } - if (IsAtEndOfLine(i) && !IsWhiteSpace(i)) - { - return i + 1; - } - while (!IsAtEndOfLine(i) && IsWhiteSpace(i)) - { - i++; - } - if (IsAtEndOfLine(i) && IsWhiteSpace(i)) - { - return i + 1; - } - return i; - } - - /// - /// Finds the end of the current/next word as defined by whitespace. - /// - private int ViFindEndOfGlob() - { - return ViFindGlobEnd(_current); - } - - /// - /// Find the end of the current/next word as defined by wordDelimiters and whitespace. - /// - private int ViFindNextWordEnd(string wordDelimiters) - { - int i = _current; - - return ViFindNextWordEnd(i, wordDelimiters); - } - - /// - /// Find the end of the current/next word as defined by wordDelimiters and whitespace. - /// - private int ViFindNextWordEnd(int i, string wordDelimiters) - { - if (IsAtEndOfLine(i)) - { - return i; - } - - if (IsDelimiter(i, wordDelimiters) && !IsDelimiter(i + 1, wordDelimiters)) - { - i++; - if (IsAtEndOfLine(i)) - { - return i; - } - } - else if (InWord(i, wordDelimiters) && !InWord(i + 1, wordDelimiters)) - { - i++; - if (IsAtEndOfLine(i)) - { - return i; - } - } - - while (!IsAtEndOfLine(i) && IsWhiteSpace(i)) - { - i++; - } - - if (IsAtEndOfLine(i)) - { - return i; - } - - if (IsDelimiter(i, wordDelimiters)) - { - while (!IsAtEndOfLine(i) && IsDelimiter(i, wordDelimiters)) - { - i++; - } - if (!IsDelimiter(i, wordDelimiters)) - { - return i - 1; - } - } - else - { - while (!IsAtEndOfLine(i) && InWord(i, wordDelimiters)) - { - i++; - } - if (!InWord(i, wordDelimiters)) - { - return i - 1; - } - } - - return i; - } - - /// - /// Return the last character in a white space defined word after skipping contiguous white space. - /// - private int ViFindGlobEnd(int i) - { - if (IsAtEndOfLine(i)) - { - return i; - } - i++; - if (IsAtEndOfLine(i)) - { - return i; - } - while (!IsAtEndOfLine(i) && IsWhiteSpace(i)) - { - i++; - } - if (IsAtEndOfLine(i)) - { - return i; - } - while (!IsAtEndOfLine(i) && !IsWhiteSpace(i)) - { - i++; - } - if (IsWhiteSpace(i)) - { - return i - 1; - } - return i; - } - - private int ViFindEndOfPreviousGlob() - { - int i = _current; - - return ViFindEndOfPreviousGlob(i); - } - - private int ViFindEndOfPreviousGlob(int i) - { - if (IsWhiteSpace(i)) - { - while (i > 0 && IsWhiteSpace(i)) - { - i--; - } - return i; - } - - while (i > 0 && !IsWhiteSpace(i)) - { - i--; - } - return ViFindEndOfPreviousGlob(i); - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/YankPaste.vi.cs b/src/Microsoft.PowerShell.PSReadLine/YankPaste.vi.cs deleted file mode 100644 index 1f894a72fea3..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/YankPaste.vi.cs +++ /dev/null @@ -1,338 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; - -namespace Microsoft.PowerShell -{ - public partial class PSConsoleReadLine - { - private string _clipboard = string.Empty; - - /// - /// Paste the clipboard after the cursor, moving the cursor to the end of the pasted text. - /// - public static void PasteAfter(ConsoleKeyInfo? key = null, object arg = null) - { - if (string.IsNullOrEmpty(_singleton._clipboard)) - { - Ding(); - return; - } - - _singleton.PasteAfterImpl(); - } - - /// - /// Paste the clipboard before the cursor, moving the cursor to the end of the pasted text. - /// - public static void PasteBefore(ConsoleKeyInfo? key = null, object arg = null) - { - if (string.IsNullOrEmpty(_singleton._clipboard)) - { - Ding(); - return; - } - _singleton.PasteBeforeImpl(); - } - - private void PasteAfterImpl() - { - if (_current < _buffer.Length) - { - _current++; - } - Insert(_clipboard); - _current--; - Render(); - } - - private void PasteBeforeImpl() - { - Insert(_clipboard); - _current--; - Render(); - } - - private void SaveToClipboard(int startIndex, int length) - { - _clipboard = _buffer.ToString(startIndex, length); - } - - /// - /// Yank the entire buffer. - /// - public static void ViYankLine(ConsoleKeyInfo? key = null, object arg = null) - { - _singleton.SaveToClipboard(0, _singleton._buffer.Length); - } - - /// - /// Yank character(s) under and to the right of the cursor. - /// - public static void ViYankRight(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int start = _singleton._current; - int length = 0; - - while (numericArg-- > 0) - { - length++; - } - - _singleton.SaveToClipboard(start, length); - } - - /// - /// Yank character(s) to the left of the cursor. - /// - public static void ViYankLeft(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int start = _singleton._current; - if (start == 0) - { - _singleton.SaveToClipboard(start, 1); - return; - } - - int length = 0; - - while (numericArg-- > 0) - { - if (start > 0) - { - start--; - length++; - } - } - - _singleton.SaveToClipboard(start, length); - } - - /// - /// Yank from the cursor to the end of the buffer. - /// - public static void ViYankToEndOfLine(ConsoleKeyInfo? key = null, object arg = null) - { - int start = _singleton._current; - int length = _singleton._buffer.Length - _singleton._current; - _singleton.SaveToClipboard(start, length); - } - - /// - /// Yank the word(s) before the cursor. - /// - public static void ViYankPreviousWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int start = _singleton._current; - - while (numericArg-- > 0) - { - start = _singleton.ViFindPreviousWordPoint(start, _singleton.Options.WordDelimiters); - } - - int length = _singleton._current - start; - if (length > 0) - { - _singleton.SaveToClipboard(start, length); - } - } - - /// - /// Yank the word(s) after the cursor. - /// - public static void ViYankNextWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int end = _singleton._current; - - while (numericArg-- > 0) - { - end = _singleton.ViFindNextWordPoint(end, _singleton.Options.WordDelimiters); - } - - int length = end - _singleton._current; - //if (_singleton.IsAtEndOfLine(end)) - //{ - // length++; - //} - if (length > 0) - { - _singleton.SaveToClipboard(_singleton._current, length); - } - } - - /// - /// Yank from the cursor to the end of the word(s). - /// - public static void ViYankEndOfWord(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int end = _singleton._current; - - while (numericArg-- > 0) - { - end = _singleton.ViFindNextWordEnd(end, _singleton.Options.WordDelimiters); - } - - int length = 1 + end - _singleton._current; - if (length > 0) - { - _singleton.SaveToClipboard(_singleton._current, length); - } - } - - /// - /// Yank from the cursor to the end of the WORD(s). - /// - public static void ViYankEndOfGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int end = _singleton._current; - - while (numericArg-- > 0) - { - end = _singleton.ViFindGlobEnd(end); - } - - int length = 1 + end - _singleton._current; - if (length > 0) - { - _singleton.SaveToClipboard(_singleton._current, length); - } - } - - /// - /// Yank from the beginning of the buffer to the cursor. - /// - public static void ViYankBeginningOfLine(ConsoleKeyInfo? key = null, object arg = null) - { - int length = _singleton._current; - if (length > 0) - { - _singleton.SaveToClipboard(0, length); - } - } - - /// - /// Yank from the first non-whitespace character to the cursor. - /// - public static void ViYankToFirstChar(ConsoleKeyInfo? key = null, object arg = null) - { - int start = 0; - while (_singleton.IsWhiteSpace(start)) - { - start++; - } - if (start == _singleton._current) - { - return; - } - - int length = _singleton._current - start; - if (length > 0) - { - _singleton.SaveToClipboard(start, length); - } - } - - /// - /// Yank to/from matching brace. - /// - public static void ViYankPercent(ConsoleKeyInfo? key = null, object arg = null) - { - int start = _singleton.ViFindBrace(_singleton._current); - if (_singleton._current < start) - { - _singleton.SaveToClipboard(_singleton._current, start - _singleton._current + 1); - } - else if (start < _singleton._current) - { - _singleton.SaveToClipboard(start, _singleton._current - start + 1); - } - else - { - Ding(); - } - } - - /// - /// Yank from beginning of the WORD(s) to cursor. - /// - public static void ViYankPreviousGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int start = _singleton._current; - while (numericArg-- > 0) - { - start = _singleton.ViFindPreviousGlob(start - 1); - } - if (start < _singleton._current) - { - _singleton.SaveToClipboard(start, _singleton._current - start); - } - else - { - Ding(); - } - } - - /// - /// Yank from cursor to the start of the next WORD(s). - /// - public static void ViYankNextGlob(ConsoleKeyInfo? key = null, object arg = null) - { - int numericArg; - if (!TryGetArgAsInt(arg, out numericArg, 1)) - { - return; - } - - int end = _singleton._current; - while (numericArg-- > 0) - { - end = _singleton.ViFindNextGlob(end); - } - _singleton.SaveToClipboard(_singleton._current, end - _singleton._current); - } - } -} diff --git a/src/Microsoft.PowerShell.PSReadLine/en-US/PSReadline.md b/src/Microsoft.PowerShell.PSReadLine/en-US/PSReadline.md deleted file mode 100644 index 2d433a945524..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/en-US/PSReadline.md +++ /dev/null @@ -1,513 +0,0 @@ -# Get-PSReadlineKeyHandler - -## SYNOPSIS -Gets the key bindings for the PSReadline module. - -## DESCRIPTION -Gets the key bindings for the PSReadline module. - -If neither -Bound nor -Unbound is specified, returns all bound keys and unbound functions. - -If -Bound is specified and -Unbound is not specified, only bound keys are returned. - -If -Unbound is specified and -Bound is not specified, only unbound keys are returned. - -If both -Bound and -Unbound are specified, returns all bound keys and unbound functions. - -## PARAMETERS - -### Bound [switch] = True - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Include functions that are bound. - - -### Unbound [switch] = True - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Include functions that are unbound. - - - -## INPUTS -### None -You cannot pipe objects to Get-PSReadlineKeyHandler - -## OUTPUTS -### Microsoft.PowerShell.KeyHandler - -Returns one entry for each key binding (or chord) for bound functions and/or one entry for each unbound function - - - -## RELATED LINKS - -[about_PSReadline]() - -# Get-PSReadlineOption - -## SYNOPSIS -Returns the values for the options that can be configured. - -## DESCRIPTION -Get-PSReadlineOption returns the current state of the settings that can be configured by Set-PSReadlineOption. - -The object returned can be used to change PSReadline options. -This provides a slightly simpler way of setting syntax coloring options for multiple kinds of tokens. - -## PARAMETERS - - -## INPUTS -### None -You cannot pipe objects to Get-PSReadlineOption - -## OUTPUTS -### - - - - - -## RELATED LINKS - -[about_PSReadline]() - -# Set-PSReadlineKeyHandler - -## SYNOPSIS -Binds or rebinds keys to user defined or PSReadline provided key handlers. - -## DESCRIPTION -This cmdlet is used to customize what happens when a particular key or sequence of keys is pressed while PSReadline is reading input. - -With user defined key bindings, you can do nearly anything that is possible from a PowerShell script. -Typically you might just edit the command line in some novel way, but because the handlers are just PowerShell scripts, you can do interesting things like change directories, launch programs, etc. - -## PARAMETERS - -### Chord [String[]] - -```powershell -[Parameter( - Mandatory = $true, - Position = 0)] -``` - -The key or sequence of keys to be bound to a Function or ScriptBlock. -A single binding is specified with a single string. -If the binding is a sequence of keys, the keys are separated with a comma, e.g. "Ctrl+X,Ctrl+X". -Note that this parameter accepts multiple strings. -Each string is a separate binding, not a sequence of keys for a single binding. - - -### ScriptBlock [ScriptBlock] - -```powershell -[Parameter( - Mandatory = $true, - Position = 1, - ParameterSetName = 'Set 1')] -``` - -The ScriptBlock is called when the Chord is entered. -The ScriptBlock is passed one or sometimes two arguments. -The first argument is the key pressed (a ConsoleKeyInfo.) The second argument could be any object depending on the context. - - -### BriefDescription [String] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -A brief description of the key binding. -Used in the output of cmdlet Get-PSReadlineKeyHandler. - - -### Description [String] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -A more verbose description of the key binding. -Used in the output of the cmdlet Get-PSReadlineKeyHandler. - - -### Function [String] - -```powershell -[Parameter( - Mandatory = $true, - Position = 1, - ParameterSetName = 'Set 2')] -``` - -The name of an existing key handler provided by PSReadline. -This parameter allows one to rebind existing key bindings or to bind a handler provided by PSReadline that is currently unbound. - -Using the ScriptBlock parameter, one can achieve equivalent functionality by calling the method directly from the ScriptBlock. -This parameter is preferred though - it makes it easier to determine which functions are bound and unbound. - - - -## INPUTS -### None -You cannot pipe objects to Set-PSReadlineKeyHandler - -## OUTPUTS -### - - - - -## EXAMPLES -### -------------- Example 1 -------------- - -```powershell -PS C:\> Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward -``` -This command binds the up arrow key to the function HistorySearchBackward which will use the currently entered command line as the beginning of the search string when searching through history. -### -------------- Example 2 -------------- - -```powershell -PS C:\> Set-PSReadlineKeyHandler -Chord Shift+Ctrl+B -ScriptBlock { - [PSConsoleUtilities.PSConsoleReadLine]::RevertLine() - [PSConsoleUtilities.PSConsoleReadLine]::Insert('build') ->>> [PSConsoleUtilities.PSConsoleReadLine]::AcceptLine() -} -``` -This example binds the key Ctrl+Shift+B to a script block that clears the line, inserts build, then accepts the line. -This example shows how a single key can be used to execute a command. - -## RELATED LINKS - -[about_PSReadline]() - -# Set-PSReadlineOption - -## SYNOPSIS -Customizes the behavior of command line editing in PSReadline. - -## DESCRIPTION -The Set-PSReadlineOption cmdlet is used to customize the behavior of the PSReadline module when editing the command line. - -## PARAMETERS - -### EditMode [EditMode] = Windows - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the command line editing mode. -This will reset any key bindings set by Set-PSReadlineKeyHandler. - -Valid values are: - --- Windows: Key bindings emulate PowerShell/cmd with some bindings emulating Visual Studio. - --- Emacs: Key bindings emulate Bash or Emacs. - - -### ContinuationPrompt [String] = >>> - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the string displayed at the beginning of the second and subsequent lines when multi-line input is being entered. -Defaults to '\>\>\> '. -The empty string is valid. - - -### ContinuationPromptForegroundColor [ConsoleColor] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the foreground color of the continuation prompt. - - -### ContinuationPromptBackgroundColor [ConsoleColor] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the background color of the continuation prompt. - - -### EmphasisForegroundColor [ConsoleColor] = Cyan - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the foreground color used for emphasis, e.g. -to highlight search text. - - -### EmphasisBackgroundColor [ConsoleColor] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the background color used for emphasis, e.g. -to highlight search text. - - -### ErrorForegroundColor [ConsoleColor] = Red - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the foreground color used for errors. - - -### ErrorBackgroundColor [ConsoleColor] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the background color used for errors. - - -### HistoryNoDuplicates [switch] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies that duplicate commands should not be added to PSReadline history. - - -### AddToHistoryHandler [Func[String, Boolean]] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies a ScriptBlock that can be used to control which commands get added to PSReadline history. - - -### ValidationHandler [Func[String, Object]] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies a ScriptBlock that is called from ValidateAndAcceptLine. -If a non-null object is returned or an exception is thrown, validation fails and the error is reported. -If the object returned/thrown has a Message property, it's value is used in the error message, and if there is an Offset property, the cursor is moved to that offset after reporting the error. -If there is no Message property, the ToString method is called to report the error. - - -### HistorySearchCursorMovesToEnd [switch] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - - - - -### MaximumHistoryCount [Int32] = 1024 - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the maximum number of commands to save in PSReadline history. -Note that PSReadline history is separate from PowerShell history. - - -### MaximumKillRingCount [Int32] = 10 - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the maximum number of items stored in the kill ring. - - -### ResetTokenColors [switch] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Restore the token colors to the default settings. - - -### ShowToolTips [switch] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -When displaying possible completions, show tooltips in the list of completions. - - -### ExtraPromptLineCount [Int32] = 0 - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Use this option if your prompt spans more than one line and you want the extra lines to appear when PSReadline displays the prompt after showing some output, e.g. -when showing a list of completions. - - -### DingTone [Int32] = 1221 - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -When BellStyle is set to Audible, specifies the tone of the beep. - - -### DingDuration [Int32] = 50ms - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -When BellStyle is set to Audible, specifies the duration of the beep. - - -### BellStyle [BellStyle] = Audible - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies how PSReadline should respond to various error and ambiguous conditions. - -Valid values are: - --- Audible: a short beep - --- Visible: a brief flash is performed - --- None: no feedback - - -### CompletionQueryItems [Int32] = 100 - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the maximum number of completion items that will be shown without prompting. -If the number of items to show is greater than this value, PSReadline will prompt y/n before displaying the completion items. - - -### WordDelimiters [string] = ;:,.[]{}()/\|^&*-=+ - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the characters that delimit words for functions like ForwardWord or KillWord. - - -### HistorySearchCaseSensitive [switch] - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the searching history is case sensitive in functions like ReverseSearchHistory or HistorySearchBackward. - - -### HistorySaveStyle [HistorySaveStyle] = SaveIncrementally - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies how PSReadline should save history. - -Valid values are: - --- SaveIncrementally: save history after each command is executed - and share across multiple instances of PowerShell - --- SaveAtExit: append history file when PowerShell exits - --- SaveNothing: don't use a history file - - -### HistorySavePath [String] = ~\AppData\Roaming\PSReadline\$($host.Name)_history.txt - -```powershell -[Parameter(ParameterSetName = 'Set 1')] -``` - -Specifies the path to the history file. - - -### TokenKind [TokenClassification] - -```powershell -[Parameter( - Mandatory = $true, - Position = 0, - ParameterSetName = 'Set 2')] -``` - -Specifies the kind of token when setting token coloring options with the -ForegroundColor and -BackgroundColor parameters. - - -### ForegroundColor [ConsoleColor] - -```powershell -[Parameter( - Position = 1, - ParameterSetName = 'Set 2')] -``` - -Specifies the foreground color for the token kind specified by the parameter -TokenKind. - - -### BackgroundColor [ConsoleColor] - -```powershell -[Parameter( - Position = 2, - ParameterSetName = 'Set 2')] -``` - -Specifies the background color for the token kind specified by the parameter -TokenKind. - - - -## INPUTS -### None -You cannot pipe objects to Set-PSReadlineOption - - -## OUTPUTS -### None -This cmdlet does not generate any output. - - - - -## RELATED LINKS - -[about_PSReadline]() - - diff --git a/src/Microsoft.PowerShell.PSReadLine/en-US/about_PSReadline.help.txt b/src/Microsoft.PowerShell.PSReadLine/en-US/about_PSReadline.help.txt deleted file mode 100644 index 3e1ff65b0c78..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/en-US/about_PSReadline.help.txt +++ /dev/null @@ -1,628 +0,0 @@ -TOPIC - about_PSReadline - -SHORT DESCRIPTION - - PSReadline provides an improved command line editing experience in - the PowerShell console. - -LONG DESCRIPTION - - PSReadline provides a powerful command line editing experience for the - PowerShell console. It provides: - - * Syntax coloring of the command line - * A visual indication of syntax errors - * A better multi-line experience (both editing and history) - * Customizable key bindings - * Cmd and Emacs modes - * Many configuration options - * Bash style completion (optional in Cmd mode, default in Emacs mode) - * Emacs yank/kill ring - * PowerShell token based "word" movement and kill - - The following functions are available in the class [Microsoft.PowerShell.PSConsoleReadLine]: - - Cursor movement - --------------- - - EndOfLine (Cmd: Emacs: or ) - - If the input has multiple lines, move to the end of the current line, - or if already at the end of the line, move to the end of the input. - If the input has a single line, move to the end of the input. - - BeginningOfLine (Cmd: Emacs: or ) - - If the input has multiple lines, move to the start of the current line, - or if already at the start of the line, move to the start of the input. - If the input has a single line, move to the start of the input. - - NextLine (Cmd: unbound Emacs: unbound) - - Move the cursor to the next line if the input has multiple lines. - - PreviousLine (Cmd: unbound Emacs: unbound) - - Move the cursor to the previous line if the input has multiple lines. - - ForwardChar (Cmd: Emacs: or ) - - Move the cursor one character to the right. This may move the cursor to the next - line of multi-line input. - - BackwardChar (Cmd: Emacs: or ) - - Move the cursor one character to the left. This may move the cursor to the previous - line of multi-line input. - - ForwardWord (Cmd: unbound Emacs: ) - - Move the cursor forward to the end of the current word, or if between words, - to the end of the next word. Word delimiter characters can be set with: - - Set-PSReadlineOption -WordDelimiters - - NextWord (Cmd: Emacs: unbound) - - Move the cursor forward to the start of the next word. Word delimiter characters - can be set with: - - Set-PSReadlineOption -WordDelimiters - - BackwardWord (Cmd: Emacs: ) - - Move the cursor back to the start of the current word, or if between words, - the start of the previous word. Word delimiter characters - can be set with: - - Set-PSReadlineOption -WordDelimiters - - ShellForwardWord (Cmd: unbound Emacs: unbound) - - Like ForwardWord except word boundaries are defined by PowerShell token boundaries. - - ShellNextWord (Cmd: unbound Emacs: unbound) - - Like NextWord except word boundaries are defined by PowerShell token boundaries. - - ShellBackwardWord (Cmd: unbound Emacs: unbound) - - Like BackwardWord except word boundaries are defined by PowerShell token boundaries. - - GotoBrace (Cmd: Emacs: unbound) - - Go to the matching parenthesis, curly brace, or square bracket. - - AddLine (Cmd: Emacs: ) - - The continuation prompt is displayed on the next line and PSReadline waits for - keys to edit the current input. This is useful to enter multi-line input as - a single command even when a single line is complete input by itself. - - Basic editing - ------------- - - CancelLine (Cmd: unbound Emacs: unbound) - - Cancel all editing to the line, leave the line of input on the screen but - return from PSReadline without executing the input. - - RevertLine (Cmd: Emacs: ) - - Reverts all of the input since the last input was accepted and executed. - This is equivalent to doing Undo until there is nothing left to undo. - - BackwardDeleteChar (Cmd: Emacs: or ) - - Delete the character before the cursor. - - DeleteChar (Cmd: Emacs: ) - - Delete the character under the cursor. - - DeleteCharOrExit (Cmd: unbound Emacs: ) - - Like DeleteChar, unless the line is empty, in which case exit the process. - - AcceptLine (Cmd: Emacs: or ) - - Attempt to execute the current input. If the current input is incomplete (for - example there is a missing closing parenthesis, bracket, or quote, then the - continuation prompt is displayed on the next line and PSReadline waits for - keys to edit the current input. - - AcceptAndGetNext (Cmd: unbound Emacs: ) - - Like AcceptLine, but after the line completes, start editing the next line - from history. - - ValidateAndAcceptLine (Cmd: unbound Emacs: unbound) - - Like AcceptLine but performs additional validation including: - - * Check for additional parse errors - * Validate command names are all found - * If using PowerShell V4 or greater, validate the parameters and arguments - - If there are any errors, the error message is displayed and not accepted nor added - to the history unless you either correct the command line or execute AcceptLine or - ValidateAndAcceptLine again while the error message is displayed. - - BackwardDeleteLine (Cmd: Emacs: unbound) - - Delete the text from the start of the input to the cursor. - - ForwardDeleteLine (Cmd: Emacs: unbound) - - Delete the text from the cursor to the end of the input. - - SelectBackwardChar (Cmd: Emacs: ) - - Adjust the current selection to include the previous character. - - SelectForwardChar (Cmd: Emacs: ) - - Adjust the current selection to include the next character. - - SelectBackwardWord (Cmd: Emacs: ) - - Adjust the current selection to include the previous word. - - SelectForwardWord (Cmd: unbound Emacs: ) - - Adjust the current selection to include the next word using ForwardWord. - - SelectNextWord (Cmd: Emacs: unbound) - - Adjust the current selection to include the next word using NextWord. - - SelectShellForwardWord (Cmd: unbound Emacs: unbound) - - Adjust the current selection to include the next word using ShellForwardWord. - - SelectShellNextWord (Cmd: unbound Emacs: unbound) - - Adjust the current selection to include the next word using ShellNextWord. - - SelectShellBackwardWord (Cmd: unbound Emacs: unbound) - - Adjust the current selection to include the previous word using ShellBackwardWord. - - SelectBackwardsLine (Cmd: Emacs: ) - - Adjust the current selection to include from the cursor to the start of the line. - - SelectLine (Cmd: Emacs: ) - - Adjust the current selection to include from the cursor to the end of the line. - - SelectAll (Cmd: Emacs: unbound) - - Select the entire line. Moves the cursor to the end of the line. - - SelfInsert (Cmd: , , ... Emacs: , , ...) - - Insert the key entered. - - Redo (Cmd: Emacs: unbound) - - Redo an insertion or deletion that was undone by Undo. - - Undo (Cmd: Emacs: ) - - Undo a previous insertion or deletion. - - History - ------- - - ClearHistory (Cmd: Alt+F7 Emacs: unbound) - - Clears history in PSReadline. This does not affect PowerShell history. - - PreviousHistory (Cmd: Emacs: or ) - - Replace the current input with the 'previous' item from PSReadline history. - - NextHistory (Cmd: Emacs: or ) - - Replace the current input with the 'next' item from PSReadline history. - - ForwardSearchHistory (Cmd: Emacs: ) - - Search forward from the current history line interactively. - - ReverseSearchHistory (Cmd: Emacs: ) - - Search backward from the current history line interactively. - - HistorySearchBackward (Cmd: Emacs: unbound) - - Replace the current input with the 'previous' item from PSReadline history - that matches the characters between the start and the input and the cursor. - - HistorySearchForward (Cmd: Emacs: unbound) - - Replace the current input with the 'next' item from PSReadline history - that matches the characters between the start and the input and the cursor. - - BeginningOfHistory (Cmd: unbound Emacs: ) - - Replace the current input with the last item from PSReadline history. - - EndOfHistory (Cmd: unbound Emacs: >) - - Replace the current input with the last item in PSReadline history, which - is the possibly empty input that was entered before any history commands. - - Tab Completion - -------------- - - TabCompleteNext (Cmd: Emacs: unbound) - - Attempt to complete the text surrounding the cursor with the next - available completion. - - TabCompletePrevious (Cmd: Emacs: unbound) - - Attempt to complete the text surrounding the cursor with the next - previous completion. - - Complete (Cmd: unbound Emacs: ) - - Attempt to perform completion on the text surrounding the cursor. - If there are multiple possible completions, the longest unambiguous - prefix is used for completion. If trying to complete the longest - unambiguous completion, a list of possible completions is displayed. - - MenuComplete (Cmd: Emacs: ) - - Attempt to perform completion on the text surrounding the cursor. - If there are multiple possible completions, a list of possible - completions is displayed and you can select the correct completion - using the arrow keys or Tab/Shift+Tab. Escape and Ctrl+G cancel - the menu selection and reverts the line to the state before invoking - MenuComplete. - - PossibleCompletions (Cmd: unbound Emacs: ) - - Display the list of possible completions. - - SetMark (Cmd: unbound Emacs: ) - - Mark the current location of the cursor for use in a subsequent editing command. - - ExchangePointAndMark (Cmd: unbound Emacs: ) - - The cursor is placed at the location of the mark and the mark is moved - to the location of the cursor. - - Kill/Yank - --------- - - Kill and yank operate on a clipboard in the PSReadline module. There is a ring - buffer called the kill ring - killed text will be added to the kill ring up - and yank will copy text from the most recent kill. YankPop will cycle through - items in the kill ring. When the kill ring is full, new items will replace the - oldest items. A kill operation that is immediately preceded by another kill operation - will append the previous kill instead of adding a new item or replacing an item - in the kill ring. This is how you can cut a part of a line, say for example with multiple - KillWord operations, then yank them back elsewhere as a single yank. - - KillLine (Cmd: unbound Emacs: ) - - Clear the input from the cursor to the end of the line. The cleared text is placed - in the kill ring. - - BackwardKillLine (Cmd: unbound Emacs: or ) - - Clear the input from the start of the input to the cursor. The cleared text is placed - in the kill ring. - - KillWord (Cmd: unbound Emacs: ) - - Clear the input from the cursor to the end of the current word. If the cursor - is between words, the input is cleared from the cursor to the end of the next word. - The cleared text is placed in the kill ring. - - BackwardKillWord (Cmd: unbound Emacs: ) - - Clear the input from the start of the current word to the cursor. If the cursor - is between words, the input is cleared from the start of the previous word to the - cursor. The cleared text is placed in the kill ring. - - ShellKillWord (Cmd: unbound Emacs: unbound) - - Like KillWord except word boundaries are defined by PowerShell token boundaries. - - ShellBackwardKillWord (Cmd: unbound Emacs: unbound) - - Like BackwardKillWord except word boundaries are defined by PowerShell token boundaries. - - UnixWordRubout (Cmd: unbound Emacs: ) - - Like BackwardKillWord except word boundaries are defined by whitespace. - - KillRegion (Cmd: unbound Emacs: unbound) - - Kill the text between the cursor and the mark. - - Copy (Cmd: Emacs: unbound) - - Copy selected region to the system clipboard. If no region is selected, copy the whole line. - - CopyOrCancelLine (Cmd: Emacs: ) - - Either copy selected text to the clipboard, or if no text is selected, cancel editing - the line with CancelLine. - - Cut (Cmd: Emacs: unbound) - - Delete selected region placing deleted text in the system clipboard. - - Yank (Cmd: unbound Emacs: ) - - Add the most recently killed text to the input. - - YankPop (Cmd: unbound Emacs: ) - - If the previous operation was Yank or YankPop, replace the previously yanked - text with the next killed text from the kill ring. - - ClearKillRing (Cmd: unbound Emacs: unbound) - - The contents of the kill ring are cleared. - - Paste (Cmd: Emacs: unbound) - - This is similar to Yank, but uses the system clipboard instead of the kill ring. - - YankLastArg (Cmd: Emacs: , ) - - Insert the last argument from the previous command in history. Repeated operations - will replace the last inserted argument with the last argument from the previous - command (so Alt+. Alt+. will insert the last argument of the second to last history - line.) - - With an argument, the first time YankLastArg behaves like YankNthArg. A negative - argument on subsequent YankLastArg calls will change the direction while going - through history. For example, if you hit Alt+. one too many times, you can type - Alt+- Alt+. to reverse the direction. - - Arguments are based on PowerShell tokens. - - YankNthArg (Cmd: unbound Emacs: ) - - Insert the first argument (not the command name) of the previous command in history. - - With an argument, insert the nth argument where 0 is typically the command. Negative - arguments start from the end. - - Arguments are based on PowerShell tokens. - - Miscellaneous - ------------- - - Abort (Cmd: unbound Emacs: ) - - Abort the current action, e.g. stop interactive history search. - Does not cancel input like CancelLine. - - CharacterSearch (Cmd: Emacs: ) - - Read a key and search forwards for that character. With an argument, search - forwards for the nth occurrence of that argument. With a negative argument, - searches backwards. - - CharacterSearchBackward (Cmd: Emacs: ) - - Like CharacterSearch, but searches backwards. With a negative argument, searches - forwards. - - ClearScreen (Cmd: Emacs: ) - - Clears the screen and displays the current prompt and input at the top of the screen. - - DigitArgument (Cmd: unbound Emacs: ,,) - - Used to pass numeric arguments to functions like CharacterSearch or YankNthArg. - Alt+- toggles the argument to be negative/non-negative. To enter 80 '*' characters, - you could type Alt+8 Alt+0 *. - - CaptureScreen (Cmd: unbound Emacs: unbound) - - Copies selected lines to the clipboard in both text and rtf formats. Use up/down - arrow keys to the first line to select, then Shift+UpArrow/Shift+DownArrow to select - multiple lines. After selecting, press Enter to copy the text. Escape/Ctrl+C/Ctrl+G - will cancel so nothing is copied to the clipboard. - - InvokePrompt (Cmd: unbound Emacs: unbound) - - Erases the current prompt and calls the prompt function to redisplay - the prompt. Useful for custom key handlers that change state, e.g. - change the current directory. - - WhatIsKey (Cmd: Emacs: ) - - Read a key or chord and display the key binding. - - ShowKeyBindings (Cmd: Emacs: ) - - Show all of the currently bound keys. - - ScrollDisplayUp (Cmd: Emacs: ) - - Scroll the display up one screen. - - ScrollDisplayUpLine (Cmd: Emacs: ) - - Scroll the display up one line. - - ScrollDisplayDown (Cmd: Emacs: ) - - Scroll the display down one screen. - - ScrollDisplayDownLine (Cmd: Emacs: ) - - Scroll the display down one line. - - ScrollDisplayTop (Cmd: unbound Emacs: ) - - Scroll the display to the top. - - ScrollDisplayToCursor (Cmd: unbound Emacs: ) - - Scroll the display to the cursor. - - Custom Key Bindings - ------------------- - - PSReadline supports custom key bindings using the cmdlet Set-PSReadlineKeyHandler. Most - custom key bindings will call one of the above functions, for example: - - Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward - - You can bind a ScriptBlock to a key. The ScriptBlock can do pretty much anything you want. - Some useful examples include: - - * edit the command line - * opening a new window (e.g. help) - * change directories without changing the command line - - The ScriptBlock is passed two arguments: - - * $key - A [ConsoleKeyInfo] that is the key that triggered the custom binding. If you bind - the same ScriptBlock to multiple keys and need to perform different actions depending - on the key, you can check $key. Many custom bindings ignore this argument. - * $arg - An arbitrary argument. Most often, this would be an integer argument that the user - passes from the key bindings DigitArgument. If your binding doesn't accept arguments, - it's reasonable to ignore this argument. - - Let's take a look at an example that adds a command line to history without executing it. This is - useful when you realize you forgot to do something, but don't want to re-enter the command line - you've already entered. - - Set-PSReadlineKeyHandler -Key Alt+w ` - -BriefDescription SaveInHistory ` - -LongDescription "Save current line in history but do not execute" ` - -ScriptBlock { - param($key, $arg) # The arguments are ignored in this example - - # We need the command line, GetBufferState gives us that (with the cursor position) - $line = $null - $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) - - # AddToHistory saves the line in history, but does not execute the line. - [Microsoft.PowerShell.PSConsoleReadLine]::AddToHistory($line) - - # RevertLine is like pressing Escape. - [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() - } - - You can see many more examples in the file SamplePSReadlineProfile.ps1 which is installed in the - PSReadline module folder. - - Most key bindings will want to take advantage of some helper functions for editing the command - line those APIs are documented in the next section. - - Custom Key Binding Support APIs - ------------------------------- - - The following functions are public in Microsoft.PowerShell.PSConsoleReadline, but cannot be directly - bound to a key. Most are useful in custom key bindings. - - void AddToHistory(string command) - - Add a command line to history without executing it. - - void ClearKillRing() - - Clear the kill ring. This is mostly used for testing. - - void Delete(int start, int length) - - Delete length characters from start. This operation supports undo/redo. - - void Ding() - - Perform the Ding action based on the users preference. - - void GetBufferState([ref] string input, [ref] int cursor) - void GetBufferState([ref] Ast ast, [ref] Token[] tokens, [ref] ParseError[] parseErrors, [ref] int cursor) - - These two functions retrieve useful information about the current state of - the input buffer. The first is more commonly used for simple cases. The - second is used if your binding is doing something more advanced with the Ast. - - IEnumerable[Microsoft.PowerShell.KeyHandler] GetKeyHandlers(bool includeBound, bool includeUnbound) - - This function is used by Get-PSReadlineKeyHandler and probably isn't useful in a custom - key binding. - - Microsoft.PowerShell.PSConsoleReadlineOptions GetOptions() - - This function is used by Get-PSReadlineOption and probably isn't too useful in a custom - key binding. - - void GetSelectionState([ref] int start, [ref] int length) - - If there is no selection on the command line, -1 will be returned in both start and length. - If there is a selection on the command line, the start and length of the selection are returned. - - void Insert(char c) - void Insert(string s) - - Insert a character or string at the cursor. This operation supports undo/redo. - - string ReadLine(runspace remoteRunspace, System.Management.Automation.EngineIntrinsics engineIntrinsics) - - This is the main entry point to PSReadline. It does not support recursion, so is not useful - in a custom key binding. - - void RemoveKeyHandler(string[] key) - - This function is used by Remove-PSReadlineKeyHandler and probably isn't too useful in a - custom key binding. - - void Replace(int start, int length, string replacement) - - Replace some of the input. This operation supports undo/redo. - This is preferred over Delete followed by Insert because it is treated as a single action - for undo. - - void SetCursorPosition(int cursor) - - Move the cursor to the given offset. Cursor movement is not tracked for undo. - - void SetOptions(Microsoft.PowerShell.SetPSReadlineOption options) - - This function is a helper method used by the cmdlet Set-PSReadlineOption, but might be - useful to a custom key binding that wants to temporarily change a setting. - - bool TryGetArgAsInt(System.Object arg, [ref] int numericArg, int defaultNumericArg) - - This helper method is used for custom bindings that honor DigitArgument. A typical call - looks like: - - [int]$numericArg = 0 - [Microsoft.PowerShell.PSConsoleReadLine]::TryGetArgAsInt($arg, [ref]$numericArg, 1) - -POWERSHELL COMPATIBILITY - - PSReadline requires PowerShell version 3 or greater and the console host. It - will not work in the ISE. - -FEEDBACK - - https://github.com/lzybkr/PSReadline - -CONTRIBUTING TO PSREADLINE - - Feel free to submit a pull request or submit feedback on the github page. - -SEE ALSO - - PSReadline is heavily influenced by the GNU Readline library: - - http://tiswww.case.edu/php/chet/readline/rltop.html diff --git a/src/Microsoft.PowerShell.PSReadLine/packages.config b/src/Microsoft.PowerShell.PSReadLine/packages.config deleted file mode 100644 index 0dc84546ba9b..000000000000 --- a/src/Microsoft.PowerShell.PSReadLine/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 311876241285..439c57da49bd 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -15,18 +15,22 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/src/Microsoft.PowerShell.ScheduledJob/AssemblyInfo.cs b/src/Microsoft.PowerShell.ScheduledJob/AssemblyInfo.cs index 8be32293508f..08853e30b8bc 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/AssemblyInfo.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/AssemblyInfo.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System.Reflection; using System.Resources; diff --git a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJob.cs b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJob.cs index bf61ff71491f..9bdc6e42e650 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJob.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJob.cs @@ -1,17 +1,17 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Text; -using System.Runtime.Serialization; +using System.ComponentModel; +using System.IO; using System.Management.Automation; +using System.Management.Automation.Host; using System.Management.Automation.Runspaces; -using System.IO; -using System.ComponentModel; +using System.Runtime.Serialization; using System.Security.Permissions; -using System.Management.Automation.Host; +using System.Text; namespace Microsoft.PowerShell.ScheduledJob { @@ -51,6 +51,7 @@ public sealed class ScheduledJob : Job2, ISerializable public ScheduledJobDefinition Definition { get { return _jobDefinition; } + internal set { _jobDefinition = value; } } @@ -115,6 +116,7 @@ public new string Command internal bool AllowSetShouldExit { get { return _allowSetShouldExit; } + set { _allowSetShouldExit = value; } } @@ -125,9 +127,9 @@ internal bool AllowSetShouldExit /// /// Constructor. /// - /// Job command string for display - /// Name of job - /// ScheduledJobDefinition defining job to run + /// Job command string for display. + /// Name of job. + /// ScheduledJobDefinition defining job to run. public ScheduledJob( string command, string name, @@ -138,10 +140,12 @@ internal bool AllowSetShouldExit { throw new PSArgumentNullException("command"); } + if (name == null) { throw new PSArgumentNullException("name"); } + if (jobDefinition == null) { throw new PSArgumentNullException("jobDefinition"); @@ -210,7 +214,7 @@ public override void StartJob() // Add this job to the local repository. ScheduledJobSourceAdapter.AddToRepository(this); - } // lock + } } /// @@ -218,7 +222,7 @@ public override void StartJob() /// public override void StartJobAsync() { - //StartJob(); + // StartJob(); throw new PSNotSupportedException(); } @@ -335,9 +339,8 @@ public override void UnblockJobAsync() throw new PSNotSupportedException(); } - /// - /// StopJob + /// StopJob. /// /// /// @@ -347,7 +350,7 @@ public override void StopJob(bool force, string reason) } /// - /// StopJobAsync + /// StopJobAsync. /// /// /// @@ -356,7 +359,7 @@ public override void StopJobAsync(bool force, string reason) throw new PSNotSupportedException(); } /// - /// SuspendJob + /// SuspendJob. /// /// /// @@ -366,7 +369,7 @@ public override void SuspendJob(bool force, string reason) } /// - /// SuspendJobAsync + /// SuspendJobAsync. /// /// /// @@ -375,7 +378,6 @@ public override void SuspendJobAsync(bool force, string reason) throw new PSNotSupportedException(); } - #endregion #region Implementation of ISerializable @@ -383,8 +385,8 @@ public override void SuspendJobAsync(bool force, string reason) /// /// Deserialize constructor. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] private ScheduledJob( SerializationInfo info, @@ -403,8 +405,8 @@ public override void SuspendJobAsync(bool force, string reason) /// /// Serialize method. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] public void GetObjectData( SerializationInfo info, @@ -739,10 +741,12 @@ private void HandleJobStateChanged(object sender, JobStateEventArgs e) _runspace = null; } } + if (disposePowerShell != null) { disposePowerShell.Dispose(); } + if (disposeRunspace != null) { disposeRunspace.Dispose(); @@ -1013,26 +1017,32 @@ Collection information { throw new PSArgumentNullException("output"); } + if (error == null) { throw new PSArgumentNullException("error"); } + if (warning == null) { throw new PSArgumentNullException("warning"); } + if (verbose == null) { throw new PSArgumentNullException("verbose"); } + if (progress == null) { throw new PSArgumentNullException("progress"); } + if (debug == null) { throw new PSArgumentNullException("debug"); } + if (information == null) { throw new PSArgumentNullException("information"); @@ -1226,6 +1236,7 @@ internal ScheduledJobDefinition Definition { _startTime = null; } + DateTime stopTime = info.GetDateTime("Status_StopTime"); if (stopTime != DateTime.MinValue) { @@ -1264,6 +1275,7 @@ internal ScheduledJobDefinition Definition { info.AddValue("Status_StartTime", DateTime.MinValue); } + if (_stopTime != null) { info.AddValue("Status_StopTime", _stopTime); diff --git a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobDefinition.cs b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobDefinition.cs index 826b4cfdc758..474265eac424 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobDefinition.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobDefinition.cs @@ -1,17 +1,17 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Runtime.Serialization; -using System.Management.Automation; -using System.Management.Automation.Runspaces; +using System.Collections.ObjectModel; using System.Globalization; using System.IO; +using System.Management.Automation; +using System.Management.Automation.Runspaces; using System.Management.Automation.Tracing; -using System.Text.RegularExpressions; +using System.Runtime.Serialization; using System.Security.Permissions; +using System.Text.RegularExpressions; namespace Microsoft.PowerShell.ScheduledJob { @@ -88,6 +88,7 @@ public ScheduledJobOptions Options public PSCredential Credential { get { return _credential; } + internal set { _credential = value; } } @@ -199,10 +200,10 @@ private ScheduledJobDefinition() /// /// Constructor. /// - /// Information to invoke Job - /// ScheduledJobTriggers - /// ScheduledJobOptions - /// Credential + /// Information to invoke Job. + /// ScheduledJobTriggers. + /// ScheduledJobOptions. + /// Credential. public ScheduledJobDefinition( JobInvocationInfo invocationInfo, IEnumerable triggers, @@ -232,8 +233,8 @@ private ScheduledJobDefinition() /// /// Serialization constructor. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] private ScheduledJobDefinition( SerializationInfo info, @@ -272,8 +273,8 @@ private ScheduledJobDefinition() /// /// Serialization constructor. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] public void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -321,7 +322,7 @@ private void UpdateWTSFromDefinition() /// Task Scheduler information: /// - Triggers /// - Options - /// - Enabled state + /// - Enabled state. /// /// Boolean if this object data is modified. private bool UpdateDefinitionFromWTS() @@ -506,7 +507,7 @@ private void UpdateJobStore() /// /// Updates definition file permissions for provided user account. /// - /// Account user name + /// Account user name. private void UpdateFilePermissions(string user) { Exception ex = null; @@ -657,8 +658,8 @@ private static void ValidateName(string name) /// /// Handles known Task Scheduler COM error codes. /// - /// COMException - /// Error message + /// COMException. + /// Error message. private string ConvertCOMErrorCode(System.Runtime.InteropServices.COMException e) { string msg = null; @@ -724,7 +725,7 @@ internal void SyncWithWTS() /// /// Renames scheduled job definition, store directory and task scheduler task. /// - /// New name of job definition + /// New name of job definition. internal void RenameAndSave(string newName) { if (InvocationInfo.Name.Equals(newName, StringComparison.OrdinalIgnoreCase)) @@ -762,6 +763,7 @@ internal void RenameAndSave(string newName) { ex = e; } + if (ex != null) { string msg; @@ -773,6 +775,7 @@ internal void RenameAndSave(string newName) { msg = StringUtil.Format(ScheduledJobErrorStrings.ErrorRenamingScheduledJob, oldName, newName); } + throw new ScheduledJobException(msg, ex); } @@ -846,6 +849,7 @@ internal void RenameAndSave(string newName) { msg = StringUtil.Format(ScheduledJobErrorStrings.BrokenRenamingScheduledJob, oldName, newName); } + throw new ScheduledJobException(msg, ex); } } @@ -977,6 +981,7 @@ public void Register() { ex = e; } + if (ex != null) { // Clean up job store. @@ -1036,6 +1041,7 @@ public void Save() { ex = e; } + if (ex != null) { // We want this object to remain synchronized with what is in WTS. @@ -1071,6 +1077,7 @@ public void Save() { ex = e; } + if (ex != null) { // Remove this from WTS for consistency. @@ -1163,7 +1170,7 @@ public void Remove(bool force) /// job is also added to the local job repository. Job results are /// not written to the job store. /// - /// ScheduledJob object for running job + /// ScheduledJob object for running job. public ScheduledJob StartJob() { IsDisposed(); @@ -1229,8 +1236,8 @@ public void RunAsTask() /// /// Adds new ScheduledJobTriggers. /// - /// Collection of ScheduledJobTrigger objects - /// Update Windows Task Scheduler and save to store + /// Collection of ScheduledJobTrigger objects. + /// Update Windows Task Scheduler and save to store. public void AddTriggers( IEnumerable triggers, bool save) @@ -1265,8 +1272,8 @@ public void RunAsTask() /// /// Removes triggers matching passed in trigger Ids. /// - /// Trigger Ids to remove - /// Update Windows Task Scheduler and save to store + /// Trigger Ids to remove. + /// Update Windows Task Scheduler and save to store. /// Trigger Ids not found. public List RemoveTriggers( IEnumerable triggerIds, @@ -1325,8 +1332,8 @@ public void RunAsTask() /// Updates triggers with provided trigger objects, matching passed in /// trigger Id with existing trigger Id. /// - /// Collection of ScheduledJobTrigger objects to update - /// Update Windows Task Scheduler and save to store + /// Collection of ScheduledJobTrigger objects to update. + /// Update Windows Task Scheduler and save to store. /// Trigger Ids not found. public List UpdateTriggers( IEnumerable triggers, @@ -1375,8 +1382,8 @@ public void RunAsTask() /// /// Creates a new set of ScheduledJobTriggers for this object. /// - /// Array of ScheduledJobTrigger objects to set - /// Update Windows Task Scheduler and save to store + /// Array of ScheduledJobTrigger objects to set. + /// Update Windows Task Scheduler and save to store. public void SetTriggers( IEnumerable newTriggers, bool save) @@ -1417,9 +1424,9 @@ public void RunAsTask() /// to the passed in trigger Ids. Also returns an array of trigger Ids /// that were not found in an out parameter. /// - /// List of trigger Ids - /// List of not found trigger Ids - /// List of ScheduledJobTrigger objects + /// List of trigger Ids. + /// List of not found trigger Ids. + /// List of ScheduledJobTrigger objects. public List GetTriggers( IEnumerable triggerIds, out List notFoundIds) @@ -1469,8 +1476,8 @@ public void RunAsTask() /// Finds and returns a copy of the ScheduledJobTrigger corresponding to /// the passed in trigger Id. /// - /// Trigger Id - /// ScheduledJobTrigger object + /// Trigger Id. + /// ScheduledJobTrigger object. public ScheduledJobTrigger GetTrigger( Int32 triggerId) { @@ -1491,8 +1498,8 @@ public void RunAsTask() /// /// Updates scheduled job options. /// - /// ScheduledJobOptions or null for default - /// Update Windows Task Scheduler and save to store + /// ScheduledJobOptions or null for default. + /// Update Windows Task Scheduler and save to store. public void UpdateOptions( ScheduledJobOptions options, bool save) @@ -1517,8 +1524,8 @@ public void RunAsTask() /// /// Sets the execution history length property. /// - /// execution history length - /// Save to store + /// Execution history length. + /// Save to store. public void SetExecutionHistoryLength( int executionHistoryLength, bool save) @@ -1547,8 +1554,8 @@ public void ClearExecutionHistory() /// /// Updates the JobInvocationInfo object. /// - /// JobInvocationInfo - /// Save to store + /// JobInvocationInfo. + /// Save to store. public void UpdateJobInvocationInfo( JobInvocationInfo jobInvocationInfo, bool save) @@ -1572,8 +1579,8 @@ public void ClearExecutionHistory() /// /// Sets the enabled state of this object. /// - /// True if enabled - /// Update Windows Task Scheduler and save to store + /// True if enabled. + /// Update Windows Task Scheduler and save to store. public void SetEnabled( bool enabled, bool save) @@ -1591,8 +1598,8 @@ public void ClearExecutionHistory() /// /// Sets the name of this scheduled job definition. /// - /// Name - /// Update Windows Task Scheduler and save to store + /// Name. + /// Update Windows Task Scheduler and save to store. public void SetName( string name, bool save) @@ -1714,9 +1721,9 @@ public void Dispose() /// Reads a ScheduledJobDefinition object from file and /// returns object. /// - /// Name of definition to load - /// Path to definition file - /// ScheduledJobDefinition object + /// Name of definition to load. + /// Path to definition file. + /// ScheduledJobDefinition object. internal static ScheduledJobDefinition LoadDefFromStore( string definitionName, string definitionPath) @@ -1844,7 +1851,7 @@ public void Dispose() /// Internal helper method to remove a scheduled job definition /// by name from job store and Task Scheduler. /// - /// Scheduled job definition name + /// Scheduled job definition name. internal static void RemoveDefinition( string definitionName) { @@ -1940,7 +1947,7 @@ private static int GetCurrentId() /// Create a Job2 job, runs it and waits for it to complete. /// Job status and results are written to the job store. /// - /// Job2 job object that was run + /// Job2 job object that was run. public Job2 Run() { Job2 job = null; @@ -2016,10 +2023,6 @@ public Job2 Run() { ex = e; } - catch (System.Threading.ThreadAbortException e) - { - ex = e; - } catch (IOException e) { ex = e; @@ -2158,6 +2161,7 @@ public void Add(ScheduledJobDefinition jobDef) string msg = StringUtil.Format(ScheduledJobErrorStrings.DefinitionAlreadyExistsInLocal, jobDef.Name, jobDef.GlobalId); throw new ScheduledJobException(msg); } + _definitions.Add(jobDef.Name, jobDef); } } @@ -2179,6 +2183,7 @@ public void AddOrReplace(ScheduledJobDefinition jobDef) { _definitions.Remove(jobDef.Name); } + _definitions.Add(jobDef.Name, jobDef); } } @@ -2207,8 +2212,8 @@ public void Remove(ScheduledJobDefinition jobDef) /// Checks to see if a ScheduledJobDefinition object exists with /// the provided definition name. /// - /// Definition name - /// True if definition exists + /// Definition name. + /// True if definition exists. public bool Contains(string jobDefName) { lock (_syncObject) @@ -2283,8 +2288,10 @@ public ScheduledJobException(string message, Exception innerException) internal string FQEID { get { return _fqeid; } + set { _fqeid = value ?? string.Empty; } } + private string _fqeid = string.Empty; } @@ -2299,12 +2306,12 @@ internal class StringUtil { internal static string Format(string formatSpec, object o) { - return String.Format(System.Threading.Thread.CurrentThread.CurrentCulture, formatSpec, o); + return string.Format(System.Threading.Thread.CurrentThread.CurrentCulture, formatSpec, o); } internal static string Format(string formatSpec, params object[] o) { - return String.Format(System.Threading.Thread.CurrentThread.CurrentCulture, formatSpec, o); + return string.Format(System.Threading.Thread.CurrentThread.CurrentCulture, formatSpec, o); } } @@ -2321,7 +2328,7 @@ internal static string Format(string formatSpec, params object[] o) /// "InitializationScript" -> ScriptBlock /// "ArgumentList" -> object[] /// "RunAs32" -> Boolean - /// "Authentication" -> AuthenticationMechanism + /// "Authentication" -> AuthenticationMechanism. /// [Serializable] public sealed class ScheduledJobInvocationInfo : JobInvocationInfo @@ -2331,8 +2338,8 @@ public sealed class ScheduledJobInvocationInfo : JobInvocationInfo /// /// Constructor. /// - /// JobDefinition - /// Dictionary of parameters + /// JobDefinition. + /// Dictionary of parameters. public ScheduledJobInvocationInfo(JobDefinition definition, Dictionary parameters) : base(definition, parameters) { @@ -2385,8 +2392,8 @@ public ScheduledJobInvocationInfo(JobDefinition definition, Dictionary /// Serialization constructor. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. internal ScheduledJobInvocationInfo( SerializationInfo info, StreamingContext context) @@ -2402,8 +2409,8 @@ public ScheduledJobInvocationInfo(JobDefinition definition, Dictionary /// Serialization implementation. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) diff --git a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobOptions.cs b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobOptions.cs index 25ad74822b15..b8582600204d 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobOptions.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobOptions.cs @@ -1,13 +1,13 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Runtime.Serialization; using System.Management.Automation; +using System.Runtime.Serialization; using System.Security.Permissions; +using System.Text; namespace Microsoft.PowerShell.ScheduledJob { @@ -53,6 +53,7 @@ public sealed class ScheduledJobOptions : ISerializable public bool StartIfOnBatteries { get { return _startIfOnBatteries; } + set { _startIfOnBatteries = value; } } @@ -62,6 +63,7 @@ public bool StartIfOnBatteries public bool StopIfGoingOnBatteries { get { return _stopIfGoingOnBatteries; } + set { _stopIfGoingOnBatteries = value; } } @@ -71,6 +73,7 @@ public bool StopIfGoingOnBatteries public bool WakeToRun { get { return _wakeToRun; } + set { _wakeToRun = value; } } @@ -80,6 +83,7 @@ public bool WakeToRun public bool StartIfNotIdle { get { return _startIfNotIdle; } + set { _startIfNotIdle = value; } } @@ -89,6 +93,7 @@ public bool StartIfNotIdle public bool StopIfGoingOffIdle { get { return _stopIfGoingOffIdle; } + set { _stopIfGoingOffIdle = value; } } /// @@ -97,6 +102,7 @@ public bool StopIfGoingOffIdle public bool RestartOnIdleResume { get { return _restartOnIdleResume; } + set { _restartOnIdleResume = value; } } @@ -106,6 +112,7 @@ public bool RestartOnIdleResume public TimeSpan IdleDuration { get { return _idleDuration; } + set { _idleDuration = value; } } @@ -115,6 +122,7 @@ public TimeSpan IdleDuration public TimeSpan IdleTimeout { get { return _idleTimeout; } + set { _idleTimeout = value; } } @@ -124,6 +132,7 @@ public TimeSpan IdleTimeout public bool ShowInTaskScheduler { get { return _showInTaskScheduler; } + set { _showInTaskScheduler = value; } } @@ -133,6 +142,7 @@ public bool ShowInTaskScheduler public bool RunElevated { get { return _runElevated; } + set { _runElevated = value; } } @@ -142,6 +152,7 @@ public bool RunElevated public bool RunWithoutNetwork { get { return _runWithoutNetwork; } + set { _runWithoutNetwork = value; } } @@ -151,6 +162,7 @@ public bool RunWithoutNetwork public bool DoNotAllowDemandStart { get { return _donotAllowDemandStart; } + set { _donotAllowDemandStart = value; } } @@ -160,6 +172,7 @@ public bool DoNotAllowDemandStart public TaskMultipleInstancePolicy MultipleInstancePolicy { get { return _multipleInstancePolicy; } + set { _multipleInstancePolicy = value; } } @@ -169,6 +182,7 @@ public TaskMultipleInstancePolicy MultipleInstancePolicy public ScheduledJobDefinition JobDefinition { get { return _jobDefAssociation; } + internal set { _jobDefAssociation = value; } } @@ -245,7 +259,7 @@ public ScheduledJobOptions() /// /// Copy Constructor. /// - /// Copy from + /// Copy from. internal ScheduledJobOptions( ScheduledJobOptions copyOptions) { @@ -278,8 +292,8 @@ public ScheduledJobOptions() /// /// Serialization constructor. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] private ScheduledJobOptions( SerializationInfo info, @@ -311,8 +325,8 @@ public ScheduledJobOptions() /// /// GetObjectData for ISerializable implementation. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] public void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -368,7 +382,7 @@ public void UpdateJobDefinition() public enum TaskMultipleInstancePolicy { /// - /// None + /// None. /// None = 0, /// @@ -384,7 +398,7 @@ public enum TaskMultipleInstancePolicy /// Queue = 3, /// - /// Stop currently running task (job) and start a new one + /// Stop currently running task (job) and start a new one. /// StopExisting = 4 } diff --git a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobSourceAdapter.cs b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobSourceAdapter.cs index 37d3eab4b234..3c5e833706c7 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobSourceAdapter.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobSourceAdapter.cs @@ -1,16 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; using System.Linq; -using System.Text; using System.Management.Automation; using System.Management.Automation.Runspaces; -using System.IO; -using System.Globalization; using System.Runtime.Serialization; +using System.Text; namespace Microsoft.PowerShell.ScheduledJob { @@ -35,17 +35,17 @@ public sealed class ScheduledJobSourceAdapter : JobSourceAdapter #region Public Strings /// - /// BeforeFilter + /// BeforeFilter. /// public const string BeforeFilter = "Before"; /// - /// AfterFilter + /// AfterFilter. /// public const string AfterFilter = "After"; /// - /// NewestFilter + /// NewestFilter. /// public const string NewestFilter = "Newest"; @@ -68,8 +68,8 @@ public ScheduledJobSourceAdapter() /// /// Create a new Job2 results instance. /// - /// Job specification - /// Job2 + /// Job specification. + /// Job2. public override Job2 NewJob(JobInvocationInfo specification) { if (specification == null) @@ -92,9 +92,9 @@ public override Job2 NewJob(JobInvocationInfo specification) /// null then a default location will be used to find the /// job definition by name. /// - /// ScheduledJob definition name - /// ScheduledJob definition file path - /// Job2 object + /// ScheduledJob definition name. + /// ScheduledJob definition file path. + /// Job2 object. public override Job2 NewJob(string definitionName, string definitionPath) { if (string.IsNullOrEmpty(definitionName)) @@ -123,9 +123,9 @@ public override Job2 NewJob(string definitionName, string definitionPath) /// /// Get the list of jobs that are currently available in this - /// store + /// store. /// - /// Collection of job objects + /// Collection of job objects. public override IList GetJobs() { RefreshRepository(); @@ -140,13 +140,13 @@ public override IList GetJobs() } /// - /// Get list of jobs that matches the specified names + /// Get list of jobs that matches the specified names. /// /// names to match, can support /// wildcard if the store supports /// - /// collection of jobs that match the specified - /// criteria + /// Collection of jobs that match the specified + /// criteria. public override IList GetJobsByName(string name, bool recurse) { if (string.IsNullOrEmpty(name)) @@ -170,12 +170,12 @@ public override IList GetJobsByName(string name, bool recurse) } /// - /// Get list of jobs that run the specified command + /// Get list of jobs that run the specified command. /// - /// command to match + /// Command to match. /// - /// collection of jobs that match the specified - /// criteria + /// Collection of jobs that match the specified + /// criteria. public override IList GetJobsByCommand(string command, bool recurse) { if (string.IsNullOrEmpty(command)) @@ -199,11 +199,11 @@ public override IList GetJobsByCommand(string command, bool recurse) } /// - /// Get job that has the specified id + /// Get job that has the specified id. /// - /// Guid to match + /// Guid to match. /// - /// job with the specified guid + /// Job with the specified guid. public override Job2 GetJobByInstanceId(Guid instanceId, bool recurse) { RefreshRepository(); @@ -220,11 +220,11 @@ public override Job2 GetJobByInstanceId(Guid instanceId, bool recurse) } /// - /// Get job that has specific session id + /// Get job that has specific session id. /// - /// Id to match + /// Id to match. /// - /// Job with the specified id + /// Job with the specified id. public override Job2 GetJobBySessionId(int id, bool recurse) { RefreshRepository(); @@ -241,12 +241,12 @@ public override Job2 GetJobBySessionId(int id, bool recurse) } /// - /// Get list of jobs that are in the specified state + /// Get list of jobs that are in the specified state. /// - /// state to match + /// State to match. /// - /// collection of jobs with the specified - /// state + /// Collection of jobs with the specified + /// state. public override IList GetJobsByState(JobState state, bool recurse) { RefreshRepository(); @@ -265,13 +265,13 @@ public override IList GetJobsByState(JobState state, bool recurse) /// /// Get list of jobs based on the adapter specific - /// filter parameters + /// filter parameters. /// /// dictionary containing name value /// pairs for adapter specific filters /// - /// collection of jobs that match the - /// specified criteria + /// Collection of jobs that match the + /// specified criteria. public override IList GetJobsByFilter(Dictionary filter, bool recurse) { if (filter == null) @@ -302,9 +302,9 @@ public override IList GetJobsByFilter(Dictionary filter, b } /// - /// Remove a job from the store + /// Remove a job from the store. /// - /// job object to remove + /// Job object to remove. public override void RemoveJob(Job2 job) { if (job == null) @@ -332,7 +332,7 @@ public override void RemoveJob(Job2 job) /// /// Saves job to scheduled job run store. /// - /// ScheduledJob + /// ScheduledJob. public override void PersistJob(Job2 job) { if (job == null) @@ -350,7 +350,7 @@ public override void PersistJob(Job2 job) /// /// Serializes a ScheduledJob and saves it to store. /// - /// ScheduledJob + /// ScheduledJob. internal static void SaveJobToStore(ScheduledJob job) { string outputPath = job.Definition.OutputPath; @@ -403,8 +403,8 @@ internal static void SaveJobToStore(ScheduledJob job) /// Writes the job status information to the provided /// file stream. /// - /// ScheduledJob job to save - /// FileStream + /// ScheduledJob job to save. + /// FileStream. private static void SaveStatusToFile(ScheduledJob job, FileStream fs) { StatusInfo statusInfo = new StatusInfo( @@ -428,8 +428,8 @@ private static void SaveStatusToFile(ScheduledJob job, FileStream fs) /// Writes the job (which implements ISerializable) to the provided /// file stream. /// - /// ScheduledJob job to save - /// FileStream + /// ScheduledJob job to save. + /// FileStream. private static void SaveResultsToFile(ScheduledJob job, FileStream fs) { XmlObjectSerializer serializer = new System.Runtime.Serialization.NetDataContractSerializer(); @@ -441,8 +441,8 @@ private static void SaveResultsToFile(ScheduledJob job, FileStream fs) /// Check the job store results and if maximum number of results exist /// remove the oldest results folder to make room for these new results. /// - /// Output path - /// Maximum size of stored job results + /// Output path. + /// Maximum size of stored job results. private static void CheckJobStoreResults(string outputPath, int executionHistoryLength) { // Get current results for this job definition. @@ -476,9 +476,9 @@ private static void CheckJobStoreResults(string outputPath, int executionHistory /// Finds and load the Job associated with this ScheduledJobDefinition object /// having the job run date time provided. /// - /// DateTime of job run to load - /// ScheduledJobDefinition name - /// Job2 job loaded from store + /// DateTime of job run to load. + /// ScheduledJobDefinition name. + /// Job2 job loaded from store. internal static Job2 LoadJobFromStore(string definitionName, DateTime jobRun) { FileStream fsResults = null; @@ -562,8 +562,8 @@ internal static Job2 LoadJobFromStore(string definitionName, DateTime jobRun) /// /// Loads the Job2 object from provided files stream. /// - /// FileStream from which to read job object - /// Created Job2 from file stream + /// FileStream from which to read job object. + /// Created Job2 from file stream. private static Job2 LoadResultsFromFile(FileStream fs) { XmlObjectSerializer serializer = new System.Runtime.Serialization.NetDataContractSerializer(); @@ -577,7 +577,7 @@ private static Job2 LoadResultsFromFile(FileStream fs) /// /// Adds a Job2 object to the repository. /// - /// Job2 + /// Job2. internal static void AddToRepository(Job2 job) { if (job == null) @@ -916,7 +916,7 @@ public int Count /// /// Add Job2 to repository. /// - /// Job2 to add + /// Job2 to add. public void Add(Job2 job) { if (job == null) @@ -931,6 +931,7 @@ public void Add(Job2 job) string msg = StringUtil.Format(ScheduledJobErrorStrings.ScheduledJobAlreadyExistsInLocal, job.Name, job.InstanceId); throw new ScheduledJobException(msg); } + _jobs.Add(job.InstanceId, job); } } @@ -938,7 +939,7 @@ public void Add(Job2 job) /// /// Add or replace passed in Job2 object to repository. /// - /// Job2 to add + /// Job2 to add. public void AddOrReplace(Job2 job) { if (job == null) @@ -952,6 +953,7 @@ public void AddOrReplace(Job2 job) { _jobs.Remove(job.InstanceId); } + _jobs.Add(job.InstanceId, job); } } @@ -974,6 +976,7 @@ public void Remove(Job2 job) string msg = StringUtil.Format(ScheduledJobErrorStrings.ScheduledJobNotInRepository, job.Name); throw new ScheduledJobException(msg); } + _jobs.Remove(job.InstanceId); } } @@ -992,8 +995,8 @@ public void Clear() /// /// Gets the latest job run Date/Time for the given definition name. /// - /// ScheduledJobDefinition name - /// Job Run DateTime + /// ScheduledJobDefinition name. + /// Job Run DateTime. public DateTime GetLatestJobRun(string definitionName) { if (string.IsNullOrEmpty(definitionName)) @@ -1045,9 +1048,9 @@ public void SetLatestJobRun(string definitionName, DateTime jobRun) /// /// Search repository for specific job run. /// - /// Definition name - /// Job run DateTime - /// Scheduled job if found + /// Definition name. + /// Job run DateTime. + /// Scheduled job if found. public ScheduledJob GetJob(string definitionName, DateTime jobRun) { lock (_syncObject) @@ -1058,6 +1061,7 @@ public ScheduledJob GetJob(string definitionName, DateTime jobRun) { continue; } + DateTime PSBeginTime = job.PSBeginTime ?? DateTime.MinValue; if (definitionName.Equals(job.Definition.Name, StringComparison.OrdinalIgnoreCase) && jobRun.Year == PSBeginTime.Year && diff --git a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobStore.cs b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobStore.cs index b73dbc7432b6..e2982d85b255 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobStore.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobStore.cs @@ -1,15 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Text; -using System.IO; using System.Globalization; +using System.IO; using System.Management.Automation; using System.Security.AccessControl; using System.Security.Principal; +using System.Text; namespace Microsoft.PowerShell.ScheduledJob { @@ -33,7 +33,6 @@ namespace Microsoft.PowerShell.ScheduledJob /// Status.xml /// Results.xml /// ... - /// /// internal class ScheduledJobStore { @@ -119,8 +118,8 @@ public enum JobRunItem /// Checks the provided path against the the default path of scheduled jobs /// for the current user. /// - /// Path for scheduled job definitions - /// True if paths are equal + /// Path for scheduled job definitions. + /// True if paths are equal. public static bool IsDefaultUserPath(string definitionPath) { return definitionPath.Equals(GetJobDefinitionLocation(), StringComparison.OrdinalIgnoreCase); @@ -163,9 +162,9 @@ public static IEnumerable GetJobDefinitions() /// Scheduled job definition name. /// DateTime of job run start time. /// Job run item. - /// File access - /// File mode - /// File share + /// File access. + /// File mode. + /// File share. /// FileStream object. public static FileStream GetFileForJobRunItem( string definitionName, @@ -264,7 +263,7 @@ public static IEnumerable GetJobDefinitions() /// /// Remove the job definition and all job runs from job store. /// - /// Scheduled Job Definition name + /// Scheduled Job Definition name. public static void RemoveJobDefinition( string definitionName) { @@ -282,8 +281,8 @@ public static IEnumerable GetJobDefinitions() /// Renames the directory containing the old job definition name /// to the new name provided. /// - /// Existing job definition directory - /// Renamed job definition directory + /// Existing job definition directory. + /// Renamed job definition directory. public static void RenameScheduledJobDefDir( string oldDefName, string newDefName) @@ -292,6 +291,7 @@ public static IEnumerable GetJobDefinitions() { throw new PSArgumentException("oldDefName"); } + if (string.IsNullOrEmpty(newDefName)) { throw new PSArgumentException("newDefName"); @@ -305,8 +305,8 @@ public static IEnumerable GetJobDefinitions() /// /// Remove a single job definition job run from the job store. /// - /// Scheduled Job Definition name - /// DateTime of job run + /// Scheduled Job Definition name. + /// DateTime of job run. public static void RemoveJobRun( string definitionName, DateTime runStart) @@ -324,8 +324,8 @@ public static IEnumerable GetJobDefinitions() /// /// Remove a single job definition job run from the job store. /// - /// Scheduled Job Definition Output path - /// DateTime of job run + /// Scheduled Job Definition Output path. + /// DateTime of job run. public static void RemoveJobRunFromOutputPath( string definitionOutputPath, DateTime runStart) @@ -343,7 +343,7 @@ public static IEnumerable GetJobDefinitions() /// /// Remove all job runs for this job definition. /// - /// Scheduled Job Definition name + /// Scheduled Job Definition name. public static void RemoveAllJobRuns( string definitionName) { @@ -363,8 +363,8 @@ public static IEnumerable GetJobDefinitions() /// /// Set read access on provided definition file for specified user. /// - /// Definition name - /// Account user name + /// Definition name. + /// Account user name. public static void SetReadAccessOnDefinitionFile( string definitionName, string user) @@ -391,8 +391,8 @@ public static IEnumerable GetJobDefinitions() /// Set write access on Output directory for provided definition for /// specified user. /// - /// Definition name - /// Account user name + /// Definition name. + /// Account user name. public static void SetWriteAccessOnJobRunOutput( string definitionName, string user) @@ -402,11 +402,11 @@ public static IEnumerable GetJobDefinitions() } /// - /// Returns the directory path for job run output for the specified - /// scheduled job definition. + /// Returns the directory path for job run output for the specified + /// scheduled job definition. /// - /// Definition name - /// Directory Path + /// Definition name. + /// Directory Path. public static string GetJobRunOutputDirectory( string definitionName) { @@ -421,7 +421,7 @@ public static IEnumerable GetJobDefinitions() /// /// Gets the directory path for a Scheduled Job Definition. /// - /// Directory Path + /// Directory Path. public static string GetJobDefinitionLocation() { #if UNIX @@ -444,7 +444,7 @@ public static void CreateDirectoryIfNotExists() /// Gets the directory path for Scheduled Jobs. Will create the directory if /// it does not exist. /// - /// Directory Path + /// Directory Path. private static string GetDirectoryPath() { string pathName; @@ -467,9 +467,9 @@ private static string GetDirectoryPath() /// ...\ScheduledJobs\definitionName\fileName.xml /// ...\ScheduledJobs\definitionName\Output\ /// - /// Definition name - /// File name - /// File path/name + /// Definition name. + /// File name. + /// File path/name. private static string CreateFilePathName(string definitionName, string fileName) { string filePath = GetJobDefinitionPath(definitionName); @@ -489,9 +489,9 @@ private static string CreateFilePathName(string definitionName, string fileName) /// /// Returns a file path/name for an existing Scheduled job definition directory. /// - /// Definition name - /// File name - /// File path/name + /// Definition name. + /// File name. + /// File path/name. private static string GetFilePathName(string definitionName, string fileName) { string filePath = GetJobDefinitionPath(definitionName); @@ -501,8 +501,8 @@ private static string GetFilePathName(string definitionName, string fileName) /// /// Gets the directory path for a Scheduled Job Definition. /// - /// Scheduled job definition name - /// Directory Path + /// Scheduled job definition name. + /// Directory Path. private static string GetJobDefinitionPath(string definitionName) { #if UNIX @@ -517,9 +517,9 @@ private static string GetJobDefinitionPath(string definitionName) /// /// Returns a directory path for an existing ScheduledJob run result directory. /// - /// Definition name - /// File name - /// Directory Path + /// Definition name. + /// File name. + /// Directory Path. private static string GetRunDirectory( string definitionName, DateTime runStart) @@ -533,9 +533,9 @@ private static string GetJobDefinitionPath(string definitionName) /// Returns a directory path for an existing ScheduledJob run based on /// provided definition Output directory path. /// - /// Output directory path - /// File name - /// Directory Path + /// Output directory path. + /// File name. + /// Directory Path. private static string GetRunDirectoryFromPath( string definitionOutputPath, DateTime runStart) @@ -548,10 +548,10 @@ private static string GetJobDefinitionPath(string definitionName) /// Returns a file path/name for a run result file. Will create the /// job run directory if it does not exist. /// - /// Definition name - /// Result type - /// Run date - /// File path/name + /// Definition name. + /// Result type. + /// Run date. + /// File path/name. private static string GetRunFilePathName( string definitionName, JobRunItem runItem, @@ -570,9 +570,9 @@ private static string GetJobDefinitionPath(string definitionName) /// job run output path. Will create the job run directory if it does not /// exist. /// - /// Definition job run output path - /// Result type - /// Run date + /// Definition job run output path. + /// Result type. + /// Run date. /// private static string GetRunFilePathNameFromPath( string outputPath, @@ -625,7 +625,7 @@ private static string ConvertDateTimeToJobRunName(DateTime dt) } /// - /// Converts a jobRun name string to an equivalent DateTime + /// Converts a jobRun name string to an equivalent DateTime. /// /// /// diff --git a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobTrigger.cs index 1ac15ed476d3..4fef0e1c45bc 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobTrigger.cs @@ -1,16 +1,17 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Text; -using System.Runtime.Serialization; -using System.Management.Automation; using System.Globalization; +using System.Management.Automation; +using System.Runtime.Serialization; +using System.Security.Permissions; +using System.Text; using System.Threading; + using Microsoft.Management.Infrastructure; -using System.Security.Permissions; namespace Microsoft.PowerShell.ScheduledJob { @@ -48,6 +49,7 @@ public sealed class ScheduledJobTrigger : ISerializable public DateTime? At { get { return _time; } + set { _time = value; } } @@ -57,6 +59,7 @@ public sealed class ScheduledJobTrigger : ISerializable public List DaysOfWeek { get { return _daysOfWeek; } + set { _daysOfWeek = value; } } @@ -66,15 +69,17 @@ public List DaysOfWeek public Int32 Interval { get { return _interval; } + set { _interval = value; } } /// - /// Trigger frequency. + /// Trigger frequency. /// public TriggerFrequency Frequency { get { return _frequency; } + set { _frequency = value; } } @@ -84,6 +89,7 @@ public TriggerFrequency Frequency public TimeSpan RandomDelay { get { return _randomDelay; } + set { _randomDelay = value; } } @@ -93,6 +99,7 @@ public TimeSpan RandomDelay public TimeSpan? RepetitionInterval { get { return _repInterval; } + set { // A TimeSpan value of zero is equivalent to a null value. @@ -107,6 +114,7 @@ public TimeSpan RandomDelay public TimeSpan? RepetitionDuration { get { return _repDuration; } + set { // A TimeSpan value of zero is equivalent to a null value. @@ -121,6 +129,7 @@ public TimeSpan RandomDelay public string User { get { return _user; } + set { _user = value; } } @@ -130,6 +139,7 @@ public string User public Int32 Id { get { return _id; } + internal set { _id = value; } } @@ -139,6 +149,7 @@ public Int32 Id public bool Enabled { get { return _enabled; } + set { _enabled = value; } } @@ -148,6 +159,7 @@ public bool Enabled public ScheduledJobDefinition JobDefinition { get { return _jobDefAssociation; } + internal set { _jobDefAssociation = value; } } @@ -164,16 +176,16 @@ public ScheduledJobTrigger() /// /// Constructor. /// - /// Enabled - /// Trigger frequency - /// Trigger time - /// Weekly days of week - /// Daily or Weekly interval - /// Random delay - /// Repetition interval - /// Repetition duration - /// Logon user - /// Trigger id + /// Enabled. + /// Trigger frequency. + /// Trigger time. + /// Weekly days of week. + /// Daily or Weekly interval. + /// Random delay. + /// Repetition interval. + /// Repetition duration. + /// Logon user. + /// Trigger id. private ScheduledJobTrigger( bool enabled, TriggerFrequency frequency, @@ -201,7 +213,7 @@ public ScheduledJobTrigger() /// /// Copy constructor. /// - /// ScheduledJobTrigger + /// ScheduledJobTrigger. internal ScheduledJobTrigger(ScheduledJobTrigger copyTrigger) { if (copyTrigger == null) @@ -224,10 +236,10 @@ internal ScheduledJobTrigger(ScheduledJobTrigger copyTrigger) } /// - /// Serialization constructor + /// Serialization constructor. /// - /// SerializationInfo - /// StreamingContext + /// SerializationInfo. + /// StreamingContext. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] private ScheduledJobTrigger( SerializationInfo info, @@ -355,10 +367,12 @@ internal void Validate() string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingJobTriggerTime, ScheduledJobErrorStrings.TriggerOnceType); throw new ScheduledJobException(msg); } + if (_repInterval != null || _repDuration != null) { ValidateOnceRepetitionParams(_repInterval, _repDuration); } + break; case TriggerFrequency.Daily: @@ -367,10 +381,12 @@ internal void Validate() string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingJobTriggerTime, ScheduledJobErrorStrings.TriggerDailyType); throw new ScheduledJobException(msg); } + if (_interval < 1) { throw new ScheduledJobException(ScheduledJobErrorStrings.InvalidDaysIntervalParam); } + break; case TriggerFrequency.Weekly: @@ -379,15 +395,18 @@ internal void Validate() string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingJobTriggerTime, ScheduledJobErrorStrings.TriggerWeeklyType); throw new ScheduledJobException(msg); } + if (_interval < 1) { throw new ScheduledJobException(ScheduledJobErrorStrings.InvalidWeeksIntervalParam); } + if (_daysOfWeek == null || _daysOfWeek.Count == 0) { string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingJobTriggerDaysOfWeek, ScheduledJobErrorStrings.TriggerWeeklyType); throw new ScheduledJobException(msg); } + break; } } @@ -456,13 +475,13 @@ internal void CopyTo(ScheduledJobTrigger targetTrigger) /// /// Creates a one time ScheduledJobTrigger object. /// - /// DateTime when trigger activates - /// Random delay - /// Repetition interval - /// Repetition duration - /// Trigger Id - /// Trigger enabled state - /// ScheduledJobTrigger + /// DateTime when trigger activates. + /// Random delay. + /// Repetition interval. + /// Repetition duration. + /// Trigger Id. + /// Trigger enabled state. + /// ScheduledJobTrigger. public static ScheduledJobTrigger CreateOnceTrigger( DateTime time, TimeSpan delay, @@ -487,12 +506,12 @@ internal void CopyTo(ScheduledJobTrigger targetTrigger) /// /// Creates a daily ScheduledJobTrigger object. /// - /// Time of day when trigger activates - /// Days interval for trigger activation - /// Random delay - /// Trigger Id - /// Trigger enabled state - /// ScheduledJobTrigger + /// Time of day when trigger activates. + /// Days interval for trigger activation. + /// Random delay. + /// Trigger Id. + /// Trigger enabled state. + /// ScheduledJobTrigger. public static ScheduledJobTrigger CreateDailyTrigger( DateTime time, Int32 interval, @@ -516,13 +535,13 @@ internal void CopyTo(ScheduledJobTrigger targetTrigger) /// /// Creates a weekly ScheduledJobTrigger object. /// - /// Time of day when trigger activates - /// Weeks interval for trigger activation - /// Days of the week for trigger activation - /// Random delay - /// Trigger Id - /// Trigger enabled state - /// ScheduledJobTrigger + /// Time of day when trigger activates. + /// Weeks interval for trigger activation. + /// Days of the week for trigger activation. + /// Random delay. + /// Trigger Id. + /// Trigger enabled state. + /// ScheduledJobTrigger. public static ScheduledJobTrigger CreateWeeklyTrigger( DateTime time, Int32 interval, @@ -549,11 +568,11 @@ internal void CopyTo(ScheduledJobTrigger targetTrigger) /// /// Creates a trigger that activates after user log on. /// - /// Name of user - /// Random delay - /// Trigger Id - /// Trigger enabled state - /// ScheduledJobTrigger + /// Name of user. + /// Random delay. + /// Trigger Id. + /// Trigger enabled state. + /// ScheduledJobTrigger. public static ScheduledJobTrigger CreateAtLogOnTrigger( string user, TimeSpan delay, @@ -576,10 +595,10 @@ internal void CopyTo(ScheduledJobTrigger targetTrigger) /// /// Creates a trigger that activates after OS boot. /// - /// Random delay - /// Trigger Id - /// Trigger enabled state - /// ScheduledJobTrigger + /// Random delay. + /// Trigger Id. + /// Trigger enabled state. + /// ScheduledJobTrigger. public static ScheduledJobTrigger CreateAtStartupTrigger( TimeSpan delay, Int32 id, @@ -678,7 +697,7 @@ public enum TriggerFrequency #region JobTriggerToCimInstanceConverter /// - /// Class providing implementation of PowerShell conversions for types in Microsoft.Management.Infrastructure namespace + /// Class providing implementation of PowerShell conversions for types in Microsoft.Management.Infrastructure namespace. /// public sealed class JobTriggerToCimInstanceConverter : PSTypeConverter { @@ -687,8 +706,8 @@ public sealed class JobTriggerToCimInstanceConverter : PSTypeConverter /// /// Determines if the converter can convert the parameter to the parameter. /// - /// The value to convert from - /// The type to convert to + /// The value to convert from. + /// The type to convert to. /// True if the converter can convert the parameter to the parameter, otherwise false. public override bool CanConvertFrom(object sourceValue, Type destinationType) { @@ -701,14 +720,14 @@ public override bool CanConvertFrom(object sourceValue, Type destinationType) } /// - /// Converts the parameter to the parameter using formatProvider and ignoreCase + /// Converts the parameter to the parameter using formatProvider and ignoreCase. /// - /// The value to convert from - /// The type to convert to - /// The format provider to use like in IFormattable's ToString - /// true if case should be ignored - /// the parameter converted to the parameter using formatProvider and ignoreCase - /// if no conversion was possible + /// The value to convert from. + /// The type to convert to. + /// The format provider to use like in IFormattable's ToString. + /// True if case should be ignored. + /// The parameter converted to the parameter using formatProvider and ignoreCase. + /// If no conversion was possible. public override object ConvertFrom(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase) { if (destinationType == null) @@ -747,10 +766,10 @@ public override object ConvertFrom(object sourceValue, Type destinationType, IFo } /// - /// Returns true if the converter can convert the parameter to the parameter + /// Returns true if the converter can convert the parameter to the parameter. /// - /// The value to convert from - /// The type to convert to + /// The value to convert from. + /// The type to convert to. /// True if the converter can convert the parameter to the parameter, otherwise false. public override bool CanConvertTo(object sourceValue, Type destinationType) { @@ -758,14 +777,14 @@ public override bool CanConvertTo(object sourceValue, Type destinationType) } /// - /// Converts the parameter to the parameter using formatProvider and ignoreCase + /// Converts the parameter to the parameter using formatProvider and ignoreCase. /// - /// The value to convert from - /// The type to convert to - /// The format provider to use like in IFormattable's ToString - /// true if case should be ignored - /// sourceValue converted to the parameter using formatProvider and ignoreCase - /// if no conversion was possible + /// The value to convert from. + /// The type to convert to. + /// The format provider to use like in IFormattable's ToString. + /// True if case should be ignored. + /// SourceValue converted to the parameter using formatProvider and ignoreCase. + /// If no conversion was possible. public override object ConvertTo(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase) { throw new NotImplementedException(); diff --git a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobWTS.cs b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobWTS.cs index e89df8051fe7..1b89e955984e 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobWTS.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobWTS.cs @@ -1,16 +1,17 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Text; -using TaskScheduler; using System.Diagnostics; using System.Globalization; using System.Management.Automation; using System.Runtime.InteropServices; using System.Security.AccessControl; +using System.Text; + +using TaskScheduler; namespace Microsoft.PowerShell.ScheduledJob { @@ -65,9 +66,9 @@ public ScheduledJobWTS() /// /// Retrieves job triggers from WTS with provided task Id. /// - /// Task Id + /// Task Id. /// Task not found. - /// ScheduledJobTriggers + /// ScheduledJobTriggers. public Collection GetJobTriggers( string taskId) { @@ -101,9 +102,9 @@ public ScheduledJobWTS() /// /// Retrieves options for the provided task Id. /// - /// Task Id + /// Task Id. /// Task not found. - /// ScheduledJobOptions + /// ScheduledJobOptions. public ScheduledJobOptions GetJobOptions( string taskId) { @@ -139,7 +140,7 @@ public ScheduledJobWTS() /// /// Creates a new task in WTS with information from ScheduledJobDefinition. /// - /// ScheduledJobDefinition + /// ScheduledJobDefinition. public void CreateTask( ScheduledJobDefinition definition) { @@ -204,8 +205,8 @@ public ScheduledJobWTS() /// Throws error if one or more instances of this task are running. /// Force parameter will stop all running instances and remove task. /// - /// ScheduledJobDefinition - /// Force running instances to stop and remove task + /// ScheduledJobDefinition. + /// Force running instances to stop and remove task. public void RemoveTask( ScheduledJobDefinition definition, bool force = false) @@ -222,9 +223,9 @@ public ScheduledJobWTS() /// Removes a Task Scheduler task from the PowerShell/ScheduledJobs folder /// based on a task name. /// - /// Task Scheduler task name - /// Force running instances to stop and remove task - /// First check for existence of task + /// Task Scheduler task name. + /// Force running instances to stop and remove task. + /// First check for existence of task. public void RemoveTaskByName( string taskName, bool force, @@ -277,7 +278,7 @@ public ScheduledJobWTS() /// /// Starts task running from Task Scheduler. /// - /// ScheduledJobDefinition + /// ScheduledJobDefinition. /// /// public void RunTask( @@ -294,7 +295,7 @@ public ScheduledJobWTS() /// Updates an existing task in WTS with information from /// ScheduledJobDefinition. /// - /// ScheduledJobDefinition + /// ScheduledJobDefinition. public void UpdateTask( ScheduledJobDefinition definition) { @@ -358,8 +359,8 @@ public ScheduledJobWTS() /// Creates a new WTS trigger based on the provided ScheduledJobTrigger object /// and adds it to the provided ITaskDefinition object. /// - /// ITaskDefinition - /// ScheduledJobTrigger + /// ITaskDefinition. + /// ScheduledJobTrigger. private void AddTaskTrigger( ITaskDefinition iTaskDefinition, ScheduledJobTrigger jobTrigger) @@ -379,6 +380,7 @@ public ScheduledJobWTS() iTrigger.Id = jobTrigger.Id.ToString(CultureInfo.InvariantCulture); iTrigger.Enabled = jobTrigger.Enabled; } + break; case TriggerFrequency.AtLogon: @@ -393,6 +395,7 @@ public ScheduledJobWTS() iTrigger.Id = jobTrigger.Id.ToString(CultureInfo.InvariantCulture); iTrigger.Enabled = jobTrigger.Enabled; } + break; case TriggerFrequency.Once: @@ -423,6 +426,7 @@ public ScheduledJobWTS() iTrigger.Id = jobTrigger.Id.ToString(CultureInfo.InvariantCulture); iTrigger.Enabled = jobTrigger.Enabled; } + break; case TriggerFrequency.Daily: @@ -438,6 +442,7 @@ public ScheduledJobWTS() iTrigger.Id = jobTrigger.Id.ToString(CultureInfo.InvariantCulture); iTrigger.Enabled = jobTrigger.Enabled; } + break; case TriggerFrequency.Weekly: @@ -454,6 +459,7 @@ public ScheduledJobWTS() iTrigger.Id = jobTrigger.Id.ToString(CultureInfo.InvariantCulture); iTrigger.Enabled = jobTrigger.Enabled; } + break; } } @@ -461,8 +467,8 @@ public ScheduledJobWTS() /// /// Creates a ScheduledJobTrigger object based on a provided WTS ITrigger. /// - /// ITrigger - /// ScheduledJobTrigger + /// ITrigger. + /// ScheduledJobTrigger. private ScheduledJobTrigger CreateJobTrigger( ITrigger iTrigger) { @@ -582,8 +588,8 @@ public ScheduledJobWTS() /// Gets and returns the unsecured password for the provided /// PSCredential object. /// - /// PSCredential - /// Unsecured password string + /// PSCredential. + /// Unsecured password string. private string GetCredentialPassword(PSCredential credential) { if (credential == null) @@ -643,8 +649,8 @@ private ITaskFolder GetRootFolder() /// Finds a task with the provided Task Id and returns it as /// a ITaskDefinition object. /// - /// Task Id - /// ITaskDefinition + /// Task Id. + /// ITaskDefinition. private ITaskDefinition FindTask(string taskId) { try @@ -691,8 +697,8 @@ private Int32 ConvertStringId(string triggerId) /// "nM" - minute value. /// "nS" - second value. /// - /// Formatted time string - /// TimeSpan + /// Formatted time string. + /// TimeSpan. private TimeSpan ParseWTSTime(string wtsTime) { if (string.IsNullOrEmpty(wtsTime)) @@ -742,6 +748,7 @@ private TimeSpan ParseWTSTime(string wtsTime) str.Append(c2); } } + break; case 'T': @@ -770,6 +777,7 @@ private TimeSpan ParseWTSTime(string wtsTime) str.Append(c2); } } + break; } } @@ -785,8 +793,8 @@ private TimeSpan ParseWTSTime(string wtsTime) /// /// Creates WTS formatted time string based on TimeSpan parameter. /// - /// TimeSpan - /// WTS time string + /// TimeSpan. + /// WTS time string. internal static string ConvertTimeSpanToWTSString(TimeSpan time) { return string.Format( @@ -801,8 +809,8 @@ internal static string ConvertTimeSpanToWTSString(TimeSpan time) /// /// Converts DateTime to string for WTS. /// - /// DateTime - /// DateTime string + /// DateTime. + /// DateTime string. internal static string ConvertDateTimeToString(DateTime? dt) { if (dt == null) @@ -819,8 +827,8 @@ internal static string ConvertDateTimeToString(DateTime? dt) /// Returns a bitmask representing days of week as /// required by Windows Task Scheduler API. /// - /// Array of DayOfWeek - /// WTS days of week mask + /// Array of DayOfWeek. + /// WTS days of week mask. internal static short ConvertDaysOfWeekToMask(IEnumerable daysOfWeek) { short rtnValue = 0; @@ -864,18 +872,24 @@ internal static short ConvertDaysOfWeekToMask(IEnumerable daysOfWeek) /// /// Converts WTS days of week mask to an array of DayOfWeek type. /// - /// WTS days of week mask - /// Days of week as List + /// WTS days of week mask. + /// Days of week as List. private List ConvertMaskToDaysOfWeekArray(short mask) { List daysOfWeek = new List(); if ((mask & WTSSunday) != 0) { daysOfWeek.Add(DayOfWeek.Sunday); } + if ((mask & WTSMonday) != 0) { daysOfWeek.Add(DayOfWeek.Monday); } + if ((mask & WTSTuesday) != 0) { daysOfWeek.Add(DayOfWeek.Tuesday); } + if ((mask & WTSWednesday) != 0) { daysOfWeek.Add(DayOfWeek.Wednesday); } + if ((mask & WTSThursday) != 0) { daysOfWeek.Add(DayOfWeek.Thursday); } + if ((mask & WTSFriday) != 0) { daysOfWeek.Add(DayOfWeek.Friday); } + if ((mask & WTSSaturday) != 0) { daysOfWeek.Add(DayOfWeek.Saturday); } return daysOfWeek; diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/AddJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/AddJobTrigger.cs index 0bfb6d8ae5be..603bfabe31f0 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/AddJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/AddJobTrigger.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Threading; -using System.Diagnostics; namespace Microsoft.PowerShell.ScheduledJob { @@ -41,8 +40,10 @@ public sealed class AddJobTriggerCommand : ScheduleJobCmdletBase public ScheduledJobTrigger[] Trigger { get { return _triggers; } + set { _triggers = value; } } + private ScheduledJobTrigger[] _triggers; /// @@ -55,8 +56,10 @@ public ScheduledJobTrigger[] Trigger public Int32[] Id { get { return _ids; } + set { _ids = value; } } + private Int32[] _ids; /// @@ -69,8 +72,10 @@ public Int32[] Id public string[] Name { get { return _names; } + set { _names = value; } } + private string[] _names; /// @@ -83,8 +88,10 @@ public string[] Name public ScheduledJobDefinition[] InputObject { get { return _definitions; } + set { _definitions = value; } } + private ScheduledJobDefinition[] _definitions; #endregion diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinition.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinition.cs index a84de3eacea3..bd1ed864a143 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinition.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinition.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinitionBase.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinitionBase.cs index 73553266f6bf..d692b4aabb1e 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinitionBase.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobDefinitionBase.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -16,17 +15,17 @@ public abstract class DisableScheduledJobDefinitionBase : ScheduleJobCmdletBase #region Parameters /// - /// DefinitionIdParameterSet + /// DefinitionIdParameterSet. /// protected const string DefinitionIdParameterSet = "DefinitionId"; /// - /// DefinitionNameParameterSet + /// DefinitionNameParameterSet. /// protected const string DefinitionNameParameterSet = "DefinitionName"; /// - /// DefinitionParameterSet + /// DefinitionParameterSet. /// protected const string DefinitionParameterSet = "Definition"; @@ -39,8 +38,10 @@ public abstract class DisableScheduledJobDefinitionBase : ScheduleJobCmdletBase public ScheduledJobDefinition InputObject { get { return _definition; } + set { _definition = value; } } + private ScheduledJobDefinition _definition; /// @@ -51,8 +52,10 @@ public ScheduledJobDefinition InputObject public Int32 Id { get { return _definitionId; } + set { _definitionId = value; } } + private Int32 _definitionId; /// @@ -64,8 +67,10 @@ public Int32 Id public string Name { get { return _definitionName; } + set { _definitionName = value; } } + private string _definitionName; /// @@ -77,8 +82,10 @@ public string Name public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } } + private SwitchParameter _passThru; #endregion diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobTrigger.cs index e8d73e93f731..9bb46d60ca42 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/DisableJobTrigger.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Threading; -using System.Diagnostics; namespace Microsoft.PowerShell.ScheduledJob { diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/EnableDisableCmdletBase.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/EnableDisableCmdletBase.cs index fc1e2ef55303..e377287e7750 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/EnableDisableCmdletBase.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/EnableDisableCmdletBase.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Threading; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.PowerShell.ScheduledJob { @@ -36,6 +35,7 @@ public abstract class EnableDisableScheduledJobCmdletBase : ScheduleJobCmdletBas public ScheduledJobTrigger[] InputObject { get { return _triggers; } + set { _triggers = value; } } @@ -46,8 +46,10 @@ public ScheduledJobTrigger[] InputObject public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } } + private SwitchParameter _passThru; private ScheduledJobTrigger[] _triggers; diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobDefinition.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobDefinition.cs index 3344785d844a..67584690694b 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobDefinition.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobDefinition.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobTrigger.cs index 54b8790aa175..39063f9c1ef8 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/EnableJobTrigger.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Threading; -using System.Diagnostics; namespace Microsoft.PowerShell.ScheduledJob { diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobDefinition.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobDefinition.cs index a59869d902c8..00ab434769c6 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobDefinition.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobDefinition.cs @@ -1,11 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; -using System.Management.Automation; using System.Diagnostics.CodeAnalysis; +using System.Management.Automation; namespace Microsoft.PowerShell.ScheduledJob { @@ -31,8 +30,10 @@ public sealed class GetScheduledJobCommand : ScheduleJobCmdletBase public Int32[] Id { get { return _definitionIds; } + set { _definitionIds = value; } } + private Int32[] _definitionIds; /// @@ -45,8 +46,10 @@ public Int32[] Id public string[] Name { get { return _definitionNames; } + set { _definitionNames = value; } } + private string[] _definitionNames; #endregion @@ -78,6 +81,7 @@ protected override void ProcessRecord() WriteObject(definition); }); } + break; case DefinitionNameParameterSet: diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobTrigger.cs index 469176d0f42d..dc1e08bc6784 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/GetJobTrigger.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Threading; -using System.Diagnostics; namespace Microsoft.PowerShell.ScheduledJob { @@ -41,8 +40,10 @@ public sealed class GetJobTriggerCommand : ScheduleJobCmdletBase public Int32[] TriggerId { get { return _triggerIds; } + set { _triggerIds = value; } } + private Int32[] _triggerIds; /// @@ -54,8 +55,10 @@ public Int32[] TriggerId public ScheduledJobDefinition InputObject { get { return _definition; } + set { _definition = value; } } + private ScheduledJobDefinition _definition; /// @@ -66,8 +69,10 @@ public ScheduledJobDefinition InputObject public Int32 Id { get { return _definitionId; } + set { _definitionId = value; } } + private Int32 _definitionId; /// @@ -79,8 +84,10 @@ public Int32 Id public string Name { get { return _name; } + set { _name = value; } } + private string _name; #endregion diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/GetScheduledJobOption.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/GetScheduledJobOption.cs index be12fb0e3e91..26458fda2dfc 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/GetScheduledJobOption.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/GetScheduledJobOption.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -30,8 +29,10 @@ public sealed class GetScheduledJobOptionCommand : ScheduleJobCmdletBase public Int32 Id { get { return _id; } + set { _id = value; } } + private Int32 _id; /// @@ -43,8 +44,10 @@ public Int32 Id public string Name { get { return _name; } + set { _name = value; } } + private string _name; /// @@ -56,8 +59,10 @@ public string Name public ScheduledJobDefinition InputObject { get { return _definition; } + set { _definition = value; } } + private ScheduledJobDefinition _definition; #endregion diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/NewJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/NewJobTrigger.cs index cabb4e3b66b1..9fcdf500838e 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/NewJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/NewJobTrigger.cs @@ -1,16 +1,15 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Threading; -using System.Diagnostics; namespace Microsoft.PowerShell.ScheduledJob { @@ -38,8 +37,10 @@ public sealed class NewJobTriggerCommand : ScheduleJobCmdletBase public Int32 DaysInterval { get { return _daysInterval; } + set { _daysInterval = value; } } + private Int32 _daysInterval = 1; /// @@ -49,8 +50,10 @@ public Int32 DaysInterval public Int32 WeeksInterval { get { return _weeksInterval; } + set { _weeksInterval = value; } } + private Int32 _weeksInterval = 1; /// @@ -64,8 +67,10 @@ public Int32 WeeksInterval public TimeSpan RandomDelay { get { return _randomDelay; } + set { _randomDelay = value; } } + private TimeSpan _randomDelay; /// @@ -80,8 +85,10 @@ public TimeSpan RandomDelay public DateTime At { get { return _atTime; } + set { _atTime = value; } } + private DateTime _atTime; /// @@ -93,8 +100,10 @@ public DateTime At public string User { get { return _user; } + set { _user = value; } } + private string _user; /// @@ -107,8 +116,10 @@ public string User public DayOfWeek[] DaysOfWeek { get { return _daysOfWeek; } + set { _daysOfWeek = value; } } + private DayOfWeek[] _daysOfWeek; /// @@ -119,8 +130,10 @@ public DayOfWeek[] DaysOfWeek public SwitchParameter AtStartup { get { return _atStartup; } + set { _atStartup = value; } } + private SwitchParameter _atStartup; /// @@ -131,8 +144,10 @@ public SwitchParameter AtStartup public SwitchParameter AtLogOn { get { return _atLogon; } + set { _atLogon = value; } } + private SwitchParameter _atLogon; /// @@ -143,8 +158,10 @@ public SwitchParameter AtLogOn public SwitchParameter Once { get { return _once; } + set { _once = value; } } + private SwitchParameter _once; /// @@ -154,8 +171,10 @@ public SwitchParameter Once public TimeSpan RepetitionInterval { get { return _repInterval; } + set { _repInterval = value; } } + private TimeSpan _repInterval; /// @@ -165,8 +184,10 @@ public TimeSpan RepetitionInterval public TimeSpan RepetitionDuration { get { return _repDuration; } + set { _repDuration = value; } } + private TimeSpan _repDuration; /// @@ -176,8 +197,10 @@ public TimeSpan RepetitionDuration public SwitchParameter RepeatIndefinitely { get { return _repRepeatIndefinitely; } + set { _repRepeatIndefinitely = value; } } + private SwitchParameter _repRepeatIndefinitely; /// @@ -188,8 +211,10 @@ public SwitchParameter RepeatIndefinitely public SwitchParameter Daily { get { return _daily; } + set { _daily = value; } } + private SwitchParameter _daily; /// @@ -200,8 +225,10 @@ public SwitchParameter Daily public SwitchParameter Weekly { get { return _weekly; } + set { _weekly = value; } } + private SwitchParameter _weekly; #endregion @@ -220,6 +247,7 @@ protected override void BeginProcessing() { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidDaysIntervalParam); } + if (_weeksInterval < 1) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidWeeksIntervalParam); @@ -273,33 +301,38 @@ private void CreateOnceTrigger() { TimeSpan? repInterval = null; TimeSpan? repDuration = null; - if (MyInvocation.BoundParameters.ContainsKey("RepetitionInterval") || MyInvocation.BoundParameters.ContainsKey("RepetitionDuration") || - MyInvocation.BoundParameters.ContainsKey("RepeatIndefinitely")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) || MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration)) || + MyInvocation.BoundParameters.ContainsKey(nameof(RepeatIndefinitely))) { - if (MyInvocation.BoundParameters.ContainsKey("RepeatIndefinitely")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepeatIndefinitely))) { - if (MyInvocation.BoundParameters.ContainsKey("RepetitionDuration")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration))) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepeatIndefinitelyParams); } - if (!MyInvocation.BoundParameters.ContainsKey("RepetitionInterval")) + + if (!MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval))) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionRepeatParams); } + _repDuration = TimeSpan.MaxValue; } - else if (!MyInvocation.BoundParameters.ContainsKey("RepetitionInterval") || !MyInvocation.BoundParameters.ContainsKey("RepetitionDuration")) + else if (!MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) || !MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration))) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionParams); } + if (_repInterval < TimeSpan.Zero || _repDuration < TimeSpan.Zero) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionParamValues); } + if (_repInterval < TimeSpan.FromMinutes(1)) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionIntervalValue); } + if (_repInterval > _repDuration) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionInterval); diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/NewScheduledJobOption.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/NewScheduledJobOption.cs index 224c11a8b5df..55fb9a4c0bda 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/NewScheduledJobOption.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/NewScheduledJobOption.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/RegisterJobDefinition.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/RegisterJobDefinition.cs index b451a9fc1684..895c4e33528e 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/RegisterJobDefinition.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/RegisterJobDefinition.cs @@ -1,14 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.Management.Automation; using System.Management.Automation.Runspaces; + using Microsoft.PowerShell.Commands; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.PowerShell.ScheduledJob { @@ -27,18 +27,20 @@ public sealed class RegisterScheduledJobCommand : ScheduleJobCmdletBase private const string FilePathParameterSet = "FilePath"; private const string ScriptBlockParameterSet = "ScriptBlock"; - /// /// File path for script to be run in job. /// [Parameter(Position = 1, Mandatory = true, ParameterSetName = RegisterScheduledJobCommand.FilePathParameterSet)] + [Alias("Path")] [ValidateNotNullOrEmpty] public string FilePath { get { return _filePath; } + set { _filePath = value; } } + private string _filePath; /// @@ -50,8 +52,10 @@ public string FilePath public ScriptBlock ScriptBlock { get { return _scriptBlock; } + set { _scriptBlock = value; } } + private ScriptBlock _scriptBlock; /// @@ -65,8 +69,10 @@ public ScriptBlock ScriptBlock public string Name { get { return _name; } + set { _name = value; } } + private string _name; /// @@ -79,8 +85,10 @@ public string Name public ScheduledJobTrigger[] Trigger { get { return _triggers; } + set { _triggers = value; } } + private ScheduledJobTrigger[] _triggers; /// @@ -92,8 +100,10 @@ public ScheduledJobTrigger[] Trigger public ScriptBlock InitializationScript { get { return _initializationScript; } + set { _initializationScript = value; } } + private ScriptBlock _initializationScript; /// @@ -104,8 +114,10 @@ public ScriptBlock InitializationScript public SwitchParameter RunAs32 { get { return _runAs32; } + set { _runAs32 = value; } } + private SwitchParameter _runAs32; /// @@ -117,8 +129,10 @@ public SwitchParameter RunAs32 public PSCredential Credential { get { return _credential; } + set { _credential = value; } } + private PSCredential _credential; /// @@ -129,8 +143,10 @@ public PSCredential Credential public AuthenticationMechanism Authentication { get { return _authenticationMechanism; } + set { _authenticationMechanism = value; } } + private AuthenticationMechanism _authenticationMechanism; /// @@ -142,8 +158,10 @@ public AuthenticationMechanism Authentication public ScheduledJobOptions ScheduledJobOption { get { return _options; } + set { _options = value; } } + private ScheduledJobOptions _options; /// @@ -156,8 +174,10 @@ public ScheduledJobOptions ScheduledJobOption public object[] ArgumentList { get { return _arguments; } + set { _arguments = value; } } + private object[] _arguments; /// @@ -168,8 +188,10 @@ public object[] ArgumentList public int MaxResultCount { get { return _executionHistoryLength; } + set { _executionHistoryLength = value; } } + private int _executionHistoryLength; /// @@ -180,8 +202,10 @@ public int MaxResultCount public SwitchParameter RunNow { get { return _runNow; } + set { _runNow = value; } } + private SwitchParameter _runNow; /// @@ -193,8 +217,10 @@ public SwitchParameter RunNow public TimeSpan RunEvery { get { return _runEvery; } + set { _runEvery = value; } } + private TimeSpan _runEvery; #endregion @@ -228,7 +254,7 @@ protected override void ProcessRecord() if (definition != null) { // Set the MaxCount value if available. - if (MyInvocation.BoundParameters.ContainsKey("MaxResultCount")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(MaxResultCount))) { if (MaxResultCount < 1) { @@ -239,6 +265,7 @@ protected override void ProcessRecord() return; } + definition.SetExecutionHistoryLength(MaxResultCount, false); } @@ -246,7 +273,7 @@ protected override void ProcessRecord() { // If RunEvery parameter is specified then create a job trigger for the definition that // runs the job at the requested interval. - if (MyInvocation.BoundParameters.ContainsKey("RunEvery")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RunEvery))) { AddRepetitionJobTriggerToDefinition( definition, @@ -334,6 +361,7 @@ private ScheduledJobDefinition CreateFilePathDefinition() return null; } + Collection pathInfos = SessionState.Path.GetResolvedPSPathFromPSPath(FilePath); if (pathInfos.Count != 1) { @@ -344,6 +372,7 @@ private ScheduledJobDefinition CreateFilePathDefinition() return null; } + parameterCollection.Add(ScheduledJobInvocationInfo.FilePathParameter, pathInfos[0].Path); JobInvocationInfo jobInvocationInfo = new ScheduledJobInvocationInfo(jobDefinition, parameterCollection); diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/RemoveJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/RemoveJobTrigger.cs index 757e52f39b91..a281d830d784 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/RemoveJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/RemoveJobTrigger.cs @@ -1,17 +1,16 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Management.Automation; -using System.Management.Automation.Internal; using System.Management.Automation.Host; +using System.Management.Automation.Internal; using System.Threading; -using System.Diagnostics; -using System.Globalization; namespace Microsoft.PowerShell.ScheduledJob { @@ -38,8 +37,10 @@ public sealed class RemoveJobTriggerCommand : ScheduleJobCmdletBase public Int32[] TriggerId { get { return _triggerIds; } + set { _triggerIds = value; } } + private Int32[] _triggerIds; /// @@ -52,8 +53,10 @@ public Int32[] TriggerId public Int32[] Id { get { return _definitionIds; } + set { _definitionIds = value; } } + private Int32[] _definitionIds; /// @@ -66,8 +69,10 @@ public Int32[] Id public string[] Name { get { return _names; } + set { _names = value; } } + private string[] _names; /// @@ -80,8 +85,10 @@ public string[] Name public ScheduledJobDefinition[] InputObject { get { return _definitions; } + set { _definitions = value; } } + private ScheduledJobDefinition[] _definitions; #endregion diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/SchedJobCmdletBase.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/SchedJobCmdletBase.cs index 25509d8cc5e9..f01d5b5ad30f 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/SchedJobCmdletBase.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/SchedJobCmdletBase.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -46,9 +45,9 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// Returns a single ScheduledJobDefinition object from the local /// scheduled job definition repository corresponding to the provided id. /// - /// Local repository scheduled job definition id - /// Errors/warnings are written to host - /// ScheduledJobDefinition object + /// Local repository scheduled job definition id. + /// Errors/warnings are written to host. + /// ScheduledJobDefinition object. internal ScheduledJobDefinition GetJobDefinitionById( Int32 id, bool writeErrorsAndWarnings = true) @@ -77,9 +76,9 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// Returns an array of ScheduledJobDefinition objects from the local /// scheduled job definition repository corresponding to the provided Ids. /// - /// Local repository scheduled job definition ids - /// Errors/warnings are written to host - /// List of ScheduledJobDefinition objects + /// Local repository scheduled job definition ids. + /// Errors/warnings are written to host. + /// List of ScheduledJobDefinition objects. internal List GetJobDefinitionsById( Int32[] ids, bool writeErrorsAndWarnings = true) @@ -113,9 +112,9 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// /// Makes delegate callback call for each scheduledjob definition object found. /// - /// Local repository scheduled job definition ids + /// Local repository scheduled job definition ids. /// Callback delegate for each discovered item. - /// Errors/warnings are written to host + /// Errors/warnings are written to host. internal void FindJobDefinitionsById( Int32[] ids, Action itemFound, @@ -147,9 +146,9 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// Returns an array of ScheduledJobDefinition objects from the local /// scheduled job definition repository corresponding to the given name. /// - /// Scheduled job definition name - /// Errors/warnings are written to host - /// ScheduledJobDefinition object + /// Scheduled job definition name. + /// Errors/warnings are written to host. + /// ScheduledJobDefinition object. internal ScheduledJobDefinition GetJobDefinitionByName( string name, bool writeErrorsAndWarnings = true) @@ -188,9 +187,9 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// Returns an array of ScheduledJobDefinition objects from the local /// scheduled job definition repository corresponding to the given names. /// - /// Scheduled job definition names - /// Errors/warnings are written to host - /// List of ScheduledJobDefinition objects + /// Scheduled job definition names. + /// Errors/warnings are written to host. + /// List of ScheduledJobDefinition objects. internal List GetJobDefinitionsByName( string[] names, bool writeErrorsAndWarnings = true) @@ -235,9 +234,9 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// /// Makes delegate callback call for each scheduledjob definition object found. /// - /// Scheduled job definition names + /// Scheduled job definition names. /// Callback delegate for each discovered item. - /// Errors/warnings are written to host + /// Errors/warnings are written to host. internal void FindJobDefinitionsByName( string[] names, Action itemFound, @@ -293,9 +292,9 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// /// Writes a "Trigger not found" error to host. /// - /// Trigger Id not found - /// ScheduledJobDefinition name - /// Error object + /// Trigger Id not found. + /// ScheduledJobDefinition name. + /// Error object. internal void WriteTriggerNotFoundError( Int32 notFoundId, string definitionName, @@ -310,7 +309,7 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// /// Writes a "Definition not found for Id" error to host. /// - /// Definition Id + /// Definition Id. internal void WriteDefinitionNotFoundByIdError( Int32 defId) { @@ -323,7 +322,7 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// /// Writes a "Definition not found for Name" error to host. /// - /// Definition Name + /// Definition Name. internal void WriteDefinitionNotFoundByNameError( string name) { @@ -336,8 +335,8 @@ public abstract class ScheduleJobCmdletBase : PSCmdlet /// /// Writes a "Load from job store" error to host. /// - /// Scheduled job definition name - /// Exception thrown during loading + /// Scheduled job definition name. + /// Exception thrown during loading. internal void WriteErrorLoadingDefinition(string name, Exception error) { string msg = StringUtil.Format(ScheduledJobErrorStrings.CantLoadDefinitionFromStore, name); @@ -351,9 +350,9 @@ internal void WriteErrorLoadingDefinition(string name, Exception error) /// infinite duration, and adds the trigger to the provided scheduled job /// definition object. /// - /// ScheduledJobDefinition - /// rep interval - /// save definition change + /// ScheduledJobDefinition. + /// Rep interval. + /// Save definition change. internal static void AddRepetitionJobTriggerToDefinition( ScheduledJobDefinition definition, TimeSpan repInterval, @@ -371,10 +370,12 @@ internal void WriteErrorLoadingDefinition(string name, Exception error) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionParamValues); } + if (repInterval < TimeSpan.FromMinutes(1)) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionIntervalValue); } + if (repInterval > repDuration) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidRepetitionInterval); diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/ScheduledJobOptionCmdletBase.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/ScheduledJobOptionCmdletBase.cs index 135bcc9cb37a..5d0bd636fa6b 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/ScheduledJobOptionCmdletBase.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/ScheduledJobOptionCmdletBase.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -27,8 +26,10 @@ public abstract class ScheduledJobOptionCmdletBase : ScheduleJobCmdletBase public SwitchParameter RunElevated { get { return _runElevated; } + set { _runElevated = value; } } + private SwitchParameter _runElevated = false; /// @@ -38,8 +39,10 @@ public SwitchParameter RunElevated public SwitchParameter HideInTaskScheduler { get { return _hideInTaskScheduler; } + set { _hideInTaskScheduler = value; } } + private SwitchParameter _hideInTaskScheduler = false; /// @@ -50,8 +53,10 @@ public SwitchParameter HideInTaskScheduler public SwitchParameter RestartOnIdleResume { get { return _restartOnIdleResume; } + set { _restartOnIdleResume = value; } } + private SwitchParameter _restartOnIdleResume = false; /// @@ -61,8 +66,10 @@ public SwitchParameter RestartOnIdleResume public TaskMultipleInstancePolicy MultipleInstancePolicy { get { return _multipleInstancePolicy; } + set { _multipleInstancePolicy = value; } } + private TaskMultipleInstancePolicy _multipleInstancePolicy = TaskMultipleInstancePolicy.IgnoreNew; /// @@ -72,8 +79,10 @@ public TaskMultipleInstancePolicy MultipleInstancePolicy public SwitchParameter DoNotAllowDemandStart { get { return _doNotAllowDemandStart; } + set { _doNotAllowDemandStart = value; } } + private SwitchParameter _doNotAllowDemandStart = false; /// @@ -83,8 +92,10 @@ public SwitchParameter DoNotAllowDemandStart public SwitchParameter RequireNetwork { get { return _requireNetwork; } + set { _requireNetwork = value; } } + private SwitchParameter _requireNetwork = false; /// @@ -94,8 +105,10 @@ public SwitchParameter RequireNetwork public SwitchParameter StopIfGoingOffIdle { get { return _stopIfGoingOffIdle; } + set { _stopIfGoingOffIdle = value; } } + private SwitchParameter _stopIfGoingOffIdle = false; /// @@ -106,8 +119,10 @@ public SwitchParameter StopIfGoingOffIdle public SwitchParameter WakeToRun { get { return _wakeToRun; } + set { _wakeToRun = value; } } + private SwitchParameter _wakeToRun = false; /// @@ -117,8 +132,10 @@ public SwitchParameter WakeToRun public SwitchParameter ContinueIfGoingOnBattery { get { return _continueIfGoingOnBattery; } + set { _continueIfGoingOnBattery = value; } } + private SwitchParameter _continueIfGoingOnBattery = false; /// @@ -128,8 +145,10 @@ public SwitchParameter ContinueIfGoingOnBattery public SwitchParameter StartIfOnBattery { get { return _startIfOnBattery; } + set { _startIfOnBattery = value; } } + private SwitchParameter _startIfOnBattery = false; /// @@ -140,8 +159,10 @@ public SwitchParameter StartIfOnBattery public TimeSpan IdleTimeout { get { return _idleTimeout; } + set { _idleTimeout = value; } } + private TimeSpan _idleTimeout = new TimeSpan(1, 0, 0); /// @@ -151,8 +172,10 @@ public TimeSpan IdleTimeout public TimeSpan IdleDuration { get { return _idleDuration; } + set { _idleDuration = value; } } + private TimeSpan _idleDuration = new TimeSpan(0, 10, 0); /// @@ -162,8 +185,10 @@ public TimeSpan IdleDuration public SwitchParameter StartIfIdle { get { return _startIfIdle; } + set { _startIfIdle = value; } } + private SwitchParameter _startIfIdle = false; #endregion @@ -176,13 +201,13 @@ public SwitchParameter StartIfIdle protected override void BeginProcessing() { // Validate parameters. - if (MyInvocation.BoundParameters.ContainsKey("IdleTimeout") && + if (MyInvocation.BoundParameters.ContainsKey(nameof(IdleTimeout)) && _idleTimeout < TimeSpan.Zero) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidIdleTimeout); } - if (MyInvocation.BoundParameters.ContainsKey("IdleDuration") && + if (MyInvocation.BoundParameters.ContainsKey(nameof(IdleDuration)) && _idleDuration < TimeSpan.Zero) { throw new PSArgumentException(ScheduledJobErrorStrings.InvalidIdleDuration); diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobDefinition.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobDefinition.cs index ca3f42809ba5..2a8da6f00ef8 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobDefinition.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobDefinition.cs @@ -1,13 +1,12 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; -using System.Management.Automation; -using System.Management.Automation.Runspaces; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Management.Automation; +using System.Management.Automation.Runspaces; namespace Microsoft.PowerShell.ScheduledJob { @@ -26,7 +25,6 @@ public sealed class SetScheduledJobCommand : ScheduleJobCmdletBase private const string ScriptBlockParameterSet = "ScriptBlock"; private const string FilePathParameterSet = "FilePath"; - /// /// Name of scheduled job definition. /// @@ -36,20 +34,25 @@ public sealed class SetScheduledJobCommand : ScheduleJobCmdletBase public string Name { get { return _name; } + set { _name = value; } } + private string _name; /// /// File path for script to be run in job. /// [Parameter(ParameterSetName = SetScheduledJobCommand.FilePathParameterSet)] + [Alias("Path")] [ValidateNotNullOrEmpty] public string FilePath { get { return _filePath; } + set { _filePath = value; } } + private string _filePath; /// @@ -60,8 +63,10 @@ public string FilePath public ScriptBlock ScriptBlock { get { return _scriptBlock; } + set { _scriptBlock = value; } } + private ScriptBlock _scriptBlock; /// @@ -74,8 +79,10 @@ public ScriptBlock ScriptBlock public ScheduledJobTrigger[] Trigger { get { return _triggers; } + set { _triggers = value; } } + private ScheduledJobTrigger[] _triggers; /// @@ -87,8 +94,10 @@ public ScheduledJobTrigger[] Trigger public ScriptBlock InitializationScript { get { return _initializationScript; } + set { _initializationScript = value; } } + private ScriptBlock _initializationScript; /// @@ -99,8 +108,10 @@ public ScriptBlock InitializationScript public SwitchParameter RunAs32 { get { return _runAs32; } + set { _runAs32 = value; } } + private SwitchParameter _runAs32; /// @@ -112,8 +123,10 @@ public SwitchParameter RunAs32 public PSCredential Credential { get { return _credential; } + set { _credential = value; } } + private PSCredential _credential; /// @@ -124,8 +137,10 @@ public PSCredential Credential public AuthenticationMechanism Authentication { get { return _authenticationMechanism; } + set { _authenticationMechanism = value; } } + private AuthenticationMechanism _authenticationMechanism; /// @@ -137,8 +152,10 @@ public AuthenticationMechanism Authentication public ScheduledJobOptions ScheduledJobOption { get { return _options; } + set { _options = value; } } + private ScheduledJobOptions _options; /// @@ -154,19 +171,23 @@ public ScheduledJobOptions ScheduledJobOption public ScheduledJobDefinition InputObject { get { return _definition; } + set { _definition = value; } } + private ScheduledJobDefinition _definition; /// - /// ClearExecutionHistory + /// ClearExecutionHistory. /// [Parameter(ParameterSetName = SetScheduledJobCommand.ExecutionParameterSet)] public SwitchParameter ClearExecutionHistory { get { return _clearExecutionHistory; } + set { _clearExecutionHistory = value; } } + private SwitchParameter _clearExecutionHistory; /// @@ -177,8 +198,10 @@ public SwitchParameter ClearExecutionHistory public int MaxResultCount { get { return _executionHistoryLength; } + set { _executionHistoryLength = value; } } + private int _executionHistoryLength; /// @@ -190,8 +213,10 @@ public int MaxResultCount public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } } + private SwitchParameter _passThru; /// @@ -204,8 +229,10 @@ public SwitchParameter PassThru public object[] ArgumentList { get { return _arguments; } + set { _arguments = value; } } + private object[] _arguments; /// @@ -216,8 +243,10 @@ public object[] ArgumentList public SwitchParameter RunNow { get { return _runNow; } + set { _runNow = value; } } + private SwitchParameter _runNow; /// @@ -229,8 +258,10 @@ public SwitchParameter RunNow public TimeSpan RunEvery { get { return _runEvery; } + set { _runEvery = value; } } + private TimeSpan _runEvery; #endregion @@ -259,7 +290,7 @@ protected override void ProcessRecord() // If RunEvery parameter is specified then create a job trigger for the definition that // runs the job at the requested interval. bool addedTrigger = false; - if (MyInvocation.BoundParameters.ContainsKey("RunEvery")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RunEvery))) { AddRepetitionJobTriggerToDefinition( _definition, @@ -341,7 +372,7 @@ private void UpdateDefinition() UpdateJobInvocationInfo(); - if (MyInvocation.BoundParameters.ContainsKey("MaxResultCount")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(MaxResultCount))) { _definition.SetExecutionHistoryLength(MaxResultCount, false); } @@ -407,7 +438,7 @@ private void UpdateJobInvocationInfo() } // RunAs32 - if (MyInvocation.BoundParameters.ContainsKey("RunAs32")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RunAs32))) { if (newParameters.ContainsKey(ScheduledJobInvocationInfo.RunAs32Parameter)) { @@ -420,7 +451,7 @@ private void UpdateJobInvocationInfo() } // Authentication - if (MyInvocation.BoundParameters.ContainsKey("Authentication")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(Authentication))) { if (newParameters.ContainsKey(ScheduledJobInvocationInfo.AuthenticationParameter)) { diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobTrigger.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobTrigger.cs index bfe72b9e0734..cac4dda17937 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobTrigger.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/SetJobTrigger.cs @@ -1,13 +1,12 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation; -using System.Diagnostics; namespace Microsoft.PowerShell.ScheduledJob { @@ -33,8 +32,10 @@ public sealed class SetJobTriggerCommand : ScheduleJobCmdletBase public ScheduledJobTrigger[] InputObject { get { return _triggers; } + set { _triggers = value; } } + private ScheduledJobTrigger[] _triggers; /// @@ -44,8 +45,10 @@ public ScheduledJobTrigger[] InputObject public Int32 DaysInterval { get { return _daysInterval; } + set { _daysInterval = value; } } + private Int32 _daysInterval = 1; /// @@ -55,8 +58,10 @@ public Int32 DaysInterval public Int32 WeeksInterval { get { return _weeksInterval; } + set { _weeksInterval = value; } } + private Int32 _weeksInterval = 1; /// @@ -66,8 +71,10 @@ public Int32 WeeksInterval public TimeSpan RandomDelay { get { return _randomDelay; } + set { _randomDelay = value; } } + private TimeSpan _randomDelay; /// @@ -77,8 +84,10 @@ public TimeSpan RandomDelay public DateTime At { get { return _atTime; } + set { _atTime = value; } } + private DateTime _atTime; /// @@ -90,8 +99,10 @@ public DateTime At public string User { get { return _user; } + set { _user = value; } } + private string _user; /// @@ -103,8 +114,10 @@ public string User public DayOfWeek[] DaysOfWeek { get { return _daysOfWeek; } + set { _daysOfWeek = value; } } + private DayOfWeek[] _daysOfWeek; /// @@ -114,8 +127,10 @@ public DayOfWeek[] DaysOfWeek public SwitchParameter AtStartup { get { return _atStartup; } + set { _atStartup = value; } } + private SwitchParameter _atStartup; /// @@ -125,8 +140,10 @@ public SwitchParameter AtStartup public SwitchParameter AtLogOn { get { return _atLogon; } + set { _atLogon = value; } } + private SwitchParameter _atLogon; /// @@ -136,8 +153,10 @@ public SwitchParameter AtLogOn public SwitchParameter Once { get { return _once; } + set { _once = value; } } + private SwitchParameter _once; /// @@ -147,8 +166,10 @@ public SwitchParameter Once public TimeSpan RepetitionInterval { get { return _repInterval; } + set { _repInterval = value; } } + private TimeSpan _repInterval; /// @@ -158,8 +179,10 @@ public TimeSpan RepetitionInterval public TimeSpan RepetitionDuration { get { return _repDuration; } + set { _repDuration = value; } } + private TimeSpan _repDuration; /// @@ -169,8 +192,10 @@ public TimeSpan RepetitionDuration public SwitchParameter RepeatIndefinitely { get { return _repRepeatIndefinitely; } + set { _repRepeatIndefinitely = value; } } + private SwitchParameter _repRepeatIndefinitely; /// @@ -180,8 +205,10 @@ public SwitchParameter RepeatIndefinitely public SwitchParameter Daily { get { return _daily; } + set { _daily = value; } } + private SwitchParameter _daily; /// @@ -191,8 +218,10 @@ public SwitchParameter Daily public SwitchParameter Weekly { get { return _weekly; } + set { _weekly = value; } } + private SwitchParameter _weekly; /// @@ -202,8 +231,10 @@ public SwitchParameter Weekly public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } } + private SwitchParameter _passThru; #endregion @@ -273,31 +304,37 @@ private bool ValidateParameterSet(ref TriggerFrequency newTriggerFrequency) { // First see if a switch parameter was set. List switchParamList = new List(); - if (MyInvocation.BoundParameters.ContainsKey(_paramAtStartup)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(AtStartup))) { switchParamList.Add(TriggerFrequency.AtStartup); } - if (MyInvocation.BoundParameters.ContainsKey(_paramAtLogon)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(AtLogon))) { switchParamList.Add(TriggerFrequency.AtLogon); } - if (MyInvocation.BoundParameters.ContainsKey(_paramOnce)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(Once))) { switchParamList.Add(TriggerFrequency.Once); } - if (MyInvocation.BoundParameters.ContainsKey(_paramDaily)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(Daily))) { switchParamList.Add(TriggerFrequency.Daily); } - if (MyInvocation.BoundParameters.ContainsKey(_paramWeekly)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(Weekly))) { switchParamList.Add(TriggerFrequency.Weekly); } + if (switchParamList.Count > 1) { WriteValidationError(ScheduledJobErrorStrings.ConflictingTypeParams); return false; } + newTriggerFrequency = (switchParamList.Count == 1) ? switchParamList[0] : TriggerFrequency.None; // Validate parameters against the new trigger frequency value. @@ -339,38 +376,43 @@ private bool ValidateParameterSet(ref TriggerFrequency newTriggerFrequency) private bool ValidateStartupParams() { - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysInterval)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysInterval, ScheduledJobErrorStrings.TriggerStartUpType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramWeeksInterval)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(WeeksInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidWeeksInterval, ScheduledJobErrorStrings.TriggerStartUpType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramAt)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(At))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidAtTime, ScheduledJobErrorStrings.TriggerStartUpType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramUser)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(User))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidUser, ScheduledJobErrorStrings.TriggerStartUpType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysOfWeek)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysOfWeek))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysOfWeek, ScheduledJobErrorStrings.TriggerStartUpType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInterval) || MyInvocation.BoundParameters.ContainsKey(_paramRepetitionDuration) || - MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInfiniteDuration)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) || MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration)) || + MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInfiniteDuration))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidSetTriggerRepetition, ScheduledJobErrorStrings.TriggerStartUpType); WriteValidationError(msg); @@ -382,32 +424,36 @@ private bool ValidateStartupParams() private bool ValidateLogonParams() { - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysInterval)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysInterval, ScheduledJobErrorStrings.TriggerLogonType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramWeeksInterval)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(WeeksInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidWeeksInterval, ScheduledJobErrorStrings.TriggerLogonType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramAt)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(At))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidAtTime, ScheduledJobErrorStrings.TriggerLogonType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysOfWeek)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysOfWeek))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysOfWeek, ScheduledJobErrorStrings.TriggerLogonType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInterval) || MyInvocation.BoundParameters.ContainsKey(_paramRepetitionDuration) || - MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInfiniteDuration)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) || MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration)) || + MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInfiniteDuration))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidSetTriggerRepetition, ScheduledJobErrorStrings.TriggerLogonType); WriteValidationError(msg); @@ -419,38 +465,41 @@ private bool ValidateLogonParams() private bool ValidateOnceParams(ScheduledJobTrigger trigger = null) { - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysInterval)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysInterval, ScheduledJobErrorStrings.TriggerOnceType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramWeeksInterval)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(WeeksInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidWeeksInterval, ScheduledJobErrorStrings.TriggerOnceType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramUser)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(User))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidUser, ScheduledJobErrorStrings.TriggerOnceType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysOfWeek)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysOfWeek))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysOfWeek, ScheduledJobErrorStrings.TriggerOnceType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInfiniteDuration)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInfiniteDuration))) { _repDuration = TimeSpan.MaxValue; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInterval) || MyInvocation.BoundParameters.ContainsKey(_paramRepetitionDuration) || - MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInfiniteDuration)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) || MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration)) || + MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInfiniteDuration))) { // Validate Once trigger repetition parameters. try @@ -466,7 +515,7 @@ private bool ValidateOnceParams(ScheduledJobTrigger trigger = null) if (trigger != null) { - if (trigger.At == null && !MyInvocation.BoundParameters.ContainsKey(_paramAt)) + if (trigger.At == null && !MyInvocation.BoundParameters.ContainsKey(nameof(At))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingAtTime, ScheduledJobErrorStrings.TriggerOnceType); WriteValidationError(msg); @@ -479,32 +528,36 @@ private bool ValidateOnceParams(ScheduledJobTrigger trigger = null) private bool ValidateDailyParams(ScheduledJobTrigger trigger = null) { - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysInterval) && + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysInterval)) && _daysInterval < 1) { WriteValidationError(ScheduledJobErrorStrings.InvalidDaysIntervalParam); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramWeeksInterval)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(WeeksInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidWeeksInterval, ScheduledJobErrorStrings.TriggerDailyType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramUser)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(User))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidUser, ScheduledJobErrorStrings.TriggerDailyType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysOfWeek)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysOfWeek))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysOfWeek, ScheduledJobErrorStrings.TriggerDailyType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInterval) || MyInvocation.BoundParameters.ContainsKey(_paramRepetitionDuration) || - MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInfiniteDuration)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) || MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration)) || + MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInfiniteDuration))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidSetTriggerRepetition, ScheduledJobErrorStrings.TriggerDailyType); WriteValidationError(msg); @@ -513,7 +566,7 @@ private bool ValidateDailyParams(ScheduledJobTrigger trigger = null) if (trigger != null) { - if (trigger.At == null && !MyInvocation.BoundParameters.ContainsKey(_paramAt)) + if (trigger.At == null && !MyInvocation.BoundParameters.ContainsKey(nameof(At))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingAtTime, ScheduledJobErrorStrings.TriggerDailyType); WriteValidationError(msg); @@ -526,26 +579,29 @@ private bool ValidateDailyParams(ScheduledJobTrigger trigger = null) private bool ValidateWeeklyParams(ScheduledJobTrigger trigger = null) { - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysInterval)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysInterval))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidDaysInterval, ScheduledJobErrorStrings.TriggerWeeklyType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramWeeksInterval) && + + if (MyInvocation.BoundParameters.ContainsKey(nameof(WeeksInterval)) && _weeksInterval < 1) { WriteValidationError(ScheduledJobErrorStrings.InvalidWeeksIntervalParam); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramUser)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(User))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidUser, ScheduledJobErrorStrings.TriggerWeeklyType); WriteValidationError(msg); return false; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInterval) || MyInvocation.BoundParameters.ContainsKey(_paramRepetitionDuration) || - MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInfiniteDuration)) + + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) || MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration)) || + MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInfiniteDuration))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.InvalidSetTriggerRepetition, ScheduledJobErrorStrings.TriggerWeeklyType); WriteValidationError(msg); @@ -554,14 +610,15 @@ private bool ValidateWeeklyParams(ScheduledJobTrigger trigger = null) if (trigger != null) { - if (trigger.At == null && !MyInvocation.BoundParameters.ContainsKey(_paramAt)) + if (trigger.At == null && !MyInvocation.BoundParameters.ContainsKey(nameof(At))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingAtTime, ScheduledJobErrorStrings.TriggerDailyType); WriteValidationError(msg); return false; } + if ((trigger.DaysOfWeek == null || trigger.DaysOfWeek.Count == 0) && - !MyInvocation.BoundParameters.ContainsKey(_paramDaysOfWeek)) + !MyInvocation.BoundParameters.ContainsKey(nameof(DaysOfWeek))) { string msg = StringUtil.Format(ScheduledJobErrorStrings.MissingDaysOfWeek, ScheduledJobErrorStrings.TriggerDailyType); WriteValidationError(msg); @@ -617,6 +674,7 @@ private bool CreateTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + CreateOnceTrigger(trigger); break; @@ -626,6 +684,7 @@ private bool CreateTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + CreateDailyTrigger(trigger); break; @@ -635,6 +694,7 @@ private bool CreateTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + CreateWeeklyTrigger(trigger); break; } @@ -652,6 +712,7 @@ private bool ModifyTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + ModifyStartupTrigger(trigger); break; @@ -661,6 +722,7 @@ private bool ModifyTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + ModifyLogonTrigger(trigger); break; @@ -670,6 +732,7 @@ private bool ModifyTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + ModifyOnceTrigger(trigger); break; @@ -679,6 +742,7 @@ private bool ModifyTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + ModifyDailyTrigger(trigger); break; @@ -688,6 +752,7 @@ private bool ModifyTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger { return false; } + ModifyWeeklyTrigger(trigger); break; } @@ -697,7 +762,7 @@ private bool ModifyTrigger(ScheduledJobTrigger trigger, TriggerFrequency trigger private void ModifyStartupTrigger(ScheduledJobTrigger trigger) { - if (MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay))) { trigger.RandomDelay = _randomDelay; } @@ -705,12 +770,12 @@ private void ModifyStartupTrigger(ScheduledJobTrigger trigger) private void ModifyLogonTrigger(ScheduledJobTrigger trigger) { - if (MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay))) { trigger.RandomDelay = _randomDelay; } - if (MyInvocation.BoundParameters.ContainsKey(_paramUser)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(User))) { trigger.User = string.IsNullOrEmpty(_user) ? ScheduledJobTrigger.AllUsers : _user; } @@ -718,22 +783,22 @@ private void ModifyLogonTrigger(ScheduledJobTrigger trigger) private void ModifyOnceTrigger(ScheduledJobTrigger trigger) { - if (MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay))) { trigger.RandomDelay = _randomDelay; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInterval)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval))) { trigger.RepetitionInterval = _repInterval; } - if (MyInvocation.BoundParameters.ContainsKey(_paramRepetitionDuration)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration))) { trigger.RepetitionDuration = _repDuration; } - if (MyInvocation.BoundParameters.ContainsKey(_paramAt)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(At))) { trigger.At = _atTime; } @@ -741,17 +806,17 @@ private void ModifyOnceTrigger(ScheduledJobTrigger trigger) private void ModifyDailyTrigger(ScheduledJobTrigger trigger) { - if (MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay))) { trigger.RandomDelay = _randomDelay; } - if (MyInvocation.BoundParameters.ContainsKey(_paramAt)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(At))) { trigger.At = _atTime; } - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysInterval)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysInterval))) { trigger.Interval = _daysInterval; } @@ -759,22 +824,22 @@ private void ModifyDailyTrigger(ScheduledJobTrigger trigger) private void ModifyWeeklyTrigger(ScheduledJobTrigger trigger) { - if (MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay))) { trigger.RandomDelay = _randomDelay; } - if (MyInvocation.BoundParameters.ContainsKey(_paramAt)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(At))) { trigger.At = _atTime; } - if (MyInvocation.BoundParameters.ContainsKey(_paramWeeksInterval)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(WeeksInterval))) { trigger.Interval = _weeksInterval; } - if (MyInvocation.BoundParameters.ContainsKey(_paramDaysOfWeek)) + if (MyInvocation.BoundParameters.ContainsKey(nameof(DaysOfWeek))) { trigger.DaysOfWeek = new List(_daysOfWeek); } @@ -792,8 +857,8 @@ private void CreateAtLogonTrigger(ScheduledJobTrigger trigger) trigger.Enabled = enabled; trigger.Id = id; - trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay) ? _randomDelay : randomDelay; - trigger.User = MyInvocation.BoundParameters.ContainsKey(_paramUser) ? _user : user; + trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay)) ? _randomDelay : randomDelay; + trigger.User = MyInvocation.BoundParameters.ContainsKey(nameof(User)) ? _user : user; } private void CreateAtStartupTrigger(ScheduledJobTrigger trigger) @@ -807,7 +872,7 @@ private void CreateAtStartupTrigger(ScheduledJobTrigger trigger) trigger.Enabled = enabled; trigger.Id = id; - trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay) ? _randomDelay : randomDelay; + trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay)) ? _randomDelay : randomDelay; } private void CreateOnceTrigger(ScheduledJobTrigger trigger) @@ -824,10 +889,10 @@ private void CreateOnceTrigger(ScheduledJobTrigger trigger) trigger.Enabled = enabled; trigger.Id = id; - trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay) ? _randomDelay : randomDelay; - trigger.At = MyInvocation.BoundParameters.ContainsKey(_paramAt) ? _atTime : atTime; - trigger.RepetitionInterval = MyInvocation.BoundParameters.ContainsKey(_paramRepetitionInterval) ? _repInterval : repInterval; - trigger.RepetitionDuration = MyInvocation.BoundParameters.ContainsKey(_paramRepetitionDuration) ? _repDuration : repDuration; + trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay)) ? _randomDelay : randomDelay; + trigger.At = MyInvocation.BoundParameters.ContainsKey(nameof(At)) ? _atTime : atTime; + trigger.RepetitionInterval = MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionInterval)) ? _repInterval : repInterval; + trigger.RepetitionDuration = MyInvocation.BoundParameters.ContainsKey(nameof(RepetitionDuration)) ? _repDuration : repDuration; } private void CreateDailyTrigger(ScheduledJobTrigger trigger) @@ -843,9 +908,9 @@ private void CreateDailyTrigger(ScheduledJobTrigger trigger) trigger.Enabled = enabled; trigger.Id = id; - trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay) ? _randomDelay : randomDelay; - trigger.At = MyInvocation.BoundParameters.ContainsKey(_paramAt) ? _atTime : atTime; - trigger.Interval = MyInvocation.BoundParameters.ContainsKey(_paramDaysInterval) ? _daysInterval : interval; + trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay)) ? _randomDelay : randomDelay; + trigger.At = MyInvocation.BoundParameters.ContainsKey(nameof(At)) ? _atTime : atTime; + trigger.Interval = MyInvocation.BoundParameters.ContainsKey(nameof(DaysInterval)) ? _daysInterval : interval; } private void CreateWeeklyTrigger(ScheduledJobTrigger trigger) @@ -862,10 +927,10 @@ private void CreateWeeklyTrigger(ScheduledJobTrigger trigger) trigger.Enabled = enabled; trigger.Id = id; - trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(_paramRandomDelay) ? _randomDelay : randomDelay; - trigger.At = MyInvocation.BoundParameters.ContainsKey(_paramAt) ? _atTime : atTime; - trigger.Interval = MyInvocation.BoundParameters.ContainsKey(_paramWeeksInterval) ? _weeksInterval : interval; - trigger.DaysOfWeek = MyInvocation.BoundParameters.ContainsKey(_paramDaysOfWeek) ? new List(_daysOfWeek) : daysOfWeek; + trigger.RandomDelay = MyInvocation.BoundParameters.ContainsKey(nameof(RandomDelay)) ? _randomDelay : randomDelay; + trigger.At = MyInvocation.BoundParameters.ContainsKey(nameof(At)) ? _atTime : atTime; + trigger.Interval = MyInvocation.BoundParameters.ContainsKey(nameof(WeeksInterval)) ? _weeksInterval : interval; + trigger.DaysOfWeek = MyInvocation.BoundParameters.ContainsKey(nameof(DaysOfWeek)) ? new List(_daysOfWeek) : daysOfWeek; } private void WriteValidationError(string msg) @@ -876,25 +941,5 @@ private void WriteValidationError(string msg) } #endregion - - #region Private Members - - private string _paramAtStartup = "AtStartup"; - private string _paramAtLogon = "AtLogon"; - private string _paramOnce = "Once"; - private string _paramDaily = "Daily"; - private string _paramWeekly = "Weekly"; - // - private string _paramDaysInterval = "DaysInterval"; - private string _paramWeeksInterval = "WeeksInterval"; - private string _paramRandomDelay = "RandomDelay"; - private string _paramRepetitionInterval = "RepetitionInterval"; - private string _paramRepetitionDuration = "RepetitionDuration"; - private string _paramRepetitionInfiniteDuration = "RepeatIndefinitely"; - private string _paramAt = "At"; - private string _paramUser = "User"; - private string _paramDaysOfWeek = "DaysOfWeek"; - - #endregion } } diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/SetScheduledJobOption.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/SetScheduledJobOption.cs index ef329895bd2a..8dbac01b4381 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/SetScheduledJobOption.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/SetScheduledJobOption.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; @@ -27,8 +26,10 @@ public class SetScheduledJobOptionCommand : ScheduledJobOptionCmdletBase public ScheduledJobOptions InputObject { get { return _jobOptions; } + set { _jobOptions = value; } } + private ScheduledJobOptions _jobOptions; /// @@ -38,8 +39,10 @@ public ScheduledJobOptions InputObject public SwitchParameter PassThru { get { return _passThru; } + set { _passThru = value; } } + private SwitchParameter _passThru; #endregion @@ -54,67 +57,67 @@ protected override void ProcessRecord() // Update ScheduledJobOptions object with current parameters. // Update switch parameters only if they were selected. // Also update the ScheduledJobDefinition object associated with this options object. - if (MyInvocation.BoundParameters.ContainsKey("StartIfOnBattery")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(StartIfOnBattery))) { _jobOptions.StartIfOnBatteries = StartIfOnBattery; } - if (MyInvocation.BoundParameters.ContainsKey("ContinueIfGoingOnBattery")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(ContinueIfGoingOnBattery))) { _jobOptions.StopIfGoingOnBatteries = !ContinueIfGoingOnBattery; } - if (MyInvocation.BoundParameters.ContainsKey("WakeToRun")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(WakeToRun))) { _jobOptions.WakeToRun = WakeToRun; } - if (MyInvocation.BoundParameters.ContainsKey("StartIfIdle")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(StartIfIdle))) { _jobOptions.StartIfNotIdle = !StartIfIdle; } - if (MyInvocation.BoundParameters.ContainsKey("StopIfGoingOffIdle")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(StopIfGoingOffIdle))) { _jobOptions.StopIfGoingOffIdle = StopIfGoingOffIdle; } - if (MyInvocation.BoundParameters.ContainsKey("RestartOnIdleResume")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RestartOnIdleResume))) { _jobOptions.RestartOnIdleResume = RestartOnIdleResume; } - if (MyInvocation.BoundParameters.ContainsKey("HideInTaskScheduler")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(HideInTaskScheduler))) { _jobOptions.ShowInTaskScheduler = !HideInTaskScheduler; } - if (MyInvocation.BoundParameters.ContainsKey("RunElevated")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RunElevated))) { _jobOptions.RunElevated = RunElevated; } - if (MyInvocation.BoundParameters.ContainsKey("RequireNetwork")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(RequireNetwork))) { _jobOptions.RunWithoutNetwork = !RequireNetwork; } - if (MyInvocation.BoundParameters.ContainsKey("DoNotAllowDemandStart")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(DoNotAllowDemandStart))) { _jobOptions.DoNotAllowDemandStart = DoNotAllowDemandStart; } - if (MyInvocation.BoundParameters.ContainsKey("IdleDuration")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(IdleDuration))) { _jobOptions.IdleDuration = IdleDuration; } - if (MyInvocation.BoundParameters.ContainsKey("IdleTimeout")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(IdleTimeout))) { _jobOptions.IdleTimeout = IdleTimeout; } - if (MyInvocation.BoundParameters.ContainsKey("MultipleInstancePolicy")) + if (MyInvocation.BoundParameters.ContainsKey(nameof(MultipleInstancePolicy))) { _jobOptions.MultipleInstancePolicy = MultipleInstancePolicy; } diff --git a/src/Microsoft.PowerShell.ScheduledJob/commands/UnregisterJobDefinition.cs b/src/Microsoft.PowerShell.ScheduledJob/commands/UnregisterJobDefinition.cs index 8eea6a6b00a8..7b25a749989a 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/commands/UnregisterJobDefinition.cs +++ b/src/Microsoft.PowerShell.ScheduledJob/commands/UnregisterJobDefinition.cs @@ -1,11 +1,10 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections.Generic; -using System.Management.Automation; using System.Diagnostics.CodeAnalysis; +using System.Management.Automation; namespace Microsoft.PowerShell.ScheduledJob { @@ -33,8 +32,10 @@ public sealed class UnregisterScheduledJobCommand : ScheduleJobCmdletBase public Int32[] Id { get { return _definitionIds; } + set { _definitionIds = value; } } + private Int32[] _definitionIds; /// @@ -47,8 +48,10 @@ public Int32[] Id public string[] Name { get { return _names; } + set { _names = value; } } + private string[] _names; /// @@ -61,8 +64,10 @@ public string[] Name public ScheduledJobDefinition[] InputObject { get { return _definitions; } + set { _definitions = value; } } + private ScheduledJobDefinition[] _definitions; /// @@ -75,8 +80,10 @@ public ScheduledJobDefinition[] InputObject public SwitchParameter Force { get { return _force; } + set { _force = value; } } + private SwitchParameter _force; #endregion diff --git a/src/Microsoft.PowerShell.ScheduledJob/resources/ScheduledJobErrorStrings.resx b/src/Microsoft.PowerShell.ScheduledJob/resources/ScheduledJobErrorStrings.resx index 56ea78881806..047abfee8293 100644 --- a/src/Microsoft.PowerShell.ScheduledJob/resources/ScheduledJobErrorStrings.resx +++ b/src/Microsoft.PowerShell.ScheduledJob/resources/ScheduledJobErrorStrings.resx @@ -355,10 +355,10 @@ The RepetitionInterval parameter cannot have a value of zero unless the RepetitionDuration parameter also has a zero value. A zero value removes repetition behavior from the Job trigger. - An error occured while attempting to rename scheduled job from {0} to {1}. + An error occurred while attempting to rename scheduled job from {0} to {1}. - An error occured while attempting to rename scheduled job from {0} to {1} with error message: {2}. + An error occurred while attempting to rename scheduled job from {0} to {1} with error message: {2}. An unrecoverable error occurred while renaming the scheduled job from {0} to {1}. The scheduled job will be removed. diff --git a/src/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.csproj b/src/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.csproj index cb9b17f03ba5..b6dae104e393 100644 --- a/src/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.csproj +++ b/src/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.csproj @@ -1,7 +1,7 @@  - PowerShell Core's Microsoft.PowerShell.Security project + PowerShell's Microsoft.PowerShell.Security project $(NoWarn);CS1570 Microsoft.PowerShell.Security @@ -10,10 +10,6 @@ - - $(DefineConstants);CORECLR - - @@ -21,16 +17,4 @@ - - portable - - - - $(DefineConstants);UNIX - - - - full - - diff --git a/src/Microsoft.PowerShell.Security/resources/ExecutionPolicyCommands.resx b/src/Microsoft.PowerShell.Security/resources/ExecutionPolicyCommands.resx index 0abbc073adc3..fc6eeb98c348 100644 --- a/src/Microsoft.PowerShell.Security/resources/ExecutionPolicyCommands.resx +++ b/src/Microsoft.PowerShell.Security/resources/ExecutionPolicyCommands.resx @@ -136,6 +136,7 @@ The execution policy helps protect you from scripts that you do not trust. Changing the execution policy might expose you to the security risks described in the about_Execution_Policies help topic at https://go.microsoft.com/fwlink/?LinkID=135170. Do you want to change the execution policy? - {0} To change the execution policy for the default (LocalMachine) scope, start PowerShell with the "Run as administrator" option. To change the execution policy for the current user, run "Set-ExecutionPolicy -Scope CurrentUser". + {0} +To change the execution policy for the default (LocalMachine) scope, start PowerShell with the "Run as administrator" option. To change the execution policy for the current user, run "Set-ExecutionPolicy -Scope CurrentUser". diff --git a/src/Microsoft.PowerShell.Security/security/AclCommands.cs b/src/Microsoft.PowerShell.Security/security/AclCommands.cs index e4a8d0421d38..5590506f4aa3 100644 --- a/src/Microsoft.PowerShell.Security/security/AclCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/AclCommands.cs @@ -1,8 +1,5 @@ -#pragma warning disable 1634, 1691 - -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #pragma warning disable 1634, 1691 #pragma warning disable 56506 @@ -105,16 +102,15 @@ internal CmdletProviderContext CmdletProviderContext return coreCommandContext; } - } // CmdletProviderContext - + } #region brokered properties /// /// Add brokered properties for easy access to important properties - /// of security descriptor + /// of security descriptor. /// - static internal void AddBrokeredProperties( + internal static void AddBrokeredProperties( Collection results, bool audit, bool allCentralAccessPolicies) @@ -123,7 +119,7 @@ internal CmdletProviderContext CmdletProviderContext { if (audit) { - //Audit + // Audit result.Properties.Add ( new PSCodeProperty @@ -133,7 +129,7 @@ internal CmdletProviderContext CmdletProviderContext ) ); } - //CentralAccessPolicyId retrieval does not require elevation, so we always add this property. + // CentralAccessPolicyId retrieval does not require elevation, so we always add this property. result.Properties.Add ( new PSCodeProperty @@ -142,11 +138,11 @@ internal CmdletProviderContext CmdletProviderContext typeof(SecurityDescriptorCommandsBase).GetMethod("GetCentralAccessPolicyId") ) ); -#if !CORECLR //GetAllCentralAccessPolicies and GetCentralAccessPolicyName are not supported in OneCore powershell - //because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer. +#if !CORECLR // GetAllCentralAccessPolicies and GetCentralAccessPolicyName are not supported in OneCore powershell + // because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer. if (allCentralAccessPolicies) { - //AllCentralAccessPolicies + // AllCentralAccessPolicies result.Properties.Add ( new PSCodeProperty @@ -156,7 +152,7 @@ internal CmdletProviderContext CmdletProviderContext ) ); } - //CentralAccessPolicyName retrieval does not require elevation, so we always add this property. + // CentralAccessPolicyName retrieval does not require elevation, so we always add this property. result.Properties.Add ( new PSCodeProperty @@ -190,9 +186,9 @@ public static string GetPath(PSObject instance) // them for null causes a presharp warning #pragma warning disable 56506 - //Get path + // Get path return instance.Properties["PSPath"].Value.ToString(); -#pragma warning enable 56506 +#pragma warning restore 56506 } } @@ -218,7 +214,7 @@ public static string GetOwner(PSObject instance) throw PSTraceSource.NewArgumentNullException("instance"); } - //Get owner + // Get owner try { IdentityReference ir = sd.GetOwner(typeof(NTAccount)); @@ -258,7 +254,7 @@ public static string GetGroup(PSObject instance) throw PSTraceSource.NewArgumentNullException("instance"); } - //Get Group + // Get Group try { IdentityReference ir = sd.GetGroup(typeof(NTAccount)); @@ -297,7 +293,7 @@ public static AuthorizationRuleCollection GetAccess(PSObject instance) PSTraceSource.NewArgumentException("instance"); } - //Get DACL + // Get DACL AuthorizationRuleCollection dacl; CommonObjectSecurity cos = sd as CommonObjectSecurity; if (cos != null) @@ -310,6 +306,7 @@ public static AuthorizationRuleCollection GetAccess(PSObject instance) Dbg.Diagnostics.Assert(dos != null, "Acl should be of type CommonObjectSecurity or DirectoryObjectSecurity"); dacl = dos.GetAccessRules(true, true, typeof(NTAccount)); } + return dacl; } @@ -347,6 +344,7 @@ public static AuthorizationRuleCollection GetAudit(PSObject instance) Dbg.Diagnostics.Assert(dos != null, "Acl should be of type CommonObjectSecurity or DirectoryObjectSecurity"); sacl = dos.GetAuditRules(true, true, typeof(NTAccount)); } + return sacl; } @@ -383,10 +381,12 @@ public static SecurityIdentifier GetCentralAccessPolicyId(PSObject instance) { throw new Win32Exception((int)rs); } + if (pSacl == IntPtr.Zero) { return null; } + NativeMethods.ACL sacl = new NativeMethods.ACL(); sacl = Marshal.PtrToStructure(pSacl); if (sacl.AceCount == 0) @@ -407,8 +407,10 @@ public static SecurityIdentifier GetCentralAccessPolicyId(PSObject instance) { break; } + pAce += ace.AceSize; } + IntPtr pSid = pAce + Marshal.SizeOf(new NativeMethods.SYSTEM_AUDIT_ACE()) - Marshal.SizeOf(new uint()); bool ret = NativeMethods.IsValidSid(pSid); @@ -445,6 +447,7 @@ public static string GetCentralAccessPolicyName(PSObject instance) { return null; // file does not have the scope ace } + int capIdSize = capId.BinaryLength; byte[] capIdArray = new byte[capIdSize]; capId.GetBinaryForm(capIdArray, 0); @@ -467,6 +470,7 @@ public static string GetCentralAccessPolicyName(PSObject instance) { throw new Win32Exception((int)rs); } + if (capCount == 0 || caps == IntPtr.Zero) { return null; @@ -516,6 +520,7 @@ public static string[] GetAllCentralAccessPolicies(PSObject instance) { throw new Win32Exception((int)rs); } + Dbg.Diagnostics.Assert(capCount < 0xFFFF, "Too many central access policies"); if (capCount == 0 || caps == IntPtr.Zero) @@ -547,11 +552,13 @@ public static string[] GetAllCentralAccessPolicies(PSObject instance) { throw new Win32Exception(Marshal.GetLastWin32Error()); } + SecurityIdentifier sid = new SecurityIdentifier(pCapId); policies[capIdx] += " (" + sid.ToString() + ")"; capPtr += Marshal.SizeOf(cap); } + return policies; } finally @@ -601,12 +608,12 @@ public static string GetSddl(PSObject instance) /// /// The glob string used to determine which items are included. /// - private string[] _include = new string[0]; + private string[] _include = Array.Empty(); /// /// The glob string used to determine which items are excluded. /// - private string[] _exclude = new string[0]; + private string[] _exclude = Array.Empty(); } #if !UNIX @@ -623,7 +630,7 @@ public sealed class GetAclCommand : SecurityDescriptorCommandsBase /// public GetAclCommand() { - //Default for path is the current location + // Default for path is the current location _path = new string[] { "." }; } #region parameters @@ -653,7 +660,7 @@ public string[] Path /// /// InputObject Parameter - /// Gets or sets the inputObject for which to obtain the security descriptor + /// Gets or sets the inputObject for which to obtain the security descriptor. /// [Parameter(Mandatory = true, ParameterSetName = "ByInputObject")] public PSObject InputObject @@ -690,6 +697,7 @@ public string[] LiteralPath _isLiteralPath = true; } } + private bool _isLiteralPath = false; /// @@ -709,6 +717,7 @@ public SwitchParameter Audit _audit = value; } } + private SwitchParameter _audit; #if CORECLR @@ -739,6 +748,7 @@ public SwitchParameter AllCentralAccessPolicies allCentralAccessPolicies = value; } } + private SwitchParameter allCentralAccessPolicies; #endif @@ -804,7 +814,6 @@ protected override void ProcessRecord() WriteError(er); } } - else { foreach (string p in Path) @@ -885,7 +894,7 @@ protected override void ProcessRecord() } } } - } // class GetAclCommand : PSCmdlet + } /// /// Defines the implementation of the 'set-acl' cmdlet. @@ -919,7 +928,7 @@ public string[] Path /// /// InputObject Parameter - /// Gets or sets the inputObject for which to set the security descriptor + /// Gets or sets the inputObject for which to set the security descriptor. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByInputObject")] public PSObject InputObject @@ -955,6 +964,7 @@ public string[] LiteralPath _isLiteralPath = true; } } + private bool _isLiteralPath = false; private object _securityDescriptor; @@ -1131,6 +1141,7 @@ private IntPtr GetSaclWithCapId(string capStr) { throw new Win32Exception((int)rs); } + Dbg.Diagnostics.Assert(capCount < 0xFFFF, "Too many central access policies"); if (capCount == 0 || caps == IntPtr.Zero) @@ -1155,9 +1166,11 @@ private IntPtr GetSaclWithCapId(string capStr) pCapId = cap.CAPID; break; } + capPtr += Marshal.SizeOf(cap); } } + if (pCapId == IntPtr.Zero) { Exception e = new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyIdentifier); @@ -1168,11 +1181,13 @@ private IntPtr GetSaclWithCapId(string capStr) AclObject)); return IntPtr.Zero; } + ret = NativeMethods.IsValidSid(pCapId); if (!ret) { throw new Win32Exception(Marshal.GetLastWin32Error()); } + uint sidSize = NativeMethods.GetLengthSid(pCapId); // Calculate the size of the SACL with one CAPID ACE, align to DWORD. @@ -1219,6 +1234,7 @@ private IntPtr GetSaclWithCapId(string capStr) Marshal.FreeHGlobal(pSacl); pSacl = IntPtr.Zero; } + rs = NativeMethods.LsaFreeMemory(caps); Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS, "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture)); @@ -1573,10 +1589,9 @@ protected override void ProcessRecord() } } } - } // class SetAclCommand + } #endif // !UNIX - -}// namespace Microsoft.PowerShell.Commands +} #pragma warning restore 56506 diff --git a/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs b/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs index 722a8b070723..dad56d9c50e8 100644 --- a/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs @@ -1,8 +1,7 @@ -#if !UNIX +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +#if !UNIX using System; using System.Management.Automation; @@ -22,7 +21,7 @@ namespace Microsoft.PowerShell.Commands public abstract class CatalogCommandsBase : PSCmdlet { /// - /// Path of folder/file to generate or validate the catalog file + /// Path of folder/file to generate or validate the catalog file. /// [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")] public string CatalogFilePath @@ -31,15 +30,17 @@ public string CatalogFilePath { return catalogFilePath; } + set { catalogFilePath = value; } } + private string catalogFilePath; /// - /// Path of folder/file to generate or validate the catalog file + /// Path of folder/file to generate or validate the catalog file. /// [Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")] public string[] Path @@ -48,11 +49,13 @@ public string[] Path { return path; } + set { path = value; } } + private string[] path; // // name of this command @@ -76,7 +79,7 @@ protected CatalogCommandsBase(string name) : base() /// /// Processes records from the input pipeline. /// For each input object, the command either generate the Catalog or - /// Validates the existing Catalog + /// Validates the existing Catalog. /// protected override void ProcessRecord() { @@ -95,7 +98,7 @@ protected override void ProcessRecord() { foreach (PathInfo tempPath in SessionState.Path.GetResolvedPSPathFromPSPath(p)) { - if (ShouldProcess("Including path " + tempPath.ProviderPath, "", "")) + if (ShouldProcess("Including path " + tempPath.ProviderPath, string.Empty, string.Empty)) { paths.Add(tempPath.ProviderPath); } @@ -118,7 +121,7 @@ protected override void ProcessRecord() } /// - /// Performs the action i.e. Generate or Validate the Windows Catalog File + /// Performs the action i.e. Generate or Validate the Windows Catalog File. /// /// /// The name of the Folder or file on which to perform the action. @@ -131,7 +134,7 @@ protected override void ProcessRecord() /// /// Defines the implementation of the 'New-FileCatalog' cmdlet. - /// This cmdlet generates the catalog for File or Folder + /// This cmdlet generates the catalog for File or Folder. /// [Cmdlet(VerbsCommon.New, "FileCatalog", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=786749")] @@ -144,7 +147,7 @@ public sealed class NewFileCatalogCommand : CatalogCommandsBase public NewFileCatalogCommand() : base("New-FileCatalog") { } /// - /// Catalog version + /// Catalog version. /// [Parameter()] public int CatalogVersion @@ -153,6 +156,7 @@ public int CatalogVersion { return catalogVersion; } + set { catalogVersion = value; @@ -163,7 +167,7 @@ public int CatalogVersion private int catalogVersion = 1; /// - /// Generate the Catalog for the Path + /// Generate the Catalog for the Path. /// /// /// File or Folder Path @@ -208,7 +212,7 @@ protected override void PerformAction(Collection path, string catalogFil /// /// Defines the implementation of the 'Test-FileCatalog' cmdlet. - /// This cmdlet validates the Integrity of catalog + /// This cmdlet validates the Integrity of catalog. /// [Cmdlet(VerbsDiagnostic.Test, "FileCatalog", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=786750")] @@ -227,12 +231,14 @@ public sealed class TestFileCatalogCommand : CatalogCommandsBase public SwitchParameter Detailed { get { return detailed; } + set { detailed = value; } } + private bool detailed = false; /// - /// Patterns used to exclude files from DiskPaths and Catalog + /// Patterns used to exclude files from DiskPaths and Catalog. /// [Parameter()] public string[] FilesToSkip @@ -241,6 +247,7 @@ public string[] FilesToSkip { return filesToSkip; } + set { filesToSkip = value; @@ -251,11 +258,12 @@ public string[] FilesToSkip } } } + private string[] filesToSkip = null; internal WildcardPattern[] excludedPatterns = null; /// - /// Validate the Integrity of given Catalog + /// Validate the Integrity of given Catalog. /// /// /// File or Folder Path diff --git a/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs b/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs index 94d032e48a73..39595a5a353c 100644 --- a/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs @@ -1,23 +1,22 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using Dbg = System.Management.Automation.Diagnostics; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Management.Automation; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using System.Diagnostics.CodeAnalysis; + +using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Commands { /// - /// Defines the implementation of the get-pfxcertificate cmdlet + /// Defines the implementation of the get-pfxcertificate cmdlet. /// [Cmdlet(VerbsCommon.Get, "PfxCertificate", DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113323")] [OutputType(typeof(X509Certificate2))] @@ -40,6 +39,7 @@ public string[] FilePath _path = value; } } + private string[] _path; /// @@ -62,17 +62,29 @@ public string[] LiteralPath _isLiteralPath = true; } } + private bool _isLiteralPath = false; + /// + /// Gets or sets the password for unlocking the certificate. + /// + [Parameter(Mandatory = false)] + public SecureString Password { get; set; } + + /// + /// Do not prompt for password if not given. + /// + [Parameter(Mandatory = false)] + public SwitchParameter NoPromptForPassword { get; set; } + // // list of files that were not found // private ArrayList _filesNotFound = new ArrayList(); - /// /// Initializes a new instance of the GetPfxCertificateCommand - /// class + /// class. /// public GetPfxCertificateCommand() : base() { @@ -123,56 +135,43 @@ protected override void ProcessRecord() string resolvedProviderPath = SecurityUtils.GetFilePathOfExistingFile(this, resolvedPath); - if (resolvedProviderPath == null) { _filesNotFound.Add(p); } else { - try - { - cert = GetCertFromPfxFile(resolvedProviderPath); - } - catch (CryptographicException) + if (Password == null && !NoPromptForPassword.IsPresent) { - // - // CryptographicException is thrown when any error - // occurs inside the crypto class library. It has a - // protected member HResult that indicates the exact - // error but it is not available outside the class. - // Thus we have to assume that the above exception - // was thrown because the pfx file is password - // protected. - // - SecureString password = null; - - string prompt = null; - prompt = CertificateCommands.GetPfxCertPasswordPrompt; - - password = SecurityUtils.PromptForSecureString(Host.UI, prompt); try { - cert = GetCertFromPfxFile(resolvedProviderPath, - password); + cert = GetCertFromPfxFile(resolvedProviderPath, null); + WriteObject(cert); + continue; } - catch (CryptographicException e) + catch (CryptographicException) { - // - // since we cannot really figure out the - // meaning of a given CryptographicException - // we have to use NotSpecified category here - // - ErrorRecord er = - new ErrorRecord(e, - "GetPfxCertificateUnknownCryptoError", - ErrorCategory.NotSpecified, - null); - WriteError(er); - continue; + Password = SecurityUtils.PromptForSecureString( + Host.UI, + CertificateCommands.GetPfxCertPasswordPrompt); } } + try + { + cert = GetCertFromPfxFile(resolvedProviderPath, Password); + } + catch (CryptographicException e) + { + ErrorRecord er = + new ErrorRecord(e, + "GetPfxCertificateUnknownCryptoError", + ErrorCategory.NotSpecified, + null); + WriteError(er); + continue; + } + WriteObject(cert); } } @@ -210,12 +209,6 @@ protected override void ProcessRecord() } } - private static X509Certificate2 GetCertFromPfxFile(string path) - { - X509Certificate2 cert = new X509Certificate2(path); - return cert; - } - private static X509Certificate2 GetCertFromPfxFile(string path, SecureString password) { var cert = new X509Certificate2(path, password, X509KeyStorageFlags.DefaultKeySet); diff --git a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs index 533cb60767b4..014eb6db9220 100644 --- a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs +++ b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs @@ -1,7 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #if !UNIX -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ using System; using System.Management.Automation; @@ -41,13 +41,14 @@ namespace Microsoft.PowerShell.Commands internal sealed class CertificateProviderCodeSigningDynamicParameters { /// - /// switch that controls whether we only return + /// Switch that controls whether we only return /// code signing certs. /// [Parameter()] public SwitchParameter CodeSigningCert { get { return _codeSigningCert; } + set { _codeSigningCert = value; } } @@ -56,23 +57,23 @@ public SwitchParameter CodeSigningCert /// /// Defines the type of DNS string - /// The structure contains punycode name and unicode name + /// The structure contains punycode name and unicode name. /// [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] public struct DnsNameRepresentation { /// - /// punycode version of DNS name + /// Punycode version of DNS name. /// private string _punycodeName; /// - /// Unicode version of DNS name + /// Unicode version of DNS name. /// private string _unicodeName; /// - /// ambiguous constructor of a DnsNameRepresentation + /// Ambiguous constructor of a DnsNameRepresentation. /// public DnsNameRepresentation(string inputDnsName) { @@ -81,7 +82,7 @@ public DnsNameRepresentation(string inputDnsName) } /// - /// specific constructor of a DnsNameRepresentation + /// Specific constructor of a DnsNameRepresentation. /// [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Punycode")] public DnsNameRepresentation( @@ -93,7 +94,7 @@ public DnsNameRepresentation(string inputDnsName) } /// - /// value comparison + /// Value comparison. /// public bool Equals(DnsNameRepresentation dnsName) { @@ -101,7 +102,7 @@ public bool Equals(DnsNameRepresentation dnsName) if (_unicodeName != null && dnsName._unicodeName != null) { - if (String.Equals( + if (string.Equals( _unicodeName, dnsName._unicodeName, StringComparison.OrdinalIgnoreCase)) @@ -113,11 +114,12 @@ public bool Equals(DnsNameRepresentation dnsName) { match = true; } + return match; } /// - /// get property of Punycode + /// Get property of Punycode. /// [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Punycode")] public string Punycode @@ -129,7 +131,7 @@ public string Punycode } /// - /// get property of Unicode + /// Get property of Unicode. /// public string Unicode { @@ -140,7 +142,7 @@ public string Unicode } /// - /// get display string + /// Get display string. /// public override string ToString() { @@ -149,7 +151,7 @@ public override string ToString() // to differ only by upper/lower case. If they do, that's really // a code bug, and the effect is to just display both strings. - return String.Equals(_punycodeName, _unicodeName) ? + return string.Equals(_punycodeName, _unicodeName) ? _punycodeName : _unicodeName + " (" + _punycodeName + ")"; } @@ -159,14 +161,13 @@ public override string ToString() /// Defines the Certificate Provider remove-item dynamic parameters. /// /// Currently, we only support one dynamic parameter: DeleteKey - /// If provided, we will delete the private key when we remove a certificate - /// + /// If provided, we will delete the private key when we remove a certificate. /// internal sealed class ProviderRemoveItemDynamicParameters { /// - /// switch that controls whether we should delete private key - /// when remove a certificate + /// Switch that controls whether we should delete private key + /// when remove a certificate. /// [Parameter()] public SwitchParameter DeleteKey @@ -214,22 +215,24 @@ protected override bool ReleaseHandle() fResult = Security.NativeMethods.CertCloseStore(handle, 0); handle = IntPtr.Zero; } + return fResult; } public IntPtr Handle { get { return handle; } + set { handle = value; } } } /// - /// Defines the Certificate Provider store handle class + /// Defines the Certificate Provider store handle class. /// internal sealed class X509NativeStore { - //#region tracer + // #region tracer /// /// Initializes a new instance of the X509NativeStore class. @@ -246,6 +249,7 @@ public void Open(bool includeArchivedCerts) { _storeHandle = null; // release the old handle } + if (_storeHandle == null) { _valid = false; @@ -273,7 +277,7 @@ public void Open(bool includeArchivedCerts) break; default: - //ThrowItemNotFound(storeLocation.ToString(), CertificateProviderItem.StoreLocation); + // ThrowItemNotFound(storeLocation.ToString(), CertificateProviderItem.StoreLocation); break; } @@ -291,8 +295,8 @@ public void Open(bool includeArchivedCerts) _storeHandle = new CertificateStoreHandle(); _storeHandle.Handle = hCertStore; - //we only do CertControlStore for stores other than UserDS - if (!String.Equals( + // we only do CertControlStore for stores other than UserDS + if (!string.Equals( _storeName, "UserDS", StringComparison.OrdinalIgnoreCase)) @@ -326,6 +330,7 @@ public IntPtr GetNextCert(IntPtr certContext) throw Marshal.GetExceptionForHR( Security.NativeMethods.CRYPT_E_NOT_FOUND); } + if (Valid) { certContext = Security.NativeMethods.CertEnumCertificatesInStore( @@ -336,6 +341,7 @@ public IntPtr GetNextCert(IntPtr certContext) { certContext = IntPtr.Zero; } + return certContext; } @@ -348,6 +354,7 @@ public IntPtr GetCertByName(string Name) throw Marshal.GetExceptionForHR( Security.NativeMethods.CRYPT_E_NOT_FOUND); } + if (Valid) { if (DownLevelHelper.HashLookupSupported()) @@ -376,8 +383,9 @@ public IntPtr GetCertByName(string Name) { break; } + X509Certificate2 cert = new X509Certificate2(certContext); - if (String.Equals( + if (string.Equals( cert.Thumbprint, Name, StringComparison.OrdinalIgnoreCase)) @@ -387,6 +395,7 @@ public IntPtr GetCertByName(string Name) } } } + return certContext; } @@ -396,7 +405,7 @@ public void FreeCert(IntPtr certContext) } /// - /// native IntPtr store handle + /// Native IntPtr store handle. /// public IntPtr StoreHandle @@ -408,7 +417,7 @@ public IntPtr StoreHandle } /// - /// X509StoreLocation store location + /// X509StoreLocation store location. /// public X509StoreLocation Location { @@ -419,7 +428,7 @@ public X509StoreLocation Location } /// - /// string store name + /// String store name. /// public string StoreName { @@ -430,7 +439,7 @@ public string StoreName } /// - /// true if a real store is open + /// True if a real store is open. /// public bool Valid @@ -467,13 +476,13 @@ internal enum CertificateProviderItem /// /// A certificate store location. - /// For example, cert:\CurrentUser + /// For example, cert:\CurrentUser. /// Store, /// /// A certificate store. - /// For example, cert:\CurrentUser\My + /// For example, cert:\CurrentUser\My. /// StoreLocation } @@ -484,7 +493,7 @@ internal enum CertificateProviderItem /// store. /// [CmdletProvider("Certificate", ProviderCapabilities.ShouldProcess)] - [OutputType(typeof(String), typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.ResolvePath)] + [OutputType(typeof(string), typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.ResolvePath)] [OutputType(typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.PushLocation)] [OutputType(typeof(Microsoft.PowerShell.Commands.X509StoreLocation), typeof(X509Certificate2), ProviderCmdlet = ProviderCmdlet.GetItem)] [OutputType(typeof(X509Store), typeof(X509Certificate2), ProviderCmdlet = ProviderCmdlet.GetChildItem)] @@ -493,7 +502,7 @@ public sealed class CertificateProvider : NavigationCmdletProvider, ICmdletProvi #region tracer /// - /// tracer for certificate provider + /// Tracer for certificate provider. /// [TraceSource("CertificateProvider", "The core command provider for certificates")] @@ -503,41 +512,41 @@ public sealed class CertificateProvider : NavigationCmdletProvider, ICmdletProvi #endregion tracer /// - /// Indicate if we already have attempted to load the PKI module + /// Indicate if we already have attempted to load the PKI module. /// private bool _hasAttemptedToLoadPkiModule = false; /// - /// lock that guards access to the following static members + /// Lock that guards access to the following static members /// -- storeLocations - /// -- pathCache + /// -- pathCache. /// private static object s_staticLock = new object(); /// - /// list of store locations. They do not change once initialized. + /// List of store locations. They do not change once initialized. /// - /// Synchronized on staticLock + /// Synchronized on staticLock. /// private static List s_storeLocations = null; /// - /// cache that stores paths and their associated objects. + /// Cache that stores paths and their associated objects. /// /// key is full path to store-location/store/certificate /// value is X509StoreLocation/X509NativeStore/X509Certificate2 object /// - /// Synchronized on staticLock + /// Synchronized on staticLock. /// private static Hashtable s_pathCache = null; /// - /// we allow either / or \ to be the path separator + /// We allow either / or \ to be the path separator. /// private static readonly char[] s_pathSeparators = new char[] { '/', '\\' }; /// - /// regex pattern that defines a valid cert path + /// Regex pattern that defines a valid cert path. /// private const string certPathPattern = @"^\\((?CurrentUser|LocalMachine)(\\(?[a-zA-Z]+)(\\(?[0-9a-f]{40}))?)?)?$"; @@ -549,14 +558,12 @@ public sealed class CertificateProvider : NavigationCmdletProvider, ICmdletProvi /// /// On demand create the Regex to avoid a hit to startup perf. /// - /// /// /// Note, its OK that staticLock is being used here because only /// IsValidPath is calling this static property so we shouldn't /// have any deadlocks due to other locked static members calling /// this property. /// - /// private static Regex s_certPathRegex = null; private static Regex CertPathRegex { @@ -570,6 +577,7 @@ private static Regex CertPathRegex s_certPathRegex = new Regex(certPathPattern, options); } } + return s_certPathRegex; } } @@ -609,28 +617,23 @@ public CertificateProvider() AddItemToCache(StoreLocation.LocalMachine.ToString(), machine); - AddItemToCache("", s_storeLocations); + AddItemToCache(string.Empty, s_storeLocations); } } - } // constructor - + } /// - /// Removes an item at the specified path + /// Removes an item at the specified path. /// - /// /// /// The path of the item to remove. /// - /// /// /// Recursively remove. /// - /// /// /// Nothing. /// - /// /// /// path is null or empty. /// destination is null or empty. @@ -647,14 +650,14 @@ public CertificateProvider() object outObj = GetItemAtPath(path, false, out isContainer); string[] pathElements = GetPathElements(path); - bool fUserContext = String.Equals(pathElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase); + bool fUserContext = string.Equals(pathElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase); // isContainer = true means not a valid certificate // if source store is user root store and UI is not allowed // we raise invalid operation if (DetectUIHelper.GetOwnerWindow(Host) == IntPtr.Zero && fUserContext && - String.Equals(pathElements[1], "ROOT", StringComparison.OrdinalIgnoreCase)) + string.Equals(pathElements[1], "ROOT", StringComparison.OrdinalIgnoreCase)) { string message = CertificateProviderStrings.UINotAllowed; string errorId = "UINotAllowed"; @@ -676,9 +679,9 @@ public CertificateProvider() if (isContainer) { - if (pathElements.Length == 2) //is a store + if (pathElements.Length == 2) // is a store { - //not support user context + // not support user context if (fUserContext) { string message = CertificateProviderStrings.CannotDeleteUserStore; @@ -689,16 +692,16 @@ public CertificateProvider() RemoveCertStore(pathElements[1], fDeleteKey, path); return; } - else //other container than a store + else // other container than a store { string message = CertificateProviderStrings.CannotRemoveContainer; string errorId = "CannotRemoveContainer"; ThrowInvalidOperation(errorId, message); } } - else //certificate + else // certificate { - //do remove + // do remove X509Certificate2 certificate = outObj as X509Certificate2; RemoveCertItem(certificate, fDeleteKey, !fUserContext, path); return; @@ -710,16 +713,13 @@ public CertificateProvider() /// Provider. We currently only support one dynamic parameter, /// "DeleteKey," that delete private key when we delete a certificate. /// - /// /// /// If the path was specified on the command line, this is the path /// to the item for which to get the dynamic parameters. /// - /// /// /// Ignored. /// - /// /// /// An object that has properties and fields decorated with /// parsing attributes similar to a cmdlet class. @@ -732,19 +732,15 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) /// /// Moves an item at the specified path to the given destination. /// - /// /// /// The path of the item to move. /// - /// /// /// The path of the destination. /// - /// /// /// Nothing. Moved items are written to the context's pipeline. /// - /// /// /// path is null or empty. /// destination is null or empty. @@ -754,11 +750,11 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) string path, string destination) { - //normalize path + // normalize path path = NormalizePath(path); destination = NormalizePath(destination); - //get elements from the path + // get elements from the path string[] pathElements = GetPathElements(path); string[] destElements = GetPathElements(destination); @@ -775,14 +771,14 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) ThrowInvalidOperation(errorId, message); } - if (destElements.Length != 2) //not a store + if (destElements.Length != 2) // not a store { - //if the destination leads to the same thumbprint + // if the destination leads to the same thumbprint if (destElements.Length == 3 && - (String.Equals(pathElements[2], destElements[2], StringComparison.OrdinalIgnoreCase))) + (string.Equals(pathElements[2], destElements[2], StringComparison.OrdinalIgnoreCase))) { - //in this case we think of destination path as valid - //and strip the thumbprint part + // in this case we think of destination path as valid + // and strip the thumbprint part destination = Path.GetDirectoryName(destination); } else @@ -793,18 +789,18 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) } } - //the second element is store location - //we do not allow cross context move - //we do not allow the destination store is the same as source + // the second element is store location + // we do not allow cross context move + // we do not allow the destination store is the same as source - if (!String.Equals(pathElements[0], destElements[0], StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(pathElements[0], destElements[0], StringComparison.OrdinalIgnoreCase)) { string message = CertificateProviderStrings.CannotMoveCrossContext; string errorId = "CannotMoveCrossContext"; ThrowInvalidOperation(errorId, message); } - if (String.Equals(pathElements[1], destElements[1], StringComparison.OrdinalIgnoreCase)) + if (string.Equals(pathElements[1], destElements[1], StringComparison.OrdinalIgnoreCase)) { string message = CertificateProviderStrings.CannotMoveToSameStore; string errorId = "CannotMoveToSameStore"; @@ -815,10 +811,10 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) // we raise invalid operation if (DetectUIHelper.GetOwnerWindow(Host) == IntPtr.Zero) { - if ((String.Equals(pathElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase) && - String.Equals(pathElements[1], "ROOT", StringComparison.OrdinalIgnoreCase)) || - (String.Equals(destElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase) && - String.Equals(destElements[1], "ROOT", StringComparison.OrdinalIgnoreCase))) + if ((string.Equals(pathElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase) && + string.Equals(pathElements[1], "ROOT", StringComparison.OrdinalIgnoreCase)) || + (string.Equals(destElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase) && + string.Equals(destElements[1], "ROOT", StringComparison.OrdinalIgnoreCase))) { string message = CertificateProviderStrings.UINotAllowed; string errorId = "UINotAllowed"; @@ -826,9 +822,9 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) } } - if (cert != null) //we get cert + if (cert != null) // we get cert { - //get destination store + // get destination store bool isDestContainer = false; object store = GetItemAtPath(destination, false, out isDestContainer); @@ -840,7 +836,7 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) certstore.Open(true); string action = CertificateProviderStrings.Action_Move; - string resource = String.Format( + string resource = string.Format( CultureInfo.CurrentCulture, CertificateProviderStrings.MoveItemTemplate, path, @@ -860,7 +856,6 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) /// /// Creates a certificate store with the given path. /// - /// /// /// New-Item doesn't go through the method "ItemExists". But for the /// CertificateProvider, New-Item can create an X509Store and return @@ -869,30 +864,23 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) /// X509Certificate2 objects to be shown to the user, so we also need /// to import the PKI module in this method, if we haven't tried it yet. /// - /// /// /// The path of the certificate store to create. /// - /// /// /// Ignored. /// Only support store. /// - /// /// /// Ignored /// - /// /// /// Nothing. The new certificate store object is /// written to the context's pipeline. /// - /// /// /// path is null or empty. /// - /// - /// protected override void NewItem( string path, string type, @@ -906,10 +894,10 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) path = NormalizePath(path); - //get the elements from the path + // get the elements from the path string[] pathElements = GetPathElements(path); - //only support creating store + // only support creating store if (pathElements.Length != 2) { string message = CertificateProviderStrings.CannotCreateItem; @@ -917,21 +905,22 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) ThrowInvalidOperation(errorId, message); } - bool fUserContext = String.Equals(pathElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase); + bool fUserContext = string.Equals(pathElements[0], "CurrentUser", StringComparison.OrdinalIgnoreCase); - //not support user context + // not support user context if (fUserContext) { string message = CertificateProviderStrings.CannotCreateUserStore; string errorId = "CannotCreateUserStore"; ThrowInvalidOperation(errorId, message); } + Security.NativeMethods.CertOpenStoreFlags StoreFlags = Security.NativeMethods.CertOpenStoreFlags.CERT_STORE_CREATE_NEW_FLAG | Security.NativeMethods.CertOpenStoreFlags.CERT_STORE_MAXIMUM_ALLOWED_FLAG | Security.NativeMethods.CertOpenStoreFlags.CERT_SYSTEM_STORE_LOCAL_MACHINE; - //Create new store + // Create new store IntPtr hCertStore = Security.NativeMethods.CertOpenStore( Security.NativeMethods.CertOpenStoreProvider.CERT_STORE_PROV_SYSTEM, Security.NativeMethods.CertOpenStoreEncodingType.X509_ASN_ENCODING, @@ -942,7 +931,7 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } - else //free native store handle + else // free native store handle { bool fResult = false; fResult = Security.NativeMethods.CertCloseStore(hCertStore, 0); @@ -953,12 +942,12 @@ protected override object RemoveItemDynamicParameters(string path, bool recurse) StoreLocation.LocalMachine); WriteItemObject(outStore, path, true); } + #region DriveCmdletProvider overrides /// /// Initializes the cert: drive. /// - /// /// /// A collection that contains the PSDriveInfo object /// that represents the cert: drive. @@ -979,26 +968,22 @@ protected override Collection InitializeDefaultDrives() drives.Add(drive); return drives; - } // InitializeDefaultDrives + } /// /// Determines if the item at the given path is a store-location /// or store with items in it. /// - /// /// /// The full path to the item. /// - /// /// /// True if the path refers to a store location, or store that contains /// certificates. False otherwise. /// - /// /// /// Path is null /// - /// /// /// This exception can be thrown if any cryptographic error occurs. /// It is not possible to know exactly what went wrong. @@ -1047,19 +1032,18 @@ protected override bool HasChildItems(string path) } } } + return result; } /// /// Determines if the specified path is syntactically and semantically valid. /// An example path looks like this: - /// cert:\CurrentUser\My\5F98EBBFE735CDDAE00E33E0FD69050EF9220254 + /// cert:\CurrentUser\My\5F98EBBFE735CDDAE00E33E0FD69050EF9220254. /// - /// /// /// The path of the item to check. /// - /// /// /// True if the path is valid, false otherwise. /// @@ -1077,7 +1061,6 @@ protected override bool IsValidPath(string path) /// Determines if the store location, store, or certificate exists /// at the specified path. /// - /// /// /// The method ItemExists will be hit by all built-in cmdlets that interact /// with the CertificateProvider except for the New-Item. They are: @@ -1091,20 +1074,16 @@ protected override bool IsValidPath(string path) /// Remove-Item /// So we import the PKI module in this method if we haven't tried yet. /// - /// /// /// The path of the item to check. /// - /// /// /// True if a the store location, store, or certificate exists /// at the specified path. False otherwise. /// - /// /// /// Path is null /// - /// /// /// This exception can be thrown if any cryptographic error occurs. /// It is not possible to know exactly what went wrong. @@ -1115,7 +1094,6 @@ protected override bool IsValidPath(string path) /// -- certificate password mismatch /// -- etc /// - /// protected override bool ItemExists(string path) { if (!_hasAttemptedToLoadPkiModule) @@ -1165,22 +1143,18 @@ protected override bool ItemExists(string path) s_tracer.WriteLine("result = {0}", result); return result; - } // ItemExists + } /// /// Gets the store location, store, or certificate /// at the specified path. /// - /// /// /// The path of the item to retrieve. /// - /// - /// /// /// Path is null /// - /// /// /// This exception can be thrown if any cryptographic error occurs. /// It is not possible to know exactly what went wrong. @@ -1191,7 +1165,6 @@ protected override bool ItemExists(string path) /// -- certificate password mismatch /// -- etc /// - /// protected override void GetItem(string path) { bool isContainer = false; @@ -1202,7 +1175,7 @@ protected override void GetItem(string path) if (item != null) { - if (!isContainer) //certificate + if (!isContainer) // certificate { // If the filter is null, output the certificate we got. if (filter == null) @@ -1226,7 +1199,7 @@ protected override void GetItem(string path) } } } - else //container + else // container { // The item is a container. If the filter is non null, we don't output it. if (filter != null) @@ -1235,16 +1208,16 @@ protected override void GetItem(string path) } X509StoreLocation storeLocation = item as X509StoreLocation; - if (storeLocation != null) //store location + if (storeLocation != null) // store location { WriteItemObject(item, path, isContainer); } - else //store + else // store { X509NativeStore store = item as X509NativeStore; if (store != null) { - //create X509Store + // create X509Store X509Store outStore = new X509Store( store.StoreName, store.Location.Location); @@ -1258,15 +1231,12 @@ protected override void GetItem(string path) /// /// Gets the parent of the given path. /// - /// /// /// The path of which to get the parent. /// - /// /// /// The root of the drive. /// - /// /// /// The parent of the given path. /// @@ -1280,17 +1250,15 @@ protected override string GetParentPath(string path, string root) /// /// Gets the name of the leaf element of the specified path. /// - /// /// /// The fully qualified path to the item. /// - /// /// /// The leaf element of the specified path. /// protected override string GetChildName(string path) { - //Path for root is empty string + // Path for root is empty string if (path != null && path.Length == 0) { return path; @@ -1321,7 +1289,6 @@ private void AttemptToImportPkiModule() return; } - CommandInfo commandInfo = new CmdletInfo( "Import-Module", @@ -1355,7 +1322,7 @@ private string MyGetChildName(string path) { // Verify the parameters - if (String.IsNullOrEmpty(path)) + if (string.IsNullOrEmpty(path)) { throw PSTraceSource.NewArgumentException("path"); } @@ -1369,7 +1336,6 @@ private string MyGetChildName(string path) int separatorIndex = path.LastIndexOf(StringLiterals.DefaultPathSeparator); - // Since there was no path separator return the entire path if (separatorIndex == -1) { @@ -1386,7 +1352,6 @@ private string MyGetChildName(string path) /// Invokes the certificate management UI (certmgr.msc) /// for any path. /// - /// /// /// Ignored. /// @@ -1402,9 +1367,9 @@ protected override void InvokeDefaultAction(string path) { System.Diagnostics.Process.Start(System.IO.Path.Combine(certPath, certmgr)); } - } // InvokeDefaultAction + } - static private string EnsureDriveIsRooted(string path) + private static string EnsureDriveIsRooted(string path) { string result = path; @@ -1427,9 +1392,9 @@ static private string EnsureDriveIsRooted(string path) s_tracer.WriteLine("result = {0}", result); return result; - } // EnsureDriveIsRooted + } - static private ErrorRecord CreateErrorRecord(string path, + private static ErrorRecord CreateErrorRecord(string path, CertificateProviderItem itemType) { Exception e = null; @@ -1458,7 +1423,7 @@ static private string EnsureDriveIsRooted(string path) break; } - message = String.Format( + message = string.Format( System.Globalization.CultureInfo.CurrentCulture, message, path); ErrorDetails ed = new ErrorDetails(message); @@ -1501,7 +1466,7 @@ private void ThrowErrorRemoting(int stat) if (this.Host.Name.Equals("ServerRemoteHost", StringComparison.OrdinalIgnoreCase)) { Exception e = new System.ComponentModel.Win32Exception(stat); - String error = e.Message; + string error = e.Message; string message = CertificateProviderStrings.RemoteErrorMessage; error += message; @@ -1540,7 +1505,7 @@ private void ThrowInvalidOperation(string errorId, string message) ThrowTerminatingError(er); } - static private string NormalizePath(string path) + private static string NormalizePath(string path) { if (path.Length > 0) { @@ -1553,13 +1518,13 @@ static private string NormalizePath(string path) string[] elts = GetPathElements(path); - path = String.Join("\\", elts); + path = string.Join("\\", elts); } return path; } - static private string[] GetPathElements(string path) + private static string[] GetPathElements(string path) { string[] allElts = path.Split(s_pathSeparators); string[] result = null; @@ -1568,7 +1533,7 @@ static private string[] GetPathElements(string path) foreach (string e in allElts) { - if ((e == ".") || (e == String.Empty)) + if ((e == ".") || (e == string.Empty)) { continue; } @@ -1592,12 +1557,10 @@ static private string[] GetPathElements(string path) } /// - /// Delete private key + /// Delete private key. /// - /// - /// key prov info - /// - /// no return + /// Key prov info. + /// No return. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Management.Automation.Security.NativeMethods.NCryptSetProperty(System.IntPtr,System.String,System.Void*,System.Int32,System.Int32)")] [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Management.Automation.Security.NativeMethods.NCryptFreeObject(System.IntPtr)")] @@ -1609,7 +1572,7 @@ private void DoDeleteKey(IntPtr pProvInfo) IntPtr hWnd = DetectUIHelper.GetOwnerWindow(Host); - if (keyProvInfo.dwProvType != 0) //legacy + if (keyProvInfo.dwProvType != 0) // legacy { if (hWnd != IntPtr.Zero) { @@ -1644,7 +1607,7 @@ private void DoDeleteKey(IntPtr pProvInfo) ThrowErrorRemoting(Marshal.GetLastWin32Error()); } } - else //cng key + else // cng key { uint cngKeyFlag = 0; int result = 0; @@ -1705,6 +1668,7 @@ private void DoDeleteKey(IntPtr pProvInfo) { ThrowErrorRemoting(stat); } + hCNGKey = IntPtr.Zero; } finally @@ -1720,20 +1684,16 @@ private void DoDeleteKey(IntPtr pProvInfo) /// /// Delete the cert store; if -DeleteKey is specified, we also delete - /// the associated private key + /// the associated private key. /// - /// - /// the store name - /// - /// boolean to specify whether or not to delete private key - /// - /// source path - /// - /// no return + /// The store name. + /// Boolean to specify whether or not to delete private key. + /// Source path. + /// No return. private void RemoveCertStore(string storeName, bool fDeleteKey, string sourcePath) { - //if recurse is true, remove every cert in the store + // if recurse is true, remove every cert in the store IntPtr localName = Security.NativeMethods.CryptFindLocalizedName(storeName); string[] pathElements = GetPathElements(sourcePath); if (IntPtr.Zero == localName)//not find, we can remove @@ -1758,7 +1718,7 @@ private void RemoveCertStore(string storeName, bool fDeleteKey, string sourcePat certContext = store.GetNextCert(certContext); } - //remove the cert store + // remove the cert store Security.NativeMethods.CertOpenStoreFlags StoreFlags = Security.NativeMethods.CertOpenStoreFlags.CERT_STORE_READONLY_FLAG | Security.NativeMethods.CertOpenStoreFlags.CERT_STORE_OPEN_EXISTING_FLAG | @@ -1766,7 +1726,7 @@ private void RemoveCertStore(string storeName, bool fDeleteKey, string sourcePat Security.NativeMethods.CertOpenStoreFlags.CERT_STORE_DELETE_FLAG | Security.NativeMethods.CertOpenStoreFlags.CERT_SYSTEM_STORE_LOCAL_MACHINE; - //delete store + // delete store IntPtr hCertStore = Security.NativeMethods.CertOpenStore( Security.NativeMethods.CertOpenStoreProvider.CERT_STORE_PROV_SYSTEM, Security.NativeMethods.CertOpenStoreEncodingType.X509_ASN_ENCODING, @@ -1776,7 +1736,7 @@ private void RemoveCertStore(string storeName, bool fDeleteKey, string sourcePat } else { - string message = String.Format( + string message = string.Format( CultureInfo.CurrentCulture, CertificateProviderStrings.RemoveStoreTemplate, storeName); @@ -1786,18 +1746,13 @@ private void RemoveCertStore(string storeName, bool fDeleteKey, string sourcePat } /// /// Delete the a single cert from the store; if -DeleteKey is specified, we also delete - /// the associated private key + /// the associated private key. /// - /// - /// an X509Certificate2 object - /// - /// boolean to specify whether or not to delete private key - /// - /// machine context or user - /// - /// source path - /// - /// no return + /// An X509Certificate2 object. + /// Boolean to specify whether or not to delete private key. + /// Machine context or user. + /// Source path. + /// No return. private void RemoveCertItem(X509Certificate2 cert, bool fDeleteKey, bool fMachine, string sourcePath) { if (cert != null) @@ -1812,7 +1767,7 @@ private void RemoveCertItem(X509Certificate2 cert, bool fDeleteKey, bool fMachin action = CertificateProviderStrings.Action_Remove; } - string resource = String.Format( + string resource = string.Format( CultureInfo.CurrentCulture, CertificateProviderStrings.RemoveItemTemplate, sourcePath); @@ -1826,23 +1781,18 @@ private void RemoveCertItem(X509Certificate2 cert, bool fDeleteKey, bool fMachin /// /// Delete the cert from the store; if -DeleteKey is specified, we also delete - /// the associated private key + /// the associated private key. /// - /// - /// an X509Certificate2 object - /// - /// boolean to specify whether or not to delete private key - /// - /// machine context or user - /// - /// source path - /// - /// no return + /// An X509Certificate2 object. + /// Boolean to specify whether or not to delete private key. + /// Machine context or user. + /// Source path. + /// No return. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")] private void DoRemove(X509Certificate2 cert, bool fDeleteKey, bool fMachine, string sourcePath) { - //get CERT_KEY_PROV_INFO_PROP_ID + // get CERT_KEY_PROV_INFO_PROP_ID int provSize = 0; IntPtr pProvInfo = IntPtr.Zero; bool fHasPrivateKey = false; @@ -1851,7 +1801,7 @@ private void DoRemove(X509Certificate2 cert, bool fDeleteKey, bool fMachine, str { if (fDeleteKey) { - //it is fine if below call fails + // it is fine if below call fails if (Security.NativeMethods.CertGetCertificateContextProperty( cert.Handle, Security.NativeMethods.CertPropertyId.CERT_KEY_PROV_INFO_PROP_ID, @@ -1872,15 +1822,15 @@ private void DoRemove(X509Certificate2 cert, bool fDeleteKey, bool fMachine, str if (!fHasPrivateKey) { - //raise a verbose message - //we should not use WriteWarning here + // raise a verbose message + // we should not use WriteWarning here string verboseNoPrivatekey = CertificateProviderStrings.VerboseNoPrivateKey; WriteVerbose(verboseNoPrivatekey); } } - //do remove certificate - //should not use the original handle + // do remove certificate + // should not use the original handle if (!Security.NativeMethods.CertDeleteCertificateFromStore( Security.NativeMethods.CertDuplicateCertificateContext(cert.Handle))) @@ -1888,7 +1838,7 @@ private void DoRemove(X509Certificate2 cert, bool fDeleteKey, bool fMachine, str throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } - //commit the change to physical store + // commit the change to physical store if (sourcePath.Contains("UserDS")) { Security.NativeMethods.CERT_CONTEXT context = @@ -1897,9 +1847,9 @@ private void DoRemove(X509Certificate2 cert, bool fDeleteKey, bool fMachine, str CommitUserDS(context.hCertStore); } - //TODO: Log Cert Delete + // TODO: Log Cert Delete - //delete private key + // delete private key if (fDeleteKey && fHasPrivateKey) { DoDeleteKey(pProvInfo); @@ -1913,13 +1863,10 @@ private void DoRemove(X509Certificate2 cert, bool fDeleteKey, bool fMachine, str } /// - /// Commit store for UserDS store + /// Commit store for UserDS store. /// - /// - /// an IntPtr for store handle - /// - /// no return - /// + /// An IntPtr for store handle. + /// No return. private void CommitUserDS(IntPtr storeHandle) { if (!Security.NativeMethods.CertControlStore( @@ -1933,26 +1880,20 @@ private void CommitUserDS(IntPtr storeHandle) } /// - /// Delete the cert from the original store and add to the destination store + /// Delete the cert from the original store and add to the destination store. /// - /// - /// destination path - /// - /// an X509Certificate2 - /// - /// an X509NativeStore - /// - /// source path - /// - /// no return - /// + /// Destination path. + /// An X509Certificate2. + /// An X509NativeStore. + /// Source path. + /// No return. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")] private void DoMove(string destination, X509Certificate2 cert, X509NativeStore store, string sourcePath) { - IntPtr dupCert = IntPtr.Zero; //should not free this + IntPtr dupCert = IntPtr.Zero; // should not free this IntPtr outCert = IntPtr.Zero; - //duplicate cert first + // duplicate cert first dupCert = Security.NativeMethods.CertDuplicateCertificateContext(cert.Handle); if (dupCert == IntPtr.Zero) @@ -1975,10 +1916,10 @@ private void DoMove(string destination, X509Certificate2 cert, X509NativeStore s throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } - //TODO: log cert move + // TODO: log cert move } - //commit the change to physical store + // commit the change to physical store if (destination.Contains("UserDS")) { CommitUserDS(store.StoreHandle); @@ -1991,7 +1932,7 @@ private void DoMove(string destination, X509Certificate2 cert, X509NativeStore s CommitUserDS(context.hCertStore); } - //get the output object + // get the output object X509Certificate2 outObj = new X509Certificate2(outCert); string certName = GetCertName(outObj); string certPath = MakePath(destination, certName); @@ -1999,17 +1940,13 @@ private void DoMove(string destination, X509Certificate2 cert, X509NativeStore s } /// - /// fetches the store-location/store/certificate at the + /// Fetches the store-location/store/certificate at the /// specified path. /// - /// - /// path to the item - /// True if this is to only for an ItemExists call. Returns True / False. - /// - /// set to true if item exists and is a container - /// - /// item at the path - /// + /// Path to the item. + /// True if this is to only for an ItemExists call. Returns True / False. + /// Set to true if item exists and is a container. + /// Item at the path. private object GetItemAtPath(string path, bool test, out bool isContainer) { Utils.CheckArgForNull(path, "path"); @@ -2071,6 +2008,7 @@ private object GetItemAtPath(string path, bool test, out bool isContainer) { ThrowItemNotFound(path, CertificateProviderItem.StoreLocation); } + break; case 2: @@ -2091,7 +2029,7 @@ private object GetItemAtPath(string path, bool test, out bool isContainer) // // items at paths of depth 3 are certificates. // - string storePath = GetParentPath(path, ""); + string storePath = GetParentPath(path, string.Empty); string[] storePathElements = GetPathElements(storePath); // @@ -2129,6 +2067,7 @@ private object GetItemAtPath(string path, bool test, out bool isContainer) { item = new X509Certificate2(certContext); } + store.FreeCert(certContext); break; @@ -2146,24 +2085,20 @@ private object GetItemAtPath(string path, bool test, out bool isContainer) } return item; - } // GetItem + } /// /// Gets the child items of a given store, or location. /// - /// /// /// The full path of the store or location to enumerate. /// - /// /// /// If true, recursively enumerates the child items as well. /// - /// /// /// Path is null or empty. /// - /// /// /// This exception can be thrown if any cryptographic error occurs. /// It is not possible to know exactly what went wrong. @@ -2174,7 +2109,6 @@ private object GetItemAtPath(string path, bool test, out bool isContainer) /// -- certificate password mismatch /// -- etc /// - /// protected override void GetChildItems(string path, bool recurse) { path = NormalizePath(path); @@ -2185,20 +2119,16 @@ protected override void GetChildItems(string path, bool recurse) /// /// Gets the child names of a given store, or location. /// - /// /// /// The full path of the store or location to enumerate. /// - /// /// /// Determines if all containers should be returned or only those containers that match the /// filter(s). /// - /// /// /// Path is null or empty. /// - /// /// /// This exception can be thrown if any cryptographic error occurs. /// It is not possible to know exactly what went wrong. @@ -2209,30 +2139,25 @@ protected override void GetChildItems(string path, bool recurse) /// -- certificate password mismatch /// -- etc /// - /// protected override void GetChildNames( string path, ReturnContainers returnContainers) { path = NormalizePath(path); GetChildItemsOrNames(path, false, returnContainers, true, GetFilter()); - } // GetChildNames - + } /// /// Determines if the item at the specified path is a store /// or location. /// - /// /// /// True if the item at the specified path is a store or location. /// False otherwise. /// - /// /// /// Path is null or empty. /// - /// /// /// This exception can be thrown if any cryptographic error occurs. /// It is not possible to know exactly what went wrong. @@ -2243,7 +2168,6 @@ protected override void GetChildItems(string path, bool recurse) /// -- certificate password mismatch /// -- etc /// - /// protected override bool IsItemContainer(string path) { path = NormalizePath(path); @@ -2269,7 +2193,7 @@ protected override bool IsItemContainer(string path) s_tracer.WriteLine("result = {0}", isContainer); return isContainer; - } // IsItemContainer + } /// /// Gets the dynamic parameters for get-item on the Certificate @@ -2277,17 +2201,14 @@ protected override bool IsItemContainer(string path) /// "CodeSigning," that returns only certificates good for signing /// code or scripts. /// - /// /// /// If the path was specified on the command line, this is the path /// to the item for which to get the dynamic parameters. /// - /// /// /// An object that has properties and fields decorated with /// parsing attributes similar to a cmdlet class. /// - /// protected override object GetItemDynamicParameters(string path) { return new CertificateProviderCodeSigningDynamicParameters(); @@ -2299,16 +2220,13 @@ protected override object GetItemDynamicParameters(string path) /// "CodeSigning," that returns only certificates good for signing /// code or scripts. /// - /// /// /// If the path was specified on the command line, this is the path /// to the item for which to get the dynamic parameters. /// - /// /// /// Ignored. /// - /// /// /// An object that has properties and fields decorated with /// parsing attributes similar to a cmdlet class. @@ -2326,24 +2244,15 @@ protected override object GetChildItemsDynamicParameters(string path, bool recur /// Helper function to get store-location/store/cert at /// the specified path. /// - /// - /// path to the item - /// - /// whether we need to recursively find all - /// + /// Path to the item. + /// Whether we need to recursively find all. /// /// Determines if all containers should be returned or only those containers that match the /// filter(s). /// - /// - /// whether we only need the names - /// - /// filter info - /// - /// Does not return a value - /// - /// - /// + /// Whether we only need the names. + /// Filter info. + /// Does not return a value. private void GetChildItemsOrNames( string path, bool recurse, @@ -2404,6 +2313,7 @@ protected override object GetChildItemsDynamicParameters(string path, bool recur { WriteItemObject(thingToReturn, l.LocationName, true); } + childPath = l.LocationName; if (recurse) { @@ -2448,34 +2358,24 @@ protected override object GetChildItemsDynamicParameters(string path, bool recur } /// - /// get the name of the specified certificate + /// Get the name of the specified certificate. /// - /// - /// - /// - /// cert name - /// + /// + /// Cert name . /// we use Thumbprint as the name - /// private static string GetCertName(X509Certificate2 cert) { return cert.Thumbprint; } /// - /// Get cert objects or their name at the specified path + /// Get cert objects or their name at the specified path. /// - /// - /// path to cert - /// - /// path elements - /// - /// whether we should return only the names (instead of objects) - /// - /// filter info - /// - /// Does not return a value - /// + /// Path to cert. + /// Path elements. + /// Whether we should return only the names (instead of objects). + /// Filter info. + /// Does not return a value. private void GetCertificatesOrNames(string path, string[] pathElements, bool returnNames, @@ -2515,20 +2415,19 @@ private static string GetCertName(X509Certificate2 cert) PSObject myPsObj = new PSObject(cert); thingToReturn = (object)myPsObj; } + WriteItemObject(thingToReturn, certPath, false); } + certContext = store.GetNextCert(certContext); } } /// - /// get X509StoreLocation object at path + /// Get X509StoreLocation object at path. /// - /// - /// - /// - /// X509StoreLocation object - /// + /// + /// X509StoreLocation object. private X509StoreLocation GetStoreLocation(string path) { // @@ -2547,16 +2446,12 @@ private X509StoreLocation GetStoreLocation(string path) } /// - /// get the X509NativeStore object at path + /// Get the X509NativeStore object at path. /// - /// - /// path to store - /// True if this should be a test for path existence. Returns True or False - /// - /// path elements - /// - /// X509NativeStore object - /// + /// Path to store. + /// True if this should be a test for path existence. Returns True or False. + /// Path elements. + /// X509NativeStore object. private X509NativeStore GetStore(string path, bool test, string[] pathElements) { X509StoreLocation location = GetStoreLocation(pathElements[0]); @@ -2578,18 +2473,13 @@ private X509NativeStore GetStore(string path, bool test, string[] pathElements) } /// - /// gets the X509NativeStore at the specified path. + /// Gets the X509NativeStore at the specified path. /// Adds to cache if not already there. /// - /// - /// path to the store - /// - /// name of store (path leaf element) - /// - /// location of store (CurrentUser or LocalMachine) - /// - /// X509NativeStore object - /// + /// Path to the store. + /// Name of store (path leaf element). + /// Location of store (CurrentUser or LocalMachine). + /// X509NativeStore object. private X509NativeStore GetStore(string storePath, string storeName, X509StoreLocation storeLocation) @@ -2598,10 +2488,11 @@ private X509NativeStore GetStore(string path, bool test, string[] pathElements) { ThrowItemNotFound(storePath, CertificateProviderItem.Store); } + if (s_storeCache != null) { if (s_storeCache.Location != storeLocation || - !String.Equals( + !string.Equals( s_storeCache.StoreName, storeName, StringComparison.OrdinalIgnoreCase)) @@ -2619,21 +2510,13 @@ private X509NativeStore GetStore(string path, bool test, string[] pathElements) } /// - /// gets X509NativeStore objects or their name at the specified path. + /// Gets X509NativeStore objects or their name at the specified path. /// - /// - /// path to the store - /// - /// recursively return all items if true - /// - /// - /// - /// filter info - /// - /// Does not return a value - /// - /// - /// + /// Path to the store. + /// Recursively return all items if true. + /// + /// Filter info. + /// Does not return a value. private void GetStoresOrNames( string path, bool recurse, @@ -2734,6 +2617,7 @@ private CertificateFilterInfo GetFilter() } } } + return filter; } @@ -2745,6 +2629,7 @@ private bool IncludeArchivedCerts() { includeArchivedCerts = true; } + return includeArchivedCerts; } @@ -2771,6 +2656,7 @@ private bool IncludeArchivedCerts() { return true; } + break; case CertificatePurpose.DocumentEncryption: @@ -2778,6 +2664,7 @@ private bool IncludeArchivedCerts() { return true; } + break; default: @@ -2819,7 +2706,7 @@ private static void AddItemToCache(string path, object item) #region ICmdletProviderSupportsHelp Members /// - /// Get provider-specific help + /// Get provider-specific help. /// /// /// Name of help item or cmdlet for which user has requested help @@ -2840,18 +2727,18 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) string noun = null; try { - if (!String.IsNullOrEmpty(helpItemName)) + if (!string.IsNullOrEmpty(helpItemName)) { CmdletInfo.SplitCmdletName(helpItemName, out verb, out noun); } else { - return String.Empty; + return string.Empty; } - if (String.IsNullOrEmpty(verb) || String.IsNullOrEmpty(noun)) + if (string.IsNullOrEmpty(verb) || string.IsNullOrEmpty(noun)) { - return String.Empty; + return string.Empty; } // @@ -2877,12 +2764,11 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) nsMgr.AddNamespace("msh", HelpCommentsParser.mshURI); nsMgr.AddNamespace("command", HelpCommentsParser.commandURI); - // Compose XPath query to select the appropriate node based on the cmdlet - string xpathQuery = String.Format( + string xpathQuery = string.Format( CultureInfo.InvariantCulture, HelpCommentsParser.ProviderHelpCommandXPath, - String.Empty, + string.Empty, verb, noun); @@ -2895,43 +2781,43 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) } catch (XmlException) { - return String.Empty; + return string.Empty; } catch (PathTooLongException) { - return String.Empty; + return string.Empty; } catch (IOException) { - return String.Empty; + return string.Empty; } catch (UnauthorizedAccessException) { - return String.Empty; + return string.Empty; } catch (NotSupportedException) { - return String.Empty; + return string.Empty; } catch (SecurityException) { - return String.Empty; + return string.Empty; } catch (XPathException) { - return String.Empty; + return string.Empty; } - return String.Empty; + return string.Empty; } #endregion - } // CertificateProvider + } /// /// Defines a class to represent a store location in the certificate /// provider. The two possible store locations are CurrentUser and - /// LocalMachine + /// LocalMachine. /// public sealed class X509StoreLocation { @@ -2962,6 +2848,7 @@ public StoreLocation Location _location = value; } } + private StoreLocation _location = StoreLocation.CurrentUser; /// @@ -2972,7 +2859,7 @@ public Hashtable StoreNames get { Hashtable storeNames; - //always try to get new names + // always try to get new names storeNames = new Hashtable(StringComparer.OrdinalIgnoreCase); // since there is no managed support to obtain store names, @@ -2998,23 +2885,23 @@ public X509StoreLocation(StoreLocation location) /// /// Defines the type of EKU string - /// The structure contains friendly name and EKU oid + /// The structure contains friendly name and EKU oid. /// [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] public struct EnhancedKeyUsageRepresentation { /// - /// Localized friendly name of EKU + /// Localized friendly name of EKU. /// private string _friendlyName; /// - /// OID of EKU + /// OID of EKU. /// private string _oid; /// - /// constructor of an EnhancedKeyUsageRepresentation + /// Constructor of an EnhancedKeyUsageRepresentation. /// [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Oid")] @@ -3026,7 +2913,7 @@ public EnhancedKeyUsageRepresentation(string inputFriendlyName, string inputOid) } /// - /// value comparison + /// Value comparison. /// public bool Equals(EnhancedKeyUsageRepresentation keyUsage) { @@ -3036,7 +2923,7 @@ public bool Equals(EnhancedKeyUsageRepresentation keyUsage) { // OID strings only contain numbers and periods - if (String.Equals(_oid, keyUsage._oid, StringComparison.Ordinal)) + if (string.Equals(_oid, keyUsage._oid, StringComparison.Ordinal)) { match = true; } @@ -3045,11 +2932,12 @@ public bool Equals(EnhancedKeyUsageRepresentation keyUsage) { match = true; } + return match; } /// - /// get property of friendlyName + /// Get property of friendlyName. /// public string FriendlyName { @@ -3060,7 +2948,7 @@ public string FriendlyName } /// - /// get property of oid + /// Get property of oid. /// public string ObjectId { @@ -3071,25 +2959,25 @@ public string ObjectId } /// - /// get display string + /// Get display string. /// public override string ToString() { - return String.IsNullOrEmpty(_friendlyName) ? + return string.IsNullOrEmpty(_friendlyName) ? _oid : _friendlyName + " (" + _oid + ")"; } } /// - /// class for SendAsTrustedIssuer + /// Class for SendAsTrustedIssuer. /// [SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors")] public sealed class SendAsTrustedIssuerProperty { /// - /// get property of SendAsTrustedIssuer + /// Get property of SendAsTrustedIssuer. /// [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] @@ -3099,20 +2987,20 @@ public static bool ReadSendAsTrustedIssuerProperty(X509Certificate2 cert) if (DownLevelHelper.TrustedIssuerSupported()) { int propSize = 0; - //try to get the property - //it is fine if fail for not there + // try to get the property + // it is fine if fail for not there if (Security.NativeMethods.CertGetCertificateContextProperty( cert.Handle, Security.NativeMethods.CertPropertyId.CERT_SEND_AS_TRUSTED_ISSUER_PROP_ID, IntPtr.Zero, ref propSize)) { - //we have the property + // we have the property fHasProperty = true; } else { - //if fail + // if fail int error = Marshal.GetLastWin32Error(); if (error != Security.NativeMethods.CRYPT_E_NOT_FOUND) { @@ -3125,7 +3013,7 @@ public static bool ReadSendAsTrustedIssuerProperty(X509Certificate2 cert) } /// - /// set property of SendAsTrustedIssuer + /// Set property of SendAsTrustedIssuer. /// [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] @@ -3143,27 +3031,27 @@ public static void WriteSendAsTrustedIssuerProperty(X509Certificate2 cert, strin { if (certPath != null) { - //try to open the store and get the cert out - //in case the store handle is already released + // try to open the store and get the cert out + // in case the store handle is already released string[] pathElements = GetPathElements(certPath); - //certpath is in the format: Microsoft.Powershell.Security\ - //Certificate::CurrentUser(LocalMachine)\my\HashID - //obtained pathElements[0] is Microsoft.Powershell.Security - //obtained pathElements[1] is Certificate::CurrentUser - //obtained pathElements[2] is MY - //obtained pathElements[3] is HashID + // certpath is in the format: Microsoft.Powershell.Security\ + // Certificate::CurrentUser(LocalMachine)\my\HashID + // obtained pathElements[0] is Microsoft.Powershell.Security + // obtained pathElements[1] is Certificate::CurrentUser + // obtained pathElements[2] is MY + // obtained pathElements[3] is HashID - bool fUserContext = String.Equals(pathElements[1], "Certificate::CurrentUser", StringComparison.OrdinalIgnoreCase); + bool fUserContext = string.Equals(pathElements[1], "Certificate::CurrentUser", StringComparison.OrdinalIgnoreCase); X509StoreLocation storeLocation = new X509StoreLocation(fUserContext ? StoreLocation.CurrentUser : StoreLocation.LocalMachine); - //get certificate from the store pathElements[2] + // get certificate from the store pathElements[2] X509NativeStore store = null; store = new X509NativeStore(storeLocation, pathElements[2]); - store.Open(true); //including archival flag + store.Open(true); // including archival flag IntPtr certContext = store.GetCertByName(pathElements[3]); @@ -3174,13 +3062,13 @@ public static void WriteSendAsTrustedIssuerProperty(X509Certificate2 cert, strin } } - if (addProperty) //should add the property + if (addProperty) // should add the property { propertyPtr = Marshal.AllocHGlobal(Marshal.SizeOf(dataBlob)); Marshal.StructureToPtr(dataBlob, propertyPtr, false); } - //set property + // set property if (!Security.NativeMethods.CertSetCertificateContextProperty( certFromStore != null ? certFromStore.Handle : cert.Handle, Security.NativeMethods.CertPropertyId.CERT_SEND_AS_TRUSTED_ISSUER_PROP_ID, @@ -3205,7 +3093,7 @@ public static void WriteSendAsTrustedIssuerProperty(X509Certificate2 cert, strin } private static readonly char[] s_separators = new char[] { '/', '\\' }; - static private string[] GetPathElements(string path) + private static string[] GetPathElements(string path) { string[] allElts = path.Split(s_separators); string[] result = null; @@ -3214,7 +3102,7 @@ static private string[] GetPathElements(string path) foreach (string e in allElts) { - if ((e == ".") || (e == String.Empty)) + if ((e == ".") || (e == string.Empty)) { continue; } @@ -3238,16 +3126,15 @@ static private string[] GetPathElements(string path) } } /// - /// class for ekulist + /// Class for ekulist. /// public sealed class EnhancedKeyUsageProperty { private List _ekuList = new List(); - /// - /// get property of EKUList + /// Get property of EKUList. /// public List EnhancedKeyUsageList { @@ -3258,7 +3145,7 @@ public List EnhancedKeyUsageList } /// - /// constructor for EnhancedKeyUsageProperty + /// Constructor for EnhancedKeyUsageProperty. /// public EnhancedKeyUsageProperty(X509Certificate2 cert) { @@ -3268,7 +3155,7 @@ public EnhancedKeyUsageProperty(X509Certificate2 cert) if (extension.Oid.Value == "2.5.29.37") { X509EnhancedKeyUsageExtension ext = extension as X509EnhancedKeyUsageExtension; - if(ext != null) + if (ext != null) { OidCollection oids = ext.EnhancedKeyUsages; foreach (Oid oid in oids) @@ -3283,7 +3170,7 @@ public EnhancedKeyUsageProperty(X509Certificate2 cert) } /// - /// class for DNSNameList + /// Class for DNSNameList. /// public sealed class DnsNameProperty @@ -3294,7 +3181,7 @@ public sealed class DnsNameProperty private const string distinguishedNamePrefix = "CN="; /// - /// get property of DnsNameList + /// Get property of DnsNameList. /// public List DnsNameList { @@ -3305,7 +3192,7 @@ public List DnsNameList } /// - /// constructor for EkuList + /// Constructor for EkuList. /// public DnsNameProperty(X509Certificate2 cert) { @@ -3317,21 +3204,21 @@ public DnsNameProperty(X509Certificate2 cert) // extract DNS name from subject distinguish name // if it exists and does not contain a comma // a comma, indicates it is not a DNS name - if(cert.Subject.StartsWith(distinguishedNamePrefix, System.StringComparison.InvariantCultureIgnoreCase) && - cert.Subject.IndexOf(",",System.StringComparison.InvariantCulture)==-1) + if (cert.Subject.StartsWith(distinguishedNamePrefix, System.StringComparison.OrdinalIgnoreCase) && + !cert.Subject.Contains(',')) { name = cert.Subject.Substring(distinguishedNamePrefix.Length); try { unicodeName = idnMapping.GetUnicode(name); } - catch(System.ArgumentException) + catch (System.ArgumentException) { // The name is not valid punyCode, assume it's valid ascii. unicodeName = name; } - dnsName = new DnsNameRepresentation(name,unicodeName); + dnsName = new DnsNameRepresentation(name, unicodeName); _dnsList.Add(dnsName); } @@ -3341,26 +3228,26 @@ public DnsNameProperty(X509Certificate2 cert) if (extension.Oid.Value == "2.5.29.17") { string[] names = extension.Format(true).Split(Environment.NewLine); - foreach(string nameLine in names) + foreach (string nameLine in names) { // Get the part after 'DNS Name=' - if(nameLine.StartsWith(dnsNamePrefix, System.StringComparison.InvariantCultureIgnoreCase)) + if (nameLine.StartsWith(dnsNamePrefix, System.StringComparison.InvariantCultureIgnoreCase)) { name = nameLine.Substring(dnsNamePrefix.Length); try { unicodeName = idnMapping.GetUnicode(name); } - catch(System.ArgumentException) + catch (System.ArgumentException) { // The name is not valid punyCode, assume it's valid ascii. unicodeName = name; } - dnsName = new DnsNameRepresentation(name,unicodeName); + dnsName = new DnsNameRepresentation(name, unicodeName); // Only add the name if it is not the same as an existing name. - if(!_dnsList.Contains(dnsName)) + if (!_dnsList.Contains(dnsName)) { _dnsList.Add(dnsName); } @@ -3371,9 +3258,8 @@ public DnsNameProperty(X509Certificate2 cert) } } - /// - /// downlevel helper function to determine if the OS is WIN8 and above + /// Downlevel helper function to determine if the OS is WIN8 and above. /// internal static class DownLevelHelper { @@ -3397,6 +3283,7 @@ internal static bool IsWin8AndAbove() s_isWin8Set = true; } + return s_isWin8; } @@ -3412,7 +3299,7 @@ internal static bool HashLookupSupported() } /// - /// Check in UI is allowed + /// Check in UI is allowed. /// internal static class DetectUIHelper { @@ -3486,20 +3373,20 @@ private static bool IsUIAllowed(PSHost host) } /// - /// container for helper functions that use pinvoke into crypt32.dll + /// Container for helper functions that use pinvoke into crypt32.dll. /// internal static class Crypt32Helpers { /// - /// lock that guards access to the following static members - /// -- storeNames + /// Lock that guards access to the following static members + /// -- storeNames. /// private static object s_staticLock = new object(); internal static List storeNames = new List(); /// - /// get a list of store names at the specified location + /// Get a list of store names at the specified location. /// [ArchitectureSensitive] internal static List GetStoreNamesAtLocation(StoreLocation location) @@ -3525,7 +3412,6 @@ internal static List GetStoreNamesAtLocation(StoreLocation location) Security.NativeMethods.CertEnumSystemStoreCallBackProto callBack = new Security.NativeMethods.CertEnumSystemStoreCallBackProto(CertEnumSystemStoreCallBack); - // Return a new list to avoid synchronization issues. List names = new List(); @@ -3544,16 +3430,15 @@ internal static List GetStoreNamesAtLocation(StoreLocation location) return names; } - /// - /// call back function used by CertEnumSystemStore + /// Call back function used by CertEnumSystemStore /// /// Currently, there is no managed support for enumerating store /// names on a machine. We use the win32 function CertEnumSystemStore() /// to get a list of stores for a given context. /// /// Each time this callback is called, we add the passed store name - /// to the list of stores + /// to the list of stores. /// internal static bool CertEnumSystemStoreCallBack(string storeName, DWORD dwFlagsNotUsed, diff --git a/src/Microsoft.PowerShell.Security/security/CmsCommands.cs b/src/Microsoft.PowerShell.Security/security/CmsCommands.cs index b93a55f5e087..e2ba38d4db44 100644 --- a/src/Microsoft.PowerShell.Security/security/CmsCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CmsCommands.cs @@ -1,16 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; -using System.Text; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Globalization; +using System.Management.Automation; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; -using System.Diagnostics.CodeAnalysis; -using System.Collections.ObjectModel; -using System.Collections.Generic; +using System.Text; namespace Microsoft.PowerShell.Commands { @@ -21,13 +19,12 @@ namespace Microsoft.PowerShell.Commands /// recipient and content supplied. /// [Cmdlet(VerbsSecurity.Protect, "CmsMessage", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=394373", DefaultParameterSetName = "ByContent")] - [OutputType(typeof(String))] + [OutputType(typeof(string))] public sealed class ProtectCmsMessageCommand : PSCmdlet { /// /// Gets or sets the recipient of the CMS Message. /// - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Parameter(Position = 0, Mandatory = true)] public CmsMessageRecipient[] To { @@ -45,6 +42,7 @@ public PSObject Content get; set; } + private PSDataCollection _inputObjects = new PSDataCollection(); /// @@ -66,6 +64,7 @@ public string LiteralPath get; set; } + private string _resolvedPath = null; /// @@ -77,26 +76,27 @@ public string OutFile get; set; } + private string _resolvedOutFile = null; /// - /// Validate / convert arguments + /// Validate / convert arguments. /// protected override void BeginProcessing() { // Validate Path - if (!String.IsNullOrEmpty(Path)) + if (!string.IsNullOrEmpty(Path)) { ProviderInfo provider = null; Collection resolvedPaths = GetResolvedProviderPathFromPSPath(Path, out provider); // Ensure the path is a single path from the file system provider if ((resolvedPaths.Count > 1) || - (!String.Equals(provider.Name, "FileSystem", StringComparison.OrdinalIgnoreCase))) + (!string.Equals(provider.Name, "FileSystem", StringComparison.OrdinalIgnoreCase))) { ErrorRecord error = new ErrorRecord( new ArgumentException( - String.Format(CultureInfo.InvariantCulture, + string.Format(CultureInfo.InvariantCulture, CmsCommands.FilePathMustBeFileSystemPath, Path)), "FilePathMustBeFileSystemPath", ErrorCategory.ObjectNotFound, provider); ThrowTerminatingError(error); @@ -105,7 +105,7 @@ protected override void BeginProcessing() _resolvedPath = resolvedPaths[0]; } - if (!String.IsNullOrEmpty(LiteralPath)) + if (!string.IsNullOrEmpty(LiteralPath)) { // Validate that the path exists SessionState.InvokeProvider.Item.Get(new string[] { LiteralPath }, false, true); @@ -113,7 +113,7 @@ protected override void BeginProcessing() } // Validate OutFile - if (!String.IsNullOrEmpty(OutFile)) + if (!string.IsNullOrEmpty(OutFile)) { _resolvedOutFile = GetUnresolvedProviderPathFromPSPath(OutFile); } @@ -126,14 +126,14 @@ protected override void BeginProcessing() /// protected override void ProcessRecord() { - if (String.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) { _inputObjects.Add(Content); } } /// - /// Encrypts and outputs the message + /// Encrypts and outputs the message. /// protected override void EndProcessing() { @@ -143,10 +143,10 @@ protected override void EndProcessing() { StringBuilder outputString = new StringBuilder(); - Collection output = System.Management.Automation.PowerShell.Create(). - AddCommand("Microsoft.PowerShell.Utility\\Out-String"). - AddParameter("Stream"). - Invoke(_inputObjects); + Collection output = System.Management.Automation.PowerShell.Create() + .AddCommand("Microsoft.PowerShell.Utility\\Out-String") + .AddParameter("Stream") + .Invoke(_inputObjects); foreach (PSObject outputObject in output) { @@ -173,7 +173,7 @@ protected override void EndProcessing() ThrowTerminatingError(terminatingError); } - if (String.IsNullOrEmpty(_resolvedOutFile)) + if (string.IsNullOrEmpty(_resolvedOutFile)) { WriteObject(encodedContent); } @@ -205,6 +205,7 @@ public string Content get; set; } + private StringBuilder _contentBuffer = new StringBuilder(); /// @@ -226,27 +227,27 @@ public string LiteralPath get; set; } - private string _resolvedPath = null; + private string _resolvedPath = null; /// - /// Validate / convert arguments + /// Validate / convert arguments. /// protected override void BeginProcessing() { // Validate Path - if (!String.IsNullOrEmpty(Path)) + if (!string.IsNullOrEmpty(Path)) { ProviderInfo provider = null; Collection resolvedPaths = GetResolvedProviderPathFromPSPath(Path, out provider); // Ensure the path is a single path from the file system provider if ((resolvedPaths.Count > 1) || - (!String.Equals(provider.Name, "FileSystem", StringComparison.OrdinalIgnoreCase))) + (!string.Equals(provider.Name, "FileSystem", StringComparison.OrdinalIgnoreCase))) { ErrorRecord error = new ErrorRecord( new ArgumentException( - String.Format(CultureInfo.InvariantCulture, + string.Format(CultureInfo.InvariantCulture, CmsCommands.FilePathMustBeFileSystemPath, Path)), "FilePathMustBeFileSystemPath", ErrorCategory.ObjectNotFound, provider); ThrowTerminatingError(error); @@ -255,7 +256,7 @@ protected override void BeginProcessing() _resolvedPath = resolvedPaths[0]; } - if (!String.IsNullOrEmpty(LiteralPath)) + if (!string.IsNullOrEmpty(LiteralPath)) { // Validate that the path exists SessionState.InvokeProvider.Item.Get(new string[] { LiteralPath }, false, true); @@ -270,7 +271,7 @@ protected override void BeginProcessing() /// protected override void ProcessRecord() { - if (String.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) { if (_contentBuffer.Length > 0) { @@ -282,14 +283,14 @@ protected override void ProcessRecord() } /// - /// Gets the CMS Message object + /// Gets the CMS Message object. /// protected override void EndProcessing() { string actualContent = null; // Read in the content - if (String.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) { actualContent = _contentBuffer.ToString(); } @@ -318,6 +319,7 @@ protected override void EndProcessing() { recipients.Add(recipient.RecipientIdentifier.Value); } + result.Properties.Add( new PSNoteProperty("Recipients", recipients)); result.Properties.Add( @@ -334,7 +336,7 @@ protected override void EndProcessing() /// message. /// [Cmdlet(VerbsSecurity.Unprotect, "CmsMessage", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=394374", DefaultParameterSetName = "ByWinEvent")] - [OutputType(typeof(String))] + [OutputType(typeof(string))] public sealed class UnprotectCmsMessageCommand : PSCmdlet { /// @@ -348,6 +350,7 @@ public string Content get; set; } + private StringBuilder _contentBuffer = new StringBuilder(); /// @@ -380,6 +383,7 @@ public string LiteralPath get; set; } + private string _resolvedPath = null; /// @@ -396,7 +400,6 @@ public SwitchParameter IncludeContext /// /// Gets or sets the recipient of the CMS Message. /// - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] [Parameter(Position = 1)] public CmsMessageRecipient[] To { @@ -405,23 +408,23 @@ public CmsMessageRecipient[] To } /// - /// Validate / convert arguments + /// Validate / convert arguments. /// protected override void BeginProcessing() { // Validate Path - if (!String.IsNullOrEmpty(Path)) + if (!string.IsNullOrEmpty(Path)) { ProviderInfo provider = null; Collection resolvedPaths = GetResolvedProviderPathFromPSPath(Path, out provider); // Ensure the path is a single path from the file system provider if ((resolvedPaths.Count > 1) || - (!String.Equals(provider.Name, "FileSystem", StringComparison.OrdinalIgnoreCase))) + (!string.Equals(provider.Name, "FileSystem", StringComparison.OrdinalIgnoreCase))) { ErrorRecord error = new ErrorRecord( new ArgumentException( - String.Format(CultureInfo.InvariantCulture, + string.Format(CultureInfo.InvariantCulture, CmsCommands.FilePathMustBeFileSystemPath, Path)), "FilePathMustBeFileSystemPath", ErrorCategory.ObjectNotFound, provider); ThrowTerminatingError(error); @@ -430,7 +433,7 @@ protected override void BeginProcessing() _resolvedPath = resolvedPaths[0]; } - if (!String.IsNullOrEmpty(LiteralPath)) + if (!string.IsNullOrEmpty(LiteralPath)) { // Validate that the path exists SessionState.InvokeProvider.Item.Get(new string[] { LiteralPath }, false, true); @@ -438,7 +441,6 @@ protected override void BeginProcessing() } } - /// /// Processes records from the input pipeline. /// For each input object, the command gets the information @@ -447,7 +449,7 @@ protected override void BeginProcessing() protected override void ProcessRecord() { // If we're process by content, collect it. - if (String.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) { if (_contentBuffer.Length > 0) { @@ -458,7 +460,7 @@ protected override void ProcessRecord() } // If we're processing event log records, decrypt those inline. - if (String.Equals("ByWinEvent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("ByWinEvent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) { string actualContent = EventLogRecord.Properties["Message"].Value.ToString(); string decrypted = Decrypt(actualContent); @@ -482,7 +484,7 @@ protected override void ProcessRecord() /// protected override void EndProcessing() { - if (String.Equals("ByWinEvent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("ByWinEvent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) { return; } @@ -490,7 +492,7 @@ protected override void EndProcessing() string actualContent = null; // Read in the content - if (String.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("ByContent", this.ParameterSetName, StringComparison.OrdinalIgnoreCase)) { actualContent = _contentBuffer.ToString(); } @@ -512,7 +514,7 @@ private string Decrypt(string actualContent) { ErrorRecord error = new ErrorRecord( new ArgumentException( - String.Format(CultureInfo.InvariantCulture, + string.Format(CultureInfo.InvariantCulture, CmsCommands.InputContainedNoEncryptedContentIncludeContext, "-IncludeContext")), "InputContainedNoEncryptedContentIncludeContext", ErrorCategory.ObjectNotFound, null); ThrowTerminatingError(error); @@ -527,6 +529,7 @@ private string Decrypt(string actualContent) { preContext = actualContent.Substring(0, startIndex); } + if (endIndex > -1) { postContext = actualContent.Substring(endIndex); @@ -571,6 +574,7 @@ private string Decrypt(string actualContent) { resultString = preContext + resultString; } + if (postContext != null) { resultString = resultString + postContext; diff --git a/src/Microsoft.PowerShell.Security/security/CredentialCommands.cs b/src/Microsoft.PowerShell.Security/security/CredentialCommands.cs index 1bc1d186d675..b3fa108afe48 100644 --- a/src/Microsoft.PowerShell.Security/security/CredentialCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CredentialCommands.cs @@ -1,11 +1,9 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Management.Automation; - namespace Microsoft.PowerShell.Commands { /// @@ -33,7 +31,6 @@ public sealed class GetCredentialCommand : PSCmdlet /// Gets or sets the underlying PSCredential of /// the instance. /// - /// [Parameter(Position = 0, ParameterSetName = credentialSet)] [ValidateNotNull] [Credential()] @@ -48,8 +45,10 @@ public sealed class GetCredentialCommand : PSCmdlet public string Message { get { return _message; } + set { _message = value; } } + private string _message = UtilsStrings.PromptForCredential_DefaultMessage; /// @@ -60,8 +59,10 @@ public string Message public string UserName { get { return _userName; } + set { _userName = value; } } + private string _userName = null; /// @@ -72,13 +73,15 @@ public string UserName public string Title { get { return _title; } + set { _title = value; } } + private string _title = UtilsStrings.PromptForCredential_DefaultCaption; /// /// Initializes a new instance of the GetCredentialCommand - /// class + /// class. /// public GetCredentialCommand() : base() { diff --git a/src/Microsoft.PowerShell.Security/security/ExecutionPolicyCommands.cs b/src/Microsoft.PowerShell.Security/security/ExecutionPolicyCommands.cs index 6720d3d9c894..73029997bfb0 100644 --- a/src/Microsoft.PowerShell.Security/security/ExecutionPolicyCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/ExecutionPolicyCommands.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. #region Using directives @@ -23,7 +22,7 @@ namespace Microsoft.PowerShell.Commands /// - Current-user Group Policy /// - Current session preference /// - Current user machine preference - /// - Local machine preference + /// - Local machine preference. /// [Cmdlet(VerbsCommon.Get, "ExecutionPolicy", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113315")] [OutputType(typeof(ExecutionPolicy))] @@ -36,8 +35,10 @@ public class GetExecutionPolicyCommand : PSCmdlet public ExecutionPolicyScope Scope { get { return _executionPolicyScope; } + set { _executionPolicyScope = value; _scopeSpecified = true; } } + private ExecutionPolicyScope _executionPolicyScope = ExecutionPolicyScope.LocalMachine; private bool _scopeSpecified = false; @@ -49,8 +50,10 @@ public ExecutionPolicyScope Scope public SwitchParameter List { get { return _list; } + set { _list = value; } } + private bool _list; /// @@ -101,8 +104,8 @@ protected override void BeginProcessing() { WriteObject(SecuritySupport.GetExecutionPolicy(shellId)); } - }//End BeginProcess() - }//End Class + } + } /// /// Defines the implementation of the 'Set-ExecutionPolicy' cmdlet. @@ -123,8 +126,10 @@ public class SetExecutionPolicyCommand : PSCmdlet public ExecutionPolicy ExecutionPolicy { get { return _executionPolicy; } + set { _executionPolicy = value; } } + private ExecutionPolicy _executionPolicy; /// @@ -134,8 +139,10 @@ public ExecutionPolicy ExecutionPolicy public ExecutionPolicyScope Scope { get { return _executionPolicyScope; } + set { _executionPolicyScope = value; } } + private ExecutionPolicyScope _executionPolicyScope = ExecutionPolicyScope.LocalMachine; /// @@ -149,11 +156,13 @@ public SwitchParameter Force { return _force; } + set { _force = value; } } + private SwitchParameter _force; /// @@ -207,7 +216,7 @@ protected override void ProcessRecord() if (ExecutionPolicy != ExecutionPolicy.Undefined) { string effectiveExecutionPolicy = SecuritySupport.GetExecutionPolicy(shellId).ToString(); - if (!String.Equals(effectiveExecutionPolicy, executionPolicy, StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(effectiveExecutionPolicy, executionPolicy, StringComparison.OrdinalIgnoreCase)) { string message = StringUtil.Format(ExecutionPolicyCommands.ExecutionPolicyOverridden, effectiveExecutionPolicy); string recommendedAction = ExecutionPolicyCommands.ExecutionPolicyOverriddenRecommendedAction; @@ -229,10 +238,10 @@ protected override void ProcessRecord() EtwLoggingStrings.ExecutionPolicyName, executionPolicy, null); #endif } - }//End ProcessRecord() + } // Determine if we should process this policy change -#if CORECLR //Seems that we cannot find if the cmdlet is executed interactive or through a script on CoreCLR +#if CORECLR // Seems that we cannot find if the cmdlet is executed interactive or through a script on CoreCLR private bool ShouldProcessPolicyChange(string localPreference) { return ShouldProcess(localPreference); @@ -331,5 +340,5 @@ private void OnAccessDeniedError(Exception exception) errorRecord.ErrorDetails = new ErrorDetails(message); ThrowTerminatingError(errorRecord); } - }//End Class -}//End namespace + } +} diff --git a/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs b/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs index c426e0d8ce46..376d25d356d3 100644 --- a/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs @@ -1,14 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; +using System.Globalization; using System.IO; using System.Management.Automation; +using System.Runtime.InteropServices; using System.Security; using System.Security.Cryptography; -using System.Runtime.InteropServices; -using System.Globalization; + using Dbg = System.Management.Automation; namespace Microsoft.PowerShell.Commands @@ -28,6 +28,7 @@ public abstract class SecureStringCommandBase : PSCmdlet protected SecureString SecureStringData { get { return _ss; } + set { _ss = value; } } @@ -40,7 +41,6 @@ protected SecureString SecureStringData /// Initializes a new instance of the SecureStringCommandBase /// class. /// - /// /// /// The command name deriving from this class /// @@ -118,7 +118,7 @@ public byte[] Key public sealed class ConvertFromSecureStringCommand : ConvertFromToSecureStringCommandBase { /// - /// Initializes a new instance of the ExportSecureStringCommand class + /// Initializes a new instance of the ExportSecureStringCommand class. /// public ConvertFromSecureStringCommand() : base("ConvertFrom-SecureString") { } @@ -174,7 +174,7 @@ protected override void ProcessRecord() { // The formatted string is Algorithm Version, // Initialization Vector, Encrypted Data - string dataPackage = String.Format( + string dataPackage = string.Format( System.Globalization.CultureInfo.InvariantCulture, "{0}|{1}|{2}", 2, @@ -199,7 +199,6 @@ protected override void ProcessRecord() } } - /// /// Defines the implementation of the 'ConvertTo-SecureString' cmdlet. /// This cmdlet imports a new SecureString from encrypted data -- @@ -222,7 +221,6 @@ public sealed class ConvertToSecureStringCommand : ConvertFromToSecureStringComm /// /// Gets or sets the unsecured string to be imported. /// - /// [Parameter(Position = 0, ValueFromPipeline = true, Mandatory = true)] public String String { @@ -236,13 +234,13 @@ public String String _s = value; } } + private string _s; /// /// Gets or sets the flag that marks the unsecured string as a plain /// text string. /// - /// [Parameter(Position = 1, ParameterSetName = "PlainText")] public SwitchParameter AsPlainText { @@ -256,13 +254,13 @@ public SwitchParameter AsPlainText _asPlainText = value; } } + private bool _asPlainText; /// /// Gets or sets the flag that will force the import of a plaintext /// unsecured string. /// - /// [Parameter(Position = 2, ParameterSetName = "PlainText")] public SwitchParameter Force { @@ -276,8 +274,8 @@ public SwitchParameter Force _force = value; } } - private bool _force; + private bool _force; /// /// Processes records from the input pipeline. diff --git a/src/Microsoft.PowerShell.Security/security/SignatureCommands.cs b/src/Microsoft.PowerShell.Security/security/SignatureCommands.cs index 94f8a8a6913b..96fd64f4473e 100644 --- a/src/Microsoft.PowerShell.Security/security/SignatureCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/SignatureCommands.cs @@ -1,21 +1,20 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; -using System.Management.Automation; -using System.Management.Automation.Internal; -using Dbg = System.Management.Automation.Diagnostics; -using System.Collections.Generic; using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Management.Automation; +using System.Management.Automation.Internal; using System.Management.Automation.Provider; +using System.Runtime.InteropServices; using System.Security; using System.Security.Cryptography.X509Certificates; -using System.Runtime.InteropServices; -using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; + +using Dbg = System.Management.Automation.Diagnostics; using DWORD = System.UInt32; @@ -44,6 +43,7 @@ public string[] FilePath _path = value; } } + private string[] _path; /// @@ -66,6 +66,7 @@ public string[] LiteralPath _isLiteralPath = true; } } + private bool _isLiteralPath = false; /// @@ -75,8 +76,10 @@ public string[] LiteralPath protected Signature Signature { get { return _signature; } + set { _signature = value; } } + private Signature _signature; /// @@ -97,10 +100,11 @@ public string[] SourcePathOrExtension _sourcePathOrExtension = value; } } + private string[] _sourcePathOrExtension; /// - /// File contents as a byte array + /// File contents as a byte array. /// [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByContent")] [ValidateNotNullOrEmpty] @@ -108,11 +112,13 @@ public string[] SourcePathOrExtension public byte[] Content { get { return _content; } + set { _content = value; } } + private byte[] _content; // @@ -124,7 +130,6 @@ public byte[] Content /// Initializes a new instance of the SignatureCommandsBase class, /// using the given command name. /// - /// /// /// The name of the command. /// @@ -284,7 +289,7 @@ protected override Signature PerformAction(string filePath) /// /// Gets the signature from the specified file contents. /// - /// The file type associated with the contents + /// The file type associated with the contents. /// /// The contents of the file on which to perform the action. /// @@ -328,6 +333,7 @@ public X509Certificate2 Certificate _certificate = value; } } + private X509Certificate2 _certificate; /// @@ -340,7 +346,6 @@ public X509Certificate2 Certificate /// /// Defaults to 'notroot'. /// - /// [Parameter(Mandatory = false)] [ValidateSet("signer", "notroot", "all")] public string IncludeChain @@ -355,6 +360,7 @@ public string IncludeChain _includeChain = value; } } + private string _includeChain = "notroot"; /// @@ -374,12 +380,14 @@ public string TimestampServer { if (value == null) { - value = String.Empty; + value = string.Empty; } + _timestampServer = value; } } - private string _timestampServer = ""; + + private string _timestampServer = string.Empty; /// /// Gets or sets the hash algorithm used for signing. @@ -399,6 +407,7 @@ public string HashAlgorithm _hashAlgorithm = value; } } + private string _hashAlgorithm = null; /// @@ -411,11 +420,13 @@ public SwitchParameter Force { return _force; } + set { _force = value; } } + private bool _force; /// @@ -468,7 +479,7 @@ protected override Signature PerformAction(string filePath) { // remember to reset the read-only attribute later readOnlyFileInfo = fInfo; - //Make sure the file is not read only + // Make sure the file is not read only fInfo.Attributes &= ~(FileAttributes.ReadOnly); } } @@ -540,7 +551,7 @@ protected override Signature PerformAction(string filePath) if (SecurityUtils.GetFileSize(filePath) < 4) { // Note that the message param comes first - string message = String.Format( + string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, UtilsStrings.FileSmallerThan4Bytes, filePath); @@ -564,7 +575,7 @@ protected override Signature PerformAction(string filePath) finally { // reset the read-only attribute - if (null != readOnlyFileInfo) + if (readOnlyFileInfo != null) { readOnlyFileInfo.Attributes |= FileAttributes.ReadOnly; } @@ -572,7 +583,7 @@ protected override Signature PerformAction(string filePath) } /// - /// Not implemented + /// Not implemented. /// protected override Signature PerformAction(string sourcePathOrExtension, byte[] content) { @@ -592,7 +603,7 @@ internal SigningOptionInfo(SigningOption o, string n) } /// - /// association between SigningOption.* values and the + /// Association between SigningOption.* values and the /// corresponding string names. /// private static readonly SigningOptionInfo[] s_sigOptionInfo = @@ -603,18 +614,15 @@ internal SigningOptionInfo(SigningOption o, string n) }; /// - /// get SigningOption value corresponding to a string name + /// Get SigningOption value corresponding to a string name. /// - /// - /// name of option - /// - /// SigningOption - /// + /// Name of option. + /// SigningOption. private static SigningOption GetSigningOption(string optionName) { foreach (SigningOptionInfo si in s_sigOptionInfo) { - if (String.Equals(optionName, si.optionName, + if (string.Equals(optionName, si.optionName, StringComparison.OrdinalIgnoreCase)) { return si.option; diff --git a/src/Microsoft.PowerShell.Security/security/Utils.cs b/src/Microsoft.PowerShell.Security/security/Utils.cs index 1e2c758f1d38..75481ff292f4 100644 --- a/src/Microsoft.PowerShell.Security/security/Utils.cs +++ b/src/Microsoft.PowerShell.Security/security/Utils.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.IO; @@ -14,15 +13,10 @@ namespace Microsoft.PowerShell internal static class SecurityUtils { /// - /// gets the size of a file + /// Gets the size of a file. /// - /// - /// path to file - /// - /// file size - /// - /// - /// + /// Path to file. + /// File size. internal static long GetFileSize(string filePath) { long size = 0; @@ -36,17 +30,11 @@ internal static long GetFileSize(string filePath) } /// - /// present a prompt for a SecureString data + /// Present a prompt for a SecureString data. /// - /// - /// ref to host ui interface - /// - /// prompt text - /// - /// user input as secure string - /// - /// - /// + /// Ref to host ui interface. + /// Prompt text. + /// user input as secure string. internal static SecureString PromptForSecureString(PSHostUserInterface hostUI, string prompt) { @@ -54,25 +42,17 @@ internal static long GetFileSize(string filePath) hostUI.Write(prompt); ss = hostUI.ReadLineAsSecureString(); - hostUI.WriteLine(""); + hostUI.WriteLine(string.Empty); return ss; } /// - /// /// - /// - /// resource string - /// - /// error identifier - /// - /// replacement params for resource string formatting - /// - /// - /// - /// - /// + /// Resource string. + /// Error identifier. + /// Replacement params for resource string formatting. + /// internal static ErrorRecord CreateFileNotFoundErrorRecord(string resourceStr, string errorId, @@ -97,17 +77,10 @@ internal static } /// - /// /// - /// - /// path that was not found - /// - /// error identifier - /// - /// ErrorRecord instance - /// - /// - /// + /// Path that was not found. + /// Error identifier. + /// ErrorRecord instance. internal static ErrorRecord CreatePathNotFoundErrorRecord(string path, string errorId) @@ -125,19 +98,12 @@ internal static } /// - /// Create an error record for 'operation not supported' condition + /// Create an error record for 'operation not supported' condition. /// - /// - /// resource string - /// - /// error identifier - /// - /// replacement params for resource string formatting - /// - /// - /// - /// - /// + /// Resource string. + /// Error identifier. + /// Replacement params for resource string formatting. + /// internal static ErrorRecord CreateNotSupportedErrorRecord(string resourceStr, string errorId, @@ -157,19 +123,12 @@ internal static return er; } - /// - /// Create an error record for 'operation not supported' condition + /// Create an error record for 'operation not supported' condition. /// - /// - /// exception to include in ErrorRecord - /// - /// error identifier - /// - /// - /// - /// - /// + /// Exception to include in ErrorRecord. + /// Error identifier. + /// internal static ErrorRecord CreateInvalidArgumentErrorRecord(Exception e, string errorId) @@ -183,31 +142,24 @@ internal static return er; } - /// - /// convert the specified provider path to a provider path + /// Convert the specified provider path to a provider path /// and make sure that all of the following is true: /// -- it represents a FileSystem path /// -- it points to a file - /// -- the file exists + /// -- the file exists. /// - /// - /// cmdlet instance - /// - /// provider path - /// + /// Cmdlet instance. + /// Provider path. /// /// filesystem path if all conditions are true, /// null otherwise /// - /// - /// - /// internal static string GetFilePathOfExistingFile(PSCmdlet cmdlet, string path) { string resolvedProviderPath = cmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path); - if (Utils.NativeFileExists(resolvedProviderPath)) + if (File.Exists(resolvedProviderPath)) { return resolvedProviderPath; } @@ -218,4 +170,3 @@ internal static } } } - diff --git a/src/Microsoft.PowerShell.Security/security/certificateproviderexceptions.cs b/src/Microsoft.PowerShell.Security/security/certificateproviderexceptions.cs index 222cdc334721..4eb3838f5ea7 100644 --- a/src/Microsoft.PowerShell.Security/security/certificateproviderexceptions.cs +++ b/src/Microsoft.PowerShell.Security/security/certificateproviderexceptions.cs @@ -1,7 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #if !UNIX -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ using System; using System.Runtime.Serialization; @@ -57,7 +57,6 @@ public CertificateProviderItemNotFoundException(string message) : base(message) /// /// The serialization information. /// - /// /// /// The streaming context. /// @@ -132,7 +131,6 @@ public CertificateNotFoundException(string message) /// /// The serialization information. /// - /// /// /// The streaming context. /// @@ -207,7 +205,6 @@ public CertificateStoreNotFoundException(string message) /// /// The serialization information. /// - /// /// /// The streaming context. /// @@ -282,7 +279,6 @@ public CertificateStoreLocationNotFoundException(string message) /// /// The serialization information. /// - /// /// /// The streaming context. /// diff --git a/src/Microsoft.PowerShell.Security/singleshell/installer/MshSecurityMshSnapin.cs b/src/Microsoft.PowerShell.Security/singleshell/installer/MshSecurityMshSnapin.cs index 7f884b13f966..1460cb8a1843 100644 --- a/src/Microsoft.PowerShell.Security/singleshell/installer/MshSecurityMshSnapin.cs +++ b/src/Microsoft.PowerShell.Security/singleshell/installer/MshSecurityMshSnapin.cs @@ -1,6 +1,5 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. using System; using System.Collections; @@ -8,22 +7,20 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.Configuration.Install; -using System.Reflection; -using Microsoft.Win32; using System.IO; using System.Management.Automation; +using System.Reflection; + +using Microsoft.Win32; namespace Microsoft.PowerShell { /// - /// /// MshSecurityMshSnapin (or MshSecurityMshSnapinInstaller) is a class for facilitating registry /// of necessary information for monad security mshsnapin. /// - /// This class will be built with monad security dll - /// + /// This class will be built with monad security dll. /// - /// [RunInstaller(true)] public sealed class PSSecurityPSSnapIn : PSSnapIn { diff --git a/src/Microsoft.WSMan.Management/ConfigProvider.cs b/src/Microsoft.WSMan.Management/ConfigProvider.cs index f2a21a1e34e4..f04c932e71fe 100644 --- a/src/Microsoft.WSMan.Management/ConfigProvider.cs +++ b/src/Microsoft.WSMan.Management/ConfigProvider.cs @@ -1,39 +1,40 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.Collections.Generic; using System.Collections; -using System.Text; -using System.Management.Automation; -using System.Management.Automation.Provider; +using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Xml; -using System.Xml.XPath; -using System.Text.RegularExpressions; -using System.IO; -using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Provider; +using System.Runtime.InteropServices; using System.Security; using System.ServiceProcess; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.XPath; namespace Microsoft.WSMan.Management { - /// /// WsMan Provider. /// [CmdletProvider(WSManStringLiterals.ProviderName, ProviderCapabilities.Credentials)] public sealed partial class WSManConfigProvider : NavigationCmdletProvider, ICmdletProviderSupportsHelp { - //Plugin Name Storage + // Plugin Name Storage private PSObject objPluginNames = null; + private ServiceController winrmServiceController; + /// /// Determines if Set-Item user input type validation is required or not. /// It is True by default, Clear-Item will set it to false so that it can - /// pass Empty String as value for Set-Item. + /// pass Empty string as value for Set-Item. /// private bool clearItemIsCalled = false; @@ -60,16 +61,17 @@ public sealed partial class WSManConfigProvider : NavigationCmdletProvider, ICmd /// string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) { - //Get the leaf node from the path for which help is requested. + // Get the leaf node from the path for which help is requested. int ChildIndex = path.LastIndexOf("\\", StringComparison.OrdinalIgnoreCase); if (ChildIndex == -1) { - //Means we are at host level, where no new-item is supported. Return empty string. - return String.Empty; + // Means we are at host level, where no new-item is supported. Return empty string. + return string.Empty; } - String child = path.Substring(ChildIndex + 1); - //We only return help for the below set of 5 commands, not for any other case. + string child = path.Substring(ChildIndex + 1); + + // We only return help for the below set of 5 commands, not for any other case. switch (helpItemName) { case "New-Item": @@ -79,14 +81,14 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) case "Remove-Item": break; default: - return String.Empty; + return string.Empty; } // Load the help file from the current UI culture subfolder of the module's root folder XmlDocument document = new XmlDocument(); CultureInfo culture = Host.CurrentUICulture; - String providerBase = this.ProviderInfo.PSSnapIn != null ? this.ProviderInfo.PSSnapIn.ApplicationBase : this.ProviderInfo.Module.ModuleBase; // "\windows\system32\WindowsPowerShell\v1.0" - String helpFile = null; + string providerBase = this.ProviderInfo.PSSnapIn != null ? this.ProviderInfo.PSSnapIn.ApplicationBase : this.ProviderInfo.Module.ModuleBase; // "\windows\system32\WindowsPowerShell\v1.0" + string helpFile = null; do { @@ -100,13 +102,14 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) break; } } + culture = culture.Parent; } while (culture != culture.Parent); if (helpFile == null) { - //Can't find help file. Return empty string - return String.Empty; + // Can't find help file. Return empty string + return string.Empty; } try @@ -118,35 +121,35 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) document.Load(reader); } } - catch(XmlException) + catch (XmlException) { - return String.Empty; + return string.Empty; } - catch(PathTooLongException) + catch (PathTooLongException) { - return String.Empty; + return string.Empty; } - catch(IOException) + catch (IOException) { - return String.Empty; + return string.Empty; } - catch(UnauthorizedAccessException) + catch (UnauthorizedAccessException) { - return String.Empty; + return string.Empty; } - catch(NotSupportedException) + catch (NotSupportedException) { - return String.Empty; + return string.Empty; } - catch(SecurityException) + catch (SecurityException) { - return String.Empty; + return string.Empty; } // Add the "msh" and "command" namespaces from the MAML schema XmlNamespaceManager nsMgr = new XmlNamespaceManager(document.NameTable); // XPath 1.0 associates empty prefix with "null" namespace; must use non-empty prefix for default namespace. - // This will not work: nsMgr.AddNamespace("", "http://msh"); + // This will not work: nsMgr.AddNamespace(string.Empty, "http://msh"); nsMgr.AddNamespace("msh", "http://msh"); nsMgr.AddNamespace("command", "http://schemas.microsoft.com/maml/dev/command/2004/10"); @@ -154,7 +157,7 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) string verb = helpItemName.Split('-')[0]; string noun = helpItemName.Substring(helpItemName.IndexOf('-') + 1); - //Compose XPath query to select the appropriate node based on the verb, noun and id + // Compose XPath query to select the appropriate node based on the verb, noun and id string xpathQuery = "/msh:helpItems/msh:providerHelp/msh:CmdletHelpPaths/msh:CmdletHelpPath[@id='" + child + "' or @ID='" + child + "']/command:command/command:details[command:verb='" + verb + "' and command:noun='" + noun + "']"; // Execute the XPath query and if the command was found, return its MAML snippet @@ -163,23 +166,23 @@ string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) { result = document.SelectSingleNode(xpathQuery, nsMgr); } - catch(XPathException) + catch (XPathException) { - return String.Empty; + return string.Empty; } + if (result != null) { return result.ParentNode.OuterXml; } - return String.Empty; + + return string.Empty; } #endregion - #region DriveCmdletProvider /// - /// /// /// /// @@ -190,7 +193,7 @@ protected override PSDriveInfo NewDrive(PSDriveInfo drive) return null; } - if (String.IsNullOrEmpty(drive.Root) == false) + if (string.IsNullOrEmpty(drive.Root) == false) { AssertError(helper.GetResourceMsgFromResourcetext("NewDriveRootDoesNotExist"), false); return null; @@ -200,19 +203,19 @@ protected override PSDriveInfo NewDrive(PSDriveInfo drive) } /// - /// Adds the required drive + /// Adds the required drive. /// /// protected override Collection InitializeDefaultDrives() { Collection drives = new Collection(); - drives.Add(new PSDriveInfo(WSManStringLiterals.rootpath, ProviderInfo, String.Empty, + drives.Add(new PSDriveInfo(WSManStringLiterals.rootpath, ProviderInfo, string.Empty, helper.GetResourceMsgFromResourcetext("ConfigStorage"), null)); return drives; } /// - /// Removes the required drive + /// Removes the required drive. /// /// protected override PSDriveInfo RemoveDrive(PSDriveInfo drive) @@ -221,7 +224,6 @@ protected override PSDriveInfo RemoveDrive(PSDriveInfo drive) return drive; } - #endregion #region ItemCmdletProvider @@ -235,10 +237,9 @@ protected override PSDriveInfo RemoveDrive(PSDriveInfo drive) /// protected override string GetChildName(string path) { - - string result = String.Empty; + string result = string.Empty; int separatorIndex = path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator); - string hostname = String.Empty; + string hostname = string.Empty; if (separatorIndex == -1) { result = path; @@ -251,7 +252,6 @@ protected override string GetChildName(string path) } return GetCorrectCaseOfName(result, hostname, path); - } /// @@ -270,7 +270,7 @@ protected override string MakePath(string parent, string child) child = child.Remove(child.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); } - //For Listeners only ... should remove Listener from listener\listener but not from listener_[Hashcode] + // For Listeners only ... should remove Listener from listener\listener but not from listener_[Hashcode] if (parent.Equals(WSManStringLiterals.containerListener, StringComparison.OrdinalIgnoreCase) && child.StartsWith(parent, StringComparison.OrdinalIgnoreCase)) { if (!child.StartsWith(parent + "_", StringComparison.OrdinalIgnoreCase)) @@ -278,6 +278,7 @@ protected override string MakePath(string parent, string child) child = child.Remove(0, parent.Length); } } + string path = string.Empty; string ChildName = string.Empty; string CorrectCaseChildName = string.Empty; @@ -289,11 +290,13 @@ protected override string MakePath(string parent, string child) { path = child; } + if (path.Length != 0) { ChildName = path.Substring(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator) + 1); CorrectCaseChildName = GetChildName(path); } + if (ChildName.Equals(CorrectCaseChildName, StringComparison.OrdinalIgnoreCase)) { if (child.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) @@ -306,13 +309,14 @@ protected override string MakePath(string parent, string child) child = CorrectCaseChildName; } } - String basepath = base.MakePath(parent, child); + + string basepath = base.MakePath(parent, child); return GetCorrectCaseOfPath(basepath); } /// /// Checks whether the path is Valid. - /// eg. winrm/config/client + /// eg. winrm/config/client. /// /// /// @@ -321,11 +325,10 @@ protected override bool IsValidPath(string path) bool result = false; result = CheckValidContainerOrPath(path); return result; - } /// - /// Check whether an Item Exist in the winrm configuration + /// Check whether an Item Exist in the winrm configuration. /// /// /// @@ -345,15 +348,15 @@ protected override bool ItemExists(string path) /// protected override bool HasChildItems(string path) { - string childname = String.Empty; - string strPathCheck = String.Empty; + string childname = string.Empty; + string strPathCheck = string.Empty; - if (path.Length == 0 && String.IsNullOrEmpty(childname)) + if (path.Length == 0 && string.IsNullOrEmpty(childname)) { return true; } - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); @@ -361,19 +364,20 @@ protected override bool HasChildItems(string path) if (path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) { - //Get the ChildName + // Get the ChildName childname = path.Substring(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator) + 1); } + Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); if (SessionObjCache.ContainsKey(path)) { return true; } - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); - //Chks the WinRM Service + // Chks the WinRM Service if (IsPathLocalMachine(host)) { if (!IsWSManServiceRunning()) @@ -382,16 +386,15 @@ protected override bool HasChildItems(string path) StartWSManService(Force); } } + string WsManURI = NormalizePath(path, host); - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { - //Gets the session object from the cache. + // Gets the session object from the cache. object sessionobj; SessionObjCache.TryGetValue(host, out sessionobj); - - /* WsMan Config Can be divided in to Four Fixed Regions to Check Whether it has Child Items. @@ -426,6 +429,7 @@ protected override bool HasChildItems(string path) { return true; } + ProcessCertMappingObjects(xmlCertificates, out CertificatesObjCache, out KeyCache); if (CertificatesObjCache.Count > 0) { @@ -435,9 +439,8 @@ protected override bool HasChildItems(string path) // 3. Plugin and its internal structure Checks else if (WsManURI.Contains(WSManStringLiterals.containerPlugin)) { - strPathCheck = strPathCheck + WSManStringLiterals.containerPlugin; - //Check for Plugin path + // Check for Plugin path XmlDocument xmlPlugins = FindResourceValue(sessionobj, WsManURI, null); string currentpluginname = string.Empty; int PluginCount = GetPluginNames(xmlPlugins, out objPluginNames, out currentpluginname, path); @@ -451,8 +454,8 @@ protected override bool HasChildItems(string path) { return false; } - } + strPathCheck = strPathCheck + WSManStringLiterals.DefaultPathSeparator + currentpluginname; if (path.EndsWith(strPathCheck, StringComparison.OrdinalIgnoreCase)) { @@ -468,6 +471,7 @@ protected override bool HasChildItems(string path) } } } + string filter = WsManURI + "?Name=" + currentpluginname; XmlDocument CurrentPluginXML = GetResourceValue(sessionobj, filter, null); ArrayList arrSecurities = null; @@ -476,11 +480,12 @@ protected override bool HasChildItems(string path) strPathCheck = strPathCheck + WSManStringLiterals.DefaultPathSeparator; if (path.EndsWith(strPathCheck + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { - if (null != arrResources && arrResources.Count > 0) + if (arrResources != null && arrResources.Count > 0) { return true; } } + if (path.EndsWith(strPathCheck + WSManStringLiterals.containerInitParameters, StringComparison.OrdinalIgnoreCase)) { if (arrInitParams != null && arrInitParams.Count > 0) @@ -488,6 +493,7 @@ protected override bool HasChildItems(string path) return true; } } + if (path.EndsWith(strPathCheck + WSManStringLiterals.containerQuotasParameters, StringComparison.OrdinalIgnoreCase)) { XmlNodeList nodeListForQuotas = CurrentPluginXML.GetElementsByTagName(WSManStringLiterals.containerQuotasParameters); @@ -499,6 +505,7 @@ protected override bool HasChildItems(string path) return false; } + if (arrResources != null) { foreach (PSObject objresource in arrResources) @@ -511,29 +518,31 @@ protected override bool HasChildItems(string path) { return true; } + strPathCheck = strPathCheck + sResourceDirName + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathCheck + WSManStringLiterals.containerSecurity)) { if (path.EndsWith(strPathCheck + WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase)) { - if (null != arrSecurities && arrSecurities.Count > 0) + if (arrSecurities != null && arrSecurities.Count > 0) { return true; } } + strPathCheck = strPathCheck + WSManStringLiterals.containerSecurity + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathCheck + WSManStringLiterals.containerSecurity + "_")) { - if (null == arrSecurities) + if (arrSecurities == null) { return false; } + foreach (PSObject security in arrSecurities) { string sSecurity = security.Properties["SecurityDIR"].Value.ToString(); if (path.EndsWith(sSecurity, StringComparison.OrdinalIgnoreCase)) return true; - } } } @@ -553,31 +562,30 @@ protected override bool HasChildItems(string path) return IsItemContainer(nodes); } } + return false; } } /// /// This cmdlet is used to get a particular item. - /// cd wsman:\localhost\client> Get-Item .\Auth + /// cd wsman:\localhost\client> Get-Item .\Auth. /// /// [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] protected override void GetItem(string path) { - string childname = string.Empty; - if (path.Length == 0 && String.IsNullOrEmpty(childname)) + if (path.Length == 0 && string.IsNullOrEmpty(childname)) { WriteItemObject(GetItemPSObjectWithTypeName(WSManStringLiterals.rootpath, WSManStringLiterals.ContainerChildValue, null, null, null, WsManElementObjectTypes.WSManConfigElement), WSManStringLiterals.rootpath, true); return; } - if (path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) { - //Get the ChildName + // Get the ChildName childname = path.Substring(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator) + 1); } else @@ -592,25 +600,26 @@ protected override void GetItem(string path) { WriteItemObject(GetItemPSObjectWithTypeName(childname, WSManStringLiterals.ContainerChildValue, null, null, "ComputerLevel", WsManElementObjectTypes.WSManConfigContainerElement), WSManStringLiterals.rootpath + WSManStringLiterals.DefaultPathSeparator + childname, true); } + return; } path = path.Substring(0, path.LastIndexOf(childname, StringComparison.OrdinalIgnoreCase)); - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); string uri = NormalizePath(path, host); - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { - //Gets the session object from the cache. + // Gets the session object from the cache. object sessionobj; SessionObjCache.TryGetValue(host, out sessionobj); XmlDocument xmlResource = FindResourceValue(sessionobj, uri, null); if (xmlResource == null) { return; } - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); @@ -645,10 +654,11 @@ protected override void GetItem(string path) strPathChk = strPathChk + WSManStringLiterals.containerPlugin + WSManStringLiterals.DefaultPathSeparator; string filter = uri + "?Name=" + currentpluginname; XmlDocument CurrentPluginXML = GetResourceValue(sessionobj, filter, null); - if (null == CurrentPluginXML) + if (CurrentPluginXML == null) { return; } + PSObject objPluginlevel = ProcessPluginConfigurationLevel(CurrentPluginXML, true); ArrayList arrSecurity = null; ArrayList arrResources = ProcessPluginResourceLevel(CurrentPluginXML, out arrSecurity); @@ -668,13 +678,15 @@ protected override void GetItem(string path) WriteItemObject(GetItemPSObjectWithTypeName(objPluginlevel.Properties[childname].Name, objPluginlevel.Properties[childname].Value.ToString(), null, null, null, WsManElementObjectTypes.WSManConfigLeafElement), path + WSManStringLiterals.DefaultPathSeparator + objPluginlevel.Properties[childname].Name, true); } } + strPathChk = strPathChk + currentpluginname + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathChk + WSManStringLiterals.containerResources)) { - if (null == arrResources) + if (arrResources == null) { return; } + if (path.EndsWith(strPathChk + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { foreach (PSObject p in arrResources) @@ -684,8 +696,10 @@ protected override void GetItem(string path) WriteItemObject(GetItemPSObjectWithTypeName(childname, WSManStringLiterals.ContainerChildValue, null, new string[] { "ResourceURI=" + p.Properties["ResourceUri"].Value.ToString() }, null, WsManElementObjectTypes.WSManConfigContainerElement), path + WSManStringLiterals.DefaultPathSeparator + childname, true); } } + return; } + strPathChk = strPathChk + WSManStringLiterals.containerResources + WSManStringLiterals.DefaultPathSeparator; int Sepindex = path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathChk.Length); string sResourceDirName = string.Empty; @@ -697,6 +711,7 @@ protected override void GetItem(string path) { sResourceDirName = path.Substring(strPathChk.Length, path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathChk.Length) - (strPathChk.Length)); } + if (path.Contains(strPathChk + sResourceDirName)) { if (path.EndsWith(strPathChk + sResourceDirName, StringComparison.OrdinalIgnoreCase)) @@ -714,18 +729,22 @@ protected override void GetItem(string path) { WriteItemObject(GetItemPSObjectWithTypeName(p.Properties[childname].Name, p.Properties[childname].TypeNameOfValue, p.Properties[childname].Value, null, null, WsManElementObjectTypes.WSManConfigLeafElement), path + WSManStringLiterals.DefaultPathSeparator + p.Properties[childname].Name, false); } + break; } } + return; } + strPathChk = strPathChk + sResourceDirName + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathChk + WSManStringLiterals.containerSecurity)) { - if (null == arrSecurity) + if (arrSecurity == null) { return; } + foreach (PSObject p in arrSecurity) { if (path.EndsWith(WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase)) @@ -743,13 +762,14 @@ protected override void GetItem(string path) } } } + return; } } } else if (path.EndsWith(host + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerPlugin + WSManStringLiterals.DefaultPathSeparator + currentpluginname + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerInitParameters, StringComparison.OrdinalIgnoreCase)) { - if (null != arrInitParams) + if (arrInitParams != null) { foreach (PSObject p in arrInitParams) { @@ -778,8 +798,8 @@ protected override void GetItem(string path) null, WsManElementObjectTypes.WSManConfigLeafElement); - String pathToAdd = - String.Format( + string pathToAdd = + string.Format( CultureInfo.InvariantCulture, "{0}{1}{2}", path, @@ -814,6 +834,7 @@ protected override void GetItem(string path) { mshObject = BuildHostLevelPSObjectArrayList(sessionobj, uri, false); } + if (mshObject != null) { if (mshObject.Properties[childname].Value.ToString().Equals(WSManStringLiterals.ContainerChildValue)) @@ -852,24 +873,22 @@ protected override void GetItem(string path) [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] protected override void SetItem(string path, object value) { - - if (null == value) + if (value == null) { throw new ArgumentException(helper.GetResourceMsgFromResourcetext("value")); } string ChildName = string.Empty; - if (path.Length == 0 && String.IsNullOrEmpty(ChildName)) + if (path.Length == 0 && string.IsNullOrEmpty(ChildName)) { AssertError(helper.GetResourceMsgFromResourcetext("SetItemNotSupported"), false); return; } - if (path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) { - //Get the ChildName + // Get the ChildName ChildName = path.Substring(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator) + 1); } else @@ -899,26 +918,26 @@ protected override void SetItem(string path, object value) // If validation is not required, that means Clear-Item cmdlet is called. // Clear-Item is not allowed on RunAsPassword, Admin should call Clear-Item RunAsUser // if he intends to disable RunAs on the Plugin. - if(String.Equals(ChildName, WSManStringLiterals.ConfigRunAsPasswordName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ChildName, WSManStringLiterals.ConfigRunAsPasswordName, StringComparison.OrdinalIgnoreCase)) { AssertError(helper.GetResourceMsgFromResourcetext("ClearItemOnRunAsPassword"), false); return; } } - string whatIfMessage = String.Format(CultureInfo.CurrentUICulture, helper.GetResourceMsgFromResourcetext("SetItemWhatIfAndConfirmText"), path, value); - if (!ShouldProcess(whatIfMessage, "", "")) + string whatIfMessage = string.Format(CultureInfo.CurrentUICulture, helper.GetResourceMsgFromResourcetext("SetItemWhatIfAndConfirmText"), path, value); + if (!ShouldProcess(whatIfMessage, string.Empty, string.Empty)) { return; } path = path.Substring(0, path.LastIndexOf(ChildName, StringComparison.OrdinalIgnoreCase)); - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); string uri = NormalizePath(path, host); - //Chk for Winrm Service + // Chk for Winrm Service if (IsPathLocalMachine(host)) { if (!IsWSManServiceRunning()) @@ -930,20 +949,21 @@ protected override void SetItem(string path, object value) bool settingPickedUpDynamically = false; - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { - //Gets the session object from the cache. + // Gets the session object from the cache. object sessionobj; Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); SessionObjCache.TryGetValue(host, out sessionobj); - List warningMessage = new List(); + List warningMessage = new List(); - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); } + string strPathChk = host + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathChk + WSManStringLiterals.containerListener)) { @@ -959,20 +979,23 @@ protected override void SetItem(string path, object value) { AssertError(helper.GetResourceMsgFromResourcetext("SetItemNotSupported"), false); } + try { XmlDocument xmlPlugins = FindResourceValue(sessionobj, uri, null); string currentpluginname = string.Empty; GetPluginNames(xmlPlugins, out objPluginNames, out currentpluginname, path); - if (String.IsNullOrEmpty(currentpluginname)) + if (string.IsNullOrEmpty(currentpluginname)) { if (!this.clearItemIsCalled) { // Don't need an error if ClearItem is called. AssertError(helper.GetResourceMsgFromResourcetext("ItemDoesNotExist"), false); } + return; } + string filter = uri + "?Name=" + currentpluginname; CurrentConfigurations pluginConfiguration = new CurrentConfigurations((IWSManSession)sessionobj); @@ -1016,9 +1039,9 @@ protected override void SetItem(string path, object value) if (WSManStringLiterals.ConfigRunAsPasswordName.Equals(ChildName, StringComparison.OrdinalIgnoreCase)) { - if(String.IsNullOrEmpty( + if (string.IsNullOrEmpty( pluginConfiguration.GetOneConfiguration( - String.Format( + string.Format( CultureInfo.InvariantCulture, "./attribute::{0}", WSManStringLiterals.ConfigRunAsUserName)))) @@ -1032,6 +1055,7 @@ protected override void SetItem(string path, object value) pluginConfiguration.UpdateOneConfiguration(".", ChildName, value.ToString()); } + strPathChk = strPathChk + currentpluginname + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathChk + WSManStringLiterals.containerResources)) { @@ -1039,8 +1063,8 @@ protected override void SetItem(string path, object value) { AssertError(helper.GetResourceMsgFromResourcetext("SetItemNotSupported"), false); return; - } + strPathChk = strPathChk + WSManStringLiterals.containerResources + WSManStringLiterals.DefaultPathSeparator; int Sepindex = path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathChk.Length); string sResourceDirName = string.Empty; @@ -1052,11 +1076,12 @@ protected override void SetItem(string path, object value) { sResourceDirName = path.Substring(strPathChk.Length, path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathChk.Length) - (strPathChk.Length)); } + if (path.Contains(strPathChk + sResourceDirName)) { if (path.EndsWith(strPathChk + sResourceDirName, StringComparison.OrdinalIgnoreCase)) { - if (null == arrResources) + if (arrResources == null) { return; } @@ -1071,7 +1096,7 @@ protected override void SetItem(string path, object value) { if (sResourceDirName.Equals(p.Properties["ResourceDir"].Value.ToString(), StringComparison.OrdinalIgnoreCase)) { - string xpathToUse = String.Format( + string xpathToUse = string.Format( CultureInfo.InvariantCulture, "{0}:{1}/{0}:{2}[attribute::{3}='{4}']", CurrentConfigurations.DefaultNameSpacePrefix, @@ -1092,6 +1117,7 @@ protected override void SetItem(string path, object value) } } } + strPathChk = strPathChk + sResourceDirName + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathChk + WSManStringLiterals.containerSecurity)) { @@ -1101,7 +1127,7 @@ protected override void SetItem(string path, object value) return; } - if (null == arrSecurity) + if (arrSecurity == null) { return; } @@ -1119,15 +1145,15 @@ protected override void SetItem(string path, object value) if (!Force) { string query = helper.GetResourceMsgFromResourcetext("ShouldContinueSecurityQuery"); - query = String.Format(CultureInfo.CurrentCulture, query, currentpluginname); + query = string.Format(CultureInfo.CurrentCulture, query, currentpluginname); if (!ShouldContinue(query, helper.GetResourceMsgFromResourcetext("ShouldContinueSecurityCaption"))) { return; } } - //NameSpace:Resources/NameSpace:Resource[@ResourceUri={''}]/NameSpace:Security[@Uri='{2}'] - string xpathToUse = String.Format( + // NameSpace:Resources/NameSpace:Resource[@ResourceUri={''}]/NameSpace:Security[@Uri='{2}'] + string xpathToUse = string.Format( CultureInfo.InvariantCulture, "{0}:{1}/{0}:{2}[@{6}='{7}']/{0}:{3}[@{4}='{5}']", CurrentConfigurations.DefaultNameSpacePrefix, @@ -1152,7 +1178,7 @@ protected override void SetItem(string path, object value) { if (p.Properties[ChildName] != null) { - string xpathToUse = String.Format( + string xpathToUse = string.Format( CultureInfo.InvariantCulture, "{0}:{1}/{0}:{2}[@{3}='{4}']", CurrentConfigurations.DefaultNameSpacePrefix, @@ -1169,7 +1195,7 @@ protected override void SetItem(string path, object value) } else if (path.EndsWith(strPathChk + WSManStringLiterals.containerQuotasParameters, StringComparison.OrdinalIgnoreCase)) { - string xpathToUse = String.Format( + string xpathToUse = string.Format( CultureInfo.InvariantCulture, "{0}:{1}", CurrentConfigurations.DefaultNameSpacePrefix, @@ -1187,7 +1213,7 @@ protected override void SetItem(string path, object value) } string pathForGlobalQuota = - String.Format( + string.Format( CultureInfo.InvariantCulture, @"{0}:\{1}\{2}\{3}", WSManStringLiterals.rootpath, @@ -1195,12 +1221,12 @@ protected override void SetItem(string path, object value) WSManStringLiterals.containerShell, adjustedChileName); - warningMessage.Add(String.Format(helper.GetResourceMsgFromResourcetext("SetItemWarnigForPPQ"), pathForGlobalQuota)); + warningMessage.Add(string.Format(helper.GetResourceMsgFromResourcetext("SetItemWarnigForPPQ"), pathForGlobalQuota)); } } SessionObjCache.TryGetValue(host, out sessionobj); - string resourceUri = String.Format( + string resourceUri = string.Format( CultureInfo.InvariantCulture, "{0}?Name={1}", uri, @@ -1219,13 +1245,13 @@ protected override void SetItem(string path, object value) } else { - warningMessage.Add(String.Format(helper.GetResourceMsgFromResourcetext("SetItemServiceRestartWarningRemote"), host)); + warningMessage.Add(string.Format(helper.GetResourceMsgFromResourcetext("SetItemServiceRestartWarningRemote"), host)); } } } finally { - if (!String.IsNullOrEmpty(pluginConfiguration.ServerSession.Error)) + if (!string.IsNullOrEmpty(pluginConfiguration.ServerSession.Error)) { AssertError(pluginConfiguration.ServerSession.Error, true); } @@ -1258,7 +1284,7 @@ protected override void SetItem(string path, object value) { if (!Force) { - string query=""; + string query = ""; string caption = helper.GetResourceMsgFromResourcetext("SetItemGeneralSecurityCaption"); if (ChildName.Equals("TrustedHosts", StringComparison.OrdinalIgnoreCase)) { @@ -1268,23 +1294,26 @@ protected override void SetItem(string path, object value) { query = helper.GetResourceMsgFromResourcetext("SetItemRootSDDLWarningQuery"); } + if (!ShouldContinue(query, caption)) { return; } } + WSManProviderSetItemDynamicParameters dynParams = DynamicParameters as WSManProviderSetItemDynamicParameters; if (dynParams != null) { if (dynParams.Concatenate) { - if (!String.IsNullOrEmpty(value.ToString())) + if (!string.IsNullOrEmpty(value.ToString())) { // ',' is used as the delimiter in WSMan for TrustedHosts. value = SplitAndUpdateStringUsingDelimiter(sessionobj, uri, ChildName, value.ToString(), ","); } } } + cmdlinevalue.Add(ChildName, value); } else @@ -1298,9 +1327,10 @@ protected override void SetItem(string path, object value) if (globalWarningUris.Contains(uri) && globalWarningConfigurations.Contains(ChildName.ToLowerInvariant())) { - warningMessage.Add(String.Format(helper.GetResourceMsgFromResourcetext("SetItemWarningForGlobalQuota"), value)); + warningMessage.Add(string.Format(helper.GetResourceMsgFromResourcetext("SetItemWarningForGlobalQuota"), value)); } } + PutResourceValue(sessionobj, uri, cmdlinevalue, host); } catch (COMException e) @@ -1310,7 +1340,7 @@ protected override void SetItem(string path, object value) } } - foreach(String warnings in warningMessage) + foreach (String warnings in warningMessage) { WriteWarning(warnings); } @@ -1329,7 +1359,7 @@ protected override void ClearItem(string path) } /// - /// This is method which create the dynamic or runtime parameter for set-item + /// This is method which create the dynamic or runtime parameter for set-item. /// /// /// @@ -1341,31 +1371,30 @@ protected override object SetItemDynamicParameters(string path, object value) string hostname = GetHostName(path); if (path.EndsWith(hostname + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerClient, StringComparison.OrdinalIgnoreCase)) { - //To have Tab completion. + // To have Tab completion. return new WSManProviderSetItemDynamicParameters(); } else if (path.EndsWith(hostname + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerClient + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerTrustedHosts, StringComparison.OrdinalIgnoreCase)) { - //To Support Concatenate parameter for trustedhosts. + // To Support Concatenate parameter for trustedhosts. return new WSManProviderSetItemDynamicParameters(); } } + return null; } - #endregion #region ContainerCmdletProvider /// /// Gets the Child items. dir functionality - /// wsman:\localhost\client> dir + /// wsman:\localhost\client> dir. /// /// /// protected override void GetChildItems(string path, bool recurse) { - GetChildItemsOrNames(path, ProviderMethods.GetChildItems, recurse); } @@ -1376,7 +1405,6 @@ protected override void GetChildItems(string path, bool recurse) /// protected override void GetChildNames(string path, ReturnContainers returnContainers) { - GetChildItemsOrNames(path, ProviderMethods.GetChildNames, false); } #endregion @@ -1384,22 +1412,21 @@ protected override void GetChildNames(string path, ReturnContainers returnContai #region NavigationalCmdletProvider /// - /// Checks whether the specified path is a container path + /// Checks whether the specified path is a container path. /// /// /// protected override bool IsItemContainer(string path) { + string childname = string.Empty; + string strPathCheck = string.Empty; - string childname = String.Empty; - string strPathCheck = String.Empty; - - if (path.Length == 0 && String.IsNullOrEmpty(childname)) + if (path.Length == 0 && string.IsNullOrEmpty(childname)) { return true; } - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); @@ -1407,27 +1434,26 @@ protected override bool IsItemContainer(string path) if (path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) { - //Get the ChildName + // Get the ChildName childname = path.Substring(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator) + 1); } + Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); if (SessionObjCache.ContainsKey(path)) { return true; } - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); string WsManURI = NormalizePath(path, host); - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { - //Gets the session object from the cache. + // Gets the session object from the cache. object sessionobj; SessionObjCache.TryGetValue(host, out sessionobj); - - /* WsMan Config Can be divided in to Four Fixed Regions to Check Whether Item is Container @@ -1447,6 +1473,7 @@ protected override bool IsItemContainer(string path) { return true; } + XmlDocument xmlListeners = EnumerateResourceValue(sessionobj, WsManURI); if (xmlListeners != null) @@ -1467,6 +1494,7 @@ protected override bool IsItemContainer(string path) { return true; } + XmlDocument xmlCertificates = EnumerateResourceValue(sessionobj, WsManURI); if (xmlCertificates != null) { @@ -1481,17 +1509,16 @@ protected override bool IsItemContainer(string path) // 3. Plugin and its internal structure Checks else if (WsManURI.Contains(WSManStringLiterals.containerPlugin)) { - strPathCheck = strPathCheck + WSManStringLiterals.containerPlugin; - //Check for Plugin path + // Check for Plugin path if (path.EndsWith(strPathCheck, StringComparison.OrdinalIgnoreCase)) { return true; } + strPathCheck = strPathCheck + WSManStringLiterals.DefaultPathSeparator; XmlDocument xmlPlugins = FindResourceValue(sessionobj, WsManURI, null); - string currentpluginname = string.Empty; GetPluginNames(xmlPlugins, out objPluginNames, out currentpluginname, path); strPathCheck = strPathCheck + currentpluginname; @@ -1499,6 +1526,7 @@ protected override bool IsItemContainer(string path) { return true; } + string filter = WsManURI + "?Name=" + currentpluginname; XmlDocument CurrentPluginXML = GetResourceValue(sessionobj, filter, null); ArrayList arrSecurities = null; @@ -1507,24 +1535,28 @@ protected override bool IsItemContainer(string path) { return true; } + strPathCheck = strPathCheck + WSManStringLiterals.DefaultPathSeparator; if (path.EndsWith(strPathCheck + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { return true; } + if (path.EndsWith(strPathCheck + WSManStringLiterals.containerInitParameters, StringComparison.OrdinalIgnoreCase)) { return true; } + if (path.EndsWith(strPathCheck + WSManStringLiterals.containerQuotasParameters, StringComparison.OrdinalIgnoreCase)) { return true; } - if (null == arrResources || arrResources.Count == 0) + if (arrResources == null || arrResources.Count == 0) { return false; } + foreach (PSObject objresource in arrResources) { string sResourceDirName = objresource.Properties["ResourceDir"].Value.ToString(); @@ -1535,6 +1567,7 @@ protected override bool IsItemContainer(string path) { return true; } + strPathCheck = strPathCheck + sResourceDirName + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathCheck + WSManStringLiterals.containerSecurity)) { @@ -1542,19 +1575,20 @@ protected override bool IsItemContainer(string path) { return true; } + strPathCheck = strPathCheck + WSManStringLiterals.containerSecurity + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathCheck + WSManStringLiterals.containerSecurity + "_")) { - if (null == arrSecurities) + if (arrSecurities == null) { return false; } + foreach (PSObject security in arrSecurities) { string sSecurity = security.Properties["SecurityDIR"].Value.ToString(); if (path.EndsWith(sSecurity, StringComparison.OrdinalIgnoreCase)) return true; - } } } @@ -1571,6 +1605,7 @@ protected override bool IsItemContainer(string path) bool result = IsItemContainer(nodes); return result; } + return false; } } @@ -1588,11 +1623,12 @@ protected override void RemoveItem(string path, bool recurse) AssertError(helper.GetResourceMsgFromResourcetext("RemoveItemNotSupported"), false); return; } - String ChildName = String.Empty; + + string ChildName = string.Empty; if (path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) { - //Get the ChildName + // Get the ChildName ChildName = path.Substring(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator) + 1); } else @@ -1606,18 +1642,18 @@ protected override void RemoveItem(string path, bool recurse) { AssertError(helper.GetResourceMsgFromResourcetext("LocalHost"), false); } + helper.RemoveFromDictionary(ChildName); return; } path = path.Substring(0, path.LastIndexOf(ChildName, StringComparison.OrdinalIgnoreCase)); - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); string uri = NormalizePath(path, host); - - //Chk for Winrm Service + // Chk for Winrm Service if (IsPathLocalMachine(host)) { if (!IsWSManServiceRunning()) @@ -1627,29 +1663,28 @@ protected override void RemoveItem(string path, bool recurse) } } - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { - //Gets the session object from the cache. + // Gets the session object from the cache. object sessionobj; Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); SessionObjCache.TryGetValue(host, out sessionobj); - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); } - string inputStr = String.Empty; - string strPathCheck = String.Empty; + string inputStr = string.Empty; + string strPathCheck = string.Empty; strPathCheck = host + WSManStringLiterals.DefaultPathSeparator; - if (path.Contains(strPathCheck + WSManStringLiterals.containerPlugin))//(path.Contains(@"\plugin")) { if (path.EndsWith(strPathCheck + WSManStringLiterals.containerPlugin, StringComparison.OrdinalIgnoreCase)) { - //Deletes all the Plugin when user is in WsMan:\Localhost\Plugin. + // Deletes all the Plugin when user is in WsMan:\Localhost\Plugin. string pluginUri = uri + "?Name=" + ChildName; DeleteResourceValue(sessionobj, pluginUri, null, recurse); return; @@ -1668,6 +1703,7 @@ protected override void RemoveItem(string path, bool recurse) { pName = path.Substring(pos); } + string filter1 = uri + "?Name=" + pName; XmlDocument pxml = GetResourceValue(sessionobj, filter1, null); @@ -1683,8 +1719,9 @@ protected override void RemoveItem(string path, bool recurse) if (path.EndsWith(strPathCheck + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { throwerror = false; - ResourceArray = RemoveItemfromResourceArray(ResourceArray, ChildName, "", "ResourceDir"); + ResourceArray = RemoveItemfromResourceArray(ResourceArray, ChildName, string.Empty, "ResourceDir"); } + if (throwerror) { strPathCheck = strPathCheck + WSManStringLiterals.containerResources + WSManStringLiterals.DefaultPathSeparator; @@ -1698,11 +1735,12 @@ protected override void RemoveItem(string path, bool recurse) { sResourceDirName = path.Substring(strPathCheck.Length, path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathCheck.Length) - (strPathCheck.Length)); } + strPathCheck = strPathCheck + sResourceDirName + WSManStringLiterals.DefaultPathSeparator; if (path.EndsWith(strPathCheck + WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase)) { throwerror = false; - SecurityArray = RemoveItemfromResourceArray(SecurityArray, ChildName, "", "SecurityDIR"); + SecurityArray = RemoveItemfromResourceArray(SecurityArray, ChildName, string.Empty, "SecurityDIR"); } } } @@ -1710,13 +1748,15 @@ protected override void RemoveItem(string path, bool recurse) { // Remove-Item is called for one of the initialization Parameters. throwerror = false; - InitParamArray = RemoveItemfromResourceArray(InitParamArray, ChildName, "InitParams", ""); + InitParamArray = RemoveItemfromResourceArray(InitParamArray, ChildName, "InitParams", string.Empty); } + if (throwerror) { AssertError(helper.GetResourceMsgFromResourcetext("RemoveItemNotSupported"), false); return; } + inputStr = ConstructPluginXml(ps, uri, host, "Set", ResourceArray, SecurityArray, InitParamArray); try { @@ -1724,7 +1764,7 @@ protected override void RemoveItem(string path, bool recurse) } finally { - if (!String.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) + if (!string.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) { AssertError(((IWSManSession)sessionobj).Error, true); } @@ -1740,6 +1780,7 @@ protected override void RemoveItem(string path, bool recurse) throwerror = false; RemoveListenerOrCertMapping(sessionobj, uri, ChildName, PKeyCertMapping, false); } + if (throwerror) { AssertError(helper.GetResourceMsgFromResourcetext("RemoveItemNotSupported"), false); @@ -1756,24 +1797,23 @@ protected override void RemoveItem(string path, bool recurse) /// protected override void NewItem(string path, string itemTypeName, object newItemValue) { - string inputStr = String.Empty; + string inputStr = string.Empty; object sessionobj; - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); return; } - if (path.Length == 0 || !path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) { NewItemCreateComputerConnection(path); return; } - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); if (string.IsNullOrEmpty(host)) @@ -1781,7 +1821,7 @@ protected override void NewItem(string path, string itemTypeName, object newItem throw new ArgumentException(helper.GetResourceMsgFromResourcetext("InvalidPath")); } - //Chk for Winrm Service + // Chk for Winrm Service if (IsPathLocalMachine(host)) { if (!IsWSManServiceRunning()) @@ -1790,14 +1830,14 @@ protected override void NewItem(string path, string itemTypeName, object newItem StartWSManService(this.Force); } } + string uri = NormalizePath(path, host); - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); SessionObjCache.TryGetValue(host, out sessionobj); - string strPathChk = host + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathChk + WSManStringLiterals.containerPlugin))//(path.Contains(@"\plugin")) { @@ -1814,18 +1854,22 @@ protected override void NewItem(string path, string itemTypeName, object newItem { listenerparams.Add("Hostname", niParams.HostName); } + if (niParams.URLPrefix != null) { listenerparams.Add("URLPrefix", niParams.URLPrefix); } + if (niParams.IsPortSpecified) { listenerparams.Add("Port", niParams.Port); } + if (niParams.CertificateThumbPrint != null) { listenerparams.Add("CertificateThumbPrint", niParams.CertificateThumbPrint); } + NewItemContainerListenerOrCertMapping(sessionobj, path, uri, host, listenerparams, WSManStringLiterals.containerListener, helper.GetResourceMsgFromResourcetext("NewItemShouldContinueListenerQuery"), helper.GetResourceMsgFromResourcetext("NewItemShouldContinueListenerCaption")); } else if (path.EndsWith(strPathChk + WSManStringLiterals.containerClientCertificate, StringComparison.OrdinalIgnoreCase)) @@ -1842,6 +1886,7 @@ protected override void NewItem(string path, string itemTypeName, object newItem Certparams.Add("UserName", nwCredentials.UserName); Certparams.Add("Password", nwCredentials.Password); } + Certparams.Add("Enabled", dynParams.Enabled); NewItemContainerListenerOrCertMapping(sessionobj, path, uri, host, Certparams, WSManStringLiterals.containerClientCertificate, helper.GetResourceMsgFromResourcetext("NewItemShouldContinueClientCertQuery"), helper.GetResourceMsgFromResourcetext("NewItemShouldContinueClientCertCaption")); } @@ -1855,7 +1900,7 @@ protected override void NewItem(string path, string itemTypeName, object newItem /// /// Dynamic parameter used by New-Item. According to different path. This method return the - /// required dynamic parameters + /// required dynamic parameters. /// /// /// @@ -1867,32 +1912,39 @@ protected override object NewItemDynamicParameters(string path, string itemTypeN { return new WSManProviderNewItemComputerParameters(); } + string hostname = GetHostName(path); string strpathchk = hostname + WSManStringLiterals.DefaultPathSeparator; if (path.EndsWith(strpathchk + WSManStringLiterals.containerPlugin, StringComparison.OrdinalIgnoreCase)) { return new WSManProviderNewItemPluginParameters(); } + if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerInitParameters, StringComparison.OrdinalIgnoreCase)) { return new WSManProviderInitializeParameters(); } + if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { return new WSManProviderNewItemResourceParameters(); } + if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase)) { return new WSManProviderNewItemSecurityParameters(); } + if (path.EndsWith(strpathchk + WSManStringLiterals.containerListener, StringComparison.OrdinalIgnoreCase)) { return new WSManProvidersListenerParameters(); } + if (path.EndsWith(strpathchk + WSManStringLiterals.containerClientCertificate, StringComparison.OrdinalIgnoreCase)) { return new WSManProviderClientCertificateParameters(); } + return null; } @@ -1901,7 +1953,7 @@ protected override object NewItemDynamicParameters(string path, string itemTypeN #region Private /// - /// this method creates the connection to new machine in wsman provider. + /// This method creates the connection to new machine in wsman provider. /// This is called from New-Item. /// /// @@ -1915,8 +1967,8 @@ private void NewItemCreateComputerConnection(string Name) if (dynParams.ConnectionURI != null) { parametersetName = "URI"; - } + helper.CreateWsManConnection(parametersetName, dynParams.ConnectionURI, dynParams.Port, Name, dynParams.ApplicationName, dynParams.UseSSL, dynParams.Authentication, dynParams.SessionOption, this.Credential, dynParams.CertificateThumbprint); if (dynParams.ConnectionURI != null) { @@ -1924,6 +1976,7 @@ private void NewItemCreateComputerConnection(string Name) string[] constrsplit1 = constrsplit[0].Split(new string[] { "//" }, StringSplitOptions.None); Name = constrsplit1[1].Trim(); } + WriteItemObject(GetItemPSObjectWithTypeName(Name, WSManStringLiterals.ContainerChildValue, null, null, "ComputerLevel", WsManElementObjectTypes.WSManConfigContainerElement), WSManStringLiterals.rootpath + WSManStringLiterals.DefaultPathSeparator + Name, true); } else @@ -1935,7 +1988,7 @@ private void NewItemCreateComputerConnection(string Name) } /// - /// this method creates the Listener or ClientCertificate in wsman provider. + /// This method creates the Listener or ClientCertificate in wsman provider. /// This is called from New-Item. /// /// @@ -1955,6 +2008,7 @@ private void NewItemContainerListenerOrCertMapping(object sessionobj, string pat return; } } + string inputstr = GetInputStringForCreate(uri, InputParams, host); CreateResourceValue(sessionobj, uri, inputstr, InputParams); XmlDocument xmlResource = GetResourceValue(sessionobj, uri, InputParams); @@ -1968,6 +2022,7 @@ private void NewItemContainerListenerOrCertMapping(object sessionobj, string pat { ProcessListenerObjects(xmlResource, out CCache, out kCache); } + if (CCache != null && CCache.Count > 0) { foreach (DictionaryEntry resource in CCache) @@ -1975,11 +2030,10 @@ private void NewItemContainerListenerOrCertMapping(object sessionobj, string pat WriteItemObject(GetItemPSObjectWithTypeName(resource.Key.ToString(), WSManStringLiterals.ContainerChildValue, null, (string[])kCache[resource.Key], string.Empty, WsManElementObjectTypes.WSManConfigContainerElement), path + WSManStringLiterals.DefaultPathSeparator + resource.Key.ToString(), true); } } - } /// - /// this method creates the Plugin and its child items in wsman provider. + /// This method creates the Plugin and its child items in wsman provider. /// This is called from New-Item. /// /// @@ -1990,7 +2044,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h { PSObject mshObj = new PSObject(); string PluginName = string.Empty; - string inputStr = String.Empty; + string inputStr = string.Empty; string strPathChk = host + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerPlugin; if (!path.Equals(strPathChk)) @@ -2008,7 +2062,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h WSManProviderNewItemPluginParameters niParams = DynamicParameters as WSManProviderNewItemPluginParameters; if (niParams != null) { - if (String.IsNullOrEmpty(niParams.File)) + if (string.IsNullOrEmpty(niParams.File)) { mshObj.Properties.Add(new PSNoteProperty("Name", niParams.Plugin)); mshObj.Properties.Add(new PSNoteProperty("Filename", niParams.FileName)); @@ -2045,6 +2099,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h { mshObj.Properties.Add(new PSNoteProperty("XmlRenderingType", "Text")); } + inputStr = ConstructPluginXml(mshObj, uri, host, "New", null, null, null); PluginName = niParams.Plugin; } @@ -2059,6 +2114,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h WriteError(er); return; } + string filter = uri + "?Name=" + PluginName; CreateResourceValue(sessionobj, filter, inputStr, null); WriteItemObject(GetItemPSObjectWithTypeName(PluginName, WSManStringLiterals.ContainerChildValue, null, new string[] { "Name=" + PluginName }, string.Empty, WsManElementObjectTypes.WSManConfigContainerElement), path + WSManStringLiterals.DefaultPathSeparator + PluginName, true); @@ -2066,10 +2122,9 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h else {// to create an internal item of as plugin string pName = string.Empty; - string NewItem = String.Empty; + string NewItem = string.Empty; string[] Keys = null; - int pos = path.LastIndexOf(strPathChk + WSManStringLiterals.DefaultPathSeparator, StringComparison.OrdinalIgnoreCase) + strPathChk.Length + 1; int pindex = path.IndexOf(WSManStringLiterals.DefaultPathSeparator, pos); if (pindex != -1) @@ -2089,7 +2144,6 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h ArrayList ResourceArray = ProcessPluginResourceLevel(pxml, out SecurityArray); ArrayList InitParamArray = ProcessPluginInitParamLevel(pxml); - strPathChk = strPathChk + WSManStringLiterals.DefaultPathSeparator + pName + WSManStringLiterals.DefaultPathSeparator; if (path.Contains(strPathChk + WSManStringLiterals.containerResources)) { @@ -2122,12 +2176,14 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h } } } + int Sepindex = path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathChk.Length); string sResourceDirName = string.Empty; if (Sepindex != -1) { sResourceDirName = path.Substring(strPathChk.Length + 1, path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathChk.Length + 1) - (strPathChk.Length + 1)); } + strPathChk = strPathChk + WSManStringLiterals.DefaultPathSeparator + sResourceDirName; if (path.EndsWith(strPathChk + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase)) @@ -2135,7 +2191,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h if (!Force) { string query = helper.GetResourceMsgFromResourcetext("ShouldContinueSecurityQuery"); - query = String.Format(CultureInfo.CurrentCulture, query, pName); + query = string.Format(CultureInfo.CurrentCulture, query, pName); if (!ShouldContinue(query, helper.GetResourceMsgFromResourcetext("ShouldContinueSecurityCaption"))) { return; @@ -2143,7 +2199,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h } // Construct the Uri from Resource_XXXX resource dir. PSObject resourceDirProperties = GetItemValue(strPathChk); - if ((null == resourceDirProperties) || (null == resourceDirProperties.Properties["ResourceUri"])) + if ((resourceDirProperties == null) || (resourceDirProperties.Properties["ResourceUri"] == null)) { string message = helper.FormatResourceMsgFromResourcetext("ResourceURIMissingInResourceDir", "ResourceUri", strPathChk); @@ -2174,11 +2230,10 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h SecurityArray = newSecurity; } } - } + if (path.EndsWith(strPathChk + WSManStringLiterals.containerInitParameters, StringComparison.OrdinalIgnoreCase)) { - WSManProviderInitializeParameters niParams = DynamicParameters as WSManProviderInitializeParameters; mshObj.Properties.Add(new PSNoteProperty(niParams.ParamName, niParams.ParamValue)); inputStr = ConstructInitParamsXml(mshObj, null); @@ -2195,6 +2250,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h InitParamArray = ProcessPluginInitParamLevel(xdoc); } } + inputStr = ConstructPluginXml(ps, uri, host, "Set", ResourceArray, SecurityArray, InitParamArray); try { @@ -2210,7 +2266,7 @@ private void NewItemPluginOrPluginChild(object sessionobj, string path, string h } finally { - if (!String.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) + if (!string.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) { AssertError(((IWSManSession)sessionobj).Error, true); } @@ -2237,11 +2293,13 @@ private PSObject GetItemPSObjectWithTypeName(string Name, string TypeNameOfEleme WSManConfigElement element = new WSManConfigElement(Name, TypeNameOfElement); mshObject = new PSObject(element); } + if (WSManElementObjectType.Equals(WsManElementObjectTypes.WSManConfigContainerElement)) { WSManConfigContainerElement element = new WSManConfigContainerElement(Name, TypeNameOfElement, keys); mshObject = new PSObject(element); } + if (WSManElementObjectType.Equals(WsManElementObjectTypes.WSManConfigLeafElement)) { object source = null; @@ -2258,9 +2316,10 @@ private PSObject GetItemPSObjectWithTypeName(string Name, string TypeNameOfEleme WSManConfigLeafElement element = new WSManConfigLeafElement(Name, Value, TypeNameOfElement, source); mshObject = new PSObject(element); } - if (!String.IsNullOrEmpty(ExtendedTypeName)) + + if (!string.IsNullOrEmpty(ExtendedTypeName)) { - StringBuilder types = new StringBuilder(""); + StringBuilder types = new StringBuilder(string.Empty); if (mshObject != null) { types.Append(mshObject.ImmediateBaseObject.GetType().FullName); @@ -2269,6 +2328,7 @@ private PSObject GetItemPSObjectWithTypeName(string Name, string TypeNameOfEleme mshObject.TypeNames.Insert(0, types.ToString()); } } + return mshObject; } @@ -2302,6 +2362,7 @@ private void SetItemListenerOrClientCertificate(object sessionObj, string Resour { ProcessCertMappingObjects(xmlResource, out objcache, out Keyscache); } + if (path.EndsWith(host + WSManStringLiterals.DefaultPathSeparator + parent, StringComparison.OrdinalIgnoreCase)) { AssertError(helper.GetResourceMsgFromResourcetext("SetItemNotSupported"), false); @@ -2315,6 +2376,7 @@ private void SetItemListenerOrClientCertificate(object sessionObj, string Resour return; } } + string item = path.Substring(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator) + 1); try { @@ -2324,6 +2386,7 @@ private void SetItemListenerOrClientCertificate(object sessionObj, string Resour { cmdlinevalue.Add(key, ((PSObject)objcache[item]).Properties[key].Value); } + PutResourceValue(sessionObj, ResourceURI, cmdlinevalue, host); } catch (COMException e) @@ -2336,7 +2399,7 @@ private void SetItemListenerOrClientCertificate(object sessionObj, string Resour } /// - /// Get the input string for create + /// Get the input string for create. /// /// /// @@ -2344,9 +2407,8 @@ private void SetItemListenerOrClientCertificate(object sessionObj, string Resour /// private string GetInputStringForCreate(string ResourceURI, Hashtable value, string host) { - - string putstr = String.Empty; - string nilns = String.Empty; + string putstr = string.Empty; + string nilns = string.Empty; StringBuilder sbvalues = new StringBuilder(); if (value.Count > 0) @@ -2363,6 +2425,7 @@ private string GetInputStringForCreate(string ResourceURI, Hashtable value, stri sbvalues.Append(WSManStringLiterals.ATTR_NIL); nilns = " " + WSManStringLiterals.NS_XSI; } + sbvalues.Append(">"); sbvalues.Append(EscapeValuesForXML(((Hashtable)value)[key].ToString())); sbvalues.Append("" + sbvalues.ToString() + ""; return putstr; @@ -2383,13 +2447,13 @@ private string GetInputStringForCreate(string ResourceURI, Hashtable value, stri /// private string ReadFile(string path) { - string putstr = String.Empty; + string putstr = string.Empty; try { string filePath = this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path); putstr = File.ReadAllText(filePath, System.Text.Encoding.UTF8); } - //known exceptions + // known exceptions catch (ArgumentNullException e) { ErrorRecord er = new ErrorRecord(e, "ArgumentNullException", ErrorCategory.InvalidOperation, null); @@ -2420,6 +2484,7 @@ private string ReadFile(string path) ErrorRecord er = new ErrorRecord(e, "SecurityException", ErrorCategory.InvalidOperation, null); WriteError(er); } + return putstr; } @@ -2434,31 +2499,33 @@ private string GetHostName(string path) string sHostname = path; try { - //HostName is always followed by root name + // HostName is always followed by root name if (path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) { sHostname = path.Substring(0, path.IndexOf(WSManStringLiterals.DefaultPathSeparator)); } + Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); if (!SessionObjCache.ContainsKey(sHostname)) sHostname = null; - } catch (ArgumentNullException e) { ErrorRecord er = new ErrorRecord(e, "ArgumentNullException", ErrorCategory.InvalidArgument, null); WriteError(er); } + return sHostname; } private string GetRootNodeName(string ResourceURI) { - string tempuri = ""; + string tempuri = string.Empty; if (ResourceURI.Contains("?")) { ResourceURI = ResourceURI.Split(new char[] { '?' }).GetValue(0).ToString(); } + string PTRN_URI_LAST = "([a-z_][-a-z0-9._]*)$"; Regex objregex = new Regex(PTRN_URI_LAST, RegexOptions.IgnoreCase); MatchCollection regexmatch = objregex.Matches(ResourceURI); @@ -2466,6 +2533,7 @@ private string GetRootNodeName(string ResourceURI) { tempuri = regexmatch[0].Value.ToString(); } + return tempuri; } @@ -2508,6 +2576,7 @@ private string EscapeValuesForXML(string value) } } } + return esc_str.ToString(); } @@ -2524,6 +2593,7 @@ private bool IsItemContainer(XmlNodeList nodes) } } } + return result; } @@ -2532,7 +2602,7 @@ private XmlNodeList SearchXml(XmlDocument resourcexmldocument, string searchitem XmlNodeList nodes = null; try { - string xpathString = String.Empty; + string xpathString = string.Empty; if (ResourceURI.EndsWith(WSManStringLiterals.containerWinrs, StringComparison.OrdinalIgnoreCase)) { if (path.Equals(host + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerShell, StringComparison.OrdinalIgnoreCase)) @@ -2540,6 +2610,7 @@ private XmlNodeList SearchXml(XmlDocument resourcexmldocument, string searchitem searchitem = WSManStringLiterals.containerWinrs.ToLowerInvariant(); } } + if (ResourceURI.EndsWith("Config", StringComparison.OrdinalIgnoreCase) || !ResourceURI.EndsWith(searchitem, StringComparison.OrdinalIgnoreCase)) { xpathString = @"/*/*[local-name()=""" + searchitem.ToLowerInvariant() + @"""]"; @@ -2548,20 +2619,21 @@ private XmlNodeList SearchXml(XmlDocument resourcexmldocument, string searchitem { xpathString = @"/*[local-name()=""" + searchitem.ToLowerInvariant() + @"""]"; } - nodes = resourcexmldocument.SelectNodes(xpathString); + nodes = resourcexmldocument.SelectNodes(xpathString); } catch (System.Xml.XPath.XPathException ex) { ErrorRecord er = new ErrorRecord(ex, "XPathException", ErrorCategory.InvalidArgument, null); WriteError(er); } + return nodes; } #region "WsMan linking Operations" /// - /// To put a resource value. Wsman put operation + /// To put a resource value. Wsman put operation. /// /// /// @@ -2588,12 +2660,12 @@ private void PutResourceValue(object sessionobj, string ResourceURI, Hashtable v { for (int i = 0; i < node.ChildNodes.Count; i++) { - if ( (node.ChildNodes[i].ChildNodes.Count == 0) || node.ChildNodes[i].FirstChild.Name.Equals("#text", StringComparison.OrdinalIgnoreCase)) + if ((node.ChildNodes[i].ChildNodes.Count == 0) || node.ChildNodes[i].FirstChild.Name.Equals("#text", StringComparison.OrdinalIgnoreCase)) { foreach (string key in value.Keys) { - //to make sure we dont set values at inner level. - //for eg: when set-item at winrm/config we dont take input at below level + // to make sure we dont set values at inner level. + // for eg: when set-item at winrm/config we dont take input at below level if (!IsPKey(key, ResourceURI)) { if (node.ChildNodes[i].LocalName.Equals(key, StringComparison.OrdinalIgnoreCase)) @@ -2605,6 +2677,7 @@ private void PutResourceValue(object sessionobj, string ResourceURI, Hashtable v } } } + if (Itemfound) { ResourceURI = GetURIWithFilter(ResourceURI, value); @@ -2621,7 +2694,7 @@ private void PutResourceValue(object sessionobj, string ResourceURI, Hashtable v } finally { - if (!String.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) + if (!string.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) { AssertError(((IWSManSession)sessionobj).Error, true); } @@ -2634,7 +2707,7 @@ private string GetResourceValueInXml(object sessionobj, string ResourceURI, Hash { ResourceURI = GetURIWithFilter(ResourceURI, cmdlinevalues); - string returnValue = String.Empty; + string returnValue = string.Empty; if (!this.getMapping.TryGetValue(ResourceURI, out returnValue)) { @@ -2646,7 +2719,7 @@ private string GetResourceValueInXml(object sessionobj, string ResourceURI, Hash } finally { - if (!String.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) + if (!string.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) { AssertError(((IWSManSession)sessionobj).Error, true); } @@ -2672,7 +2745,7 @@ private XmlDocument GetResourceValue(object sessionobj, string ResourceURI, Hash } /// - /// WsMan Enumerate operation + /// WsMan Enumerate operation. /// /// /// @@ -2685,7 +2758,7 @@ private XmlDocument EnumerateResourceValue(object sessionobj, string ResourceURI { try { - object value = ((IWSManSession)sessionobj).Enumerate(ResourceURI, "", "", 0); + object value = ((IWSManSession)sessionobj).Enumerate(ResourceURI, string.Empty, string.Empty, 0); string strXmlValue = string.Empty; while (!((IWSManEnumerator)value).AtEndOfStream) @@ -2695,29 +2768,28 @@ private XmlDocument EnumerateResourceValue(object sessionobj, string ResourceURI Marshal.ReleaseComObject(value); - if (!String.IsNullOrEmpty(strXmlValue)) + if (!string.IsNullOrEmpty(strXmlValue)) { xmlEnumResources = new XmlDocument(); strXmlValue = "" + strXmlValue + ""; xmlEnumResources.LoadXml(strXmlValue); this.enumerateMapping.Add(ResourceURI, xmlEnumResources); } - } finally { - if (!String.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) + if (!string.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) { AssertError(((IWSManSession)sessionobj).Error, true); } } } - return xmlEnumResources; + return xmlEnumResources; } /// - /// WsMan Delete Operation + /// WsMan Delete Operation. /// /// /// @@ -2727,20 +2799,20 @@ private void DeleteResourceValue(object sessionobj, string ResourceURI, Hashtabl { try { - //Support only for Listener,plugin and ClientCertificate. + // Support only for Listener,plugin and ClientCertificate. if (ResourceURI.Contains(WSManStringLiterals.containerPlugin) || ResourceURI.Contains(WSManStringLiterals.containerListener) || ResourceURI.Contains(WSManStringLiterals.containerCertMapping)) { if (cmdlinevalues != null) { ResourceURI = GetURIWithFilter(ResourceURI, cmdlinevalues); } - ((IWSManSession)sessionobj).Delete(ResourceURI, 0); + ((IWSManSession)sessionobj).Delete(ResourceURI, 0); } } finally { - if (!String.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) + if (!string.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) { AssertError(((IWSManSession)sessionobj).Error, true); } @@ -2748,7 +2820,7 @@ private void DeleteResourceValue(object sessionobj, string ResourceURI, Hashtabl } /// - /// WsMan Create Operation + /// WsMan Create Operation. /// /// /// @@ -2766,12 +2838,11 @@ private void CreateResourceValue(object sessionobj, string ResourceURI, string r } finally { - if (!String.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) + if (!string.IsNullOrEmpty(((IWSManSession)sessionobj).Error)) { AssertError(((IWSManSession)sessionobj).Error, true); } } - } /// @@ -2786,7 +2857,7 @@ private XmlDocument FindResourceValue(object sessionobj, string ResourceURI, Has XmlDocument outval = null; if (ResourceURI.Contains(WSManStringLiterals.containerListener) || ResourceURI.Contains(WSManStringLiterals.containerPlugin) || ResourceURI.Contains(WSManStringLiterals.containerCertMapping)) { - if (null == cmdlinevalues || cmdlinevalues.Count == 0) + if (cmdlinevalues == null || cmdlinevalues.Count == 0) { outval = EnumerateResourceValue(sessionobj, ResourceURI); } @@ -2799,11 +2870,12 @@ private XmlDocument FindResourceValue(object sessionobj, string ResourceURI, Has { outval = GetResourceValue(sessionobj, ResourceURI, cmdlinevalues); } + return outval; } /// - /// Checks whether a value is present in Wsman config + /// Checks whether a value is present in Wsman config. /// /// /// @@ -2814,31 +2886,35 @@ private XmlDocument FindResourceValue(object sessionobj, string ResourceURI, Has private bool ContainResourceValue(object sessionobj, string ResourceURI, string childname, string path, string host) { bool result = false; - string valuexml = String.Empty; + string valuexml = string.Empty; try { if (ResourceURI.Contains(WSManStringLiterals.containerListener) || ResourceURI.Contains(WSManStringLiterals.containerPlugin) || ResourceURI.Contains(WSManStringLiterals.containerCertMapping)) { - object value = ((IWSManSession)sessionobj).Enumerate(ResourceURI, "", "", 0); + object value = ((IWSManSession)sessionobj).Enumerate(ResourceURI, string.Empty, string.Empty, 0); while (!((IWSManEnumerator)value).AtEndOfStream) { valuexml = valuexml + ((IWSManEnumerator)value).ReadItem(); } - if ((valuexml != "") && !(String.IsNullOrEmpty(valuexml))) + + if ((valuexml != string.Empty) && !(string.IsNullOrEmpty(valuexml))) { valuexml = "" + valuexml + ""; } + Marshal.ReleaseComObject(value); } else { valuexml = this.GetResourceValueInXml(((IWSManSession)sessionobj), ResourceURI, null); } + if (string.IsNullOrEmpty(valuexml)) { return false; } + XmlDocument xmlResourceValues = new XmlDocument(); xmlResourceValues.LoadXml(valuexml.ToLowerInvariant()); XmlNodeList nodes = SearchXml(xmlResourceValues, childname, ResourceURI, path, host); @@ -2848,6 +2924,7 @@ private bool ContainResourceValue(object sessionobj, string ResourceURI, string } } catch (COMException) { result = false; } + return result; } @@ -2874,6 +2951,7 @@ private string GetURIWithFilter(string uri, Hashtable cmdlinevalues) sburi.Append(GetFilterString(cmdlinevalues, PKeyPlugin)); } } + return sburi.ToString(); } @@ -2890,7 +2968,8 @@ private string GetFilterString(Hashtable cmdlinevalues, string[] pkey) filter.Append("+"); } } - if (filter.ToString().EndsWith("+", StringComparison.OrdinalIgnoreCase)) + + if (filter.ToString().EndsWith('+')) filter.Remove(filter.ToString().Length - 1, 1); return filter.ToString(); } @@ -2910,6 +2989,7 @@ private bool IsPKey(string value, string ResourceURI) { result = CheckPkeysArray(null, value, PKeyCertMapping); } + return result; } @@ -2924,7 +3004,7 @@ private bool CheckPkeysArray(Hashtable values, string value, string[] pkeys) result = true; } } - else if (!String.IsNullOrEmpty(value)) + else if (!string.IsNullOrEmpty(value)) { foreach (string key in pkeys) { @@ -2935,6 +3015,7 @@ private bool CheckPkeysArray(Hashtable values, string value, string[] pkeys) } } } + return result; } @@ -2978,11 +3059,13 @@ private void WritePSObjectPropertiesAsWSManElementObjects(PSObject psobject, str WSManConfigElement element = new WSManConfigElement(prop.Name, prop.Value.ToString()); mshObject = new PSObject(element); } + if (WSManElementObjectType.Equals(WsManElementObjectTypes.WSManConfigContainerElement)) { WSManConfigContainerElement element = new WSManConfigContainerElement(prop.Name, prop.Value.ToString(), keys); mshObject = new PSObject(element); } + if (WSManElementObjectType.Equals(WsManElementObjectTypes.WSManConfigLeafElement)) { string sourceProp = prop.Name + WSManStringLiterals.HiddenSuffixForSourceOfValue; @@ -3001,14 +3084,16 @@ private void WritePSObjectPropertiesAsWSManElementObjects(PSObject psobject, str { element = new WSManConfigLeafElement(prop.Name, null, prop.Value.ToString()); } + if (element != null) { mshObject = new PSObject(element); } } - if (!String.IsNullOrEmpty(ExtendedTypeName)) + + if (!string.IsNullOrEmpty(ExtendedTypeName)) { - StringBuilder types = new StringBuilder(""); + StringBuilder types = new StringBuilder(string.Empty); if (mshObject != null) { types.Append(mshObject.ImmediateBaseObject.GetType().FullName); @@ -3017,6 +3102,7 @@ private void WritePSObjectPropertiesAsWSManElementObjects(PSObject psobject, str mshObject.TypeNames.Insert(0, types.ToString()); } } + if (!prop.Value.ToString().Equals(WSManStringLiterals.ContainerChildValue)) { // This path is used by WriteItemObject to construct PSPath. @@ -3044,6 +3130,7 @@ private void WritePSObjectPropertiesAsWSManElementObjects(PSObject psobject, str } } } + if (recurse) { foreach (string dir in directory) @@ -3061,6 +3148,7 @@ private string SplitAndUpdateStringUsingDelimiter(object sessionobj, string uri, { mshObject = ConvertToPSObject(innerResourceNodes); } + string existingvalue = string.Empty; try { @@ -3069,7 +3157,7 @@ private string SplitAndUpdateStringUsingDelimiter(object sessionobj, string uri, existingvalue = mshObject.Properties[childname].Value.ToString(); } - if (!String.IsNullOrEmpty(existingvalue)) + if (!string.IsNullOrEmpty(existingvalue)) { string[] existingsplitvalues = existingvalue.Split(new string[] { Delimiter }, StringSplitOptions.None); string[] newvalues = value.Split(new string[] { Delimiter }, StringSplitOptions.None); @@ -3088,8 +3176,8 @@ private string SplitAndUpdateStringUsingDelimiter(object sessionobj, string uri, } catch (PSArgumentException) { - } + return existingvalue; } @@ -3115,34 +3203,34 @@ private PSObject BuildHostLevelPSObjectArrayList(object objSessionObject, string } else { - if (null != objSessionObject) + if (objSessionObject != null) { XmlDocument ConfigXml = GetResourceValue(objSessionObject, uri, null); - //Moving in to + // Moving in to foreach (XmlNode node in ConfigXml.ChildNodes) { foreach (XmlNode node1 in node.ChildNodes) { - //Getting Top Element in - if ( (node1.ChildNodes.Count == 0) || node1.FirstChild.Name.Equals("#text", StringComparison.OrdinalIgnoreCase)) + // Getting Top Element in + if ((node1.ChildNodes.Count == 0) || node1.FirstChild.Name.Equals("#text", StringComparison.OrdinalIgnoreCase)) { mshobject.Properties.Add(new PSNoteProperty(node1.LocalName, node1.InnerText)); } } } } - //Getting the Fixed root nodes. + // Getting the Fixed root nodes. foreach (string root in WinRmRootConfigs) { mshobject.Properties.Add(new PSNoteProperty(root, WSManStringLiterals.ContainerChildValue)); - } } + return mshobject; } /// - /// Converts XmlNodes ChildNodes to Properties of PSObject + /// Converts XmlNodes ChildNodes to Properties of PSObject. /// /// /// @@ -3151,8 +3239,8 @@ private PSObject ConvertToPSObject(XmlNode xmlnode) PSObject mshObject = new PSObject(); foreach (XmlNode node in xmlnode.ChildNodes) { - //If node contains 0 child-nodes, it is empty node, if it's name = "#text" then it's a simple node. - if ( (node.ChildNodes.Count == 0) || node.FirstChild.Name.Equals("#text", StringComparison.OrdinalIgnoreCase)) + // If node contains 0 child-nodes, it is empty node, if it's name = "#text" then it's a simple node. + if ((node.ChildNodes.Count == 0) || node.FirstChild.Name.Equals("#text", StringComparison.OrdinalIgnoreCase)) { XmlAttribute attrSource = null; foreach (XmlAttribute attr in node.Attributes) @@ -3168,7 +3256,7 @@ private PSObject ConvertToPSObject(XmlNode xmlnode) if (attrSource != null) { - String propName = node.LocalName + WSManStringLiterals.HiddenSuffixForSourceOfValue; + string propName = node.LocalName + WSManStringLiterals.HiddenSuffixForSourceOfValue; mshObject.Properties.Remove(propName); mshObject.Properties.Add(new PSNoteProperty(propName, attrSource.Value)); } @@ -3178,8 +3266,8 @@ private PSObject ConvertToPSObject(XmlNode xmlnode) mshObject.Properties.Add(new PSNoteProperty(node.LocalName, WSManStringLiterals.ContainerChildValue)); } } - return mshObject; + return mshObject; } private string SetXPathString(string uri) @@ -3209,13 +3297,14 @@ private string SetXPathString(string uri) { parent = WSManStringLiterals.containerPlugin; } + parent = "/cfg:" + parent; return parent; } private string SetSchemaPath(string uri) { - string schemapath = String.Empty; + string schemapath = string.Empty; uri = uri.Remove(0, WinrmRootName[0].Length); if (uri.Contains(WSManStringLiterals.containerPlugin)) { @@ -3285,10 +3374,13 @@ private string NormalizePath(string path, string host) uri = uri.Remove(index); } } + uri = WinrmRootName[0].ToString() + uri; } + return uri; } + return uri; } @@ -3298,7 +3390,7 @@ private string NormalizePath(string path, string host) /// /// Currently this supports only retrieving Resource_XXXX dir contents. /// if you need support at other levels implement them. - /// Example resource dir: WSMan:\localhost\Plugin\someplugin\Resources\Resource_XXXXXXX + /// Example resource dir: WSMan:\localhost\Plugin\someplugin\Resources\Resource_XXXXXXX. /// /// /// @@ -3321,33 +3413,33 @@ private PSObject GetItemValue(string path) throw new ArgumentNullException(path); } - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); } - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); - if (String.IsNullOrEmpty(host)) + if (string.IsNullOrEmpty(host)) { throw new InvalidOperationException("InvalidPath"); } - //Chks the WinRM Service + // Chks the WinRM Service if (IsPathLocalMachine(host) && (!IsWSManServiceRunning())) { AssertError("WinRMServiceError", false); } - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { object sessionobj; - //gets the sessionobject + // gets the sessionobject Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); SessionObjCache.TryGetValue(host, out sessionobj); - //Normalize to the required uri + // Normalize to the required uri string uri = NormalizePath(path, host); string strPathchk = host + WSManStringLiterals.DefaultPathSeparator; @@ -3377,7 +3469,7 @@ private PSObject GetItemValue(string path) } else if (path.Contains(strPathchk + WSManStringLiterals.containerPlugin)) { - string currentpluginname = String.Empty; + string currentpluginname = string.Empty; GetPluginNames(outxml, out objPluginNames, out currentpluginname, path); if (path.EndsWith(strPathchk + WSManStringLiterals.containerPlugin, StringComparison.OrdinalIgnoreCase)) { @@ -3390,10 +3482,11 @@ private PSObject GetItemValue(string path) // Example resource dir: WSMan:\localhost\Plugin\someplugin\Resources\Resource_67830040 string filter = uri + "?Name=" + currentpluginname; XmlDocument CurrentPluginXML = GetResourceValue(sessionobj, filter, null); - if (null == CurrentPluginXML) + if (CurrentPluginXML == null) { return null; } + PSObject objPluginlevel = ProcessPluginConfigurationLevel(CurrentPluginXML); ArrayList arrSecurity = null; ArrayList arrResources = ProcessPluginResourceLevel(CurrentPluginXML, out arrSecurity); @@ -3403,13 +3496,14 @@ private PSObject GetItemValue(string path) // We support only retrieving Resource_XXX dir properties only. // other directory support can be added as needed. - if (null == arrResources) + if (arrResources == null) { return null; } + strPathchk = strPathchk + WSManStringLiterals.containerResources + WSManStringLiterals.DefaultPathSeparator; int Sepindex = path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathchk.Length); - string sResourceDirName = String.Empty; + string sResourceDirName = string.Empty; if (Sepindex == -1) { sResourceDirName = path.Substring(strPathchk.Length); @@ -3434,6 +3528,7 @@ private PSObject GetItemValue(string path) } } } + return null; } @@ -3464,6 +3559,7 @@ private string GetCorrectCaseOfPath(string path) sbPath.Append(GetChildName(tempPath.ToString())); } } + return sbPath.ToString(); } @@ -3502,7 +3598,7 @@ private string GetCorrectCaseOfName(string ChildName, string hostname, string pa result = WSManStringLiterals.containerListener; else { - if (!String.IsNullOrEmpty(hostname)) + if (!string.IsNullOrEmpty(hostname)) { Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); if (ChildName.Equals(hostname, StringComparison.OrdinalIgnoreCase)) @@ -3521,27 +3617,28 @@ private string GetCorrectCaseOfName(string ChildName, string hostname, string pa StartWSManService(this.Force); } } + string uri = NormalizePath(path, hostname); - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { object sessionobj; SessionObjCache.TryGetValue(hostname, out sessionobj); XmlDocument outxml = FindResourceValue(sessionobj, uri, null); if (outxml != null) { - string currentPluginName = String.Empty; - GetPluginNames(outxml, out objPluginNames, out currentPluginName, path); - if (path.EndsWith(hostname + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerPlugin + WSManStringLiterals.DefaultPathSeparator + currentPluginName, StringComparison.OrdinalIgnoreCase)) - { - result = currentPluginName; + string currentPluginName = string.Empty; + GetPluginNames(outxml, out objPluginNames, out currentPluginName, path); + if (path.EndsWith(hostname + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerPlugin + WSManStringLiterals.DefaultPathSeparator + currentPluginName, StringComparison.OrdinalIgnoreCase)) + { + result = currentPluginName; + } } } } } } } - } else { if (ChildName.StartsWith(WSManStringLiterals.containerListener, StringComparison.OrdinalIgnoreCase)) @@ -3554,6 +3651,7 @@ private string GetCorrectCaseOfName(string ChildName, string hostname, string pa result = WSManStringLiterals.containerClientCertificate + "_" + ChildName.Substring(ChildName.IndexOf('_') + 1); } } + return result; } @@ -3581,11 +3679,14 @@ private ArrayList RemoveItemfromResourceArray(ArrayList resourceArray, string Ch break; } } + index++; } + if (itemfound) resourceArray.RemoveAt(index); } + return resourceArray; } @@ -3601,7 +3702,7 @@ private ArrayList RemoveItemfromResourceArray(ArrayList resourceArray, string Ch private void GetChildItemOrNamesForListenerOrCertMapping(XmlDocument xmlResource, string ListenerOrCerMapping, string path, string host, ProviderMethods methodname, bool recurse) { Hashtable Objcache, Keyscache; - string PathEnd = String.Empty; + string PathEnd = string.Empty; if (ListenerOrCerMapping.Equals(WSManStringLiterals.containerClientCertificate)) { ProcessCertMappingObjects(xmlResource, out Objcache, out Keyscache); @@ -3612,29 +3713,32 @@ private void GetChildItemOrNamesForListenerOrCertMapping(XmlDocument xmlResource } else { return; } - if (null == Objcache || null == Keyscache) + + if (Objcache == null || Keyscache == null) { return; } + if (path.EndsWith(host + WSManStringLiterals.DefaultPathSeparator + ListenerOrCerMapping, StringComparison.OrdinalIgnoreCase)) { foreach (string key in Keyscache.Keys) { switch (methodname) { - //Get the items at Config level + // Get the items at Config level case ProviderMethods.GetChildItems: PSObject obj = new PSObject(); obj.Properties.Add(new PSNoteProperty(key, WSManStringLiterals.ContainerChildValue)); WritePSObjectPropertiesAsWSManElementObjects(obj, path, (string[])Keyscache[key], null, WsManElementObjectTypes.WSManConfigContainerElement, recurse); - //WriteItemObject(new WSManConfigContainerElement(key, WSManStringLiterals.ContainerChildValue, (string[])Keyscache[key]), path, true); + // WriteItemObject(new WSManConfigContainerElement(key, WSManStringLiterals.ContainerChildValue, (string[])Keyscache[key]), path, true); break; - //Get the names of container at config level + // Get the names of container at config level case ProviderMethods.GetChildNames: WriteItemObject(key, path, true); break; } } + return; } else @@ -3651,9 +3755,9 @@ private void GetChildItemOrNamesForListenerOrCertMapping(XmlDocument xmlResource WriteItemObject(prop.Name, path + WSManStringLiterals.DefaultPathSeparator + prop.Name, false); } } + return; } - } /// @@ -3677,10 +3781,12 @@ private void GetItemListenerOrCertMapping(string path, XmlDocument xmlResource, } else { return; } - if (null == Objcache || null == Keyscache) + + if (Objcache == null || Keyscache == null) { return; } + if (path.EndsWith(host + WSManStringLiterals.DefaultPathSeparator + ContainerListenerOrClientCert, StringComparison.OrdinalIgnoreCase)) { if (Objcache.ContainsKey(childname)) @@ -3721,6 +3827,7 @@ private void RemoveListenerOrCertMapping(object sessionobj, string WsManUri, str { ProcessListenerObjects(xmlresources, out ResourcesCache, out KeysCache); } + if (KeysCache.Contains(childname)) { PSObject objResource = (PSObject)ResourcesCache[childname]; @@ -3729,14 +3836,14 @@ private void RemoveListenerOrCertMapping(object sessionobj, string WsManUri, str { SelectorParams.Add(pKey, objResource.Properties[pKey].Value); } + DeleteResourceValue(sessionobj, WsManUri, SelectorParams, false); } } } - /// - /// Used By ItemExists, HasChildItem,IsValidPath, IsItemContainer + /// Used By ItemExists, HasChildItem,IsValidPath, IsItemContainer. /// /// /// @@ -3746,12 +3853,12 @@ private bool CheckValidContainerOrPath(string path) { return true; } - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); - string ChildName = String.Empty; + string ChildName = string.Empty; string strpathChk = string.Empty; if (path.Contains(WSManStringLiterals.DefaultPathSeparator.ToString())) @@ -3763,17 +3870,15 @@ private bool CheckValidContainerOrPath(string path) ChildName = path; } - - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); - if (String.IsNullOrEmpty(host)) + if (string.IsNullOrEmpty(host)) { return false; - } - //Chks the WinRM Service + // Chks the WinRM Service if (IsPathLocalMachine(host)) { if (!IsWSManServiceRunning()) @@ -3783,41 +3888,43 @@ private bool CheckValidContainerOrPath(string path) } } - //Get URI to pass to WsMan Automation API + // Get URI to pass to WsMan Automation API string uri = NormalizePath(path, host); - if (String.IsNullOrEmpty(uri)) + if (string.IsNullOrEmpty(uri)) { return false; } - lock(WSManHelper.AutoSession) + lock (WSManHelper.AutoSession) { object sessionobj = null; Dictionary SessionObjCache = WSManHelper.GetSessionObjCache(); SessionObjCache.TryGetValue(host, out sessionobj); strpathChk = host + WSManStringLiterals.DefaultPathSeparator; - //Check for host path + // Check for host path if (path.Equals(host, StringComparison.OrdinalIgnoreCase)) { return true; } + if (path.StartsWith(strpathChk + WSManStringLiterals.containerPlugin, StringComparison.OrdinalIgnoreCase)) { - //Check for Plugin path + // Check for Plugin path if (path.Equals(strpathChk + WSManStringLiterals.containerPlugin, StringComparison.OrdinalIgnoreCase)) { return true; } XmlDocument outxml = FindResourceValue(sessionobj, uri, null); - string currentpluginname = String.Empty; + string currentpluginname = string.Empty; GetPluginNames(outxml, out objPluginNames, out currentpluginname, path); - if (String.IsNullOrEmpty(currentpluginname)) + if (string.IsNullOrEmpty(currentpluginname)) { return false; } + string filter = uri + "?Name=" + currentpluginname; XmlDocument CurrentPluginXML = GetResourceValue(sessionobj, filter, null); PSObject mshPluginLvl = ProcessPluginConfigurationLevel(CurrentPluginXML); @@ -3834,13 +3941,15 @@ private bool CheckValidContainerOrPath(string path) { return true; } + if (path.StartsWith(strpathChk + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { if (path.Equals(strpathChk + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { return true; } - if (null != arrResources) + + if (arrResources != null) { strpathChk = strpathChk + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerResources; foreach (PSObject objresource in arrResources) @@ -3859,17 +3968,20 @@ private bool CheckValidContainerOrPath(string path) return true; } } + if (path.StartsWith(strpathChk + WSManStringLiterals.DefaultPathSeparator + sResourceDirName + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase)) { if (path.Equals(strpathChk + WSManStringLiterals.DefaultPathSeparator + sResourceDirName + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase)) { return true; } + strpathChk = strpathChk + WSManStringLiterals.DefaultPathSeparator + sResourceDirName + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerSecurity + WSManStringLiterals.DefaultPathSeparator; - if (null == arrSecurities) + if (arrSecurities == null) { return false; } + foreach (PSObject security in arrSecurities) { string sSecurity = security.Properties["SecurityDIR"].Value.ToString(); @@ -3886,7 +3998,6 @@ private bool CheckValidContainerOrPath(string path) } } } - } } } @@ -3900,7 +4011,7 @@ private bool CheckValidContainerOrPath(string path) } else { - if (null != arrInitParams) + if (arrInitParams != null) { foreach (PSObject obj in arrInitParams) { @@ -3932,6 +4043,7 @@ private bool CheckValidContainerOrPath(string path) { return (ContainResourceValue(sessionobj, uri, ChildName, path, host)); } + return false; } } @@ -3943,11 +4055,13 @@ private bool ItemExistListenerOrClientCertificate(object sessionobj, string Reso { return true; } - if (null == outxml) + + if (outxml == null) { return false; } - Hashtable KeysCache=null, objcache=null; + + Hashtable KeysCache = null, objcache = null; if (parentListenerOrCert.Equals(WSManStringLiterals.containerClientCertificate, StringComparison.OrdinalIgnoreCase)) { ProcessCertMappingObjects(outxml, out objcache, out KeysCache); @@ -3957,10 +4071,10 @@ private bool ItemExistListenerOrClientCertificate(object sessionobj, string Reso ProcessListenerObjects(outxml, out objcache, out KeysCache); } - String PathChecked = host + WSManStringLiterals.DefaultPathSeparator + parentListenerOrCert; + string PathChecked = host + WSManStringLiterals.DefaultPathSeparator + parentListenerOrCert; int pos = PathChecked.Length + 1; - String RemainingPath = path.Substring(pos); - String CurrentNode = null; + string RemainingPath = path.Substring(pos); + string CurrentNode = null; pos = RemainingPath.IndexOf(WSManStringLiterals.DefaultPathSeparator); if (pos == -1) { @@ -3978,17 +4092,17 @@ private bool ItemExistListenerOrClientCertificate(object sessionobj, string Reso if (pos == -1) { - //means the path was only till the CurrentNode. Nothing ahead + // means the path was only till the CurrentNode. Nothing ahead return true; } - //Get the object cache from the listener object + // Get the object cache from the listener object PSObject obj = (PSObject)objcache[CurrentNode]; - CurrentNode = RemainingPath.Substring(pos+1); + CurrentNode = RemainingPath.Substring(pos + 1); if (CurrentNode.IndexOf(WSManStringLiterals.DefaultPathSeparator) != -1) { - //No more directories allowed after listeners objects + // No more directories allowed after listeners objects return false; } @@ -3996,11 +4110,12 @@ private bool ItemExistListenerOrClientCertificate(object sessionobj, string Reso { return true; } + return false; } /// - /// for the recurse operation of Get-ChildItems. + /// For the recurse operation of Get-ChildItems. /// /// /// @@ -4016,11 +4131,11 @@ private void GetChildItemsRecurse(string path, string childname, ProviderMethods { path = path + WSManStringLiterals.DefaultPathSeparator + childname; } + if (HasChildItems(path)) { GetChildItemsOrNames(path, ProviderMethods.GetChildItems, recurse); } - } /// @@ -4038,7 +4153,7 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool switch (methodname) { case ProviderMethods.GetChildItems: - PSObject obj = BuildHostLevelPSObjectArrayList(null, "", true); + PSObject obj = BuildHostLevelPSObjectArrayList(null, string.Empty, true); WritePSObjectPropertiesAsWSManElementObjects(obj, WSManStringLiterals.rootpath, null, "ComputerLevel", WsManElementObjectTypes.WSManConfigContainerElement, recurse); break; @@ -4047,26 +4162,27 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool { WriteItemObject(hostname, WSManStringLiterals.rootpath, true); } + break; } + return; } - //if endswith '\', removes it. + // if endswith '\', removes it. if (path.EndsWith(WSManStringLiterals.DefaultPathSeparator.ToString(), StringComparison.OrdinalIgnoreCase)) { path = path.Remove(path.LastIndexOf(WSManStringLiterals.DefaultPathSeparator)); } - //Get the wsman host name to find the session object + // Get the wsman host name to find the session object string host = GetHostName(path); - if (String.IsNullOrEmpty(host)) + if (string.IsNullOrEmpty(host)) { throw new InvalidOperationException("InvalidPath"); } - - //Checks the WinRM Service + // Checks the WinRM Service if (IsPathLocalMachine(host)) { if (!IsWSManServiceRunning()) @@ -4082,13 +4198,14 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool } } } - lock(WSManHelper.AutoSession) + + lock (WSManHelper.AutoSession) { object sessionobj; - //gets the sessionobject + // gets the sessionobject SessionObjCache.TryGetValue(host, out sessionobj); - //Normalize to the required uri + // Normalize to the required uri string uri = NormalizePath(path, host); string strPathchk = host + WSManStringLiterals.DefaultPathSeparator; @@ -4098,22 +4215,25 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool PSObject obj = BuildHostLevelPSObjectArrayList(sessionobj, uri, false); switch (methodname) { - //Get the items at Config level + // Get the items at Config level case ProviderMethods.GetChildItems: WritePSObjectPropertiesAsWSManElementObjects(obj, path, null, null, WsManElementObjectTypes.WSManConfigLeafElement, recurse); break; - //Get the names of container at config level + // Get the names of container at config level case ProviderMethods.GetChildNames: WritePSObjectPropertyNames(obj, path); break; } + return; } + XmlDocument outxml = FindResourceValue(sessionobj, uri, null); if (outxml == null || !outxml.HasChildNodes) { return; } + if (path.Contains(strPathchk + WSManStringLiterals.containerListener)) { GetChildItemOrNamesForListenerOrCertMapping(outxml, WSManStringLiterals.containerListener, path, host, methodname, recurse); @@ -4124,37 +4244,40 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool } else if (path.Contains(strPathchk + WSManStringLiterals.containerPlugin)) { - string currentpluginname = String.Empty; + string currentpluginname = string.Empty; GetPluginNames(outxml, out objPluginNames, out currentpluginname, path); if (path.EndsWith(strPathchk + WSManStringLiterals.containerPlugin, StringComparison.OrdinalIgnoreCase)) { switch (methodname) { - //Get the items at Plugin level + // Get the items at Plugin level case ProviderMethods.GetChildItems: foreach (PSPropertyInfo p in objPluginNames.Properties) { PSObject obj = new PSObject(); obj.Properties.Add(new PSNoteProperty(p.Name, p.Value)); WritePSObjectPropertiesAsWSManElementObjects(obj, path, new string[] { "Name=" + p.Name }, null, WsManElementObjectTypes.WSManConfigContainerElement, recurse); - //WriteItemObject(new PSObject(new WSManConfigContainerElement(p.Name, p.Value.ToString(), new string[] { "Name=" + p.Name })), path + WSManStringLiterals.DefaultPathSeparator + p.Name, true); + // WriteItemObject(new PSObject(new WSManConfigContainerElement(p.Name, p.Value.ToString(), new string[] { "Name=" + p.Name })), path + WSManStringLiterals.DefaultPathSeparator + p.Name, true); } + break; - //Get the names of container at Plugin level + // Get the names of container at Plugin level case ProviderMethods.GetChildNames: WritePSObjectPropertyNames(objPluginNames, path); break; } + return; } else { string filter = uri + "?Name=" + currentpluginname; XmlDocument CurrentPluginXML = GetResourceValue(sessionobj, filter, null); - if (null == CurrentPluginXML) + if (CurrentPluginXML == null) { return; } + PSObject objPluginlevel = ProcessPluginConfigurationLevel(CurrentPluginXML, true); ArrayList arrSecurity = null; ArrayList arrResources = ProcessPluginResourceLevel(CurrentPluginXML, out arrSecurity); @@ -4164,19 +4287,19 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool { switch (methodname) { - //Get the items at Plugin level + // Get the items at Plugin level case ProviderMethods.GetChildItems: WritePSObjectPropertiesAsWSManElementObjects(objPluginlevel, path, null, null, WsManElementObjectTypes.WSManConfigLeafElement, recurse); break; - //Get the names of container at Plugin level + // Get the names of container at Plugin level case ProviderMethods.GetChildNames: WritePSObjectPropertyNames(objPluginlevel, path); break; } - return; + return; } - else if(path.EndsWith(WSManStringLiterals.containerQuotasParameters, StringComparison.OrdinalIgnoreCase)) + else if (path.EndsWith(WSManStringLiterals.containerQuotasParameters, StringComparison.OrdinalIgnoreCase)) { // Get the Quotas element from the config XML. XmlNodeList nodeListForQuotas = CurrentPluginXML.GetElementsByTagName(WSManStringLiterals.containerQuotasParameters); @@ -4185,8 +4308,8 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool XmlNode pluginQuotas = nodeListForQuotas[0]; foreach (XmlAttribute attrOfQuotas in pluginQuotas.Attributes) { - String pathToAdd = - String.Format( + string pathToAdd = + string.Format( CultureInfo.InvariantCulture, "{0}{1}{2}", path, @@ -4217,34 +4340,34 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool strPathchk = strPathchk + currentpluginname + WSManStringLiterals.DefaultPathSeparator; if (path.EndsWith(strPathchk + WSManStringLiterals.containerResources, StringComparison.OrdinalIgnoreCase)) { - if (null != arrResources) + if (arrResources != null) { foreach (PSObject p in arrResources) { switch (methodname) { - //Get the items at Plugin level + // Get the items at Plugin level case ProviderMethods.GetChildItems: string[] key = new string[] { "Uri" + WSManStringLiterals.Equalto + p.Properties["ResourceURI"].Value.ToString() }; PSObject obj = new PSObject(); obj.Properties.Add(new PSNoteProperty(p.Properties["ResourceDir"].Value.ToString(), WSManStringLiterals.ContainerChildValue)); WritePSObjectPropertiesAsWSManElementObjects(obj, path, key, null, WsManElementObjectTypes.WSManConfigContainerElement, recurse); - - - //WriteItemObject(new WSManConfigContainerElement(p.Properties["ResourceDir"].Value.ToString(), WSManStringLiterals.ContainerChildValue, key), path + WSManStringLiterals.DefaultPathSeparator + p.Properties["ResourceDir"].Value.ToString(), true); + // WriteItemObject(new WSManConfigContainerElement(p.Properties["ResourceDir"].Value.ToString(), WSManStringLiterals.ContainerChildValue, key), path + WSManStringLiterals.DefaultPathSeparator + p.Properties["ResourceDir"].Value.ToString(), true); break; case ProviderMethods.GetChildNames: WriteItemObject(p.Properties["ResourceDir"].Value.ToString(), path, true); break; } } + return; } } + strPathchk = strPathchk + WSManStringLiterals.containerResources + WSManStringLiterals.DefaultPathSeparator; int Sepindex = path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathchk.Length); - string sResourceDirName = String.Empty; + string sResourceDirName = string.Empty; if (Sepindex == -1) { sResourceDirName = path.Substring(strPathchk.Length); @@ -4254,10 +4377,11 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool sResourceDirName = path.Substring(strPathchk.Length, path.IndexOf(WSManStringLiterals.DefaultPathSeparator, strPathchk.Length) - (strPathchk.Length)); } - if (null == arrResources) + if (arrResources == null) { return; } + if (path.Contains(strPathchk + sResourceDirName)) { if (path.EndsWith(strPathchk + sResourceDirName, StringComparison.OrdinalIgnoreCase)) @@ -4269,7 +4393,7 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool p.Properties.Remove("ResourceDir"); switch (methodname) { - //Get the items at Initparams level + // Get the items at Initparams level case ProviderMethods.GetChildItems: WritePSObjectPropertiesAsWSManElementObjects(p, path, null, null, WsManElementObjectTypes.WSManConfigLeafElement, recurse); break; @@ -4279,12 +4403,14 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool } } } + return; } + strPathchk = strPathchk + sResourceDirName + WSManStringLiterals.DefaultPathSeparator; if (path.EndsWith(strPathchk + WSManStringLiterals.containerSecurity, StringComparison.OrdinalIgnoreCase) || path.Contains(WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerSecurity + "_")) { - if (null != arrSecurity) + if (arrSecurity != null) { foreach (PSObject objsecurity in arrSecurity) { @@ -4295,13 +4421,13 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool objsecurity.Properties.Remove("ResourceDir"); switch (methodname) { - //Get the items at Security level + // Get the items at Security level case ProviderMethods.GetChildItems: string key = "Uri" + WSManStringLiterals.Equalto + objsecurity.Properties["Uri"].Value.ToString(); PSObject obj = new PSObject(); obj.Properties.Add(new PSNoteProperty(objsecurity.Properties["SecurityDIR"].Value.ToString(), WSManStringLiterals.ContainerChildValue)); WritePSObjectPropertiesAsWSManElementObjects(obj, path, new string[] { key }, null, WsManElementObjectTypes.WSManConfigContainerElement, recurse); - //WriteItemObject(new WSManConfigContainerElement(objsecurity.Properties["SecurityDIR"].Value.ToString(), WSManStringLiterals.ContainerChildValue, new string[] { key }), path + WSManStringLiterals.DefaultPathSeparator + objsecurity.Properties["SecurityDIR"].Value.ToString(), true); + // WriteItemObject(new WSManConfigContainerElement(objsecurity.Properties["SecurityDIR"].Value.ToString(), WSManStringLiterals.ContainerChildValue, new string[] { key }), path + WSManStringLiterals.DefaultPathSeparator + objsecurity.Properties["SecurityDIR"].Value.ToString(), true); break; case ProviderMethods.GetChildNames: @@ -4318,7 +4444,7 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool objsecurity.Properties.Remove("SecurityDIR"); switch (methodname) { - //Get the items at Security level + // Get the items at Security level case ProviderMethods.GetChildItems: WritePSObjectPropertiesAsWSManElementObjects(objsecurity, path, null, null, WsManElementObjectTypes.WSManConfigLeafElement, recurse); break; @@ -4336,15 +4462,16 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool } else if (path.EndsWith(host + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerPlugin + WSManStringLiterals.DefaultPathSeparator + currentpluginname + WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerInitParameters, StringComparison.OrdinalIgnoreCase)) { - if (null == arrInitParams) + if (arrInitParams == null) { return; } + foreach (PSObject p in arrInitParams) { switch (methodname) { - //Get the items at Initparams level + // Get the items at Initparams level case ProviderMethods.GetChildItems: WritePSObjectPropertiesAsWSManElementObjects(p, path, null, "InitParams", WsManElementObjectTypes.WSManConfigLeafElement, recurse); break; @@ -4354,7 +4481,6 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool } } } - } } else @@ -4392,7 +4518,7 @@ private void GetChildItemsOrNames(string path, ProviderMethods methodname, bool private int GetPluginNames(XmlDocument xmlPlugins, out PSObject PluginNames, out string CurrentPluginName, string path) { PluginNames = new PSObject(); - CurrentPluginName = String.Empty; + CurrentPluginName = string.Empty; // If the execution is reached this point ... that means the path should for plugins directory (..\Plugins...). if (!path.Contains(WSManStringLiterals.DefaultPathSeparator + WSManStringLiterals.containerPlugin)) @@ -4458,15 +4584,16 @@ private void AssertError(string ErrorMessage, bool IsWSManError) /// private bool IsWSManServiceRunning() { - ServiceController svc = new ServiceController("WinRM"); - if (svc != null) + if (winrmServiceController == null) { - if (svc.Status.Equals(ServiceControllerStatus.Running)) - { - return true; - } + winrmServiceController = new ServiceController("WinRM"); } - return false; + else + { + winrmServiceController.Refresh(); + } + + return (winrmServiceController.Status.Equals(ServiceControllerStatus.Running)); } /// @@ -4487,7 +4614,7 @@ private void StartWSManService(bool force) } catch (CmdletInvocationException) { - //Eating cmdlet invocation exception. The exception is thrown when No is given. + // Eating cmdlet invocation exception. The exception is thrown when No is given. } } @@ -4499,13 +4626,13 @@ private void StartWSManService(bool force) private bool IsPathLocalMachine(string host) { bool hostfound = false; - //Check is Localhost + // Check is Localhost if (host.Equals("localhost", StringComparison.OrdinalIgnoreCase)) { hostfound = true; } - //Check is TestMac + // Check is TestMac if (!hostfound) { if (host.Equals(System.Net.Dns.GetHostName(), StringComparison.OrdinalIgnoreCase)) @@ -4514,7 +4641,7 @@ private bool IsPathLocalMachine(string host) } } - //Check is TestMac.redmond.microsoft.corp.com + // Check is TestMac.redmond.microsoft.corp.com if (!hostfound) { System.Net.IPHostEntry hostentry = System.Net.Dns.GetHostEntry("localhost"); @@ -4523,7 +4650,7 @@ private bool IsPathLocalMachine(string host) hostfound = true; } - //Check is 127.0.0.1 or ::1 + // Check is 127.0.0.1 or ::1 if (!hostfound) { foreach (System.Net.IPAddress ipaddress in hostentry.AddressList) @@ -4536,7 +4663,7 @@ private bool IsPathLocalMachine(string host) } } - //check if any IPAddress. + // check if any IPAddress. if (!hostfound) { foreach (System.Net.IPAddress ipaddress in System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName())) @@ -4547,6 +4674,7 @@ private bool IsPathLocalMachine(string host) } } } + return hostfound; } @@ -4555,7 +4683,7 @@ private bool IsPathLocalMachine(string host) private void GenerateObjectNameAndKeys(Hashtable InputAttributes, string ResourceURI, string ContainerItem, out string ItemName, out string[] keys) { StringBuilder sbHashKey = new StringBuilder(); - string keysColumns = String.Empty; + string keysColumns = string.Empty; foreach (DictionaryEntry attribute in InputAttributes) { if (IsPKey(attribute.Key.ToString(), ResourceURI)) @@ -4585,57 +4713,60 @@ private void GenerateObjectNameAndKeys(Hashtable InputAttributes, string Resourc keys = keysColumns.Split('|'); } - private void ProcessCertMappingObjects(XmlDocument xmlCerts, out Hashtable Certcache, out Hashtable Keyscache) { Hashtable lCache = new Hashtable(); Hashtable kCache = new Hashtable(); XmlNodeList xmlnodesCerts = xmlCerts.GetElementsByTagName("cfg:" + "CertMapping"); - if (null == xmlnodesCerts) + if (xmlnodesCerts == null) { Certcache = null; Keyscache = null; return; } + foreach (XmlNode node in xmlnodesCerts) { Hashtable InputAttributes = new Hashtable(); PSObject objCerts = new PSObject(); string[] keys = null; - string ItemName = String.Empty; + string ItemName = string.Empty; foreach (XmlNode childnode in node.ChildNodes) { // if (childnode.LocalName.Equals("URI")) // { - // //sbCerts.Append(childnode.LocalName); - // //sbCerts.Append(WSManStringLiterals.Equalto); - // //sbCerts.Append(childnode.InnerText); - // //keys[0] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; + // // sbCerts.Append(childnode.LocalName); + // // sbCerts.Append(WSManStringLiterals.Equalto); + // // sbCerts.Append(childnode.InnerText); + // // keys[0] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; // } // else if (childnode.LocalName.Equals("Subject")) // { - // //sbCerts.Append(childnode.LocalName); - // //sbCerts.Append(WSManStringLiterals.Equalto); - // //sbCerts.Append(childnode.InnerText); - // //keys[1] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; + // // sbCerts.Append(childnode.LocalName); + // // sbCerts.Append(WSManStringLiterals.Equalto); + // // sbCerts.Append(childnode.InnerText); + // // keys[1] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; // } // else if (childnode.LocalName.Equals("Issuer")) // { - // //sbCerts.Append(childnode.LocalName); - // //sbCerts.Append(WSManStringLiterals.Equalto); - // //sbCerts.Append(childnode.InnerText); - // //keys[2] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; + // // sbCerts.Append(childnode.LocalName); + // // sbCerts.Append(WSManStringLiterals.Equalto); + // // sbCerts.Append(childnode.InnerText); + // // keys[2] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; // } + InputAttributes.Add(childnode.LocalName, childnode.InnerText); objCerts.Properties.Add(new PSNoteProperty(childnode.LocalName, childnode.InnerText)); } + GenerateObjectNameAndKeys(InputAttributes, WSManStringLiterals.containerCertMapping, WSManStringLiterals.containerClientCertificate, out ItemName, out keys); - //lCache.Add(WSManStringLiterals.containerClientCertificate + "_" + Math.Abs(sbCerts.ToString().GetHashCode()), objCerts); + // lCache.Add(WSManStringLiterals.containerClientCertificate + "_" + Math.Abs(sbCerts.ToString().GetHashCode()), objCerts); lCache.Add(ItemName, objCerts); kCache.Add(ItemName, keys); - //kCache.Add(WSManStringLiterals.containerClientCertificate + "_" + Math.Abs(sbCerts.ToString().GetHashCode()), keys); + // kCache.Add(WSManStringLiterals.containerClientCertificate + "_" + Math.Abs(sbCerts.ToString().GetHashCode()), keys); } + Certcache = lCache; Keyscache = kCache; } @@ -4645,36 +4776,38 @@ private void ProcessListenerObjects(XmlDocument xmlListeners, out Hashtable list Hashtable lCache = new Hashtable(); Hashtable kCache = new Hashtable(); XmlNodeList xmlnodesListeners = xmlListeners.GetElementsByTagName("cfg:" + WSManStringLiterals.containerListener); - if (null == xmlnodesListeners) + if (xmlnodesListeners == null) { listenercache = null; Keyscache = null; return; } + foreach (XmlNode node in xmlnodesListeners) { Hashtable InputAttributes = new Hashtable(); PSObject objListener = new PSObject(); string[] Keys = null; - string ItemName = String.Empty; + string ItemName = string.Empty; foreach (XmlNode childnode in node.ChildNodes) { - //if (childnode.LocalName.Equals("Address")) - //{ + // if (childnode.LocalName.Equals("Address")) + // { // sbListener.Append(childnode.LocalName); // sbListener.Append(WSManStringLiterals.Equalto); // sbListener.Append(childnode.InnerText); // Keys[0] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; // objListener.Properties.Add(new PSNoteProperty(childnode.LocalName, childnode.InnerText)); - //} - //else if (childnode.LocalName.Equals("Transport")) - //{ + // } + // else if (childnode.LocalName.Equals("Transport")) + // { // sbListener.Append(childnode.LocalName); // sbListener.Append(WSManStringLiterals.Equalto); // sbListener.Append(childnode.InnerText); // Keys[1] = childnode.LocalName + WSManStringLiterals.Equalto + childnode.InnerText; // objListener.Properties.Add(new PSNoteProperty(childnode.LocalName, childnode.InnerText)); - //} + // } + if (childnode.LocalName.Equals("ListeningOn")) { string ListeningOnItem = childnode.LocalName + "_" + Math.Abs(childnode.InnerText.GetHashCode()); @@ -4687,12 +4820,14 @@ private void ProcessListenerObjects(XmlDocument xmlListeners, out Hashtable list objListener.Properties.Add(new PSNoteProperty(childnode.LocalName, childnode.InnerText)); } } + GenerateObjectNameAndKeys(InputAttributes, WSManStringLiterals.containerListener, WSManStringLiterals.containerListener, out ItemName, out Keys); - //lCache.Add(WSManStringLiterals.containerListener + "_" + Math.Abs(sbListener.ToString().GetHashCode()), objListener); + // lCache.Add(WSManStringLiterals.containerListener + "_" + Math.Abs(sbListener.ToString().GetHashCode()), objListener); lCache.Add(ItemName, objListener); kCache.Add(ItemName, Keys); - //kCache.Add(WSManStringLiterals.containerListener + "_" + Math.Abs(sbListener.ToString().GetHashCode()), Keys); + // kCache.Add(WSManStringLiterals.containerListener + "_" + Math.Abs(sbListener.ToString().GetHashCode()), Keys); } + listenercache = lCache; Keyscache = kCache; } @@ -4701,7 +4836,7 @@ private PSObject ProcessPluginConfigurationLevel(XmlDocument xmldoc, bool setRun { PSObject objConfiglvl = null; - if (null != xmldoc) + if (xmldoc != null) { XmlNodeList nodelistPlugin = xmldoc.GetElementsByTagName("PlugInConfiguration"); if (nodelistPlugin.Count > 0) @@ -4710,11 +4845,11 @@ private PSObject ProcessPluginConfigurationLevel(XmlDocument xmldoc, bool setRun XmlAttributeCollection attributecol = nodelistPlugin.Item(0).Attributes; XmlNode runAsUserNode = attributecol.GetNamedItem(WSManStringLiterals.ConfigRunAsUserName); - bool runAsUserPresent = runAsUserNode != null && !String.IsNullOrEmpty(runAsUserNode.Value); + bool runAsUserPresent = runAsUserNode != null && !string.IsNullOrEmpty(runAsUserNode.Value); for (int i = 0; i <= attributecol.Count - 1; i++) { - if (String.Equals(attributecol[i].LocalName, WSManStringLiterals.ConfigRunAsPasswordName, StringComparison.OrdinalIgnoreCase) + if (string.Equals(attributecol[i].LocalName, WSManStringLiterals.ConfigRunAsPasswordName, StringComparison.OrdinalIgnoreCase) && runAsUserPresent && setRunasPasswordAsSecureString) { @@ -4726,7 +4861,7 @@ private PSObject ProcessPluginConfigurationLevel(XmlDocument xmldoc, bool setRun } } } - //Containers in Plugin Level Configs + // Containers in Plugin Level Configs if (objConfiglvl != null) { objConfiglvl.Properties.Add(new PSNoteProperty("InitializationParameters", WSManStringLiterals.ContainerChildValue)); @@ -4742,7 +4877,7 @@ private ArrayList ProcessPluginResourceLevel(XmlDocument xmldoc, out ArrayList a { ArrayList Resources = null; ArrayList nSecurity = null; - if (null != xmldoc) + if (xmldoc != null) { XmlNodeList xmlpluginResource = xmldoc.GetElementsByTagName("Resource"); if (xmlpluginResource.Count > 0) @@ -4756,7 +4891,7 @@ private ArrayList ProcessPluginResourceLevel(XmlDocument xmldoc, out ArrayList a XmlAttributeCollection attributecol = xe.Attributes; bool ExactMatchFound = false; bool SupportsOptionsFound = false; - string resourceUri = String.Empty; + string resourceUri = string.Empty; for (int i = 0; i <= attributecol.Count - 1; i++) { @@ -4765,33 +4900,36 @@ private ArrayList ProcessPluginResourceLevel(XmlDocument xmldoc, out ArrayList a resourceUri = attributecol[i].Value; strUniqueResourceId = "Resource_" + Convert.ToString(Math.Abs(attributecol[i].Value.GetHashCode()), CultureInfo.InvariantCulture); objResource.Properties.Add(new PSNoteProperty("ResourceDir", strUniqueResourceId)); - } + if (attributecol[i].LocalName.Equals("ExactMatch", StringComparison.OrdinalIgnoreCase)) { objResource.Properties.Add(new PSNoteProperty(attributecol[i].LocalName, attributecol[i].Value)); ExactMatchFound = true; continue; } + if (attributecol[i].LocalName.Equals("SupportsOptions", StringComparison.OrdinalIgnoreCase)) { objResource.Properties.Add(new PSNoteProperty(attributecol[i].LocalName, attributecol[i].Value)); SupportsOptionsFound = true; continue; } + objResource.Properties.Add(new PSNoteProperty(attributecol[i].LocalName, attributecol[i].Value)); } + if (!ExactMatchFound) { objResource.Properties.Add(new PSNoteProperty("ExactMatch", false)); } + if (!SupportsOptionsFound) { objResource.Properties.Add(new PSNoteProperty("SupportsOptions", false)); } - - //Processing capabilities + // Processing capabilities XmlDocument xmlCapabilities = new XmlDocument(); xmlCapabilities.LoadXml("" + xe.InnerXml + ""); @@ -4805,17 +4943,18 @@ private ArrayList ProcessPluginResourceLevel(XmlDocument xmldoc, out ArrayList a enumcapability.SetValue(nodeCapabilities[i].Attributes["Type"].Value, i); } } + objResource.Properties.Add(new PSNoteProperty("Capability", enumcapability)); objResource.Properties.Add(new PSNoteProperty(WSManStringLiterals.containerSecurity, WSManStringLiterals.ContainerChildValue)); - //Process Security in Resources. We add the resource Unique ID in to each security to - //identify in the Provider methods. + // Process Security in Resources. We add the resource Unique ID in to each security to + // identify in the Provider methods. nSecurity = ProcessPluginSecurityLevel(nSecurity, xmlCapabilities, strUniqueResourceId, resourceUri); Resources.Add(objResource); } - } } + arrSecurity = nSecurity; return Resources; } @@ -4823,7 +4962,7 @@ private ArrayList ProcessPluginResourceLevel(XmlDocument xmldoc, out ArrayList a private ArrayList ProcessPluginInitParamLevel(XmlDocument xmldoc) { ArrayList InitParamLvl = null; - if (null != xmldoc) + if (xmldoc != null) { XmlNodeList nodelistInitParam = xmldoc.GetElementsByTagName("Param"); if (nodelistInitParam.Count > 0) @@ -4833,25 +4972,28 @@ private ArrayList ProcessPluginInitParamLevel(XmlDocument xmldoc) { PSObject objInitParam = new PSObject(); XmlAttributeCollection attributecol = xe.Attributes; - String Name = String.Empty; - String Value = String.Empty; + string Name = string.Empty; + string Value = string.Empty; for (int i = 0; i <= attributecol.Count - 1; i++) { if (attributecol[i].LocalName.Equals("Name", StringComparison.OrdinalIgnoreCase)) { Name = attributecol[i].Value; } + if (attributecol[i].LocalName.Equals("Value", StringComparison.OrdinalIgnoreCase)) { - String ValueAsXML = attributecol[i].Value; + string ValueAsXML = attributecol[i].Value; Value = SecurityElement.Escape(ValueAsXML); } } + objInitParam.Properties.Add(new PSNoteProperty(Name, Value)); InitParamLvl.Add(objInitParam); } } } + return InitParamLvl; } @@ -4863,7 +5005,7 @@ private ArrayList ProcessPluginSecurityLevel(ArrayList arrSecurity, XmlDocument XmlNodeList nodelistSecurity = xmlSecurity.GetElementsByTagName(WSManStringLiterals.containerSecurity); if (nodelistSecurity.Count > 0) { - //SecurityLvl = new ArrayList(); + // SecurityLvl = new ArrayList(); foreach (XmlElement xe in nodelistSecurity) { bool ExactMatchFound = false; @@ -4876,18 +5018,22 @@ private ArrayList ProcessPluginSecurityLevel(ArrayList arrSecurity, XmlDocument { objSecurity.Properties.Add(new PSNoteProperty("SecurityDIR", "Security_" + Math.Abs(UniqueResourceID.GetHashCode()))); } + if (attributecol[i].LocalName.Equals("ExactMatch", StringComparison.OrdinalIgnoreCase)) { objSecurity.Properties.Add(new PSNoteProperty(attributecol[i].LocalName, attributecol[i].Value)); ExactMatchFound = true; continue; } + objSecurity.Properties.Add(new PSNoteProperty(attributecol[i].LocalName, attributecol[i].Value)); } + if (!ExactMatchFound) { objSecurity.Properties.Add(new PSNoteProperty("ExactMatch", false)); } + objSecurity.Properties.Add(new PSNoteProperty("ResourceDir", UniqueResourceID)); objSecurity.Properties.Add(new PSNoteProperty("ParentResourceUri", ParentResourceUri)); @@ -4895,6 +5041,7 @@ private ArrayList ProcessPluginSecurityLevel(ArrayList arrSecurity, XmlDocument } } } + return arrSecurity; } @@ -4914,12 +5061,11 @@ private ArrayList ProcessPluginSecurityLevel(ArrayList arrSecurity, XmlDocument /// An Configuration XML, ready to send to server. private string ConstructPluginXml(PSObject objinputparam, string ResourceURI, string host, string Operation, ArrayList resources, ArrayList securities, ArrayList initParams) { - StringBuilder sbvalues = new StringBuilder(); sbvalues.Append(""); return sbvalues.ToString(); } @@ -5001,7 +5148,7 @@ private object ValidateAndGetUserObject(string configurationName, object value) } else { - string error = String.Format( + string error = string.Format( helper.GetResourceMsgFromResourcetext("InvalidValueType"), WSManStringLiterals.ConfigRunAsPasswordName, typeof(SecureString).FullName); @@ -5022,7 +5169,7 @@ private object ValidateAndGetUserObject(string configurationName, object value) } else { - string error = String.Format( + string error = string.Format( helper.GetResourceMsgFromResourcetext("InvalidValueType"), WSManStringLiterals.ConfigRunAsUserName, typeof(PSCredential).FullName); @@ -5039,11 +5186,11 @@ private object ValidateAndGetUserObject(string configurationName, object value) /// Appends the plain text value of a SecureString variable to the StringBuilder. /// if the propertyValue provided is not SecureString appends empty string. /// - /// Value to append + /// Value to append. private string GetStringFromSecureString(object propertyValue) { SecureString value = propertyValue as SecureString; - string passwordValueToAdd = String.Empty; + string passwordValueToAdd = string.Empty; if (value != null) { @@ -5057,11 +5204,12 @@ private string GetStringFromSecureString(object propertyValue) private string ConstructResourceXml(PSObject objinputparams, ArrayList resources, ArrayList securities) { - StringBuilder sbvalues = new StringBuilder(""); + StringBuilder sbvalues = new StringBuilder(string.Empty); if (objinputparams == null && resources == null) { return sbvalues.ToString(); } + object[] capability = null; sbvalues.Append(""); if (objinputparams != null) @@ -5088,9 +5236,10 @@ private string ConstructResourceXml(PSObject objinputparams, ArrayList resources } } } + sbvalues.Append(WSManStringLiterals.GreaterThan); if (securities != null) - sbvalues.Append(ConstructSecurityXml(null, securities, String.Empty)); + sbvalues.Append(ConstructSecurityXml(null, securities, string.Empty)); sbvalues.Append(ConstructCapabilityXml(capability)); sbvalues.Append(""); } @@ -5127,6 +5276,7 @@ private string ConstructResourceXml(PSObject objinputparams, ArrayList resources } } } + sbvalues.Append(WSManStringLiterals.GreaterThan); if (securities != null) sbvalues.Append(ConstructSecurityXml(null, securities, p.Properties["ResourceDir"].Value.ToString())); @@ -5134,18 +5284,20 @@ private string ConstructResourceXml(PSObject objinputparams, ArrayList resources sbvalues.Append(""); } } + sbvalues.Append(""); return sbvalues.ToString(); } private string ConstructSecurityXml(PSObject objinputparams, ArrayList securities, string strResourceIdentity) { - // - StringBuilder sbvalues = new StringBuilder(""); + // + StringBuilder sbvalues = new StringBuilder(string.Empty); if (objinputparams == null && securities == null) { return sbvalues.ToString(); } + if (objinputparams != null) { AddSecurityProperties(objinputparams.Properties, sbvalues); @@ -5160,6 +5312,7 @@ private string ConstructSecurityXml(PSObject objinputparams, ArrayList securitie } } } + return sbvalues.ToString(); } @@ -5183,6 +5336,7 @@ private string ConstructSecurityXml(PSObject objinputparams, ArrayList securitie sbValues.Append(WSManStringLiterals.EnclosingDoubleQuotes + propValueStr + WSManStringLiterals.EnclosingDoubleQuotes); } } + sbValues.Append(WSManStringLiterals.GreaterThan); sbValues.Append(""); } @@ -5190,13 +5344,14 @@ private string ConstructSecurityXml(PSObject objinputparams, ArrayList securitie private string ConstructInitParamsXml(PSObject objinputparams, ArrayList initparams) { // - // - // - StringBuilder sbvalues = new StringBuilder(""); + // + // + StringBuilder sbvalues = new StringBuilder(string.Empty); if (objinputparams == null && initparams == null) { return sbvalues.ToString(); } + sbvalues.Append(""); if (objinputparams != null) { @@ -5233,13 +5388,14 @@ private string ConstructInitParamsXml(PSObject objinputparams, ArrayList initpar } } } + sbvalues.Append(""); return sbvalues.ToString(); } private string ConstructCapabilityXml(object[] capabilities) { - StringBuilder sbvalues = new StringBuilder(""); + StringBuilder sbvalues = new StringBuilder(string.Empty); foreach (object cap in capabilities) { sbvalues.Append(""); } + return sbvalues.ToString(); } @@ -5263,16 +5420,16 @@ private bool IsValueOfParamList(string name, string[] paramcontainer) break; } } + return result; } -#endregion Plugin private functions + #endregion Plugin private functions enum ProviderMethods { GetChildItems, GetChildNames - }; enum WsManElementObjectTypes @@ -5282,7 +5439,7 @@ enum WsManElementObjectTypes WSManConfigLeafElement }; -#region def + #region def private static readonly string[] WinrmRootName = new string[] { "winrm/Config" }; private static readonly string[] WinRmRootConfigs = new string[] { "Client", @@ -5291,10 +5448,9 @@ enum WsManElementObjectTypes "Listener", "Plugin", "ClientCertificate" +}; - }; - - //Defining Primarykeys for resource uri's + // Defining Primarykeys for resource uri's private static readonly string[] PKeyListener = new string[] { "Address", "Transport" }; private static readonly string[] PKeyPlugin = new string[] { "Name" }; private static readonly string[] PKeyCertMapping = new string[] { "Issuer", "Subject", "Uri" }; @@ -5332,15 +5488,14 @@ enum WsManElementObjectTypes WinrmRootName[0].ToString() + WSManStringLiterals.WinrmPathSeparator + WSManStringLiterals.containerWinrs, WinrmRootName[0].ToString() + WSManStringLiterals.WinrmPathSeparator + WSManStringLiterals.containerService}; -#endregion def - -#endregion private + #endregion def + #endregion private } -#region "Dynamic Parameter Classes" + #region "Dynamic Parameter Classes" -#region "New-Item Dynamic Parameters" + #region "New-Item Dynamic Parameters" /// /// Computer dynamic parameters. This is similar to connect-wsman parameters. @@ -5348,7 +5503,6 @@ enum WsManElementObjectTypes /// public class WSManProviderNewItemComputerParameters { - /// /// The following is the definition of the input parameter "OptionSet". /// OptionSet is a hash table and is used to pass a set of switches to the @@ -5361,10 +5515,11 @@ public class WSManProviderNewItemComputerParameters public Hashtable OptionSet { get { return optionset; } + set { optionset = value; } } - private Hashtable optionset; + private Hashtable optionset; /// /// The following is the definition of the input parameter "Authentication". @@ -5386,8 +5541,10 @@ public Hashtable OptionSet public AuthenticationMechanism Authentication { get { return authentication; } + set { authentication = value; } } + private AuthenticationMechanism authentication = AuthenticationMechanism.Default; /// @@ -5399,14 +5556,16 @@ public AuthenticationMechanism Authentication public string CertificateThumbprint { get { return thumbPrint; } + set { thumbPrint = value; } } + private string thumbPrint = null; /// /// The following is the definition of the input parameter "SessionOption". /// Defines a set of extended options for the WSMan session. This hashtable can - /// be created using New-WSManSessionOption + /// be created using New-WSManSessionOption. /// [Parameter] [ValidateNotNullOrEmpty] @@ -5415,8 +5574,10 @@ public string CertificateThumbprint public SessionOption SessionOption { get { return sessionoption; } + set { sessionoption = value; } } + private SessionOption sessionoption; /// @@ -5425,12 +5586,14 @@ public SessionOption SessionOption /// [Parameter(ParameterSetName = "nameSet")] [ValidateNotNullOrEmpty] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { applicationname = value; } } - private String applicationname = "wsman"; + + private string applicationname = "wsman"; /// /// The following is the definition of the input parameter "Port". @@ -5443,8 +5606,10 @@ public String ApplicationName public Int32 Port { get { return port; } + set { port = value; } } + private Int32 port = 0; /// @@ -5458,8 +5623,10 @@ public Int32 Port public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } + private SwitchParameter usessl; /// @@ -5474,10 +5641,11 @@ public SwitchParameter UseSSL public Uri ConnectionURI { get { return connectionuri; } + set { connectionuri = value; } } - private Uri connectionuri; + private Uri connectionuri; } /// @@ -5496,8 +5664,10 @@ public class WSManProviderNewItemPluginParameters public string Plugin { get { return _plugin; } + set { _plugin = value; } } + private string _plugin; /// @@ -5508,8 +5678,10 @@ public string Plugin public string FileName { get { return _filename; } + set { _filename = value; } } + private string _filename; /// @@ -5521,8 +5693,10 @@ public string FileName public string SDKVersion { get { return _sdkversion; } + set { _sdkversion = value; } } + private string _sdkversion; /// @@ -5533,8 +5707,10 @@ public string SDKVersion public System.Uri Resource { get { return _resourceuri; } + set { _resourceuri = value; } } + private System.Uri _resourceuri; /// @@ -5546,8 +5722,10 @@ public System.Uri Resource public object[] Capability { get { return _capability; } + set { _capability = value; } } + private object[] _capability; /// @@ -5559,8 +5737,10 @@ public object[] Capability public string XMLRenderingType { get { return _xmlRenderingtype; } + set { _xmlRenderingtype = value; } } + private string _xmlRenderingtype; /// @@ -5571,8 +5751,10 @@ public string XMLRenderingType public string File { get { return _file; } + set { _file = value; } } + private string _file; /// @@ -5582,9 +5764,11 @@ public string File [Parameter()] public PSCredential RunAsCredential { - get { return this.runAsCredentials; } + get { return this.runAsCredentials; } + set { this.runAsCredentials = value; } } + private PSCredential runAsCredentials; /// @@ -5594,8 +5778,10 @@ public PSCredential RunAsCredential public SwitchParameter UseSharedProcess { get { return this.sharedHost; } + set { this.sharedHost = value; } } + private bool sharedHost; /// @@ -5605,8 +5791,10 @@ public SwitchParameter UseSharedProcess public SwitchParameter AutoRestart { get { return this.autoRestart; } + set { this.autoRestart = value; } } + private bool autoRestart; /// @@ -5619,11 +5807,13 @@ public SwitchParameter AutoRestart { return this.processIdleTimeoutSeconds; } + set { this.processIdleTimeoutSeconds = value; } } + private uint? processIdleTimeoutSeconds; } @@ -5633,7 +5823,6 @@ public SwitchParameter AutoRestart /// public class WSManProviderInitializeParameters { - /// /// Parameter ParamName. /// @@ -5643,8 +5832,10 @@ public class WSManProviderInitializeParameters public string ParamName { get { return _paramname; } + set { _paramname = value; } } + private string _paramname; /// @@ -5656,8 +5847,10 @@ public string ParamName public string ParamValue { get { return _paramvalue; } + set { _paramvalue = value; } } + private string _paramvalue; } @@ -5675,8 +5868,10 @@ public class WSManProviderNewItemResourceParameters public System.Uri ResourceUri { get { return _resourceuri; } + set { _resourceuri = value; } } + private System.Uri _resourceuri; /// @@ -5688,8 +5883,10 @@ public System.Uri ResourceUri public object[] Capability { get { return _capability; } + set { _capability = value; } } + private object[] _capability; } @@ -5707,15 +5904,17 @@ public class WSManProviderNewItemSecurityParameters public string Sddl { get { return _sddl; } + set { _sddl = value; } } + private string _sddl; } -#region "ClientCertificate Dynamic Parameters" + #region "ClientCertificate Dynamic Parameters" /// /// Client Certificate Dynamic Parameters - /// Path - WsMan:\Localhost\ClientCertificate + /// Path - WsMan:\Localhost\ClientCertificate. /// public class WSManProviderClientCertificateParameters { @@ -5730,11 +5929,13 @@ public string Issuer { return _issuer; } + set { _issuer = value; } } + private string _issuer; /// @@ -5748,11 +5949,13 @@ public string Subject { return _subject; } + set { _subject = value; } } + private string _subject = "*"; /// @@ -5767,11 +5970,13 @@ public System.Uri URI { return _uri; } + set { _uri = value; } } + private System.Uri _uri = new Uri("*", UriKind.RelativeOrAbsolute); /// @@ -5784,19 +5989,19 @@ public bool Enabled { return _enabled; } + set { _enabled = value; } } - private bool _enabled = true; + private bool _enabled = true; } + #endregion -#endregion - -#region Listener Dynamic Parameters + #region Listener Dynamic Parameters /// /// Listener Dynamic parameters @@ -5815,11 +6020,13 @@ public string Address { return _address; } + set { _address = value; } } + private string _address; /// @@ -5833,11 +6040,13 @@ public string Transport { return _transport; } + set { _transport = value; } } + private string _transport = "http"; /// @@ -5851,12 +6060,14 @@ public int Port { return _port; } + set { _port = value; _IsPortSpecified = true; } } + private int _port = 0; /// @@ -5870,11 +6081,13 @@ public string HostName { return _hostName; } + set { _hostName = value; } } + private string _hostName; /// @@ -5887,11 +6100,13 @@ public bool Enabled { return _enabled; } + set { _enabled = value; } } + private bool _enabled = true; /// @@ -5907,11 +6122,13 @@ public string URLPrefix { return _urlprefix; } + set { _urlprefix = value; } } + private string _urlprefix = "wsman"; /// @@ -5926,11 +6143,13 @@ public string CertificateThumbPrint { return _certificatethumbprint; } + set { _certificatethumbprint = value; } } + private string _certificatethumbprint; /// @@ -5942,24 +6161,25 @@ public bool IsPortSpecified { return _IsPortSpecified; } + set { _IsPortSpecified = value; } - } + private bool _IsPortSpecified = false; } -#endregion + #endregion -#endregion + #endregion -#region SetItemDynamicParameters + #region SetItemDynamicParameters /// /// Set-Item Dynamic parameters - /// Path - WsMan:\Localhost\Client> Set-Item .\TrustedHosts + /// Path - WsMan:\Localhost\Client> Set-Item .\TrustedHosts. /// public class WSManProviderSetItemDynamicParameters { @@ -5970,17 +6190,18 @@ public class WSManProviderSetItemDynamicParameters public SwitchParameter Concatenate { get { return _concatenate; } + set { _concatenate = value; } } + private SwitchParameter _concatenate = false; } + #endregion SetItemDynamicParameters -#endregion SetItemDynamicParameters - -#endregion + #endregion -#region "String Literals" + #region "String Literals" internal static class WSManStringLiterals { @@ -5989,144 +6210,134 @@ internal static class WSManStringLiterals /// /// The default path separator used by the base implementation of the providers. /// - /// internal const char DefaultPathSeparator = '\\'; /// /// The alternate path separator used by the base implementation of the providers. /// - /// internal const char AlternatePathSeparator = '/'; /// - /// Double Quotes used while constructing XML + /// Double Quotes used while constructing XML. /// internal const char EnclosingDoubleQuotes = '\"'; /// - /// Equalto Used while constructing XML + /// Equalto Used while constructing XML. /// internal const char Equalto = '='; /// - /// For XML Construction + /// For XML Construction. /// internal const char GreaterThan = '>'; /// - /// XML Closing Tag + /// XML Closing Tag. /// internal const string XmlClosingTag = "/>"; /// - /// White space used while constructing XML + /// White space used while constructing XML. /// internal const char SingleWhiteSpace = ' '; /// - /// Root node of WsMan + /// Root node of WsMan. /// internal const string ProviderName = "WSMan"; /// - /// /// internal const string WsMan_Schema = "http://schemas.microsoft.com/wbem/wsman/1/config"; /// - /// /// internal const string NS_XSI = "xmlns:xsi=" + "\"http://www.w3.org/2001/XMLSchema-instance\""; /// - /// /// internal const string ATTR_NIL = "xsi:nil=" + "\"true\""; /// - /// /// internal const string ATTR_NIL_NAME = "xsi:nil"; /// - /// /// internal const char WinrmPathSeparator = '/'; /// - /// /// internal const string rootpath = "WSMan"; /// - /// /// internal const string ContainerChildValue = "Container"; -#region WsMan Containers + #region WsMan Containers /// - /// Plugin Container + /// Plugin Container. /// internal const string containerPlugin = "Plugin"; /// - /// Client Container + /// Client Container. /// internal const string containerClient = "Client"; /// - /// Shell Container + /// Shell Container. /// internal const string containerShell = "Shell"; /// - /// ClientCertificate Container + /// ClientCertificate Container. /// internal const string containerClientCertificate = "ClientCertificate"; /// - /// Listener Container + /// Listener Container. /// internal const string containerListener = "Listener"; /// - /// Service Container + /// Service Container. /// internal const string containerService = "Service"; /// - /// Auth Container - Under Client,Service + /// Auth Container - Under Client,Service. /// internal const string containerAuth = "Auth"; /// - /// DefaultPorts Container - Under Client,Service + /// DefaultPorts Container - Under Client,Service. /// internal const string containerDefaultPorts = "DefaultPorts"; /// - /// TrustedHosts Container - Under Client,Service + /// TrustedHosts Container - Under Client,Service. /// internal const string containerTrustedHosts = "TrustedHosts"; /// - /// Security Container - Under Plugin + /// Security Container - Under Plugin. /// internal const string containerSecurity = "Security"; /// - /// Resources Container - Under Plugin + /// Resources Container - Under Plugin. /// internal const string containerResources = "Resources"; /// - /// Resource in Resources Container - Under Plugin + /// Resource in Resources Container - Under Plugin. /// internal const string containerSingleResource = "Resource"; /// - /// InitParameters Container - Under Plugin + /// InitParameters Container - Under Plugin. /// internal const string containerInitParameters = "InitializationParameters"; /// - /// Quotas Container - Under Plugin + /// Quotas Container - Under Plugin. /// internal const string containerQuotasParameters = "Quotas"; /// - /// Winrs Container - Exposed as Shell + /// Winrs Container - Exposed as Shell. /// internal const string containerWinrs = "Winrs"; /// - /// certmapping Container - Exposed as ClientCertificate in the provider. + /// Certmapping Container - Exposed as ClientCertificate in the provider. /// internal const string containerCertMapping = "Service/certmapping"; - /// - /// Possible Values in Plugin Top Level XML + /// Possible Values in Plugin Top Level XML. /// internal static readonly string[] NewItemPluginConfigParams = new string[] { @@ -6152,9 +6363,9 @@ internal static class WSManStringLiterals /// Possible Values in Plugin Top Security XML internal static readonly string[] NewItemSecurityParams = new string[] { "Uri", "Sddl", "ExactMatch" }; -#endregion WsMan Containers + #endregion WsMan Containers -#region WSMAN Config Names + #region WSMAN Config Names /// /// Name of the configuration which represents RunAs Password. /// @@ -6210,7 +6421,7 @@ internal static class WSManStringLiterals /// internal const string HiddenSuffixForSourceOfValue = "___Source"; -#endregion + #endregion /// /// This is used to start the service. return a bool value. if false we throw error. @@ -6239,26 +6450,27 @@ internal static class WSManStringLiterals Restart-Service WinRM -Force -Confirm:$false return $true }} + return $false }} #end of Begin block }} $_ | Start-WSManServiceD15A7957836142a18627D7E1D342DD82 -force $args[0] -captionForStart $args[1] -queryForStart $args[2] "; - } -#endregion "String Literals" + #endregion "String Literals" -#region "WsMan Output Objects" + #region "WsMan Output Objects" /// - /// Base Output object + /// Base Output object. /// public class WSManConfigElement { internal WSManConfigElement() { } + internal WSManConfigElement(string name, string typenameofelement) { _name = name; @@ -6271,9 +6483,10 @@ internal WSManConfigElement(string name, string typenameofelement) public string Name { get { return _name; } - set { _name = value; } + set { _name = value; } } + private string _name; /// @@ -6282,8 +6495,10 @@ public string Name public string TypeNameOfElement { get { return _typenameofelement; } + set { _typenameofelement = value; } } + private string _typenameofelement; /// @@ -6292,17 +6507,19 @@ public string TypeNameOfElement public string Type { get { return _typenameofelement; } + set { _typenameofelement = value; } } } /// - /// Leaf Element + /// Leaf Element. /// public class WSManConfigLeafElement : WSManConfigElement { internal WSManConfigLeafElement() { } + internal WSManConfigLeafElement(string Name, object Value, string TypeNameOfElement, object SourceOfValue = null) { _value = Value; @@ -6317,9 +6534,10 @@ internal WSManConfigLeafElement(string Name, object Value, string TypeNameOfElem public object SourceOfValue { get { return _SourceOfValue; } - set { _SourceOfValue = value; } + set { _SourceOfValue = value; } } + private object _SourceOfValue; /// @@ -6328,13 +6546,14 @@ public object SourceOfValue public object Value { get { return _value; } - set { _value = value; } + set { _value = value; } } + private object _value; } /// - /// Container Element + /// Container Element. /// public class WSManConfigContainerElement : WSManConfigElement { @@ -6352,17 +6571,13 @@ internal WSManConfigContainerElement(string Name, string TypeNameOfElement, stri public string[] Keys { get { return _keys; } - set { _keys = value; } + set { _keys = value; } } + private string[] _keys; } - - -#endregion "WsMan Output Objects" - - + #endregion "WsMan Output Objects" } - diff --git a/src/Microsoft.WSMan.Management/CredSSP.cs b/src/Microsoft.WSMan.Management/CredSSP.cs index cfe47a63a516..c4dbc0684f9e 100644 --- a/src/Microsoft.WSMan.Management/CredSSP.cs +++ b/src/Microsoft.WSMan.Management/CredSSP.cs @@ -1,26 +1,24 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Management.Automation; -using System.Management.Automation.Provider; -using System.Xml; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using Microsoft.Win32; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Provider; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Security; using System.Threading; -#if CORECLR -using System.Xml.XPath; -#endif +using System.Xml; + +using Microsoft.Win32; using Dbg = System.Management.Automation; @@ -52,15 +50,16 @@ public class WSManCredSSPCommandBase : PSCmdlet public string Role { get { return role; } + set { role = value; } } + private string role; #endregion #region Utilities /// - /// /// /// /// Returns a session object upon successful creation..otherwise @@ -96,10 +95,9 @@ internal IWSManSession CreateWSManSession() /// Disables CredSSP authentication on the client. CredSSP authentication /// enables an application to delegate the user's credentials from the client to /// the server, hence allowing the user to perform management operations that - /// access a second hop + /// access a second hop. /// - [Cmdlet(VerbsLifecycle.Disable, "WSManCredSSP", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141438")] [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cred")] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SSP")] @@ -115,7 +113,7 @@ private void DisableClientSideSettings() { WSManHelper helper = new WSManHelper(this); IWSManSession m_SessionObj = CreateWSManSession(); - if (null == m_SessionObj) + if (m_SessionObj == null) { return; } @@ -140,6 +138,7 @@ private void DisableClientSideSettings() WriteError(er); return; } + m_SessionObj.Put(helper.CredSSP_RUri, inputXml, 0); if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) @@ -167,7 +166,7 @@ private void DisableClientSideSettings() } finally { - if (!String.IsNullOrEmpty(m_SessionObj.Error)) + if (!string.IsNullOrEmpty(m_SessionObj.Error)) { helper.AssertError(m_SessionObj.Error, true, null); } @@ -181,7 +180,7 @@ private void DisableServerSideSettings() { WSManHelper helper = new WSManHelper(this); IWSManSession m_SessionObj = CreateWSManSession(); - if (null == m_SessionObj) + if (m_SessionObj == null) { return; } @@ -216,7 +215,7 @@ private void DisableServerSideSettings() } finally { - if (!String.IsNullOrEmpty(m_SessionObj.Error)) + if (!string.IsNullOrEmpty(m_SessionObj.Error)) { helper.AssertError(m_SessionObj.Error, true, null); } @@ -245,6 +244,7 @@ private void DeleteUserDelegateSettings() DeleteDelegateSettings(applicationname, Registry.CurrentUser, key, GPO); } } + KeyHandle = System.IntPtr.Zero; } @@ -256,7 +256,6 @@ private void DeleteDelegateSettings(string applicationname, RegistryKey rootKey, bool otherkeys = false; try { - string Registry_Path_Credentials_Delegation = Registry_Path + @"\CredentialsDelegation"; RegistryKey Allow_Fresh_Credential_Key = rootKey.OpenSubKey(Registry_Path_Credentials_Delegation + @"\" + helper.Key_Allow_Fresh_Credentials, true); if (Allow_Fresh_Credential_Key != null) @@ -276,8 +275,10 @@ private void DeleteDelegateSettings(string applicationname, RegistryKey rootKey, otherkeys = true; } } + Allow_Fresh_Credential_Key.DeleteValue(value); } + foreach (string keyvalue in KeyCollection) { Allow_Fresh_Credential_Key.SetValue(Convert.ToString(i + 1, CultureInfo.InvariantCulture), keyvalue, RegistryValueKind.String); @@ -285,6 +286,7 @@ private void DeleteDelegateSettings(string applicationname, RegistryKey rootKey, } } } + if (!otherkeys) { rKey = rootKey.OpenSubKey(Registry_Path_Credentials_Delegation, true); @@ -295,17 +297,20 @@ private void DeleteDelegateSettings(string applicationname, RegistryKey rootKey, { rKey.DeleteValue(helper.Key_Allow_Fresh_Credentials, false); } + object regval2 = rKey.GetValue(helper.Key_Concatenate_Defaults_AllowFresh); if (regval2 != null) { rKey.DeleteValue(helper.Key_Concatenate_Defaults_AllowFresh, false); } + if (rKey.OpenSubKey(helper.Key_Allow_Fresh_Credentials) != null) { rKey.DeleteSubKeyTree(helper.Key_Allow_Fresh_Credentials); } } } + GPO.Save(true, true, new Guid("35378EAC-683F-11D2-A89A-00C04FBBCFA2"), new Guid("6AD20875-336C-4e22-968F-C709ACB15814")); } catch (InvalidOperationException ex) @@ -331,20 +336,11 @@ private void DeleteDelegateSettings(string applicationname, RegistryKey rootKey, } #endregion private /// - /// begin processing method. + /// Begin processing method. /// protected override void BeginProcessing() { -#if !CORECLR - if (Environment.OSVersion.Version.Major < 6) - { - //OS is XP/Win2k3. Throw error. - WSManHelper helper = new WSManHelper(this); - string message = helper.FormatResourceMsgFromResourcetext("CmdletNotAvailable"); - throw new InvalidOperationException(message); - } -#endif - //If not running elevated, then throw an "elevation required" error message. + // If not running elevated, then throw an "elevation required" error message. WSManHelper.ThrowIfNotAdministrator(); if (Role.Equals(Client, StringComparison.OrdinalIgnoreCase)) @@ -356,22 +352,22 @@ protected override void BeginProcessing() { DisableServerSideSettings(); } - }//End BeginProcessing() + } #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -382,7 +378,7 @@ protected override void BeginProcessing() } #endregion IDisposable Members - }//End Class + } #endregion DisableWsManCredSSP #region EnableCredSSP @@ -397,33 +393,27 @@ protected override void BeginProcessing() /// 1. Enables WSMan local configuration on client to enable CredSSP /// 2. Sets CredSSP policy AllowFreshCredentials to wsman/Delegate. This policy /// allows delegating explicit credentials to a server when server - /// authentication is achieved via a trusted X509 certificate or Kerberos + /// authentication is achieved via a trusted X509 certificate or Kerberos. /// [Cmdlet(VerbsLifecycle.Enable, "WSManCredSSP", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141442")] [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cred")] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SSP")] public class EnableWSManCredSSPCommand : WSManCredSSPCommandBase, IDisposable/*, IDynamicParameters*/ { - #region Private Data - - //private const string DelegateComputerParam = "DelegateComputer"; - //private String[] delegatecomputer; - //private RuntimeDefinedParameterDictionary dynamicParameters = new RuntimeDefinedParameterDictionary(); - - #endregion - /// - /// delegate parameter + /// Delegate parameter. /// [Parameter(Position = 1)] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public String[] DelegateComputer + public string[] DelegateComputer { get { return delegatecomputer; } + set { delegatecomputer = value; } } - private String[] delegatecomputer; + + private string[] delegatecomputer; /// /// Property that sets force parameter. @@ -432,11 +422,13 @@ public String[] DelegateComputer public SwitchParameter Force { get { return force; } + set { force = value; } } + private bool force = false; - //helper variable + // helper variable private WSManHelper helper; // The application name MUST be "wsman" as wsman got approval from security @@ -450,17 +442,9 @@ public SwitchParameter Force /// protected override void BeginProcessing() { - //If not running elevated, then throw an "elevation required" error message. + // If not running elevated, then throw an "elevation required" error message. WSManHelper.ThrowIfNotAdministrator(); helper = new WSManHelper(this); -#if !CORECLR - if (Environment.OSVersion.Version.Major < 6) - { - //OS is XP/Win2k3. Throw error. - string message = helper.FormatResourceMsgFromResourcetext("CmdletNotAvailable"); - throw new InvalidOperationException(message); - } -#endif // DelegateComputer cannot be specified when Role is other than client if ((delegatecomputer != null) && !Role.Equals(Client, StringComparison.OrdinalIgnoreCase)) @@ -494,70 +478,33 @@ protected override void BeginProcessing() { EnableServerSideSettings(); } - }//End BeginProcessing() - - /* - /// - /// This method returns DynamicParameters used for Enable-WSManCredSSP cmdlet. Enable-WSManCredSSP - /// supports -DelegateComputer parameter when -Role is client. - /// - /// - /// An object representing the dynamic parameters for the cmdlet or null if there - /// are none. - /// - object IDynamicParameters.GetDynamicParameters() - { - // return null if the role is not client. - if (!Role.Equals(ClientRole, StringComparison.OrdinalIgnoreCase)) - { - return dynamicParameters; - } - - // Construct attributes for the DelegateComputer parameter - Collection delegateComputerAttributeCollection = new Collection(); - ParameterAttribute paramAttribute = new ParameterAttribute(); - paramAttribute.Mandatory = true; - paramAttribute.Position = 1; - ValidateNotNullOrEmptyAttribute notNullAttribute = new ValidateNotNullOrEmptyAttribute(); - delegateComputerAttributeCollection.Add(paramAttribute); - delegateComputerAttributeCollection.Add(notNullAttribute); - - // Construct the parameter and return. - RuntimeDefinedParameter delegateComputer = new RuntimeDefinedParameter( - DelegateComputerParam, - typeof(string[]), - delegateComputerAttributeCollection); - dynamicParameters.Add(DelegateComputerParam, delegateComputer); - - return dynamicParameters; + } - } // GetDynamicParameters*/ #endregion /// - /// /// /// /// private void EnableClientSideSettings() { - String query = helper.GetResourceMsgFromResourcetext("CredSSPContinueQuery"); - String caption = helper.GetResourceMsgFromResourcetext("CredSSPContinueCaption"); + string query = helper.GetResourceMsgFromResourcetext("CredSSPContinueQuery"); + string caption = helper.GetResourceMsgFromResourcetext("CredSSPContinueCaption"); if (!force && !ShouldContinue(query, caption)) { return; } IWSManSession m_SessionObj = CreateWSManSession(); - if (null == m_SessionObj) + if (m_SessionObj == null) { return; } try { - //get the credssp node to check if wsman is configured on this machine + // get the credssp node to check if wsman is configured on this machine string result = m_SessionObj.Get(helper.CredSSP_RUri, 0); XmlNode node = helper.GetXmlNode(result, helper.CredSSP_SNode, helper.CredSSP_XMLNmsp); @@ -568,15 +515,12 @@ private void EnableClientSideSettings() WriteError(er); return; } - // Extract delegateComputer information from dynamic parameters collection - //RuntimeDefinedParameter delegateComputerParameter = dynamicParameters[DelegateComputerParam]; - //delegatecomputer = (string[])delegateComputerParameter.Value; string newxmlcontent = @"true"; try { XmlDocument xmldoc = new XmlDocument(); - //push the xml string with credssp enabled + // push the xml string with credssp enabled xmldoc.LoadXml(m_SessionObj.Put(helper.CredSSP_RUri, newxmlcontent, 0)); // set the Registry using GroupPolicyObject @@ -609,7 +553,7 @@ private void EnableClientSideSettings() } finally { - if (!String.IsNullOrEmpty(m_SessionObj.Error)) + if (!string.IsNullOrEmpty(m_SessionObj.Error)) { helper.AssertError(m_SessionObj.Error, true, delegatecomputer); } @@ -623,22 +567,22 @@ private void EnableClientSideSettings() private void EnableServerSideSettings() { - String query = helper.GetResourceMsgFromResourcetext("CredSSPServerContinueQuery"); - String caption = helper.GetResourceMsgFromResourcetext("CredSSPContinueCaption"); + string query = helper.GetResourceMsgFromResourcetext("CredSSPServerContinueQuery"); + string caption = helper.GetResourceMsgFromResourcetext("CredSSPContinueCaption"); if (!force && !ShouldContinue(query, caption)) { return; } IWSManSession m_SessionObj = CreateWSManSession(); - if (null == m_SessionObj) + if (m_SessionObj == null) { return; } try { - //get the credssp node to check if wsman is configured on this machine + // get the credssp node to check if wsman is configured on this machine string result = m_SessionObj.Get(helper.Service_CredSSP_Uri, 0); XmlNode node = helper.GetXmlNode(result, helper.CredSSP_SNode, @@ -658,7 +602,7 @@ private void EnableServerSideSettings() string newxmlcontent = string.Format(CultureInfo.InvariantCulture, @"true", helper.Service_CredSSP_XMLNmsp); - //push the xml string with credssp enabled + // push the xml string with credssp enabled xmldoc.LoadXml(m_SessionObj.Put(helper.Service_CredSSP_Uri, newxmlcontent, 0)); WriteObject(xmldoc.FirstChild); } @@ -669,7 +613,7 @@ private void EnableServerSideSettings() } finally { - if (!String.IsNullOrEmpty(m_SessionObj.Error)) + if (!string.IsNullOrEmpty(m_SessionObj.Error)) { helper.AssertError(m_SessionObj.Error, true, delegatecomputer); } @@ -682,7 +626,6 @@ private void EnableServerSideSettings() } /// - /// /// private void UpdateCurrentUserRegistrySettings() { @@ -699,15 +642,14 @@ private void UpdateCurrentUserRegistrySettings() { string key = GPOpath + "\\" + keyname + "\\" + @"Software\Policies\Microsoft\Windows"; UpdateGPORegistrySettings(applicationname, this.delegatecomputer, Registry.CurrentUser, key); - } } - //saving gpo settings + // saving gpo settings GPO.Save(true, true, new Guid("35378EAC-683F-11D2-A89A-00C04FBBCFA2"), new Guid("7A9206BD-33AF-47af-B832-D4128730E990")); } /// - /// Updates the grouppolicy registry settings + /// Updates the grouppolicy registry settings. /// /// /// @@ -715,21 +657,17 @@ private void UpdateCurrentUserRegistrySettings() /// private void UpdateGPORegistrySettings(string applicationname, string[] delegatestring, RegistryKey rootKey, string Registry_Path) { - //RegistryKey rootKey = Registry.LocalMachine; + // RegistryKey rootKey = Registry.LocalMachine; RegistryKey Credential_Delegation_Key; RegistryKey Allow_Fresh_Credential_Key; int i = 0; try { string Registry_Path_Credentials_Delegation = Registry_Path + @"\CredentialsDelegation"; - //open the registry key.If key is not present,create a new one + // open the registry key.If key is not present,create a new one Credential_Delegation_Key = rootKey.OpenSubKey(Registry_Path_Credentials_Delegation, true); if (Credential_Delegation_Key == null) - Credential_Delegation_Key = rootKey.CreateSubKey(Registry_Path_Credentials_Delegation -#if !CORECLR - , RegistryKeyPermissionCheck.ReadWriteSubTree -#endif - ); + Credential_Delegation_Key = rootKey.CreateSubKey(Registry_Path_Credentials_Delegation, RegistryKeyPermissionCheck.ReadWriteSubTree); Credential_Delegation_Key.SetValue(helper.Key_Allow_Fresh_Credentials, 1, RegistryValueKind.DWord); Credential_Delegation_Key.SetValue(helper.Key_Concatenate_Defaults_AllowFresh, 1, RegistryValueKind.DWord); @@ -737,11 +675,7 @@ private void UpdateGPORegistrySettings(string applicationname, string[] delegate // add the delegate value Allow_Fresh_Credential_Key = rootKey.OpenSubKey(Registry_Path_Credentials_Delegation + @"\" + helper.Key_Allow_Fresh_Credentials, true); if (Allow_Fresh_Credential_Key == null) - Allow_Fresh_Credential_Key = rootKey.CreateSubKey(Registry_Path_Credentials_Delegation + @"\" + helper.Key_Allow_Fresh_Credentials -#if !CORECLR - , RegistryKeyPermissionCheck.ReadWriteSubTree -#endif - ); + Allow_Fresh_Credential_Key = rootKey.CreateSubKey(Registry_Path_Credentials_Delegation + @"\" + helper.Key_Allow_Fresh_Credentials, RegistryKeyPermissionCheck.ReadWriteSubTree); if (Allow_Fresh_Credential_Key != null) { @@ -768,23 +702,21 @@ private void UpdateGPORegistrySettings(string applicationname, string[] delegate ErrorRecord er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidOperation, null); WriteError(er); } - } #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -795,7 +727,7 @@ private void UpdateGPORegistrySettings(string applicationname, string[] delegate } #endregion IDisposable Members - }//End Class + } #endregion EnableCredSSP #region Get-CredSSP @@ -811,17 +743,17 @@ private void UpdateGPORegistrySettings(string applicationname, string[] delegate /// 2. Gets the configuration information for the CredSSP policy /// AllowFreshCredentials . This policy allows delegating explicit credentials /// to a server when server authentication is achieved via a trusted X509 - /// certificate or Kerberos + /// certificate or Kerberos. /// [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cred")] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SSP")] [Cmdlet(VerbsCommon.Get, "WSManCredSSP", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141443")] public class GetWSManCredSSPCommand : PSCmdlet, IDisposable { - # region private + #region private WSManHelper helper = null; /// - /// method to get the values. + /// Method to get the values. /// private string GetDelegateSettings(string applicationname) { @@ -853,6 +785,7 @@ private string GetDelegateSettings(string applicationname) } } } + if (result.EndsWith(listvalue, StringComparison.OrdinalIgnoreCase)) { result = result.Remove(result.Length - 1); @@ -876,29 +809,20 @@ private string GetDelegateSettings(string applicationname) ErrorRecord er = new ErrorRecord(ex, "ObjectDisposedException", ErrorCategory.PermissionDenied, null); WriteError(er); } - return result; + + return result; } - # endregion private + #endregion private - # region overrides + #region overrides /// /// Method to begin processing. /// protected override void BeginProcessing() { - //If not running elevated, then throw an "elevation required" error message. + // If not running elevated, then throw an "elevation required" error message. WSManHelper.ThrowIfNotAdministrator(); - helper = new WSManHelper(this); -#if !CORECLR - if (Environment.OSVersion.Version.Major < 6) - { - //OS is XP/Win2k3. Throw error. - string message = helper.FormatResourceMsgFromResourcetext("CmdletNotAvailable"); - throw new InvalidOperationException(message); - } -#endif - IWSManSession m_SessionObj = null; try { @@ -968,7 +892,7 @@ protected override void BeginProcessing() } finally { - if (!String.IsNullOrEmpty(m_SessionObj.Error)) + if (!string.IsNullOrEmpty(m_SessionObj.Error)) { helper.AssertError(m_SessionObj.Error, true, null); } @@ -983,17 +907,16 @@ protected override void BeginProcessing() #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -1004,15 +927,7 @@ protected override void BeginProcessing() } #endregion IDisposable Members - - - - - } - - - #endregion } diff --git a/src/Microsoft.WSMan.Management/CurrentConfigurations.cs b/src/Microsoft.WSMan.Management/CurrentConfigurations.cs index 02b2038fdb6d..41427678150d 100644 --- a/src/Microsoft.WSMan.Management/CurrentConfigurations.cs +++ b/src/Microsoft.WSMan.Management/CurrentConfigurations.cs @@ -1,26 +1,12 @@ -//------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// -// -// Pankaj Sarda -// -// -// -// Class that queries the server and gets current configurations. -// Also provides a generic way to update the configurations. -// -// -// -//------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Globalization; +using System.Xml; namespace Microsoft.WSMan.Management { - using System; - using System.Globalization; - using System.Xml; - /// /// Class that queries the server and gets current configurations. /// Also provides a generic way to update the configurations. @@ -93,7 +79,7 @@ public CurrentConfigurations(IWSManSession serverSession) /// False, if operation failed. public bool RefreshCurrentConfiguration(string responseOfGet) { - if (String.IsNullOrEmpty(responseOfGet)) + if (string.IsNullOrEmpty(responseOfGet)) { throw new ArgumentNullException("responseOfGet"); } @@ -104,7 +90,7 @@ public bool RefreshCurrentConfiguration(string responseOfGet) this.nameSpaceManger = new XmlNamespaceManager(this.rootDocument.NameTable); this.nameSpaceManger.AddNamespace(CurrentConfigurations.DefaultNameSpacePrefix, this.documentElement.NamespaceURI); - return String.IsNullOrEmpty(this.serverSession.Error); + return string.IsNullOrEmpty(this.serverSession.Error); } /// @@ -115,7 +101,7 @@ public bool RefreshCurrentConfiguration(string responseOfGet) /// False, if operation is not succesful. public void PutConfigurationOnServer(string resourceUri) { - if (String.IsNullOrEmpty(resourceUri)) + if (string.IsNullOrEmpty(resourceUri)) { throw new ArgumentNullException("resourceUri"); } @@ -169,7 +155,7 @@ public void UpdateOneConfiguration(string pathToNodeFromRoot, string configurati throw new ArgumentNullException("pathToNodeFromRoot"); } - if (String.IsNullOrEmpty(configurationName)) + if (string.IsNullOrEmpty(configurationName)) { throw new ArgumentNullException("configurationName"); } @@ -195,7 +181,7 @@ public void UpdateOneConfiguration(string pathToNodeFromRoot, string configurati } } - XmlNode attr = this.rootDocument.CreateNode(XmlNodeType.Attribute, configurationName, String.Empty); + XmlNode attr = this.rootDocument.CreateNode(XmlNodeType.Attribute, configurationName, string.Empty); attr.Value = configurationValue; nodeToUpdate.Attributes.SetNamedItem(attr); diff --git a/src/Microsoft.WSMan.Management/Interop.cs b/src/Microsoft.WSMan.Management/Interop.cs index 5d8a6802db44..d9394f4a9411 100644 --- a/src/Microsoft.WSMan.Management/Interop.cs +++ b/src/Microsoft.WSMan.Management/Interop.cs @@ -1,29 +1,26 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Management.Automation; -using System.Management.Automation.Provider; -using System.Xml; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Provider; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; +using System.Xml; #pragma warning disable 1591 namespace Microsoft.WSMan.Management { - #region "public Api" - - #region WsManEnumFlags /// _WSManEnumFlags enumeration. @@ -60,12 +57,8 @@ public enum WSManEnumFlags #endregion WsManEnumFlags - - - #region WsManSessionFlags /// WSManSessionFlags enumeration. - /// [SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags")] [TypeLibType((short)0)] public enum WSManSessionFlags @@ -132,20 +125,19 @@ public enum WSManSessionFlags #region AuthenticationMechanism /// WSManEnumFlags enumeration - /// [SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags")] public enum AuthenticationMechanism { /// - /// Use no authentication + /// Use no authentication. /// None = 0x0, /// - /// Use Default authentication + /// Use Default authentication. /// Default = 0x1, /// - /// Use digest authentication for a remote operation + /// Use digest authentication for a remote operation. /// Digest = 0x2, /// @@ -153,23 +145,23 @@ public enum AuthenticationMechanism /// Negotiate = 0x4, /// - /// Use basic authentication for a remote operation + /// Use basic authentication for a remote operation. /// Basic = 0x8, /// - /// Use kerberos authentication for a remote operation + /// Use kerberos authentication for a remote operation. /// Kerberos = 0x10, /// - /// Use client certificate authentication for a remote operation + /// Use client certificate authentication for a remote operation. /// ClientCertificate = 0x20, /// - /// Use CredSSP authentication for a remote operation + /// Use CredSSP authentication for a remote operation. /// [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Credssp")] Credssp = 0x80, - } + } #endregion AuthenticationMechanism @@ -204,8 +196,8 @@ public interface IWSMan #endif /// CreateSession method of IWSMan interface. - /// An original IDL definition of CreateSession method was the following: HRESULT CreateSession ([optional, defaultvalue("")] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); - // IDL: HRESULT CreateSession ([optional, defaultvalue("")] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); + /// An original IDL definition of CreateSession method was the following: HRESULT CreateSession ([optional, defaultvalue(string.Empty)] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); + // IDL: HRESULT CreateSession ([optional, defaultvalue(string.Empty)] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); [DispId(1)] #if CORECLR @@ -338,7 +330,6 @@ string CertificateThumbprint [DispId(1)] set; } - } /// IWSManConnectionOptions interface. @@ -388,7 +379,6 @@ public interface IWSManConnectionOptionsEx2 : IWSManConnectionOptionsEx int ProxyAuthenticationUseDigest(); }; - #endregion IWSManConnectionOptions #region IWSManEnumerator @@ -486,8 +476,8 @@ public interface IWSManEx #endif /// CreateSession method of IWSManEx interface. - /// An original IDL definition of CreateSession method was the following: HRESULT CreateSession ([optional, defaultvalue("")] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); - // IDL: HRESULT CreateSession ([optional, defaultvalue("")] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); + /// An original IDL definition of CreateSession method was the following: HRESULT CreateSession ([optional, defaultvalue(string.Empty)] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); + // IDL: HRESULT CreateSession ([optional, defaultvalue(string.Empty)] BSTR connection, [optional, defaultvalue(0)] long flags, [optional] IDispatch* connectionOptions, [out, retval] IDispatch** ReturnValue); [DispId(1)] #if CORECLR @@ -498,7 +488,6 @@ public interface IWSManEx object CreateSession([MarshalAs(UnmanagedType.BStr)] string connection, int flags, [MarshalAs(UnmanagedType.IDispatch)] object connectionOptions); #endif - /// CreateConnectionOptions method of IWSManEx interface. /// An original IDL definition of CreateConnectionOptions method was the following: HRESULT CreateConnectionOptions ([out, retval] IDispatch** ReturnValue); // IDL: HRESULT CreateConnectionOptions ([out, retval] IDispatch** ReturnValue); @@ -511,9 +500,7 @@ public interface IWSManEx #endif object CreateConnectionOptions(); - /// - /// /// /// string CommandLine @@ -540,11 +527,9 @@ string Error get; } - /// CreateResourceLocator method of IWSManEx interface. - /// An original IDL definition of CreateResourceLocator method was the following: HRESULT CreateResourceLocator ([optional, defaultvalue("")] BSTR strResourceLocator, [out, retval] IDispatch** ReturnValue); - // IDL: HRESULT CreateResourceLocator ([optional, defaultvalue("")] BSTR strResourceLocator, [out, retval] IDispatch** ReturnValue); - + /// An original IDL definition of CreateResourceLocator method was the following: HRESULT CreateResourceLocator ([optional, defaultvalue(string.Empty)] BSTR strResourceLocator, [out, retval] IDispatch** ReturnValue); + // IDL: HRESULT CreateResourceLocator ([optional, defaultvalue(string.Empty)] BSTR strResourceLocator, [out, retval] IDispatch** ReturnValue); [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "str")] [DispId(5)] @@ -567,7 +552,6 @@ string Error /// An original IDL definition of SessionFlagCredUsernamePassword method was the following: HRESULT SessionFlagCredUsernamePassword ([out, retval] long* ReturnValue); // IDL: HRESULT SessionFlagCredUsernamePassword ([out, retval] long* ReturnValue); - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Username")] [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cred")] [DispId(7)] @@ -708,16 +692,15 @@ string Error [DispId(29)] int EnumerationFlagAssociatedInstance(); } -#endregion IWsManEx + #endregion IWsManEx -#region IWsManResourceLocator + #region IWsManResourceLocator /// IWSManResourceLocator interface. [SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces")] [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")] - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sel")] [Guid("A7A1BA28-DE41-466A-AD0A-C4059EAD7428")] @@ -729,7 +712,6 @@ string Error [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] #endif - public interface IWSManResourceLocator { #if CORECLR @@ -753,7 +735,6 @@ public interface IWSManResourceLocator [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")] string ResourceUri { - // IDL: HRESULT resourceUri (BSTR value); [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "resource")] [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")] @@ -767,7 +748,6 @@ string ResourceUri [DispId(1)] [return: MarshalAs(UnmanagedType.BStr)] get; - } /// AddSelector method of IWSManResourceLocator interface. Add selector to resource locator @@ -775,7 +755,6 @@ string ResourceUri // Add selector to resource locator // IDL: HRESULT AddSelector (BSTR resourceSelName, VARIANT selValue); - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "resource")] [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "sel")] [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sel")] @@ -787,8 +766,6 @@ string ResourceUri // Clear all selectors // IDL: HRESULT ClearSelectors (void); - - [DispId(3)] void ClearSelectors(); @@ -810,7 +787,6 @@ string FragmentPath set; } - /// FragmentDialect property of IWSManResourceLocator interface. Gets the Fragment dialect /// An original IDL definition of FragmentDialect property was the following: BSTR FragmentDialect; // Gets the Fragment dialect @@ -837,7 +813,6 @@ string FragmentDialect [DispId(6)] void AddOption([MarshalAs(UnmanagedType.BStr)] string OptionName, object OptionValue, int mustComply); - /// MustUnderstandOptions property of IWSManResourceLocator interface. Sets the MustUnderstandOptions value /// An original IDL definition of MustUnderstandOptions property was the following: long MustUnderstandOptions; // Sets the MustUnderstandOptions value @@ -855,7 +830,6 @@ int MustUnderstandOptions set; } - /// ClearOptions method of IWSManResourceLocator interface. Clear all options /// An original IDL definition of ClearOptions method was the following: HRESULT ClearOptions (void); // Clear all options @@ -864,8 +838,6 @@ int MustUnderstandOptions [DispId(8)] void ClearOptions(); - - /// Error property of IWSManResourceLocator interface. /// An original IDL definition of Error property was the following: BSTR Error; // IDL: BSTR Error; @@ -881,13 +853,10 @@ string Error [return: MarshalAs(UnmanagedType.BStr)] get; } - - - } -#endregion IWsManResourceLocator + #endregion IWsManResourceLocator -#region IWSManSession + #region IWSManSession /// IWSManSession interface. [Guid("FC84FC58-1286-40C4-9DA0-C8EF6EC241E0")] [ComImport] @@ -922,7 +891,6 @@ public interface IWSManSession /// An original IDL definition of Get method was the following: HRESULT Get (VARIANT resourceUri, [optional, defaultvalue(0)] long flags, [out, retval] BSTR* ReturnValue); // IDL: HRESULT Get (VARIANT resourceUri, [optional, defaultvalue(0)] long flags, [out, retval] BSTR* ReturnValue); - [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] [DispId(1)] [return: MarshalAs(UnmanagedType.BStr)] @@ -952,7 +920,6 @@ public interface IWSManSession void Delete(object resourceUri, int flags); /// - /// /// /// /// @@ -963,12 +930,11 @@ public interface IWSManSession [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "URI")] [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#")] [DispId(5)] - String Invoke([MarshalAs(UnmanagedType.BStr)] string actionURI, [In] object resourceUri, [MarshalAs(UnmanagedType.BStr)] string parameters, [In] int flags); - + string Invoke([MarshalAs(UnmanagedType.BStr)] string actionURI, [In] object resourceUri, [MarshalAs(UnmanagedType.BStr)] string parameters, [In] int flags); /// Enumerate method of IWSManSession interface. - /// An original IDL definition of Enumerate method was the following: HRESULT Enumerate (VARIANT resourceUri, [optional, defaultvalue("")] BSTR filter, [optional, defaultvalue("")] BSTR dialect, [optional, defaultvalue(0)] long flags, [out, retval] IDispatch** ReturnValue); - // IDL: HRESULT Enumerate (VARIANT resourceUri, [optional, defaultvalue("")] BSTR filter, [optional, defaultvalue("")] BSTR dialect, [optional, defaultvalue(0)] long flags, [out, retval] IDispatch** ReturnValue); + /// An original IDL definition of Enumerate method was the following: HRESULT Enumerate (VARIANT resourceUri, [optional, defaultvalue(string.Empty)] BSTR filter, [optional, defaultvalue(string.Empty)] BSTR dialect, [optional, defaultvalue(0)] long flags, [out, retval] IDispatch** ReturnValue); + // IDL: HRESULT Enumerate (VARIANT resourceUri, [optional, defaultvalue(string.Empty)] BSTR filter, [optional, defaultvalue(string.Empty)] BSTR dialect, [optional, defaultvalue(0)] long flags, [out, retval] IDispatch** ReturnValue); [DispId(6)] #if CORECLR @@ -1001,7 +967,6 @@ string Error get; } - /// BatchItems property of IWSManSession interface. /// An original IDL definition of BatchItems property was the following: long BatchItems; // IDL: long BatchItems; @@ -1018,7 +983,6 @@ int BatchItems set; } - /// Timeout property of IWSManSession interface. /// An original IDL definition of Timeout property was the following: long Timeout; // IDL: long Timeout; @@ -1036,9 +1000,9 @@ int Timeout } } -#endregion IWSManSession + #endregion IWSManSession -#region IWSManResourceLocatorInternal + #region IWSManResourceLocatorInternal /// IWSManResourceLocatorInternal interface. [Guid("EFFAEAD7-7EC8-4716-B9BE-F2E7E9FB4ADB")] [ComImport] @@ -1068,7 +1032,6 @@ public interface IWSManResourceLocatorInternal #endregion IWSManResourceLocatorInternal - /// WSMan interface. [Guid("BCED617B-EC03-420b-8508-977DC7A686BD")] [ComImport] @@ -1090,6 +1053,7 @@ public class WSManClass public class GPClass { } + [ComImport, Guid("EA502723-A23D-11d1-A7D3-0000F87571E3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IGroupPolicyObject @@ -1155,7 +1119,7 @@ interface IGroupPolicyObject uint GetPropertySheetPages(out IntPtr hPages); } -#endregion IGroupPolicyObject + #endregion IGroupPolicyObject /// GpoNativeApi public sealed class GpoNativeApi @@ -1167,11 +1131,11 @@ public sealed class GpoNativeApi [In, MarshalAs(UnmanagedType.Bool)] bool bMachine); [DllImport("Userenv.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool LeaveCriticalPolicySection( [In] System.IntPtr hSection); } -#endregion - + #endregion } #pragma warning restore 1591 diff --git a/src/Microsoft.WSMan.Management/InvokeWSManAction.cs b/src/Microsoft.WSMan.Management/InvokeWSManAction.cs index 6d9aba72967a..2ff653a4c8c0 100644 --- a/src/Microsoft.WSMan.Management/InvokeWSManAction.cs +++ b/src/Microsoft.WSMan.Management/InvokeWSManAction.cs @@ -1,20 +1,18 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Management.Automation; using System.Management.Automation.Provider; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Xml; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - - namespace Microsoft.WSMan.Management { @@ -32,17 +30,19 @@ public class InvokeWSManActionCommand : AuthenticatingWSManCommand, IDisposable /// /// The following is the definition of the input parameter "Action". /// Indicates the method which needs to be executed on the management object - /// specified by the ResourceURI and selectors + /// specified by the ResourceURI and selectors. /// [Parameter(Mandatory = true, Position = 1)] [ValidateNotNullOrEmpty] - public String Action + public string Action { get { return action; } + set { action = value; } } - private String action; + + private string action; /// /// The following is the definition of the input parameter "ApplicationName". @@ -50,12 +50,14 @@ public String Action /// [Parameter(ParameterSetName = "ComputerName")] [ValidateNotNullOrEmpty] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { applicationname = value; } } - private String applicationname = null; + + private string applicationname = null; /// /// The following is the definition of the input parameter "ComputerName". @@ -65,20 +67,21 @@ public String ApplicationName /// [Parameter(ParameterSetName = "ComputerName")] [Alias("cn")] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } - } } - private String computername = null; + + private string computername = null; /// /// The following is the definition of the input parameter "ConnectionURI". @@ -93,23 +96,28 @@ public String ComputerName public Uri ConnectionURI { get { return connectionuri; } + set { connectionuri = value; } } + private Uri connectionuri; /// /// The following is the definition of the input parameter "FilePath". /// Updates the management resource specified by the ResourceURI and SelectorSet - /// via this input file + /// via this input file. /// [Parameter] + [Alias("Path")] [ValidateNotNullOrEmpty] - public String FilePath + public string FilePath { get { return filepath; } + set { filepath = value; } } - private String filepath; + + private string filepath; /// /// The following is the definition of the input parameter "OptionSet". @@ -124,8 +132,10 @@ public String FilePath public Hashtable OptionSet { get { return optionset; } + set { optionset = value; } } + private Hashtable optionset; /// @@ -138,15 +148,17 @@ public Hashtable OptionSet public Int32 Port { get { return port; } + set { port = value; } } + private Int32 port = 0; /// /// The following is the definition of the input parameter "SelectorSet". /// SelectorSet is a hash table which helps in identify an instance of the /// management resource if there are are more than 1 instance of the resource - /// class + /// class. /// [Parameter(Position = 2, ValueFromPipeline = true, @@ -156,14 +168,16 @@ public Int32 Port public Hashtable SelectorSet { get { return selectorset; } + set { selectorset = value; } } + private Hashtable selectorset; /// /// The following is the definition of the input parameter "SessionOption". /// Defines a set of extended options for the WSMan session. This hashtable can - /// be created using New-WSManSessionOption + /// be created using New-WSManSessionOption. /// [Parameter] [ValidateNotNullOrEmpty] @@ -172,8 +186,10 @@ public Hashtable SelectorSet public SessionOption SessionOption { get { return sessionoption; } + set { sessionoption = value; } } + private SessionOption sessionoption; /// @@ -187,8 +203,10 @@ public SessionOption SessionOption public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } + private SwitchParameter usessl; /// @@ -202,14 +220,15 @@ public SwitchParameter UseSSL public Hashtable ValueSet { get { return valueset; } + set { valueset = value; } } - private Hashtable valueset; + private Hashtable valueset; /// /// The following is the definition of the input parameter "ResourceURI". - /// URI of the resource class/instance representation + /// URI of the resource class/instance representation. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] @@ -219,17 +238,17 @@ public Hashtable ValueSet public Uri ResourceURI { get { return resourceuri; } + set { resourceuri = value; } } - private Uri resourceuri; + private Uri resourceuri; private WSManHelper helper; IWSManEx m_wsmanObject = (IWSManEx)new WSManClass(); IWSManSession m_session = null; string connectionStr = string.Empty; - /// /// BeginProcessing method. /// @@ -239,10 +258,8 @@ protected override void BeginProcessing() helper.WSManOp = "invoke"; - //create the connection string + // create the connection string connectionStr = helper.CreateConnectionString(connectionuri, port, computername, applicationname); - - } /// @@ -250,14 +267,12 @@ protected override void BeginProcessing() /// protected override void ProcessRecord() { - - try { - //create the resourcelocator object + // create the resourcelocator object IWSManResourceLocator m_resource = helper.InitializeResourceLocator(optionset, selectorset, null, null, m_wsmanObject, resourceuri); - //create the session object + // create the session object m_session = helper.CreateSessionObject(m_wsmanObject, Authentication, sessionoption, Credential, connectionStr, CertificateThumbprint, usessl.IsPresent); string rootNode = helper.GetRootNodeName(helper.WSManOp, m_resource.ResourceUri, action); @@ -267,39 +282,38 @@ protected override void ProcessRecord() XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(resultXml); WriteObject(xmldoc.DocumentElement); - } finally { - if (!String.IsNullOrEmpty(m_wsmanObject.Error)) + if (!string.IsNullOrEmpty(m_wsmanObject.Error)) { helper.AssertError(m_wsmanObject.Error, true, resourceuri); } - if (!String.IsNullOrEmpty(m_session.Error)) + + if (!string.IsNullOrEmpty(m_session.Error)) { helper.AssertError(m_session.Error, true, resourceuri); } + if (m_session != null) Dispose(m_session); - } - - }//End ProcessRecord() + } #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -319,11 +333,5 @@ protected override void EndProcessing() // WSManHelper helper = new WSManHelper(); helper.CleanUp(); } - - - - - - - }//End Class + } } diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 1d4f4e581b68..281623fc86dd 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -1,14 +1,15 @@  - PowerShell Core's Microsoft.WSMan.Management project + PowerShell's Microsoft.WSMan.Management project Microsoft.WSMan.Management - + + @@ -19,16 +20,4 @@ - - portable - - - - $(DefineConstants);UNIX - - - - full - - diff --git a/src/Microsoft.WSMan.Management/NewWSManSession.cs b/src/Microsoft.WSMan.Management/NewWSManSession.cs index ab730bcdd267..edf5a3672931 100644 --- a/src/Microsoft.WSMan.Management/NewWSManSession.cs +++ b/src/Microsoft.WSMan.Management/NewWSManSession.cs @@ -1,21 +1,19 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Management.Automation; -using System.Management.Automation.Provider; -using System.Xml; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Provider; using System.Net; - - +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Xml; namespace Microsoft.WSMan.Management { @@ -25,15 +23,13 @@ namespace Microsoft.WSMan.Management /// Get-WSManInstance /// Set-WSManInstance /// Invoke-WSManAction - /// Connect-WSMan + /// Connect-WSMan. /// - [Cmdlet(VerbsCommon.New, "WSManSessionOption", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141449")] public class NewWSManSessionOptionCommand : PSCmdlet { /// - /// /// [Parameter] [ValidateNotNullOrEmpty] @@ -43,11 +39,13 @@ public ProxyAccessType ProxyAccessType { return _proxyaccesstype; } + set { _proxyaccesstype = value; } } + private ProxyAccessType _proxyaccesstype; /// @@ -57,18 +55,20 @@ public ProxyAccessType ProxyAccessType /// - Negotiate: Use the default authentication (ad defined by the underlying /// protocol) for establishing a remote connection. /// - Basic: Use basic authentication for establishing a remote connection - /// - Digest: Use Digest authentication for establishing a remote connection + /// - Digest: Use Digest authentication for establishing a remote connection. /// [Parameter] [ValidateNotNullOrEmpty] public ProxyAuthentication ProxyAuthentication { get { return proxyauthentication; } + set { proxyauthentication = value; } } + private ProxyAuthentication proxyauthentication; /// @@ -80,13 +80,14 @@ public ProxyAuthentication ProxyAuthentication public PSCredential ProxyCredential { get { return _proxycredential; } + set { _proxycredential = value; } } - private PSCredential _proxycredential; + private PSCredential _proxycredential; /// /// The following is the definition of the input parameter "SkipCACheck". @@ -94,58 +95,64 @@ public PSCredential ProxyCredential /// certificate is signed by a trusted certificate authority (CA). Use only when /// the remote computer is trusted by other means, for example, if the remote /// computer is part of a network that is physically secure and isolated or the - /// remote computer is listed as a trusted host in WinRM configuration + /// remote computer is listed as a trusted host in WinRM configuration. /// [Parameter] public SwitchParameter SkipCACheck { get { return skipcacheck; } + set { skipcacheck = value; } } + private bool skipcacheck; /// /// The following is the definition of the input parameter "SkipCNCheck". /// Indicates that certificate common name (CN) of the server need not match the /// hostname of the server. Used only in remote operations using https. This - /// option should only be used for trusted machines + /// option should only be used for trusted machines. /// [Parameter] public SwitchParameter SkipCNCheck { get { return skipcncheck; } + set { skipcncheck = value; } } + private bool skipcncheck; /// /// The following is the definition of the input parameter "SkipRevocation". /// Indicates that certificate common name (CN) of the server need not match the /// hostname of the server. Used only in remote operations using https. This - /// option should only be used for trusted machines + /// option should only be used for trusted machines. /// [Parameter] public SwitchParameter SkipRevocationCheck { get { return skiprevocationcheck; } + set { skiprevocationcheck = value; } } + private bool skiprevocationcheck; /// /// The following is the definition of the input parameter "SPNPort". /// Appends port number to the connection Service Principal Name SPN of the /// remote server. - /// SPN is used when authentication mechanism is Kerberos or Negotiate + /// SPN is used when authentication mechanism is Kerberos or Negotiate. /// [Parameter] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SPN")] @@ -153,16 +160,18 @@ public SwitchParameter SkipRevocationCheck public Int32 SPNPort { get { return spnport; } + set { spnport = value; } } + private Int32 spnport; /// /// The following is the definition of the input parameter "Timeout". - /// Defines the timeout in ms for the wsman operation + /// Defines the timeout in ms for the wsman operation. /// [Parameter] [Alias("OperationTimeoutMSec")] @@ -170,28 +179,32 @@ public Int32 SPNPort public Int32 OperationTimeout { get { return operationtimeout; } + set { operationtimeout = value; } } + private Int32 operationtimeout; /// /// The following is the definition of the input parameter "UnEncrypted". /// Specifies that no encryption will be used when doing remote operations over /// http. Unencrypted traffic is not allowed by default and must be enabled in - /// the local configuration + /// the local configuration. /// [Parameter] public SwitchParameter NoEncryption { get { return noencryption; } + set { noencryption = value; } } + private bool noencryption; /// @@ -204,16 +217,14 @@ public SwitchParameter NoEncryption public SwitchParameter UseUTF16 { get { return useutf16; } + set { useutf16 = value; } } - private bool useutf16; - - - + private bool useutf16; /// /// BeginProcessing method. @@ -241,9 +252,7 @@ protected override void BeginProcessing() return; } - - - //Creating the Session Object + // Creating the Session Object SessionOption objSessionOption = new SessionOption(); objSessionOption.SPNPort = spnport; @@ -252,7 +261,7 @@ protected override void BeginProcessing() objSessionOption.SkipCACheck = skipcacheck; objSessionOption.OperationTimeout = operationtimeout; objSessionOption.SkipRevocationCheck = skiprevocationcheck; - //Proxy Settings + // Proxy Settings objSessionOption.ProxyAccessType = _proxyaccesstype; objSessionOption.ProxyAuthentication = proxyauthentication; @@ -260,13 +269,14 @@ protected override void BeginProcessing() { objSessionOption.UseEncryption = false; } + if (_proxycredential != null) { NetworkCredential nwCredentials = _proxycredential.GetNetworkCredential(); objSessionOption.ProxyCredential = nwCredentials; } - WriteObject(objSessionOption); - }//End BeginProcessing() - }//End Class + WriteObject(objSessionOption); + } + } } diff --git a/src/Microsoft.WSMan.Management/PingWSMan.cs b/src/Microsoft.WSMan.Management/PingWSMan.cs index 21e9bd956956..0195305f7069 100644 --- a/src/Microsoft.WSMan.Management/PingWSMan.cs +++ b/src/Microsoft.WSMan.Management/PingWSMan.cs @@ -1,28 +1,26 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Management.Automation; using System.Management.Automation.Provider; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Xml; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.WSMan.Management { - #region Test-WSMAN /// /// Issues an operation against the remote machine to ensure that the wsman - /// service is running + /// service is running. /// [Cmdlet(VerbsDiagnostic.Test, "WSMan", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141464")] @@ -32,23 +30,25 @@ public class TestWSManCommand : AuthenticatingWSManCommand, IDisposable /// The following is the definition of the input parameter "ComputerName". /// Executes the management operation on the specified computer. The default is /// the local computer. Type the fully qualified domain name, NETBIOS name or IP - /// address to indicate the remote host + /// address to indicate the remote host. /// [Parameter(Position = 0, ValueFromPipeline = true)] [Alias("cn")] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } } } - private String computername = null; + + private string computername = null; /// /// The following is the definition of the input parameter "Authentication". @@ -74,12 +74,14 @@ public String ComputerName public override AuthenticationMechanism Authentication { get { return authentication; } + set { authentication = value; ValidateSpecifiedAuthentication(); } } + private AuthenticationMechanism authentication = AuthenticationMechanism.None; /// @@ -92,8 +94,10 @@ public override AuthenticationMechanism Authentication public Int32 Port { get { return port; } + set { port = value; } } + private Int32 port = 0; /// @@ -107,8 +111,10 @@ public Int32 Port public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } + private SwitchParameter usessl; /// @@ -117,38 +123,38 @@ public SwitchParameter UseSSL /// [Parameter(ParameterSetName = "ComputerName")] [ValidateNotNullOrEmpty] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { applicationname = value; } } - private String applicationname = null; + private string applicationname = null; /// /// ProcessRecord method. /// protected override void ProcessRecord() { - WSManHelper helper = new WSManHelper(this); IWSManEx wsmanObject = (IWSManEx)new WSManClass(); - string connectionStr = String.Empty; + string connectionStr = string.Empty; connectionStr = helper.CreateConnectionString(null, port, computername, applicationname); IWSManSession m_SessionObj = null; try { m_SessionObj = helper.CreateSessionObject(wsmanObject, Authentication, null, Credential, connectionStr, CertificateThumbprint, usessl.IsPresent); - m_SessionObj.Timeout = 1000; //1 sec. we are putting this low so that Test-WSMan can return promptly if the server goes unresponsive. + m_SessionObj.Timeout = 1000; // 1 sec. we are putting this low so that Test-WSMan can return promptly if the server goes unresponsive. XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(m_SessionObj.Identify(0)); WriteObject(xmldoc.DocumentElement); } - catch(Exception) + catch (Exception) { try { - if (!String.IsNullOrEmpty(m_SessionObj.Error)) + if (!string.IsNullOrEmpty(m_SessionObj.Error)) { XmlDocument ErrorDoc = new XmlDocument(); ErrorDoc.LoadXml(m_SessionObj.Error); @@ -157,30 +163,30 @@ protected override void ProcessRecord() this.WriteError(er); } } - catch(Exception) - {} + catch (Exception) + { } } finally { if (m_SessionObj != null) Dispose(m_SessionObj); } - }//End BeginProcessing() + } #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -191,7 +197,6 @@ protected override void ProcessRecord() } #endregion IDisposable Members - - }//End Class + } #endregion } diff --git a/src/Microsoft.WSMan.Management/Set-QuickConfig.cs b/src/Microsoft.WSMan.Management/Set-QuickConfig.cs index 6edb2b0d0ed8..b06805b0a94c 100644 --- a/src/Microsoft.WSMan.Management/Set-QuickConfig.cs +++ b/src/Microsoft.WSMan.Management/Set-QuickConfig.cs @@ -1,19 +1,18 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Management.Automation; using System.Management.Automation.Provider; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Xml; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.WSMan.Management { @@ -28,7 +27,7 @@ namespace Microsoft.WSMan.Management /// 2. Set the WinRM service type to auto start /// 3. Create a listener to accept request on any IP address. By default /// transport is http - /// 4. Enable firewall exception for WS-Management traffic + /// 4. Enable firewall exception for WS-Management traffic. /// [Cmdlet(VerbsCommon.Set, "WSManQuickConfig", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=141463")] public class SetWSManQuickConfigCommand : PSCmdlet, IDisposable @@ -36,18 +35,20 @@ public class SetWSManQuickConfigCommand : PSCmdlet, IDisposable /// /// The following is the definition of the input parameter "UseSSL". /// Indicates a https listener to be created. If this switch is not specified - /// then by default a http listener will be created + /// then by default a http listener will be created. /// [Parameter] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SSL")] public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } + private SwitchParameter usessl; - //helper variable + // helper variable private WSManHelper helper; /// @@ -58,8 +59,10 @@ public SwitchParameter UseSSL public SwitchParameter Force { get { return force; } + set { force = value; } } + private bool force = false; /// @@ -69,8 +72,10 @@ public SwitchParameter Force public SwitchParameter SkipNetworkProfileCheck { get { return skipNetworkProfileCheck; } + set { skipNetworkProfileCheck = value; } } + private bool skipNetworkProfileCheck = false; /// @@ -78,24 +83,22 @@ public SwitchParameter SkipNetworkProfileCheck /// protected override void BeginProcessing() { - //If not running elevated, then throw an "elevation required" error message. + // If not running elevated, then throw an "elevation required" error message. WSManHelper.ThrowIfNotAdministrator(); helper = new WSManHelper(this); - String query = helper.GetResourceMsgFromResourcetext("QuickConfigContinueQuery"); - String caption = helper.GetResourceMsgFromResourcetext("QuickConfigContinueCaption"); + string query = helper.GetResourceMsgFromResourcetext("QuickConfigContinueQuery"); + string caption = helper.GetResourceMsgFromResourcetext("QuickConfigContinueCaption"); if (!force && !ShouldContinue(query, caption)) { return; } + QuickConfigRemoting(true); QuickConfigRemoting(false); - }//End BeginProcessing() - - + } #region private - private void QuickConfigRemoting(bool serviceonly) { IWSManSession m_SessionObj = null; @@ -112,7 +115,6 @@ private void QuickConfigRemoting(bool serviceonly) string xpathStatus = string.Empty; string xpathResult = string.Empty; - if (!usessl) { transport = "http"; @@ -129,12 +131,11 @@ private void QuickConfigRemoting(bool serviceonly) } else { - string openAllProfiles = skipNetworkProfileCheck ? "" : String.Empty; + string openAllProfiles = skipNetworkProfileCheck ? "" : string.Empty; analysisInputXml = @"" + transport + "" + openAllProfiles + ""; action = "Analyze"; } - string analysisOutputXml = m_SessionObj.Invoke(action, "winrm/config/service", analysisInputXml, 0); XmlDocument resultopxml = new XmlDocument(); resultopxml.LoadXml(analysisOutputXml); @@ -152,8 +153,6 @@ private void QuickConfigRemoting(bool serviceonly) xpathUpdate = "/cfg:Analyze_OUTPUT/cfg:EnableRemoting_INPUT"; } - - XmlNamespaceManager nsmgr = new XmlNamespaceManager(resultopxml.NameTable); nsmgr.AddNamespace("cfg", "http://schemas.microsoft.com/wbem/wsman/1/config/service"); string enabled = resultopxml.SelectSingleNode(xpathEnabled, nsmgr).InnerText; @@ -163,10 +162,11 @@ private void QuickConfigRemoting(bool serviceonly) { source = sourceAttribute.Value; } - string rxml = ""; + + string rxml = string.Empty; if (enabled.Equals("true")) { - string Err_Msg = ""; + string Err_Msg = string.Empty; if (serviceonly) { Err_Msg = WSManResourceLoader.GetResourceString("L_QuickConfigNoServiceChangesNeeded_Message"); @@ -181,6 +181,7 @@ private void QuickConfigRemoting(bool serviceonly) WriteObject(Err_Msg); return; } + if (!enabled.Equals("false")) { ArgumentException e = new ArgumentException(WSManResourceLoader.GetResourceString("L_QuickConfig_InvalidBool_0_ErrorMessage")); @@ -190,9 +191,9 @@ private void QuickConfigRemoting(bool serviceonly) } string resultAction = resultopxml.SelectSingleNode(xpathText, nsmgr).InnerText; - if ( source != null && source.Equals("GPO")) + if (source != null && source.Equals("GPO")) { - String Info_Msg = WSManResourceLoader.GetResourceString("L_QuickConfig_RemotingDisabledbyGP_00_ErrorMessage"); + string Info_Msg = WSManResourceLoader.GetResourceString("L_QuickConfig_RemotingDisabledbyGP_00_ErrorMessage"); Info_Msg += " " + resultAction; ArgumentException e = new ArgumentException(Info_Msg); WriteError(new ErrorRecord(e, "NotSpecified", ErrorCategory.NotSpecified, null)); @@ -200,7 +201,7 @@ private void QuickConfigRemoting(bool serviceonly) } string inputXml = resultopxml.SelectSingleNode(xpathUpdate, nsmgr).OuterXml; - if (resultAction.Equals("") || inputXml.Equals("")) + if (resultAction.Equals(string.Empty) || inputXml.Equals(string.Empty)) { ArgumentException e = new ArgumentException(WSManResourceLoader.GetResourceString("L_ERR_Message") + WSManResourceLoader.GetResourceString("L_QuickConfig_MissingUpdateXml_0_ErrorMessage")); ErrorRecord er = new ErrorRecord(e, "InvalidOperation", ErrorCategory.InvalidOperation, null); @@ -216,6 +217,7 @@ private void QuickConfigRemoting(bool serviceonly) { action = "EnableRemoting"; } + rxml = m_SessionObj.Invoke(action, "winrm/config/service", inputXml, 0); XmlDocument finalxml = new XmlDocument(); finalxml.LoadXml(rxml); @@ -230,6 +232,7 @@ private void QuickConfigRemoting(bool serviceonly) xpathStatus = "/cfg:EnableRemoting_OUTPUT/cfg:Status"; xpathResult = "/cfg:EnableRemoting_OUTPUT/cfg:Results"; } + if (finalxml.SelectSingleNode(xpathStatus, nsmgr).InnerText.ToString().Equals("succeeded")) { if (serviceonly) @@ -240,6 +243,7 @@ private void QuickConfigRemoting(bool serviceonly) { WriteObject(WSManResourceLoader.GetResourceString("L_QuickConfigUpdated_Message")); } + WriteObject(finalxml.SelectSingleNode(xpathResult, nsmgr).InnerText); } else @@ -249,13 +253,13 @@ private void QuickConfigRemoting(bool serviceonly) } finally { - if (!String.IsNullOrEmpty(m_SessionObj.Error)) + if (!string.IsNullOrEmpty(m_SessionObj.Error)) { helper.AssertError(m_SessionObj.Error, true, null); } + if (m_SessionObj != null) Dispose(m_SessionObj); - } } #endregion private @@ -263,17 +267,17 @@ private void QuickConfigRemoting(bool serviceonly) #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -284,7 +288,6 @@ private void QuickConfigRemoting(bool serviceonly) } #endregion IDisposable Members - - }//End Class + } #endregion Set-WsManQuickConfig } diff --git a/src/Microsoft.WSMan.Management/WSManConnections.cs b/src/Microsoft.WSMan.Management/WSManConnections.cs index dd8b14e20cf7..76f9326936b3 100644 --- a/src/Microsoft.WSMan.Management/WSManConnections.cs +++ b/src/Microsoft.WSMan.Management/WSManConnections.cs @@ -1,21 +1,21 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Management.Automation; using System.Management.Automation.Provider; -using System.Xml; -using System.Collections; -using System.Collections.Generic; using System.Management.Automation.Runspaces; -using System.Diagnostics.CodeAnalysis; -using Dbg = System.Management.Automation; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Xml; +using Dbg = System.Management.Automation; namespace Microsoft.WSMan.Management { @@ -23,7 +23,7 @@ namespace Microsoft.WSMan.Management /// /// Common base class for all WSMan cmdlets that - /// take Authentication, CertificateThumbprint and Credential parameters + /// take Authentication, CertificateThumbprint and Credential parameters. /// public class AuthenticatingWSManCommand : PSCmdlet { @@ -39,12 +39,14 @@ public class AuthenticatingWSManCommand : PSCmdlet public virtual PSCredential Credential { get { return credential; } + set { credential = value; ValidateSpecifiedAuthentication(); } } + private PSCredential credential; /// @@ -68,12 +70,14 @@ public virtual PSCredential Credential public virtual AuthenticationMechanism Authentication { get { return authentication; } + set { authentication = value; ValidateSpecifiedAuthentication(); } } + private AuthenticationMechanism authentication = AuthenticationMechanism.Default; /// @@ -85,12 +89,14 @@ public virtual AuthenticationMechanism Authentication public virtual string CertificateThumbprint { get { return thumbPrint; } + set { thumbPrint = value; ValidateSpecifiedAuthentication(); } } + private string thumbPrint = null; internal void ValidateSpecifiedAuthentication() @@ -106,12 +112,11 @@ internal void ValidateSpecifiedAuthentication() #region Connect-WsMan /// - /// connect wsman cmdlet + /// Connect wsman cmdlet. /// [Cmdlet(VerbsCommunications.Connect, "WSMan", DefaultParameterSetName = "ComputerName", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141437")] public class ConnectWSManCommand : AuthenticatingWSManCommand { - #region Parameters /// @@ -120,12 +125,14 @@ public class ConnectWSManCommand : AuthenticatingWSManCommand /// [Parameter(ParameterSetName = "ComputerName")] [ValidateNotNullOrEmpty] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { applicationname = value; } } - private String applicationname = null; + + private string applicationname = null; /// /// The following is the definition of the input parameter "ComputerName". @@ -135,19 +142,21 @@ public String ApplicationName /// [Parameter(ParameterSetName = "ComputerName", Position = 0)] [Alias("cn")] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } } } - private String computername = null; + + private string computername = null; /// /// The following is the definition of the input parameter "ConnectionURI". @@ -161,8 +170,10 @@ public String ComputerName public Uri ConnectionURI { get { return connectionuri; } + set { connectionuri = value; } } + private Uri connectionuri; /// @@ -177,8 +188,10 @@ public Uri ConnectionURI public Hashtable OptionSet { get { return optionset; } + set { optionset = value; } } + private Hashtable optionset; /// @@ -192,14 +205,16 @@ public Hashtable OptionSet public Int32 Port { get { return port; } + set { port = value; } } + private Int32 port = 0; /// /// The following is the definition of the input parameter "SessionOption". /// Defines a set of extended options for the WSMan session. This hashtable can - /// be created using New-WSManSessionOption + /// be created using New-WSManSessionOption. /// [Parameter] [ValidateNotNullOrEmpty] @@ -208,8 +223,10 @@ public Int32 Port public SessionOption SessionOption { get { return sessionoption; } + set { sessionoption = value; } } + private SessionOption sessionoption; /// @@ -223,11 +240,11 @@ public SessionOption SessionOption public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } - private SwitchParameter usessl; - + private SwitchParameter usessl; #endregion @@ -236,13 +253,12 @@ public SwitchParameter UseSSL /// protected override void BeginProcessing() { - WSManHelper helper = new WSManHelper(this); if (connectionuri != null) { try { - //always in the format http://server:port/applicationname + // always in the format http://server:port/applicationname string[] constrsplit = connectionuri.OriginalString.Split(new string[] { ":" + port + "/" + applicationname }, StringSplitOptions.None); string[] constrsplit1 = constrsplit[0].Split(new string[] { "//" }, StringSplitOptions.None); computername = constrsplit1[1].Trim(); @@ -252,22 +268,24 @@ protected override void BeginProcessing() helper.AssertError(helper.GetResourceMsgFromResourcetext("NotProperURI"), false, connectionuri); } } + string crtComputerName = computername; if (crtComputerName == null) { crtComputerName = "localhost"; } - if (this.SessionState.Path.CurrentProviderLocation(WSManStringLiterals.rootpath).Path.StartsWith(this.SessionState.Drive.Current.Name + ":" + WSManStringLiterals.DefaultPathSeparator + crtComputerName, StringComparison.CurrentCultureIgnoreCase)) + + if (this.SessionState.Path.CurrentProviderLocation(WSManStringLiterals.rootpath).Path.StartsWith(this.SessionState.Drive.Current.Name + ":" + WSManStringLiterals.DefaultPathSeparator + crtComputerName, StringComparison.OrdinalIgnoreCase)) { helper.AssertError(helper.GetResourceMsgFromResourcetext("ConnectFailure"), false, computername); } - helper.CreateWsManConnection(ParameterSetName, connectionuri, port, computername, applicationname, usessl.IsPresent, Authentication, sessionoption, Credential, CertificateThumbprint); - }//End BeginProcessing() - }//end class + helper.CreateWsManConnection(ParameterSetName, connectionuri, port, computername, applicationname, usessl.IsPresent, Authentication, sessionoption, Credential, CertificateThumbprint); + } + } #endregion - # region Disconnect-WSMAN + #region Disconnect-WSMAN /// /// The following is the definition of the input parameter "ComputerName". /// Executes the management operation on the specified computer(s). The default @@ -285,35 +303,36 @@ public class DisconnectWSManCommand : PSCmdlet, IDisposable /// IP address to indicate the remote host(s) /// [Parameter(Position = 0)] - public String ComputerName + public string ComputerName { get { return computername; } + set { - computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } } } - private String computername = null; + + private string computername = null; #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -321,7 +340,6 @@ public String ComputerName { session = null; this.Dispose(); - } #endregion IDisposable Members @@ -336,11 +354,13 @@ protected override void BeginProcessing() { computername = "localhost"; } - if (this.SessionState.Path.CurrentProviderLocation(WSManStringLiterals.rootpath).Path.StartsWith(WSManStringLiterals.rootpath + ":" + WSManStringLiterals.DefaultPathSeparator + computername, StringComparison.CurrentCultureIgnoreCase)) + + if (this.SessionState.Path.CurrentProviderLocation(WSManStringLiterals.rootpath).Path.StartsWith(WSManStringLiterals.rootpath + ":" + WSManStringLiterals.DefaultPathSeparator + computername, StringComparison.OrdinalIgnoreCase)) { helper.AssertError(helper.GetResourceMsgFromResourcetext("DisconnectFailure"), false, computername); } - if (computername.Equals("localhost", StringComparison.CurrentCultureIgnoreCase)) + + if (computername.Equals("localhost", StringComparison.OrdinalIgnoreCase)) { helper.AssertError(helper.GetResourceMsgFromResourcetext("LocalHost"), false, computername); } @@ -354,10 +374,7 @@ protected override void BeginProcessing() { helper.AssertError(helper.GetResourceMsgFromResourcetext("InvalidComputerName"), false, computername); } - }//End BeginProcessing() - - - - }//End Class + } + } #endregion Disconnect-WSMAN } diff --git a/src/Microsoft.WSMan.Management/WSManInstance.cs b/src/Microsoft.WSMan.Management/WSManInstance.cs index 96dfa8e84346..60251db32543 100644 --- a/src/Microsoft.WSMan.Management/WSManInstance.cs +++ b/src/Microsoft.WSMan.Management/WSManInstance.cs @@ -1,22 +1,22 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.IO; -using System.Reflection; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Management.Automation; -using System.Management.Automation.Provider; -using System.Xml; using System.Collections; using System.Collections.Generic; -using System.Management.Automation.Runspaces; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -using Dbg = System.Management.Automation; using System.Globalization; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Provider; +using System.Management.Automation.Runspaces; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Xml; +using Dbg = System.Management.Automation; namespace Microsoft.WSMan.Management { @@ -39,32 +39,36 @@ public class GetWSManInstanceCommand : AuthenticatingWSManCommand, IDisposable /// [Parameter(ParameterSetName = "GetInstance")] [Parameter(ParameterSetName = "Enumerate")] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { { applicationname = value; } } } - private String applicationname = null; + + private string applicationname = null; /// /// The following is the definition of the input parameter "BasePropertiesOnly". /// Enumerate only those properties that are part of the base class /// specification in the Resource URI. When - /// Shallow is specified then this flag has no effect + /// Shallow is specified then this flag has no effect. /// [Parameter(ParameterSetName = "Enumerate")] [Alias("UBPO", "Base")] public SwitchParameter BasePropertiesOnly { get { return basepropertiesonly; } + set { { basepropertiesonly = value; } } } + private SwitchParameter basepropertiesonly; /// @@ -76,19 +80,21 @@ public SwitchParameter BasePropertiesOnly [Parameter(ParameterSetName = "GetInstance")] [Parameter(ParameterSetName = "Enumerate")] [Alias("CN")] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } } } - private String computername = null; + + private string computername = null; /// /// The following is the definition of the input parameter "ConnectionURI". @@ -106,32 +112,36 @@ public String ComputerName public Uri ConnectionURI { get { return connectionuri; } + set { { connectionuri = value; } } } + private Uri connectionuri; /// /// The following is the definition of the input parameter "Dialect". - /// Defines the dialect for the filter predicate + /// Defines the dialect for the filter predicate. /// [Parameter] public Uri Dialect { get { return dialect; } + set { { dialect = value; } } } + private Uri dialect; /// /// The following is the definition of the input parameter "Enumerate". /// Switch indicates list all instances of a management resource. Equivalent to - /// WSManagement Enumerate + /// WSManagement Enumerate. /// [Parameter(Mandatory = true, @@ -139,46 +149,52 @@ public Uri Dialect public SwitchParameter Enumerate { get { return enumerate; } + set { { enumerate = value; } } } + private SwitchParameter enumerate; /// /// The following is the definition of the input parameter "Filter". - /// Indicates the filter expression for the enumeration + /// Indicates the filter expression for the enumeration. /// [Parameter(ParameterSetName = "Enumerate")] [ValidateNotNullOrEmpty] - public String Filter + public string Filter { get { return filter; } + set { { filter = value; } } } - private String filter; + + private string filter; /// /// The following is the definition of the input parameter "Fragment". /// Specifies a section inside the instance that is to be updated or retrieved - /// for the given operation + /// for the given operation. /// [Parameter(ParameterSetName = "GetInstance")] [ValidateNotNullOrEmpty] - public String Fragment + public string Fragment { get { return fragment; } + set { { fragment = value; } } } - private String fragment; + + private string fragment; /// /// The following is the definition of the input parameter "OptionSet". @@ -193,11 +209,13 @@ public String Fragment public Hashtable OptionSet { get { return optionset; } + set { { optionset = value; } } } + private Hashtable optionset; /// @@ -209,34 +227,38 @@ public Hashtable OptionSet public Int32 Port { get { return port; } + set { { port = value; } } } + private Int32 port = 0; /// /// The following is the definition of the input parameter "Associations". /// Associations indicates retrieval of association instances as opposed to /// associated instances. This can only be used when specifying the Dialect as - /// Association + /// Association. /// [Parameter(ParameterSetName = "Enumerate")] public SwitchParameter Associations { get { return associations; } + set { { associations = value; } } } + private SwitchParameter associations; /// /// The following is the definition of the input parameter "ResourceURI". - /// URI of the resource class/instance representation + /// URI of the resource class/instance representation. /// [Parameter(Mandatory = true, Position = 0, @@ -248,11 +270,13 @@ public SwitchParameter Associations public Uri ResourceURI { get { return resourceuri; } + set { { resourceuri = value; } } } + private Uri resourceuri; /// @@ -265,28 +289,30 @@ public Uri ResourceURI /// are returned. EPRs contain information about the Resource URI and selectors /// for the instance /// If ObjectAndEPR is specified, then both the object and the associated EPRs - /// are returned + /// are returned. /// [Parameter(ParameterSetName = "Enumerate")] [ValidateNotNullOrEmpty] [ValidateSetAttribute(new string[] { "object", "epr", "objectandepr" })] [Alias("RT")] - public String ReturnType + public string ReturnType { get { return returntype; } + set { { returntype = value; } } } - private String returntype="object"; + + private string returntype = "object"; /// /// The following is the definition of the input parameter "SelectorSet". /// SelectorSet is a hash table which helps in identify an instance of the /// management resource if there are are more than 1 instance of the resource - /// class + /// class. /// [Parameter( ParameterSetName = "GetInstance")] @@ -295,17 +321,19 @@ public String ReturnType public Hashtable SelectorSet { get { return selectorset; } + set { { selectorset = value; } } } + private Hashtable selectorset; /// /// The following is the definition of the input parameter "SessionOption". /// Defines a set of extended options for the WSMan session. This can be - /// created by using the cmdlet New-WSManSessionOption + /// created by using the cmdlet New-WSManSessionOption. /// [Parameter] [ValidateNotNullOrEmpty] @@ -314,29 +342,33 @@ public Hashtable SelectorSet public SessionOption SessionOption { get { return sessionoption; } + set { { sessionoption = value; } } } + private SessionOption sessionoption; /// /// The following is the definition of the input parameter "Shallow". /// Enumerate only instances of the base class specified in the resource URI. If /// this flag is not specified, instances of the base class specified in the URI - /// and all its derived classes are returned + /// and all its derived classes are returned. /// [Parameter(ParameterSetName = "Enumerate")] public SwitchParameter Shallow { get { return shallow; } + set { { shallow = value; } } } + private SwitchParameter shallow; /// @@ -353,11 +385,13 @@ public SwitchParameter Shallow public SwitchParameter UseSSL { get { return usessl; } + set { { usessl = value; } } } + private SwitchParameter usessl; #endregion parameter @@ -368,19 +402,21 @@ private string GetFilter() { string name; string value; - string[] Split = filter.Trim().Split(new Char[] { '=', ';' }); - if ((Split.Length)%2 != 0) + string[] Split = filter.Trim().Split(new char[] { '=', ';' }); + if ((Split.Length) % 2 != 0) { - //mismatched property name/value pair + // mismatched property name/value pair return null; } + filter = ""; - for (int i = 0; i" + value + ""; } + filter = filter + ""; return (filter.ToString()); } @@ -394,17 +430,17 @@ private void ReturnEnumeration(IWSManEx wsmanObject, IWSManResourceLocator wsman IWSManEnumerator obj; if (returntype != null) { - if (returntype.Equals("object", StringComparison.CurrentCultureIgnoreCase)) + if (returntype.Equals("object", StringComparison.OrdinalIgnoreCase)) { flags = wsmanObject.EnumerationFlagReturnObject(); } - else if (returntype.Equals("epr", StringComparison.CurrentCultureIgnoreCase)) + else if (returntype.Equals("epr", StringComparison.OrdinalIgnoreCase)) { - flags = wsmanObject.EnumerationFlagReturnEPR(); + flags = wsmanObject.EnumerationFlagReturnEPR(); } else { - flags = wsmanObject.EnumerationFlagReturnObjectAndEPR(); + flags = wsmanObject.EnumerationFlagReturnObjectAndEPR(); } } @@ -420,44 +456,46 @@ private void ReturnEnumeration(IWSManEx wsmanObject, IWSManResourceLocator wsman { flags |= wsmanObject.EnumerationFlagHierarchyDeep(); } + if (dialect != null && filter != null) { - - if (dialect.ToString().Equals(helper.ALIAS_WQL, StringComparison.CurrentCultureIgnoreCase) || dialect.ToString().Equals(helper.URI_WQL_DIALECT, StringComparison.CurrentCultureIgnoreCase)) + if (dialect.ToString().Equals(helper.ALIAS_WQL, StringComparison.OrdinalIgnoreCase) || dialect.ToString().Equals(helper.URI_WQL_DIALECT, StringComparison.OrdinalIgnoreCase)) { fragment = helper.URI_WQL_DIALECT; dialect = new Uri(fragment); } - else if (dialect.ToString().Equals(helper.ALIAS_ASSOCIATION, StringComparison.CurrentCultureIgnoreCase) || dialect.ToString().Equals(helper.URI_ASSOCIATION_DIALECT, StringComparison.CurrentCultureIgnoreCase)) + else if (dialect.ToString().Equals(helper.ALIAS_ASSOCIATION, StringComparison.OrdinalIgnoreCase) || dialect.ToString().Equals(helper.URI_ASSOCIATION_DIALECT, StringComparison.OrdinalIgnoreCase)) { - if (associations) - { - flags |= wsmanObject.EnumerationFlagAssociationInstance(); - } - else - { - flags |= wsmanObject.EnumerationFlagAssociatedInstance(); - } - fragment = helper.URI_ASSOCIATION_DIALECT; - dialect = new Uri(fragment); + if (associations) + { + flags |= wsmanObject.EnumerationFlagAssociationInstance(); + } + else + { + flags |= wsmanObject.EnumerationFlagAssociatedInstance(); + } + + fragment = helper.URI_ASSOCIATION_DIALECT; + dialect = new Uri(fragment); } - else if (dialect.ToString().Equals(helper.ALIAS_SELECTOR, StringComparison.CurrentCultureIgnoreCase) || dialect.ToString().Equals(helper.URI_SELECTOR_DIALECT, StringComparison.CurrentCultureIgnoreCase)) + else if (dialect.ToString().Equals(helper.ALIAS_SELECTOR, StringComparison.OrdinalIgnoreCase) || dialect.ToString().Equals(helper.URI_SELECTOR_DIALECT, StringComparison.OrdinalIgnoreCase)) { - filter = GetFilter(); - fragment = helper.URI_SELECTOR_DIALECT; - dialect = new Uri(fragment); + filter = GetFilter(); + fragment = helper.URI_SELECTOR_DIALECT; + dialect = new Uri(fragment); } + obj = (IWSManEnumerator)wsmanSession.Enumerate(wsmanResourceLocator, filter, dialect.ToString(), flags); } else if (filter != null) { - fragment = helper.URI_WQL_DIALECT; - dialect = new Uri(fragment); - obj = (IWSManEnumerator)wsmanSession.Enumerate(wsmanResourceLocator, filter, dialect.ToString(), flags); + fragment = helper.URI_WQL_DIALECT; + dialect = new Uri(fragment); + obj = (IWSManEnumerator)wsmanSession.Enumerate(wsmanResourceLocator, filter, dialect.ToString(), flags); } else { - obj = (IWSManEnumerator)wsmanSession.Enumerate(wsmanResourceLocator, filter, null, flags); + obj = (IWSManEnumerator)wsmanSession.Enumerate(wsmanResourceLocator, filter, null, flags); } while (!obj.AtEndOfStream) { @@ -472,8 +510,8 @@ private void ReturnEnumeration(IWSManEx wsmanObject, IWSManResourceLocator wsman WriteError(er); } } - # endregion private - # region override + #endregion private + #region override /// /// ProcessRecord method. /// @@ -489,7 +527,7 @@ protected override void ProcessRecord() { try { - //in the format http(s)://server[:port/applicationname] + // in the format http(s)://server[:port/applicationname] string[] constrsplit = connectionuri.OriginalString.Split(new string[] { ":" + port + "/" + applicationname }, StringSplitOptions.None); string[] constrsplit1 = constrsplit[0].Split(new string[] { "//" }, StringSplitOptions.None); computername = constrsplit1[1].Trim(); @@ -498,8 +536,8 @@ protected override void ProcessRecord() { helper.AssertError(helper.GetResourceMsgFromResourcetext("NotProperURI"), false, connectionuri); } - } + try { IWSManResourceLocator m_resource = helper.InitializeResourceLocator(optionset, selectorset, fragment, dialect, m_wsmanObject, resourceuri); @@ -512,7 +550,7 @@ protected override void ProcessRecord() { xmldoc.LoadXml(m_session.Get(m_resource, 0)); } - catch(XmlException ex) + catch (XmlException ex) { helper.AssertError(ex.Message, false, computername); } @@ -537,18 +575,19 @@ protected override void ProcessRecord() helper.AssertError(ex.Message, false, computername); } } - } finally { - if (!String.IsNullOrEmpty(m_wsmanObject.Error)) + if (!string.IsNullOrEmpty(m_wsmanObject.Error)) { helper.AssertError(m_wsmanObject.Error, true, resourceuri); } - if (!String.IsNullOrEmpty(m_session.Error)) + + if (!string.IsNullOrEmpty(m_session.Error)) { helper.AssertError(m_session.Error, true, resourceuri); } + if (m_session != null) Dispose(m_session); } @@ -557,17 +596,17 @@ protected override void ProcessRecord() #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -579,17 +618,13 @@ protected override void ProcessRecord() #endregion IDisposable Members - /// /// BeginProcessing method. /// protected override void EndProcessing() { - helper.CleanUp(); } - - } #endregion @@ -605,7 +640,6 @@ protected override void EndProcessing() [Cmdlet(VerbsCommon.Set, "WSManInstance", DefaultParameterSetName = "ComputerName", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141458")] public class SetWSManInstanceCommand : AuthenticatingWSManCommand, IDisposable { - #region Parameters /// /// The following is the definition of the input parameter "ApplicationName". @@ -613,12 +647,14 @@ public class SetWSManInstanceCommand : AuthenticatingWSManCommand, IDisposable /// [Parameter(ParameterSetName = "ComputerName")] [ValidateNotNullOrEmpty] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { applicationname = value; } } - private String applicationname = null; + + private string applicationname = null; /// /// The following is the definition of the input parameter "ComputerName". @@ -628,19 +664,21 @@ public String ApplicationName /// [Parameter(ParameterSetName = "ComputerName")] [Alias("cn")] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } } } - private String computername = null; + + private string computername = null; /// /// The following is the definition of the input parameter "ConnectionURI". @@ -654,58 +692,66 @@ public String ComputerName public Uri ConnectionURI { get { return connectionuri; } + set { connectionuri = value; } } + private Uri connectionuri; /// /// The following is the definition of the input parameter "Dialect". - /// Defines the dialect for the filter predicate + /// Defines the dialect for the filter predicate. /// [Parameter] [ValidateNotNullOrEmpty] public Uri Dialect { get { return dialect; } + set { dialect = value; } } + private Uri dialect; /// /// The following is the definition of the input parameter "FilePath". /// Updates the management resource specified by the ResourceURI and SelectorSet - /// via this input file + /// via this input file. /// [Parameter(ValueFromPipelineByPropertyName = true)] + [Alias("Path")] [ValidateNotNullOrEmpty] public string FilePath { get { return filepath; } + set { filepath = value; } } - private string filepath; + private string filepath; /// /// The following is the definition of the input parameter "Fragment". /// Specifies a section inside the instance that is to be updated or retrieved - /// for the given operation + /// for the given operation. /// [Parameter(ParameterSetName = "ComputerName")] [Parameter(ParameterSetName = "URI")] [ValidateNotNullOrEmpty] - public String Fragment + public string Fragment { get { return fragment; } + set { fragment = value; } } - private String fragment; + + private string fragment; /// /// The following is the definition of the input parameter "OptionSet". /// OptionSet is a hahs table which help modify or refine the nature of the /// request. These are similar to switches used in command line shells in that - /// they are service-specific + /// they are service-specific. /// [Parameter] @@ -715,8 +761,10 @@ public String Fragment public Hashtable OptionSet { get { return optionset; } + set { optionset = value; } } + private Hashtable optionset; /// @@ -729,13 +777,15 @@ public Hashtable OptionSet public Int32 Port { get { return port; } + set { port = value; } } + private Int32 port = 0; /// /// The following is the definition of the input parameter "ResourceURI". - /// URI of the resource class/instance representation + /// URI of the resource class/instance representation. /// [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "URI")] @@ -747,15 +797,17 @@ public Int32 Port public Uri ResourceURI { get { return resourceuri; } + set { resourceuri = value; } } + private Uri resourceuri; /// /// The following is the definition of the input parameter "SelectorSet". /// SelectorSet is a hash table which helps in identify an instance of the /// management resource if there are are more than 1 instance of the resource - /// class + /// class. /// [Parameter(Position = 1, ValueFromPipeline = true, @@ -765,14 +817,16 @@ public Uri ResourceURI public Hashtable SelectorSet { get { return selectorset; } + set { selectorset = value; } } + private Hashtable selectorset; /// /// The following is the definition of the input parameter "SessionOption". /// Defines a set of extended options for the WSMan session. This can be created - /// by using the cmdlet New-WSManSessionOption + /// by using the cmdlet New-WSManSessionOption. /// [Parameter] [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] @@ -781,8 +835,10 @@ public Hashtable SelectorSet public SessionOption SessionOption { get { return sessionoption; } + set { sessionoption = value; } } + private SessionOption sessionoption; /// @@ -797,8 +853,10 @@ public SessionOption SessionOption public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } + private SwitchParameter usessl; /// @@ -812,15 +870,15 @@ public SwitchParameter UseSSL public Hashtable ValueSet { get { return valueset; } + set { valueset = value; } } - private Hashtable valueset; - + private Hashtable valueset; #endregion - private WSManHelper helper ; + private WSManHelper helper; /// /// ProcessRecord method. /// @@ -831,26 +889,25 @@ protected override void ProcessRecord() helper.WSManOp = "set"; IWSManSession m_session = null; - if (dialect != null) { - if (dialect.ToString().Equals(helper.ALIAS_WQL, StringComparison.CurrentCultureIgnoreCase)) + if (dialect.ToString().Equals(helper.ALIAS_WQL, StringComparison.OrdinalIgnoreCase)) dialect = new Uri(helper.URI_WQL_DIALECT); - if (dialect.ToString().Equals(helper.ALIAS_SELECTOR, StringComparison.CurrentCultureIgnoreCase)) + if (dialect.ToString().Equals(helper.ALIAS_SELECTOR, StringComparison.OrdinalIgnoreCase)) dialect = new Uri(helper.URI_SELECTOR_DIALECT); - if (dialect.ToString().Equals(helper.ALIAS_ASSOCIATION, StringComparison.CurrentCultureIgnoreCase)) + if (dialect.ToString().Equals(helper.ALIAS_ASSOCIATION, StringComparison.OrdinalIgnoreCase)) dialect = new Uri(helper.URI_ASSOCIATION_DIALECT); } try { - string connectionStr = String.Empty; + string connectionStr = string.Empty; connectionStr = helper.CreateConnectionString(connectionuri, port, computername, applicationname); if (connectionuri != null) { try { - //in the format http(s)://server[:port/applicationname] + // in the format http(s)://server[:port/applicationname] string[] constrsplit = connectionuri.OriginalString.Split(new string[] { ":" + port + "/" + applicationname }, StringSplitOptions.None); string[] constrsplit1 = constrsplit[0].Split(new string[] { "//" }, StringSplitOptions.None); computername = constrsplit1[1].Trim(); @@ -859,8 +916,8 @@ protected override void ProcessRecord() { helper.AssertError(helper.GetResourceMsgFromResourcetext("NotProperURI"), false, connectionuri); } - } + IWSManResourceLocator m_resource = helper.InitializeResourceLocator(optionset, selectorset, fragment, dialect, m_wsmanObject, resourceuri); m_session = helper.CreateSessionObject(m_wsmanObject, Authentication, sessionoption, Credential, connectionStr, CertificateThumbprint, usessl.IsPresent); string rootNode = helper.GetRootNodeName(helper.WSManOp, m_resource.ResourceUri, null); @@ -871,7 +928,7 @@ protected override void ProcessRecord() { xmldoc.LoadXml(m_session.Put(m_resource, input, 0)); } - catch(XmlException ex) + catch (XmlException ex) { helper.AssertError(ex.Message, false, computername); } @@ -882,44 +939,45 @@ protected override void ProcessRecord() { foreach (XmlNode node in xmldoc.DocumentElement.ChildNodes) { - if (node.Name.Equals(fragment, StringComparison.CurrentCultureIgnoreCase)) + if (node.Name.Equals(fragment, StringComparison.OrdinalIgnoreCase)) WriteObject(node.Name + " = " + node.InnerText); } } } else WriteObject(xmldoc.DocumentElement); - } finally { - if (!String.IsNullOrEmpty(m_wsmanObject.Error)) + if (!string.IsNullOrEmpty(m_wsmanObject.Error)) { helper.AssertError(m_wsmanObject.Error, true, resourceuri); } - if (!String.IsNullOrEmpty(m_session.Error)) + + if (!string.IsNullOrEmpty(m_session.Error)) { helper.AssertError(m_session.Error, true, resourceuri); } + if (m_session != null) Dispose(m_session); } - }//End ProcessRecord() + } #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -938,14 +996,10 @@ protected override void EndProcessing() { helper.CleanUp(); } - } - - #endregion - #region Remove-WsManInstance /// @@ -958,7 +1012,6 @@ protected override void EndProcessing() [Cmdlet(VerbsCommon.Remove, "WSManInstance", DefaultParameterSetName = "ComputerName", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141453")] public class RemoveWSManInstanceCommand : AuthenticatingWSManCommand, IDisposable { - #region Parameters /// /// The following is the definition of the input parameter "ApplicationName". @@ -966,12 +1019,14 @@ public class RemoveWSManInstanceCommand : AuthenticatingWSManCommand, IDisposabl /// [Parameter(ParameterSetName = "ComputerName")] [ValidateNotNullOrEmpty] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { applicationname = value; } } - private String applicationname = null; + + private string applicationname = null; /// /// The following is the definition of the input parameter "ComputerName". @@ -981,19 +1036,21 @@ public String ApplicationName /// [Parameter(ParameterSetName = "ComputerName")] [Alias("cn")] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } } } - private String computername = null; + + private string computername = null; /// /// The following is the definition of the input parameter "ConnectionURI". @@ -1007,15 +1064,17 @@ public String ComputerName public Uri ConnectionURI { get { return connectionuri; } + set { connectionuri = value; } } + private Uri connectionuri; /// /// The following is the definition of the input parameter "OptionSet". /// OptionSet is a hahs table which help modify or refine the nature of the /// request. These are similar to switches used in command line shells in that - /// they are service-specific + /// they are service-specific. /// [Parameter] @@ -1025,8 +1084,10 @@ public Uri ConnectionURI public Hashtable OptionSet { get { return optionset; } + set { optionset = value; } } + private Hashtable optionset; /// @@ -1039,13 +1100,15 @@ public Hashtable OptionSet public Int32 Port { get { return port; } + set { port = value; } } + private Int32 port = 0; /// /// The following is the definition of the input parameter "ResourceURI". - /// URI of the resource class/instance representation + /// URI of the resource class/instance representation. /// [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "URI")] @@ -1057,15 +1120,17 @@ public Int32 Port public Uri ResourceURI { get { return resourceuri; } + set { resourceuri = value; } } + private Uri resourceuri; /// /// The following is the definition of the input parameter "SelectorSet". /// SelectorSet is a hash table which helps in identify an instance of the /// management resource if there are are more than 1 instance of the resource - /// class + /// class. /// [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, @@ -1075,14 +1140,16 @@ public Uri ResourceURI public Hashtable SelectorSet { get { return selectorset; } + set { selectorset = value; } } + private Hashtable selectorset; /// /// The following is the definition of the input parameter "SessionOption". /// Defines a set of extended options for the WSMan session. This can be created - /// by using the cmdlet New-WSManSessionOption + /// by using the cmdlet New-WSManSessionOption. /// [Parameter] [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] @@ -1091,8 +1158,10 @@ public Hashtable SelectorSet public SessionOption SessionOption { get { return sessionoption; } + set { sessionoption = value; } } + private SessionOption sessionoption; /// @@ -1107,16 +1176,14 @@ public SessionOption SessionOption public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } - private SwitchParameter usessl; - - + private SwitchParameter usessl; #endregion - /// /// ProcessRecord method. /// @@ -1128,13 +1195,13 @@ protected override void ProcessRecord() IWSManSession m_session = null; try { - string connectionStr = String.Empty; + string connectionStr = string.Empty; connectionStr = helper.CreateConnectionString(connectionuri, port, computername, applicationname); if (connectionuri != null) { try { - //in the format http(s)://server[:port/applicationname] + // in the format http(s)://server[:port/applicationname] string[] constrsplit = connectionuri.OriginalString.Split(new string[] { ":" + port + "/" + applicationname }, StringSplitOptions.None); string[] constrsplit1 = constrsplit[0].Split(new string[] { "//" }, StringSplitOptions.None); computername = constrsplit1[1].Trim(); @@ -1143,8 +1210,8 @@ protected override void ProcessRecord() { helper.AssertError(helper.GetResourceMsgFromResourcetext("NotProperURI"), false, connectionuri); } - } + IWSManResourceLocator m_resource = helper.InitializeResourceLocator(optionset, selectorset, null, null, m_wsmanObject, resourceuri); m_session = helper.CreateSessionObject(m_wsmanObject, Authentication, sessionoption, Credential, connectionStr, CertificateThumbprint, usessl.IsPresent); string ResourceURI = helper.GetURIWithFilter(resourceuri.ToString(), null, selectorset, helper.WSManOp); @@ -1156,39 +1223,38 @@ protected override void ProcessRecord() { helper.AssertError(ex.Message, false, computername); } - } finally { - if (!String.IsNullOrEmpty(m_session.Error)) + if (!string.IsNullOrEmpty(m_session.Error)) { helper.AssertError(m_session.Error, true, resourceuri); } - if (!String.IsNullOrEmpty(m_wsmanObject.Error)) + + if (!string.IsNullOrEmpty(m_wsmanObject.Error)) { helper.AssertError(m_wsmanObject.Error, true, resourceuri); } + if (m_session != null) Dispose(m_session); - } - - }//End ProcessRecord() + } #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -1199,17 +1265,14 @@ protected override void ProcessRecord() } #endregion IDisposable Members - - } - #endregion #region New-WsManInstance /// /// Creates an instance of a management resource identified by the resource URI - /// using specified ValueSet or input File + /// using specified ValueSet or input File. /// [Cmdlet(VerbsCommon.New, "WSManInstance", DefaultParameterSetName = "ComputerName", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=141448")] @@ -1221,12 +1284,14 @@ public class NewWSManInstanceCommand : AuthenticatingWSManCommand, IDisposable /// [Parameter(ParameterSetName = "ComputerName")] [ValidateNotNullOrEmpty] - public String ApplicationName + public string ApplicationName { get { return applicationname; } + set { applicationname = value; } } - private String applicationname = null; + + private string applicationname = null; /// /// The following is the definition of the input parameter "ComputerName". @@ -1236,19 +1301,21 @@ public String ApplicationName /// [Parameter(ParameterSetName = "ComputerName")] [Alias("cn")] - public String ComputerName + public string ComputerName { get { return computername; } + set { computername = value; - if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.CurrentCultureIgnoreCase))) + if ((string.IsNullOrEmpty(computername)) || (computername.Equals(".", StringComparison.OrdinalIgnoreCase))) { computername = "localhost"; } } } - private String computername = null; + + private string computername = null; /// /// The following is the definition of the input parameter "ConnectionURI". @@ -1263,23 +1330,28 @@ public String ComputerName public Uri ConnectionURI { get { return connectionuri; } + set { connectionuri = value; } } + private Uri connectionuri; /// /// The following is the definition of the input parameter "FilePath". /// Updates the management resource specified by the ResourceURI and SelectorSet - /// via this input file + /// via this input file. /// [Parameter] [ValidateNotNullOrEmpty] - public String FilePath + [Alias("Path")] + public string FilePath { get { return filepath; } + set { filepath = value; } } - private String filepath; + + private string filepath; /// /// The following is the definition of the input parameter "OptionSet". @@ -1293,8 +1365,10 @@ public String FilePath public Hashtable OptionSet { get { return optionset; } + set { optionset = value; } } + private Hashtable optionset; /// @@ -1307,13 +1381,15 @@ public Hashtable OptionSet public Int32 Port { get { return port; } + set { port = value; } } + private Int32 port = 0; /// /// The following is the definition of the input parameter "ResourceURI". - /// URI of the resource class/instance representation + /// URI of the resource class/instance representation. /// [Parameter(Mandatory = true, Position = 0)] [ValidateNotNullOrEmpty] @@ -1322,15 +1398,17 @@ public Int32 Port public Uri ResourceURI { get { return resourceuri; } + set { resourceuri = value; } } + private Uri resourceuri; /// /// The following is the definition of the input parameter "SelectorSet". /// SelectorSet is a hash table which helps in identify an instance of the /// management resource if there are are more than 1 instance of the resource - /// class + /// class. /// [Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true)] @@ -1339,8 +1417,10 @@ public Uri ResourceURI public Hashtable SelectorSet { get { return selectorset; } + set { selectorset = value; } } + private Hashtable selectorset; /// @@ -1354,8 +1434,10 @@ public Hashtable SelectorSet public SessionOption SessionOption { get { return sessionoption; } + set { sessionoption = value; } } + private SessionOption sessionoption; /// @@ -1369,8 +1451,10 @@ public SessionOption SessionOption public SwitchParameter UseSSL { get { return usessl; } + set { usessl = value; } } + private SwitchParameter usessl; /// @@ -1383,28 +1467,30 @@ public SwitchParameter UseSSL public Hashtable ValueSet { get { return valueset; } + set { valueset = value; } } + private Hashtable valueset; private WSManHelper helper; IWSManEx m_wsmanObject = (IWSManEx)new WSManClass(); IWSManSession m_session = null; - string connectionStr = String.Empty; + string connectionStr = string.Empty; /// /// BeginProcessing method. /// protected override void BeginProcessing() { - helper = new WSManHelper(this ); + helper = new WSManHelper(this); helper.WSManOp = "new"; connectionStr = helper.CreateConnectionString(connectionuri, port, computername, applicationname); if (connectionuri != null) { try { - //in the format http(s)://server[:port/applicationname] + // in the format http(s)://server[:port/applicationname] string[] constrsplit = connectionuri.OriginalString.Split(new string[] { ":" + port + "/" + applicationname }, StringSplitOptions.None); string[] constrsplit1 = constrsplit[0].Split(new string[] { "//" }, StringSplitOptions.None); computername = constrsplit1[1].Trim(); @@ -1413,11 +1499,8 @@ protected override void BeginProcessing() { helper.AssertError(helper.GetResourceMsgFromResourcetext("NotProperURI"), false, connectionuri); } - } - - }//End BeginProcessing() - + } /// /// ProcessRecord method. @@ -1427,7 +1510,7 @@ protected override void ProcessRecord() try { IWSManResourceLocator m_resource = helper.InitializeResourceLocator(optionset, selectorset, null, null, m_wsmanObject, resourceuri); - //create the session object + // create the session object m_session = helper.CreateSessionObject(m_wsmanObject, Authentication, sessionoption, Credential, connectionStr, CertificateThumbprint, usessl.IsPresent); string rootNode = helper.GetRootNodeName(helper.WSManOp, m_resource.ResourceUri, null); string input = helper.ProcessInput(m_wsmanObject, filepath, helper.WSManOp, rootNode, valueset, m_resource, m_session); @@ -1446,36 +1529,37 @@ protected override void ProcessRecord() } finally { - if (!String.IsNullOrEmpty(m_wsmanObject.Error)) + if (!string.IsNullOrEmpty(m_wsmanObject.Error)) { helper.AssertError(m_wsmanObject.Error, true, resourceuri); } - if (!String.IsNullOrEmpty(m_session.Error)) + + if (!string.IsNullOrEmpty(m_session.Error)) { helper.AssertError(m_session.Error, true, resourceuri); } + if (m_session != null) { Dispose(m_session); } } - - }//End ProcessRecord() + } #region IDisposable Members /// - /// public dispose method + /// Public dispose method. /// public void Dispose() { - //CleanUp(); + // CleanUp(); GC.SuppressFinalize(this); } /// - /// public dispose method + /// Public dispose method. /// public void @@ -1493,9 +1577,8 @@ protected override void ProcessRecord() protected override void EndProcessing() { helper.CleanUp(); - - }//End EndProcessing() - }//End Class + } + } #endregion } diff --git a/src/Microsoft.WSMan.Management/WsManHelper.cs b/src/Microsoft.WSMan.Management/WsManHelper.cs index f0843fad94a3..81762a099f9d 100644 --- a/src/Microsoft.WSMan.Management/WsManHelper.cs +++ b/src/Microsoft.WSMan.Management/WsManHelper.cs @@ -1,37 +1,35 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Text.RegularExpressions; using System.Collections; -using System.Xml; -using System.Runtime.InteropServices; -using System.Reflection; -using System.Resources; -using System.Globalization; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using Microsoft.Win32; +using System.Globalization; +using System.IO; using System.Management.Automation; using System.Management.Automation.Provider; +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; using System.Threading; -#if CORECLR -using System.Xml.XPath; -#endif +using System.Xml; + +using Microsoft.Win32; namespace Microsoft.WSMan.Management { [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#")] internal class WSManHelper { - //regular expressions + // regular expressions private const string PTRN_URI_LAST = @"([a-z_][-a-z0-9._]*)$"; private const string PTRN_OPT = @"^-([a-z]+):(.*)"; private const string PTRN_HASH_TOK = @"\s*([\w:]+)\s*=\s*(\$null|""([^""]*)"")\s*"; - //schemas + // schemas private const string URI_IPMI = @"http://schemas.dmtf.org/wbem/wscim/1/cim-schema"; private const string URI_WMI = @"http://schemas.microsoft.com/wbem/wsman/1/wmi"; private const string NS_IPMI = @"http://schemas.dmtf.org/wbem/wscim/1/cim-schema"; @@ -44,7 +42,7 @@ internal class WSManHelper private const string ALIAS_XPATH = @"xpath"; private const string URI_XPATH_DIALECT = @"http://www.w3.org/TR/1999/REC-xpath-19991116"; - //credSSP strings + // credSSP strings internal string CredSSP_RUri = "winrm/config/client/auth"; internal string CredSSP_XMLNmsp = "http://schemas.microsoft.com/wbem/wsman/1/config/client/auth"; internal string CredSSP_SNode = "/cfg:Auth/cfg:CredSSP"; @@ -58,18 +56,18 @@ internal class WSManHelper internal string Service_CredSSP_Uri = "winrm/config/service/auth"; internal string Service_CredSSP_XMLNmsp = "http://schemas.microsoft.com/wbem/wsman/1/config/service/auth"; - //gpo registry path and keys + // gpo registry path and keys internal string Registry_Path_Credentials_Delegation = @"SOFTWARE\Policies\Microsoft\Windows"; internal string Key_Allow_Fresh_Credentials = "AllowFreshCredentials"; internal string Key_Concatenate_Defaults_AllowFresh = "ConcatenateDefaults_AllowFresh"; internal string Delegate = "delegate"; internal string keyAllowcredssp = "AllowCredSSP"; - //'Constants for MS-XML + // 'Constants for MS-XML private const string NODE_ATTRIBUTE = "2"; private const int NODE_TEXT = 3; - //strings for dialects + // strings for dialects internal string ALIAS_WQL = @"wql"; internal string ALIAS_ASSOCIATION = @"association"; internal string ALIAS_SELECTOR = @"selector"; @@ -77,7 +75,7 @@ internal class WSManHelper internal string URI_SELECTOR_DIALECT = @"http://schemas.dmtf.org/wbem/wsman/1/wsman/SelectorFilter"; internal string URI_ASSOCIATION_DIALECT = @" http://schemas.dmtf.org/wbem/wsman/1/cimbinding/associationFilter"; - //string for operation + // string for operation internal string WSManOp = null; private PSCmdlet cmdletname; @@ -88,14 +86,13 @@ internal class WSManHelper private static ResourceManager _resourceMgr = new ResourceManager("Microsoft.WSMan.Management.resources.WsManResources", typeof(WSManHelper).GetTypeInfo().Assembly); - // // - //Below class is just a static container which would release sessions in case this DLL is unloaded. + // Below class is just a static container which would release sessions in case this DLL is unloaded. internal class Sessions { /// - /// dictionary object to store the connection + /// Dictionary object to store the connection. /// internal static Dictionary SessionObjCache = new Dictionary(); @@ -104,12 +101,12 @@ internal class Sessions ReleaseSessions(); } } + internal static Sessions AutoSession = new Sessions(); // // // - internal static void ReleaseSessions() { lock (Sessions.SessionObjCache) @@ -124,10 +121,12 @@ internal static void ReleaseSessions() } catch (ArgumentException) { - //Somehow the object was a null reference. Ignore the error + // Somehow the object was a null reference. Ignore the error } - sessionobj=null; + + sessionobj = null; } + Sessions.SessionObjCache.Clear(); } } @@ -162,7 +161,7 @@ internal string GetResourceMsgFromResourcetext(string rscname) return _resourceMgr.GetString(rscname); } - static internal string FormatResourceMsgFromResourcetextS(string rscname, + internal static string FormatResourceMsgFromResourcetextS(string rscname, params object[] args) { return FormatResourceMsgFromResourcetextS(_resourceMgr, rscname, args); @@ -174,7 +173,7 @@ internal string GetResourceMsgFromResourcetext(string rscname) return FormatResourceMsgFromResourcetextS(_resourceMgr, resourceName, args); } - static private string FormatResourceMsgFromResourcetextS( + private static string FormatResourceMsgFromResourcetextS( ResourceManager resourceManager, string resourceName, object[] args) @@ -184,7 +183,7 @@ internal string GetResourceMsgFromResourcetext(string rscname) throw new ArgumentNullException("resourceManager"); } - if (String.IsNullOrEmpty(resourceName)) + if (string.IsNullOrEmpty(resourceName)) { throw new ArgumentNullException("resourceName"); } @@ -192,21 +191,21 @@ internal string GetResourceMsgFromResourcetext(string rscname) string template = resourceManager.GetString(resourceName); string result = null; - if (null != template) + if (template != null) { - result = String.Format(CultureInfo.CurrentCulture, + result = string.Format(CultureInfo.CurrentCulture, template, args); } + return result; } - /// - /// add a session to dictionary + /// Add a session to dictionary. /// - /// connection string - /// session object - internal void AddtoDictionary(string key, Object value) + /// Connection string. + /// Session object. + internal void AddtoDictionary(string key, object value) { key = key.ToLowerInvariant(); lock (Sessions.SessionObjCache) @@ -225,13 +224,13 @@ internal void AddtoDictionary(string key, Object value) } catch (ArgumentException) { - //Somehow the object was a null reference. Ignore the error + // Somehow the object was a null reference. Ignore the error } + Sessions.SessionObjCache.Remove(key); Sessions.SessionObjCache.Add(key, value); } } - } internal object RemoveFromDictionary(string computer) @@ -249,11 +248,13 @@ internal object RemoveFromDictionary(string computer) } catch (ArgumentException) { - //Somehow the object was a null reference. Ignore the error + // Somehow the object was a null reference. Ignore the error } + Sessions.SessionObjCache.Remove(computer); } } + return objsession; } @@ -283,6 +284,7 @@ internal object RemoveFromDictionary(string computer) catch (COMException) { } + return Sessions.SessionObjCache; } @@ -301,7 +303,7 @@ internal string GetRootNodeName(string operation, string resourceUri, string act if (operation.Equals("invoke", StringComparison.OrdinalIgnoreCase)) { sfx = "_INPUT"; - resultStr = String.Concat(actionStr, sfx); + resultStr = string.Concat(actionStr, sfx); } else { @@ -310,9 +312,10 @@ internal string GetRootNodeName(string operation, string resourceUri, string act } else { - //error + // error } } + return resultStr; } @@ -331,21 +334,19 @@ internal string ReadFile(string path) { throw new ArgumentException(GetResourceMsgFromResourcetext("InvalidFileName")); } + string strOut = null; try { - _fs = new FileStream(path, FileMode.Open, FileAccess.Read); // create stream Reader _sr = new StreamReader(_fs); strOut = _sr.ReadToEnd(); } - catch (ArgumentNullException e) { ErrorRecord er = new ErrorRecord(e, "ArgumentNullException", ErrorCategory.InvalidArgument, null); cmdletname.ThrowTerminatingError(er); - } catch (UnauthorizedAccessException e) { @@ -371,30 +372,32 @@ internal string ReadFile(string path) { if (_sr != null) { - // _sr.Close(); + // _sr.Close(); _sr.Dispose(); } + if (_fs != null) { - //_fs.Close(); + // _fs.Close(); _fs.Dispose(); } } + return strOut; } internal string ProcessInput(IWSManEx wsman, string filepath, string operation, string root, Hashtable valueset, IWSManResourceLocator resourceUri, IWSManSession sessionObj) { - string resultString = null; - //if file path is given + // if file path is given if (!string.IsNullOrEmpty(filepath) && valueset == null) { if (!File.Exists(filepath)) { throw new FileNotFoundException(_resourceMgr.GetString("InvalidFileName")); } + resultString = ReadFile(filepath); return resultString; } @@ -407,7 +410,7 @@ internal string ProcessInput(IWSManEx wsman, string filepath, string operation, string parameters = null, nilns = null; string xmlns = GetXmlNs(resourceUri.ResourceUri); - //if valueset is given, i.e hashtable + // if valueset is given, i.e hashtable if (valueset != null) { foreach (DictionaryEntry entry in valueset) @@ -418,9 +421,11 @@ internal string ProcessInput(IWSManEx wsman, string filepath, string operation, parameters = parameters + " " + ATTR_NIL; nilns = " " + NS_XSI; } + parameters = parameters + ">" + entry.Value.ToString() + ""; } } + resultString = "" + parameters + ""; break; @@ -438,7 +443,7 @@ internal string ProcessInput(IWSManEx wsman, string filepath, string operation, xpathString = @"/*/*[local-name()=""" + entry.Key + @"""]"; if (entry.Key.ToString().Equals("location", StringComparison.OrdinalIgnoreCase)) { - //'Ignore cim:Location + // 'Ignore cim:Location xpathString = @"/*/*[local-name()=""" + entry.Key + @""" and namespace-uri() != """ + NS_CIMBASE + @"""]"; } @@ -469,14 +474,15 @@ internal string ProcessInput(IWSManEx wsman, string filepath, string operation, } } } + if (string.IsNullOrEmpty(entry.Key.ToString())) { - //XmlNode newnode = xmlfile.CreateNode(XmlNodeType.Attribute, ATTR_NIL_NAME, NS_XSI_URI); + // XmlNode newnode = xmlfile.CreateNode(XmlNodeType.Attribute, ATTR_NIL_NAME, NS_XSI_URI); XmlAttribute newnode = xmlfile.CreateAttribute(XmlNodeType.Attribute.ToString(), ATTR_NIL_NAME, NS_XSI_URI); newnode.Value = "true"; node.Attributes.Append(newnode); - //(newnode.Attributes.Item(0).FirstChild ); - node.Value = ""; + // (newnode.Attributes.Item(0).FirstChild ); + node.Value = string.Empty; } else { @@ -484,12 +490,13 @@ internal string ProcessInput(IWSManEx wsman, string filepath, string operation, node.InnerText = entry.Value.ToString(); } } + } + } - }//end for - }//end if valueset resultString = xmlfile.OuterXml; break; - }//end switch + } + return resultString; } @@ -508,6 +515,7 @@ internal XmlNode GetXmlNode(string xmlString, string xpathpattern, string xmlnam { nsmgr.AddNamespace("cfg", xmlnamespace); } + node = xDoc.SelectSingleNode(xpathpattern, nsmgr); return node; } @@ -534,23 +542,24 @@ internal string CreateConnectionString(Uri ConnUri, int port, string computernam { ConnectionString = ConnectionString + ":" + port; } + if (applicationname != null) { ConnectionString = ConnectionString + "/" + applicationname; } } - return ConnectionString; + return ConnectionString; } internal IWSManResourceLocator InitializeResourceLocator(Hashtable optionset, Hashtable selectorset, string fragment, Uri dialect, IWSManEx wsmanObj, Uri resourceuri) { - string resource = null; if (resourceuri != null) { resource = resourceuri.ToString(); } + if (selectorset != null) { resource = resource + "?"; @@ -563,12 +572,12 @@ internal IWSManResourceLocator InitializeResourceLocator(Hashtable optionset, Ha resource += "+"; } } + IWSManResourceLocator m_resource = null; try { m_resource = (IWSManResourceLocator)wsmanObj.CreateResourceLocator(resource); - if (optionset != null) { foreach (DictionaryEntry entry in optionset) @@ -598,6 +607,7 @@ internal IWSManResourceLocator InitializeResourceLocator(Hashtable optionset, Ha { AssertError(ex.Message, false, null); } + return m_resource; } @@ -612,11 +622,11 @@ internal IWSManResourceLocator InitializeResourceLocator(Hashtable optionset, Ha /// /// If there is ambiguity as specified above. /// - static internal void ValidateSpecifiedAuthentication(AuthenticationMechanism authentication, PSCredential credential, string certificateThumbprint) + internal static void ValidateSpecifiedAuthentication(AuthenticationMechanism authentication, PSCredential credential, string certificateThumbprint) { if ((credential != null) && (certificateThumbprint != null)) { - String message = FormatResourceMsgFromResourcetextS( + string message = FormatResourceMsgFromResourcetextS( "AmbiguosAuthentication", "CertificateThumbPrint", "credential"); @@ -627,7 +637,7 @@ static internal void ValidateSpecifiedAuthentication(AuthenticationMechanism aut (authentication != AuthenticationMechanism.ClientCertificate) && (certificateThumbprint != null)) { - String message = FormatResourceMsgFromResourcetextS( + string message = FormatResourceMsgFromResourcetextS( "AmbiguosAuthentication", "CertificateThumbPrint", authentication.ToString()); @@ -648,44 +658,49 @@ internal IWSManSession CreateSessionObject(IWSManEx wsmanObject, AuthenticationM { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUseNoAuthentication; } + if (authentication.Equals(AuthenticationMechanism.Basic)) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUseBasic | (int)WSManSessionFlags.WSManFlagCredUserNamePassword; } + if (authentication.Equals(AuthenticationMechanism.Negotiate)) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUseNegotiate; } + if (authentication.Equals(AuthenticationMechanism.Kerberos)) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUseKerberos; } + if (authentication.Equals(AuthenticationMechanism.Digest)) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUseDigest | (int)WSManSessionFlags.WSManFlagCredUserNamePassword; } + if (authentication.Equals(AuthenticationMechanism.Credssp)) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUseCredSsp | (int)WSManSessionFlags.WSManFlagCredUserNamePassword; } + if (authentication.Equals(AuthenticationMechanism.ClientCertificate)) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUseClientCertificate; } - } IWSManConnectionOptionsEx2 connObject = (IWSManConnectionOptionsEx2)wsmanObject.CreateConnectionOptions(); if (credential != null) { - //connObject = (IWSManConnectionOptionsEx2)wsmanObject.CreateConnectionOptions(); + // connObject = (IWSManConnectionOptionsEx2)wsmanObject.CreateConnectionOptions(); System.Net.NetworkCredential nwCredential = new System.Net.NetworkCredential(); if (credential.UserName != null) { nwCredential = credential.GetNetworkCredential(); - if (String.IsNullOrEmpty(nwCredential.Domain)) + if (string.IsNullOrEmpty(nwCredential.Domain)) { - if ( authentication.Equals(AuthenticationMechanism.Digest) || authentication.Equals(AuthenticationMechanism.Basic) ) + if (authentication.Equals(AuthenticationMechanism.Digest) || authentication.Equals(AuthenticationMechanism.Basic)) { connObject.UserName = nwCredential.UserName; } @@ -699,6 +714,7 @@ internal IWSManSession CreateSessionObject(IWSManEx wsmanObject, AuthenticationM { connObject.UserName = nwCredential.Domain + "\\" + nwCredential.UserName; } + connObject.Password = nwCredential.Password; if (!authentication.Equals(AuthenticationMechanism.Credssp) || !authentication.Equals(AuthenticationMechanism.Digest) || authentication.Equals(AuthenticationMechanism.Basic)) { @@ -715,7 +731,6 @@ internal IWSManSession CreateSessionObject(IWSManEx wsmanObject, AuthenticationM if (sessionoption != null) { - if (sessionoption.ProxyAuthentication != 0) { int ProxyAccessflags = 0; @@ -749,6 +764,7 @@ internal IWSManSession CreateSessionObject(IWSManEx wsmanObject, AuthenticationM { ProxyAuthenticationFlags = connObject.ProxyAuthenticationUseDigest(); } + if (sessionoption.ProxyCredential != null) { try @@ -764,34 +780,38 @@ internal IWSManSession CreateSessionObject(IWSManEx wsmanObject, AuthenticationM { connObject.SetProxy((int)sessionoption.ProxyAccessType, (int)sessionoption.ProxyAuthentication, null, null); } - - } + if (sessionoption.SkipCACheck) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagSkipCACheck; } + if (sessionoption.SkipCNCheck) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagSkipCNCheck; } + if (sessionoption.SPNPort > 0) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagEnableSpnServerPort; } + if (sessionoption.UseUtf16) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUtf16; } else { - //If UseUtf16 is false, then default Encoding is Utf8 + // If UseUtf16 is false, then default Encoding is Utf8 sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUtf8; } + if (!sessionoption.UseEncryption) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagNoEncryption; } + if (sessionoption.SkipRevocationCheck) { sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagSkipRevocationCheck; @@ -799,7 +819,7 @@ internal IWSManSession CreateSessionObject(IWSManEx wsmanObject, AuthenticationM } else { - //If SessionOption is null then, default Encoding is Utf8 + // If SessionOption is null then, default Encoding is Utf8 sessionFlags = sessionFlags | (int)WSManSessionFlags.WSManFlagUtf8; } @@ -824,24 +844,23 @@ internal IWSManSession CreateSessionObject(IWSManEx wsmanObject, AuthenticationM { AssertError(ex.Message, false, null); } + return m_SessionObj; } internal void CleanUp() { - - if (_sr != null) { _sr.Dispose(); _sr = null; } + if (_fs != null) { _fs.Dispose(); _fs = null; } - } internal string GetFilterString(Hashtable seletorset) @@ -857,6 +876,7 @@ internal string GetFilterString(Hashtable seletorset) filter.Append("+"); } } + filter.Remove(filter.ToString().Length - 1, 1); return filter.ToString(); } @@ -902,7 +922,7 @@ internal string GetURIWithFilter(string uri, string filter, Hashtable selectorse if (operation.Equals("remove", StringComparison.OrdinalIgnoreCase)) { sburi.Append(GetFilterString(selectorset)); - if (sburi.ToString().EndsWith("?", StringComparison.OrdinalIgnoreCase)) + if (sburi.ToString().EndsWith('?')) { sburi.Remove(sburi.Length - 1, 1); } @@ -912,7 +932,7 @@ internal string GetURIWithFilter(string uri, string filter, Hashtable selectorse } /// - /// This method is used by Connect-WsMan Cmdlet and New-Item of WsMan Provider to create connection to WsMan + /// This method is used by Connect-WsMan Cmdlet and New-Item of WsMan Provider to create connection to WsMan. /// /// /// @@ -932,11 +952,12 @@ internal void CreateWsManConnection(string ParameterSetName, Uri connectionuri, string connectionStr = CreateConnectionString(connectionuri, port, computername, applicationname); if (connectionuri != null) { - //in the format http(s)://server[:port/applicationname] + // in the format http(s)://server[:port/applicationname] string[] constrsplit = connectionStr.Split(new string[] { ":" + port + "/" + applicationname }, StringSplitOptions.None); string[] constrsplit1 = constrsplit[0].Split(new string[] { "//" }, StringSplitOptions.None); computername = constrsplit1[1].Trim(); } + IWSManSession m_session = CreateSessionObject(m_wsmanObject, authentication, sessionoption, credential, connectionStr, certificateThumbprint, usessl); m_session.Identify(0); string key = computername; @@ -944,6 +965,7 @@ internal void CreateWsManConnection(string ParameterSetName, Uri connectionuri, { key = "localhost"; } + AddtoDictionary(key, m_session); } catch (IndexOutOfRangeException) @@ -956,11 +978,10 @@ internal void CreateWsManConnection(string ParameterSetName, Uri connectionuri, } finally { - if (!String.IsNullOrEmpty(m_wsmanObject.Error)) + if (!string.IsNullOrEmpty(m_wsmanObject.Error)) { AssertError(m_wsmanObject.Error, true, computername); } - } } @@ -996,17 +1017,14 @@ internal bool ValidateCredSSPRegistry(bool AllowFreshCredentialsValueShouldBePre { RegistryKey rGPOLocalMachineKey = Registry.LocalMachine.OpenSubKey( Registry_Path_Credentials_Delegation + @"\CredentialsDelegation", -#if !CORECLR RegistryKeyPermissionCheck.ReadWriteSubTree, -#endif System.Security.AccessControl.RegistryRights.FullControl); if (rGPOLocalMachineKey != null) { - rGPOLocalMachineKey = rGPOLocalMachineKey.OpenSubKey(Key_Allow_Fresh_Credentials, -#if !CORECLR + rGPOLocalMachineKey = rGPOLocalMachineKey.OpenSubKey( + Key_Allow_Fresh_Credentials, RegistryKeyPermissionCheck.ReadWriteSubTree, -#endif System.Security.AccessControl.RegistryRights.FullControl); if (rGPOLocalMachineKey == null) { @@ -1068,7 +1086,7 @@ internal static void LoadResourceData() #if CORECLR "0409" /* TODO: don't assume it is always English on CSS? */ #else - String.Concat("0", String.Format(CultureInfo.CurrentCulture, "{0:x2}", checked((uint)CultureInfo.CurrentUICulture.LCID))) + string.Concat("0", string.Format(CultureInfo.CurrentCulture, "{0:x2}", checked((uint)CultureInfo.CurrentUICulture.LCID))) #endif + "\\" + "winrm.ini"; if (File.Exists(filepath)) @@ -1090,42 +1108,37 @@ internal static void LoadResourceData() } } } - catch (IOException e) { - throw (e); } - - } /// /// Get the resource value from WinRm.ini - /// from %windir%\system32\winrm\[Hexadecimal Language Folder]\winrm.ini + /// from %windir%\system32\winrm\[Hexadecimal Language Folder]\winrm.ini. /// /// /// internal static string GetResourceString(string Key) { - //Checks whether resource values already loaded and loads. + // Checks whether resource values already loaded and loads. if (ResourceValueCache.Count <= 0) { LoadResourceData(); } - string value = ""; + + string value = string.Empty; if (ResourceValueCache.ContainsKey(Key.Trim())) { ResourceValueCache.TryGetValue(Key.Trim(), out value); } + return value.Trim(); } /// - /// /// private static Dictionary ResourceValueCache = new Dictionary(); - - } } diff --git a/src/Microsoft.WSMan.Management/WsManSnapin.cs b/src/Microsoft.WSMan.Management/WsManSnapin.cs index b47e57f424f9..903d02c7784a 100644 --- a/src/Microsoft.WSMan.Management/WsManSnapin.cs +++ b/src/Microsoft.WSMan.Management/WsManSnapin.cs @@ -1,14 +1,14 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; +using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; -using System.Text; using System.Management; using System.Management.Automation; -using System.ComponentModel; -using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Text; namespace Microsoft.WSMan.Management { diff --git a/src/Microsoft.WSMan.Management/resources/WsManResources.txt b/src/Microsoft.WSMan.Management/resources/WsManResources.txt index fd0bd37eb740..61be75be1183 100644 --- a/src/Microsoft.WSMan.Management/resources/WsManResources.txt +++ b/src/Microsoft.WSMan.Management/resources/WsManResources.txt @@ -3,7 +3,7 @@ # {0} = Delegate Vendor=Microsoft -Description=This Windows PowerShell snap-in contains cmdlets (such as Get-WSManInstance and Set-WSManInstance) that are used by the Windows PowerShell host to manage WSMan operations. +Description=This PowerShell snap-in contains cmdlets (such as Get-WSManInstance and Set-WSManInstance) that are used by the PowerShell host to manage WSMan operations. InvalidComputerName=The WinRM client cannot complete the operation.Check if the computer name is valid. InvalidFileName=This command cannot be used because file does not exist.Check the file existence and run your command. InvalidPath=This command cannot be used because root path does not exist.Check the root path and run your command. @@ -65,4 +65,4 @@ SetItemWhatIfAndConfirmText= "Set-Item" on the WinRM configuration setting "{0}" SetItemWarnigForPPQ=The updated configuration is effective only if it is less than or equal to the value of global quota {0}. Verify the value for the global quota using the PowerShell cmdlet "Get-Item {0}". SetItemWarningForGlobalQuota=The updated configuration might affect the operation of the plugins having a per plugin quota value greater than {0}. Verify the configuration of all the registered plugins and change the per plugin quota values for the affected plugins. SetItemServiceRestartWarning= The configuration changes you made will only be effective after the WinRM service is restarted. To restart the WinRM service, run the following command: 'Restart-Service winrm' -SetItemServiceRestartWarningRemote= The configuration changes you made will only be effective after the WinRM service is restarted on {0}. \ No newline at end of file +SetItemServiceRestartWarningRemote= The configuration changes you made will only be effective after the WinRM service is restarted on {0}. diff --git a/src/Microsoft.WSMan.Runtime/Microsoft.WSMan.Runtime.csproj b/src/Microsoft.WSMan.Runtime/Microsoft.WSMan.Runtime.csproj index 0715bacb694b..7ebc728020fd 100644 --- a/src/Microsoft.WSMan.Runtime/Microsoft.WSMan.Runtime.csproj +++ b/src/Microsoft.WSMan.Runtime/Microsoft.WSMan.Runtime.csproj @@ -1,24 +1,8 @@  - PowerShell Core's Microsoft.WSMan.Runtime project + PowerShell's Microsoft.WSMan.Runtime project Microsoft.WSMan.Runtime - - $(DefineConstants);CORECLR - - - - portable - - - - $(DefineConstants);UNIX - - - - full - - diff --git a/src/Microsoft.WSMan.Runtime/WSManSessionOption.cs b/src/Microsoft.WSMan.Runtime/WSManSessionOption.cs index 0a5a9c2268d1..42c684a9c8d7 100644 --- a/src/Microsoft.WSMan.Runtime/WSManSessionOption.cs +++ b/src/Microsoft.WSMan.Runtime/WSManSessionOption.cs @@ -1,13 +1,13 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using System; +using System.ComponentModel; using System.IO; -using System.Xml; using System.Net; -using System.Resources; using System.Reflection; -using System.ComponentModel; +using System.Resources; +using System.Xml; using System.Collections; using System.Collections.Generic; @@ -16,108 +16,114 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; - - - - [assembly: CLSCompliant(true)] + namespace Microsoft.WSMan.Management { - /// - /// Session option class + /// Session option class. /// public sealed class SessionOption { - /// - /// property + /// Property. /// public bool SkipCACheck { get { return _SkipCACheck; } + set { _SkipCACheck = value; } } + private bool _SkipCACheck; /// - /// property + /// Property. /// public bool SkipCNCheck { get { return _SkipCNCheck; } + set { _SkipCNCheck = value; } } + private bool _SkipCNCheck; /// - /// property + /// Property. /// - /// public bool SkipRevocationCheck { get { return _SkipRevocationCheck; } + set { _SkipRevocationCheck = value; } - } + private bool _SkipRevocationCheck; /// - /// property + /// Property. /// public bool UseEncryption { get { return _useencryption; } + set { _useencryption = value; } } + private bool _useencryption = true; /// - /// property + /// Property. /// public bool UseUtf16 { get { return _UTF16; } + set { _UTF16 = value; } } + private bool _UTF16; /// - /// property + /// Property. /// public ProxyAuthentication ProxyAuthentication { get { return _ProxyAuthentication; } + set { _ProxyAuthentication = value; } } + private ProxyAuthentication _ProxyAuthentication; /// - /// property + /// Property. /// [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SPN")] public int SPNPort { get { return _SPNPort; } + set { _SPNPort = value; @@ -127,37 +133,42 @@ public int SPNPort private int _SPNPort; /// - /// property + /// Property. /// public int OperationTimeout { get { return _OperationTimeout; } + set { _OperationTimeout = value; } } + private int _OperationTimeout; /// - /// property + /// Property. /// public NetworkCredential ProxyCredential { get { return _ProxyCredential; } + set { _ProxyCredential = value; } } + private NetworkCredential _ProxyCredential; /// - /// property + /// Property. /// public ProxyAccessType ProxyAccessType { get { return _proxyaccesstype; } + set { _proxyaccesstype = value; @@ -168,45 +179,45 @@ public ProxyAccessType ProxyAccessType } /// - /// property + /// Property. /// public enum ProxyAccessType { /// - /// property + /// Property. /// ProxyIEConfig = 0, /// - /// property + /// Property. /// ProxyWinHttpConfig = 1, /// - /// property + /// Property. /// ProxyAutoDetect = 2, /// - /// property + /// Property. /// ProxyNoProxyServer = 3 } /// - /// property + /// Property. /// [SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags")] [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")] public enum ProxyAuthentication { /// - /// property + /// Property. /// Negotiate = 1, /// - /// property + /// Property. /// Basic = 2, /// - /// property + /// Property. /// Digest = 4 } diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj new file mode 100644 index 000000000000..bba8fba176ba --- /dev/null +++ b/src/Modules/PSGalleryModules.csproj @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/Modules/README.md b/src/Modules/README.md index ccc66161d0e0..5911951a5ad2 100644 --- a/src/Modules/README.md +++ b/src/Modules/README.md @@ -11,11 +11,8 @@ Content files includes: These files are copied as-is by `dotnet` -- Shared (shared between all variations) -- Windows+Unix-Core -- Windows-Core -- Windows-Core+Full -- Windows-Full +- Shared (shared between Windows and Unix) +- Windows - Unix Notes diff --git a/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 b/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 index 88a0034539f4..3f075079cfb9 100644 --- a/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 +++ b/src/Modules/Shared/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 @@ -1,14 +1,14 @@ @{ GUID="56D66100-99A0-4FFC-A12D-EEE9A6718AEF" -Author="Microsoft Corporation" +Author="PowerShell" CompanyName="Microsoft Corporation" Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.0.0.0" +ModuleVersion="7.0.0.0" +CompatiblePSEditions = @("Core") PowerShellVersion="3.0" -CLRVersion="4.0" -AliasesToExport = @() FunctionsToExport = @() CmdletsToExport="Start-Transcript", "Stop-Transcript" +AliasesToExport = @() NestedModules="Microsoft.PowerShell.ConsoleHost.dll" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855956' } diff --git a/src/Modules/Shared/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 b/src/Modules/Shared/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 deleted file mode 100644 index cd915abe7ae6..000000000000 --- a/src/Modules/Shared/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 +++ /dev/null @@ -1,174 +0,0 @@ - -## Converts a SDDL string into an object-based representation of a security -## descriptor -function ConvertFrom-SddlString -{ - [CmdletBinding(HelpUri = "https://go.microsoft.com/fwlink/?LinkId=623636")] - param( - ## The string representing the security descriptor in SDDL syntax - [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] - [String] $Sddl, - - ## The type of rights that this SDDL string represents, if any. - [Parameter()] - [ValidateSet( - "FileSystemRights", "RegistryRights", "ActiveDirectoryRights", - "MutexRights", "SemaphoreRights", "CryptoKeyRights", - "EventWaitHandleRights")] - $Type - ) - - Begin - { - # On CoreCLR CryptoKeyRights and ActiveDirectoryRights are not supported. - if ($PSEdition -eq "Core" -and ($Type -eq "CryptoKeyRights" -or $Type -eq "ActiveDirectoryRights")) - { - $errorId = "TypeNotSupported" - $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument - $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::TypeNotSupported -f $Type - $exception = [System.ArgumentException]::New($errorMessage) - $errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $null) - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - - ## Translates a SID into a NT Account - function ConvertTo-NtAccount - { - param($Sid) - - if($Sid) - { - $securityIdentifier = [System.Security.Principal.SecurityIdentifier] $Sid - - try - { - $ntAccount = $securityIdentifier.Translate([System.Security.Principal.NTAccount]).ToString() - } - catch{} - - $ntAccount - } - } - - ## Gets the access rights that apply to an access mask, preferring right types - ## of 'Type' if specified. - function Get-AccessRights - { - param($AccessMask, $Type) - - if ($PSEdition -eq "Core") - { - ## All the types of access rights understood by .NET Core - $rightTypes = [Ordered] @{ - "FileSystemRights" = [System.Security.AccessControl.FileSystemRights] - "RegistryRights" = [System.Security.AccessControl.RegistryRights] - "MutexRights" = [System.Security.AccessControl.MutexRights] - "SemaphoreRights" = [System.Security.AccessControl.SemaphoreRights] - "EventWaitHandleRights" = [System.Security.AccessControl.EventWaitHandleRights] - } - } - else - { - ## All the types of access rights understood by .NET - $rightTypes = [Ordered] @{ - "FileSystemRights" = [System.Security.AccessControl.FileSystemRights] - "RegistryRights" = [System.Security.AccessControl.RegistryRights] - "ActiveDirectoryRights" = [System.DirectoryServices.ActiveDirectoryRights] - "MutexRights" = [System.Security.AccessControl.MutexRights] - "SemaphoreRights" = [System.Security.AccessControl.SemaphoreRights] - "CryptoKeyRights" = [System.Security.AccessControl.CryptoKeyRights] - "EventWaitHandleRights" = [System.Security.AccessControl.EventWaitHandleRights] - } - } - $typesToExamine = $rightTypes.Values - - ## If they know the access mask represents a certain type, prefer its names - ## (i.e.: CreateLink for the registry over CreateDirectories for the filesystem) - if($Type) - { - $typesToExamine = @($rightTypes[$Type]) + $typesToExamine - } - - - ## Stores the access types we've found that apply - $foundAccess = @() - - ## Store the access types we've already seen, so that we don't report access - ## flags that are essentially duplicate. Many of the access values in the different - ## enumerations have the same value but with different names. - $foundValues = @{} - - ## Go through the entries in the different right types, and see if they apply to the - ## provided access mask. If they do, then add that to the result. - foreach($rightType in $typesToExamine) - { - foreach($accessFlag in [Enum]::GetNames($rightType)) - { - $longKeyValue = [long] $rightType::$accessFlag - if(-not $foundValues.ContainsKey($longKeyValue)) - { - $foundValues[$longKeyValue] = $true - if(($AccessMask -band $longKeyValue) -eq ($longKeyValue)) - { - $foundAccess += $accessFlag - } - } - } - } - - $foundAccess | Sort-Object - } - - ## Converts an ACE into a string representation - function ConvertTo-AceString - { - param( - [Parameter(ValueFromPipeline)] - $Ace, - $Type - ) - - process - { - foreach($aceEntry in $Ace) - { - $AceString = (ConvertTo-NtAccount $aceEntry.SecurityIdentifier) + ": " + $aceEntry.AceQualifier - if($aceEntry.AceFlags -ne "None") - { - $AceString += " " + $aceEntry.AceFlags - } - - if($aceEntry.AccessMask) - { - $foundAccess = Get-AccessRights $aceEntry.AccessMask $Type - - if($foundAccess) - { - $AceString += " ({0})" -f ($foundAccess -join ", ") - } - } - - $AceString - } - } - } - } - - Process - { - $rawSecurityDescriptor = [Security.AccessControl.CommonSecurityDescriptor]::new($false,$false,$Sddl) - - $owner = ConvertTo-NtAccount $rawSecurityDescriptor.Owner - $group = ConvertTo-NtAccount $rawSecurityDescriptor.Group - $discretionaryAcl = ConvertTo-AceString $rawSecurityDescriptor.DiscretionaryAcl $Type - $systemAcl = ConvertTo-AceString $rawSecurityDescriptor.SystemAcl $Type - - [PSCustomObject] @{ - Owner = $owner - Group = $group - DiscretionaryAcl = @($discretionaryAcl) - SystemAcl = @($systemAcl) - RawDescriptor = $rawSecurityDescriptor - } - } -} diff --git a/src/Modules/Shared/PSReadLine/PSReadLine.psd1 b/src/Modules/Shared/PSReadLine/PSReadLine.psd1 deleted file mode 100644 index a634495d19d2..000000000000 --- a/src/Modules/Shared/PSReadLine/PSReadLine.psd1 +++ /dev/null @@ -1,17 +0,0 @@ -@{ -RootModule = 'PSReadLine.psm1' -NestedModules = @("Microsoft.PowerShell.PSReadLine.dll") -ModuleVersion = '1.2' -GUID = '5714753b-2afd-4492-a5fd-01d9e2cff8b5' -Author = 'Microsoft Corporation' -CompanyName = 'Microsoft Corporation' -Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.' -Description = 'Great command line editing in the PowerShell console host' -PowerShellVersion = '3.0' -DotNetFrameworkVersion = '4.0' -CLRVersion = '4.0' -FunctionsToExport = 'PSConsoleHostReadline' -CmdletsToExport = 'Get-PSReadlineKeyHandler','Set-PSReadlineKeyHandler','Remove-PSReadlineKeyHandler', - 'Get-PSReadlineOption','Set-PSReadlineOption' -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855966' -} diff --git a/src/Modules/Shared/PSReadLine/PSReadLine.psm1 b/src/Modules/Shared/PSReadLine/PSReadLine.psm1 deleted file mode 100644 index 4f2bf37fe896..000000000000 --- a/src/Modules/Shared/PSReadLine/PSReadLine.psm1 +++ /dev/null @@ -1,5 +0,0 @@ -function PSConsoleHostReadline -{ - Microsoft.PowerShell.Core\Set-StrictMode -Off - [Microsoft.PowerShell.PSConsoleReadLine]::ReadLine($host.Runspace, $ExecutionContext) -} diff --git a/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 index c270ed538488..540ad83e280d 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 @@ -1,14 +1,15 @@ @{ GUID="EEFCB906-B326-4E99-9F54-8B4BB6EF3C6D" -Author="Microsoft Corporation" +Author="PowerShell" CompanyName="Microsoft Corporation" Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.1.0.0" +ModuleVersion="7.0.0.0" +CompatiblePSEditions = @("Core") PowerShellVersion="3.0" NestedModules="Microsoft.PowerShell.Commands.Management.dll" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855958' -AliasesToExport = @("gtz") FunctionsToExport = @() +AliasesToExport = @("gtz") CmdletsToExport=@("Add-Content", "Clear-Content", "Clear-ItemProperty", @@ -45,6 +46,7 @@ CmdletsToExport=@("Add-Content", "Wait-Process", "Debug-Process", "Start-Process", + "Test-Connection", "Remove-ItemProperty", "Rename-ItemProperty", "Resolve-Path", diff --git a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 index 20df5b5ea268..a99c984b3375 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 @@ -1,13 +1,14 @@ @{ GUID="A94C8C7E-9810-47C0-B8AF-65089C13A35A" -Author="Microsoft Corporation" +Author="PowerShell" CompanyName="Microsoft Corporation" Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.0.0.0" +ModuleVersion="7.0.0.0" +CompatiblePSEditions = @("Core") PowerShellVersion="3.0" -AliasesToExport = @() FunctionsToExport = @() CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate" +AliasesToExport = @() NestedModules="Microsoft.PowerShell.Security.dll" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855959' } diff --git a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 index 65f4c80fc5b5..267ddc928d56 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 @@ -1,30 +1,44 @@ @{ -GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59" -Author="Microsoft Corporation" -CompanyName="Microsoft Corporation" -Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.1.0.0" -PowerShellVersion="3.0" -CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide", - "Out-File", "Out-String", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json", - "Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent", - "Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event", "New-Guid", - "New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertTo-Html", "ConvertFrom-StringData", - "Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression", - "Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture", - "Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData", - "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date", - "Start-Sleep", "Tee-Object", "Measure-Command", "Update-TypeData", "Update-FormatData", - "Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object", - "Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable", - "Clear-Variable", "Export-Clixml", "Import-Clixml", "Import-PowerShellDataFile", "ConvertTo-Xml", "Select-Xml", "Write-Debug", - "Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint", - "Get-PSBreakpoint", "Remove-PSBreakpoint", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack", - "Send-MailMessage", "Get-TraceSource", "Set-TraceSource", "Trace-Command", "Get-FileHash", - "Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug", - "Get-RunspaceDebug", "Wait-Debugger" , "Get-Uptime", "New-TemporaryFile", "Get-Verb", "Format-Hex", "Remove-Alias" -FunctionsToExport= "Import-PowerShellDataFile" -AliasesToExport= "fhx" -NestedModules="Microsoft.PowerShell.Commands.Utility.dll","Microsoft.PowerShell.Utility.psm1" +GUID = "1DA87E53-152B-403E-98DC-74D7B4D63D59" +Author = "PowerShell" +CompanyName = "Microsoft Corporation" +Copyright = "Copyright (c) Microsoft Corporation. All rights reserved." +ModuleVersion = "7.0.0.0" +CompatiblePSEditions = @("Core") +PowerShellVersion = "3.0" +CmdletsToExport = @( + 'Export-Alias', 'Get-Alias', 'Import-Alias', 'New-Alias', 'Remove-Alias', 'Set-Alias', 'Export-Clixml', + 'Import-Clixml', 'Measure-Command', 'Trace-Command', 'ConvertFrom-Csv', 'ConvertTo-Csv', 'Export-Csv', + 'Import-Csv', 'Get-Culture', 'Format-Custom', 'Get-Date', 'Set-Date', 'Write-Debug', 'Wait-Debugger', + 'Register-EngineEvent', 'Write-Error', 'Get-Event', 'New-Event', 'Remove-Event', 'Unregister-Event', + 'Wait-Event', 'Get-EventSubscriber', 'Invoke-Expression', 'Out-File', 'Get-FileHash', 'Export-FormatData', + 'Get-FormatData', 'Update-FormatData', 'New-Guid', 'Format-Hex', 'Get-Host', 'Read-Host', 'Write-Host', + 'ConvertTo-Html', 'Write-Information', 'ConvertFrom-Json', 'ConvertTo-Json', 'Test-Json', 'Format-List', + 'Import-LocalizedData', 'Send-MailMessage', 'ConvertFrom-Markdown', 'Show-Markdown', 'Get-MarkdownOption', + 'Set-MarkdownOption', 'Add-Member', 'Get-Member', 'Compare-Object', 'Group-Object', 'Measure-Object', + 'New-Object', 'Select-Object', 'Sort-Object', 'Tee-Object', 'Register-ObjectEvent', 'Write-Output', + 'Import-PowerShellDataFile', 'Write-Progress', 'Disable-PSBreakpoint', 'Enable-PSBreakpoint', + 'Get-PSBreakpoint', 'Remove-PSBreakpoint', 'Set-PSBreakpoint', 'New-PSBreakpoint', 'Get-PSCallStack', 'Export-PSSession', + 'Import-PSSession', 'Get-Random', 'Invoke-RestMethod', 'Debug-Runspace', 'Get-Runspace', + 'Disable-RunspaceDebug', 'Enable-RunspaceDebug', 'Get-RunspaceDebug', 'Start-Sleep', 'Join-String', + 'Out-String', 'Select-String', 'ConvertFrom-StringData', 'Format-Table', 'New-TemporaryFile', 'New-TimeSpan', + 'Get-TraceSource', 'Set-TraceSource', 'Add-Type', 'Get-TypeData', 'Remove-TypeData', 'Update-TypeData', + 'Get-UICulture', 'Get-Unique', 'Get-Uptime', 'Clear-Variable', 'Get-Variable', 'New-Variable', + 'Remove-Variable', 'Set-Variable', 'Get-Verb', 'Write-Verbose', 'Write-Warning', 'Invoke-WebRequest', + 'Format-Wide', 'ConvertTo-Xml', 'Select-Xml' +) +FunctionsToExport = @() +AliasesToExport = @('fhx') +NestedModules = @("Microsoft.PowerShell.Commands.Utility.dll") HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855960' +PrivateData = @{ + PSData = @{ + ExperimentalFeatures = @( + @{ + Name = 'Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints' + Description = "Enables the New-PSBreakpoint cmdlet and the -Breakpoint parameter on Debug-Runspace to set breakpoints in another Runspace upfront." + } + ) + } +} } diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Windows-Core/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 deleted file mode 100644 index 6aa5b03d76a3..000000000000 --- a/src/Modules/Windows-Core/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 +++ /dev/null @@ -1,30 +0,0 @@ -@{ -GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59" -Author="Microsoft Corporation" -CompanyName="Microsoft Corporation" -Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.1.0.0" -PowerShellVersion="3.0" -CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide", - "Out-File", "Out-String", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json", - "Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent", - "Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event", "New-Guid", - "New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertTo-Html", "ConvertFrom-StringData", - "Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression", - "Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture", - "Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData", - "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date", - "Start-Sleep", "Tee-Object", "Measure-Command", "Update-TypeData", "Update-FormatData", - "Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object", - "Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable", - "Clear-Variable", "Export-Clixml", "Import-Clixml", "Import-PowerShellDataFile","ConvertTo-Xml", "Select-Xml", "Write-Debug", - "Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint", - "Get-PSBreakpoint", "Remove-PSBreakpoint", "New-TemporaryFile", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack", - "Send-MailMessage", "Get-TraceSource", "Set-TraceSource", "Trace-Command", "Get-FileHash", - "Unblock-File", "Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug", - "Get-RunspaceDebug", "Wait-Debugger" , "Get-Uptime", "Get-Verb", "Format-Hex", "Remove-Alias" -FunctionsToExport= "ConvertFrom-SddlString" -AliasesToExport= "fhx" -NestedModules="Microsoft.PowerShell.Commands.Utility.dll","Microsoft.PowerShell.Utility.psm1" -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855960' -} diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml b/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml deleted file mode 100644 index 8e0c106f7dd2..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - Counter - - Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet - - - - - - 25 - left - - - - left - 100 - - - - - - - - Timestamp - - - Readings - - - - - - - - Counter - - Microsoft.PowerShell.Commands.GetCounter.CounterFileInfo - - - - - 30 - left - - - 30 - left - - - 30 - left - - - - - - - - OldestRecord - - - NewestRecord - - - SampleCount - - - - - - - - diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml b/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml deleted file mode 100644 index 3d105bc7c313..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Default - - System.Diagnostics.Eventing.Reader.EventLogRecord - - - ProviderName - - - - - - 25 - - - 8 - right - - - 16 - - - - - - - - - TimeCreated - - - Id - - - LevelDisplayName - - - Message - - - - - - - - - Default - - System.Diagnostics.Eventing.Reader.EventLogConfiguration - - - - - - - 9 - - - - 18 - right - - - - 11 - right - - - - - - - - LogMode - - - MaximumSizeInBytes - - - RecordCount - - - LogName - - - - - - - - Default - - System.Diagnostics.Eventing.Reader.ProviderMetadata - - - - - - - Name - - - LogLinks - - - Opcodes - - - Tasks - - - - - - - - - diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml b/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml deleted file mode 100644 index c52b8e6c2c2f..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - System.Diagnostics.Eventing.Reader.EventLogConfiguration - - - PSStandardMembers - - - DefaultDisplayPropertySet - - LogName - MaximumSizeInBytes - RecordCount - LogMode - - - - - - - - System.Diagnostics.Eventing.Reader.EventLogRecord - - - PSStandardMembers - - - DefaultDisplayPropertySet - - TimeCreated - ProviderName - Id - Message - - - - - - - - System.Diagnostics.Eventing.Reader.ProviderMetadata - - - ProviderName - Name - - - PSStandardMembers - - - DefaultDisplayPropertySet - - Name - LogLinks - - - - - - - - Microsoft.PowerShell.Commands.GetCounter.CounterSet - - - Counter - Paths - - - - - Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSample - - - PSStandardMembers - - - DefaultDisplayPropertySet - - Path - InstanceName - CookedValue - - - - - - - - Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet - - - PSStandardMembers - - - DefaultDisplayPropertySet - - Timestamp - Readings - - - - - - - - Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet - - - Readings - - $strPaths = "" - foreach ($ctr in $this.CounterSamples) - { - $strPaths += ($ctr.Path + " :" + "`n") - $strPaths += ($ctr.CookedValue.ToString() + "`n`n") - } - return $strPaths - - - - - diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 b/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 deleted file mode 100644 index 5d95cfb3a7da..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 +++ /dev/null @@ -1,16 +0,0 @@ -@{ -GUID="CA046F10-CA64-4740-8FF9-2565DBA61A4F" -Author="Microsoft Corporation" -CompanyName="Microsoft Corporation" -Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.0.0.0" -PowerShellVersion="3.0" -CLRVersion="4.0" -AliasesToExport = @() -FunctionsToExport = @() -CmdletsToExport="Get-WinEvent", "Get-Counter", "Import-Counter", "Export-Counter", "New-WinEvent" -NestedModules="Microsoft.PowerShell.Commands.Diagnostics.dll" -TypesToProcess="GetEvent.types.ps1xml" -FormatsToProcess="Event.format.ps1xml","Diagnostics.format.ps1xml" -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855954' -} diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.LocalAccounts/LocalAccounts.format.ps1xml b/src/Modules/Windows-Full/Microsoft.PowerShell.LocalAccounts/LocalAccounts.format.ps1xml deleted file mode 100644 index 91b3b358a230..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.LocalAccounts/LocalAccounts.format.ps1xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - Microsoft.PowerShell.Commands.LocalUser - - Microsoft.PowerShell.Commands.LocalUser - - - - - - - - - - - - - - - Name - - - Enabled - - - Description - - - - - - - - Microsoft.PowerShell.Commands.LocalGroup - - Microsoft.PowerShell.Commands.LocalGroup - - - - - - - - - - - - - Name - - - Description - - - - - - - - Microsoft.PowerShell.Commands.LocalPrincipal - - Microsoft.PowerShell.Commands.LocalPrincipal - - - - - - - - - - - - - - - ObjectClass - - - Name - - - PrincipalSource - - - - - - - - \ No newline at end of file diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.LocalAccounts/Microsoft.PowerShell.LocalAccounts.psd1 b/src/Modules/Windows-Full/Microsoft.PowerShell.LocalAccounts/Microsoft.PowerShell.LocalAccounts.psd1 deleted file mode 100644 index 8f682e536755..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.LocalAccounts/Microsoft.PowerShell.LocalAccounts.psd1 +++ /dev/null @@ -1,32 +0,0 @@ -@{ -RootModule = 'Microsoft.Powershell.LocalAccounts' -ModuleVersion = '1.0.0.0' -GUID = '8e362604-2c0b-448f-a414-a6a690a644e2' -Author = 'Microsoft Corporation' -CompanyName = 'Microsoft Corporation' -Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.' -Description = 'Provides cmdlets to work with local users and local groups' -PowerShellVersion = '3.0' -CLRVersion = '4.0' -FormatsToProcess = @('LocalAccounts.format.ps1xml') -CmdletsToExport = @( - 'Add-LocalGroupMember', - 'Disable-LocalUser', - 'Enable-LocalUser', - 'Get-LocalGroup', - 'Get-LocalGroupMember', - 'Get-LocalUser', - 'New-LocalGroup', - 'New-LocalUser', - 'Remove-LocalGroup', - 'Remove-LocalGroupMember', - 'Remove-LocalUser', - 'Rename-LocalGroup', - 'Rename-LocalUser', - 'Set-LocalGroup', - 'Set-LocalUser' - ) -AliasesToExport= @( "algm", "dlu", "elu", "glg", "glgm", "glu", "nlg", "nlu", "rlg", "rlgm", "rlu", "rnlg", "rnlu", "slg", "slu") -HelpInfoURI = 'https://go.microsoft.com/fwlink/?LinkId=717973' -} - diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Modules/Windows-Full/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 deleted file mode 100644 index 1f68c7822b51..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 +++ /dev/null @@ -1,103 +0,0 @@ -@{ -GUID="EEFCB906-B326-4E99-9F54-8B4BB6EF3C6D" -Author="Microsoft Corporation" -CompanyName="Microsoft Corporation" -Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.1.0.0" -PowerShellVersion="3.0" -CLRVersion="4.0" -NestedModules="Microsoft.PowerShell.Commands.Management.dll" -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855958' -AliasesToExport = @("gcb", "scb", "gin", "gtz", "stz") -FunctionsToExport = @() -CmdletsToExport=@("Add-Content", - "Clear-Content", - "Clear-ItemProperty", - "Join-Path", - "Convert-Path", - "Copy-ItemProperty", - "Get-EventLog", - "Clear-EventLog", - "Write-EventLog", - "Limit-EventLog", - "Show-EventLog", - "New-EventLog", - "Remove-EventLog", - "Get-ChildItem", - "Get-Content", - "Get-ItemProperty", - "Get-ItemPropertyValue", - "Get-WmiObject", - "Invoke-WmiMethod", - "Move-ItemProperty", - "Get-Location", - "Set-Location", - "Push-Location", - "Pop-Location", - "New-PSDrive", - "Remove-PSDrive", - "Get-PSDrive", - "Get-Item", - "New-Item", - "Set-Item", - "Remove-Item", - "Move-Item", - "Rename-Item", - "Copy-Item", - "Clear-Item", - "Invoke-Item", - "Get-PSProvider", - "New-ItemProperty", - "Split-Path", - "Test-Path", - "Get-Process", - "Stop-Process", - "Wait-Process", - "Debug-Process", - "Start-Process", - "Remove-ItemProperty", - "Remove-WmiObject", - "Rename-ItemProperty", - "Register-WmiEvent", - "Resolve-Path", - "Get-Service", - "Stop-Service", - "Start-Service", - "Suspend-Service", - "Resume-Service", - "Restart-Service", - "Set-Service", - "New-Service", - "Remove-Service", - "Set-Content", - "Set-ItemProperty", - "Set-WmiInstance", - "Get-Transaction", - "Start-Transaction", - "Complete-Transaction", - "Undo-Transaction", - "Use-Transaction", - "New-WebServiceProxy", - "Get-HotFix", - "Test-Connection", - "Enable-ComputerRestore", - "Disable-ComputerRestore", - "Checkpoint-Computer", - "Get-ComputerRestorePoint", - "Restart-Computer", - "Stop-Computer", - "Restore-Computer", - "Add-Computer", - "Remove-Computer", - "Test-ComputerSecureChannel", - "Reset-ComputerMachinePassword", - "Rename-Computer", - "Get-ControlPanelItem", - "Show-ControlPanelItem", - "Clear-Recyclebin", - "Get-Clipboard", - "Set-Clipboard", - "Get-ComputerInfo", - "Get-TimeZone", - "Set-TimeZone") -} diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataAdapter.ps1 b/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataAdapter.ps1 deleted file mode 100644 index 0c0921821d94..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataAdapter.ps1 +++ /dev/null @@ -1,2070 +0,0 @@ -Import-LocalizedData LocalizedData -FileName Microsoft.PowerShell.ODataUtilsStrings.psd1 - - -# Add .NET classes used by the module -Add-Type -TypeDefinition $global:BaseClassDefinitions - -######################################################### -# Generates PowerShell module containing client side -# proxy cmdlets that can be used to interact with an -# OData based server side endpoint. -######################################################### -function ExportODataEndpointProxy -{ - param - ( - [string] $Uri, - [string] $OutputModule, - [string] $MetadataUri, - [PSCredential] $Credential, - [string] $CreateRequestMethod, - [string] $UpdateRequestMethod, - [string] $CmdletAdapter, - [Hashtable] $ResourceNameMapping, - [switch] $Force, - [Hashtable] $CustomData, - [switch] $AllowClobber, - [switch] $AllowUnsecureConnection, - [Hashtable] $Headers, - [string] $ProgressBarStatus, - [System.Management.Automation.PSCmdlet] $PSCmdlet - ) - - [xml] $metadataXML = GetMetaData $MetadataUri $PSCmdlet $Credential $Headers - - [ODataUtils.Metadata] $metaData = ParseMetadata $metadataXML $MetadataUri $CmdletAdapter $PSCmdlet - - VerifyMetaData $MetadataUri $metaData $AllowClobber.IsPresent $PSCmdlet $progressBarStatus $CmdletAdapter $CustomData $ResourceNameMapping - - GenerateClientSideProxyModule $metaData $MetadataUri $Uri $OutputModule $CreateRequestMethod $UpdateRequestMethod $CmdletAdapter $ResourceNameMapping $CustomData $ProgressBarStatus $PSCmdlet -} - -######################################################### -# ParseMetaData is a helper function used to parse the -# metadata to convert it in to an object structure for -# further consumption during proxy generation. -######################################################### -function ParseMetaData -{ - param - ( - [xml] $metadataXml, - [string] $metaDataUri, - [string] $cmdletAdapter, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - # $metaDataUri is already validated at the cmdlet layer. - if($null -eq $callerPSCmdlet) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "ParseMetadata") } - - if($null -eq $metadataXml) - { - $errorMessage = ($LocalizedData.InValidXmlInMetadata -f $metaDataUri) - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetadataUriFormat" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $metaDataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - Write-Verbose $LocalizedData.VerboseParsingMetadata - - # Check the OData version in the fetched metadata to make sure that - # OData version (and hence the protocol) used in the metadata is - # supported by the adapter used for executing the generated - # proxy cmdlets. - if(($null -ne $metadataXML) -and ($null -ne $metadataXML.Edmx)) - { - if($null -eq $metadataXML.Edmx.Version) - { - $errorMessage = ($LocalizedData.ODataVersionNotFound -f $MetadataUri) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyODataVersionNotFound" $null ([System.Management.Automation.ErrorCategory]::InvalidData) $exception $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - $metaDataVersion = New-Object -TypeName System.Version -ArgumentList @($metadataXML.Edmx.Version) - - # When we support plug-in model, We would have to fetch the - # $minSupportedVersionString & $maxSupportedVersionString - # from the plug-in instead of using an hardcoded value. - $minSupportedVersionString = '1.0' - $maxSupportedVersionString = '3.0' - $minSupportedVersion = New-Object -TypeName System.Version -ArgumentList @($minSupportedVersionString) - $maxSupportedVersion = New-Object -TypeName System.Version -ArgumentList @($maxSupportedVersionString) - - $minVersionComparisonResult = $minSupportedVersion.CompareTo($metaDataVersion) - $maxVersionComparisonResult = $maxSupportedVersion.CompareTo($metaDataVersion) - - if(-not($minVersionComparisonResult -lt $maxVersionComparisonResult)) - { - $errorMessage = ($LocalizedData.ODataVersionNotSupported -f $metadataXML.Edmx.Version, $MetadataUri, $minSupportedVersionString, $maxSupportedVersionString, $CmdletAdapter) - $exception = [System.NotSupportedException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyODataVersionNotSupported" $null ([System.Management.Automation.ErrorCategory]::InvalidData) $exception $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - } - else - { - $errorMessage = ($LocalizedData.InValidMetadata -f $MetadataUri) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetadata" $null ([System.Management.Automation.ErrorCategory]::InvalidData) $exception $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - foreach ($schema in $MetadataXML.Edmx.DataServices.Schema) - { - if (($null -ne $schema) -and [string]::IsNullOrEmpty($schema.NameSpace )) - { - $callerPSCmdlet = $callerPSCmdlet -as [System.Management.Automation.PSCmdlet] - $errorMessage = ($LocalizedData.InValidSchemaNamespace -f $metaDataUri) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidSchemaNamespace" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $metaDataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - } - - $metaData = New-Object -TypeName ODataUtils.Metadata - - # this is a processing queue for those types that require base types that haven't been defined yet - $entityAndComplexTypesQueue = @{} - - foreach ($schema in $metadataXml.Edmx.DataServices.Schema) - { - if ($null -eq $schema) - { - Write-Error $LocalizedData.EmptySchema - continue - } - - if ($null -eq $metadata.Namespace) - { - $metaData.Namespace = $schema.Namespace - } - - foreach ($entityType in $schema.EntityType) - { - $baseType = $null - - if ($null -ne $entityType.BaseType) - { - # add it to the processing queue - $baseType = GetBaseType $entityType $metaData - if ($null -eq $baseType) - { - $entityAndComplexTypesQueue[$entityType.BaseType] += @(@{type='EntityType'; value=$entityType}) - continue - } - } - - [ODataUtils.EntityType] $newType = ParseMetadataTypeDefinition $entityType $baseType $metaData $schema.Namespace $true - $metaData.EntityTypes += $newType - AddDerivedTypes $newType $entityAndComplexTypesQueue $metaData $schema.Namespace - } - - foreach ($complexType in $schema.ComplexType) - { - $baseType = $null - - if ($null -ne $complexType.BaseType) - { - # add it to the processing queue - $baseType = GetBaseType $complexType $metaData - if ($null -eq $baseType) - { - $entityAndComplexTypesQueue[$entityType.BaseType] += @(@{type='ComplexType'; value=$complexType}) - continue - } - } - - [ODataUtils.EntityType] $newType = ParseMetadataTypeDefinition $complexType $baseType $metaData $schema.Namespace $false - $metaData.ComplexTypes += $newType - AddDerivedTypes $newType $entityAndComplexTypesQueue $metaData $schema.Namespace - } - } - - foreach ($schema in $metadataXml.Edmx.DataServices.Schema) - { - foreach ($entityContainer in $schema.EntityContainer) - { - if ($entityContainer.IsDefaultEntityContainer) - { - $metaData.DefaultEntityContainerName = $entityContainer.Name - } - - $entityTypeToEntitySetMapping = @{}; - foreach ($entitySet in $entityContainer.EntitySet) - { - $entityType = $metaData.EntityTypes | Where-Object { $_.Name -eq $entitySet.EntityType.Split('.')[-1] } - $entityTypeName = $entityType.Name - - if($entityTypeToEntitySetMapping.ContainsKey($entityTypeName)) - { - $existingEntitySetName = $entityTypeToEntitySetMapping[$entityTypeName] - - $errorMessage = ($LocalizedData.EntityNameConflictError -f $metaDataUri, $existingEntitySetName, $entitySet.Name, $entityTypeName) - $exception = [System.NotSupportedException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyEntityTypeMappingError" $null ([System.Management.Automation.ErrorCategory]::InvalidData) $exception $metaDataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - else - { - $entityTypeToEntitySetMapping.Add($entityTypeName, $entitySet.Name) - } - - $newEntitySet = [ODataUtils.EntitySet] @{ - "Namespace" = $schema.Namespace; - "Name" = $entitySet.Name; - "Type" = $entityType; - } - - $metaData.EntitySets += $newEntitySet - } - } - } - - foreach ($schema in $metadataXml.Edmx.DataServices.Schema) - { - foreach ($association in $schema.Association) - { - $newAssociationType = [ODataUtils.AssociationType] @{ - "Namespace" = $schema.Namespace; - "EndType1" = $metaData.EntityTypes | Where-Object { $_.Name -eq $association.End[0].Type.Split('.')[-1] }; - "NavPropertyName1" = $association.End[0].Role; - "Multiplicity1" = $association.End[0].Multiplicity; - - "EndType2" = $metaData.EntityTypes | Where-Object { $_.Name -eq $association.End[1].Type.Split('.')[-1] }; - "NavPropertyName2" = $association.End[1].Role; - "Multiplicity2" = $association.End[1].Multiplicity; - } - - $newAssociation = [ODataUtils.AssociationSet] @{ - "Namespace" = $schema.Namespace; - "Name" = $association.Name; - "Type" = $newAssociationType; - } - - $metaData.Associations += $newAssociation - } - } - - foreach ($schema in $metadataXml.Edmx.DataServices.Schema) - { - foreach ($action in $schema.EntityContainer.FunctionImport) - { - # HttpMethod is only used for legacy Service Operations - if ($null -eq $action.HttpMethod) - { - if ($null -ne $action.IsSideEffecting) - { - $isSideEffecting = $action.IsSideEffecting - } - else - { - $isSideEffecting = $true - } - - $newAction = [ODataUtils.Action] @{ - "Namespace" = $schema.Namespace; - "Verb" = $action.Name; - "IsSideEffecting" = $isSideEffecting; - "IsBindable" = $action.IsBindable; - # we don't care about IsAlwaysBindable, since we populate actions information from $metaData - # so we can't know the state of the entity - } - - # Actions are always SideEffecting, otherwise it's an OData function - if ($newAction.IsSideEffecting -ne $false) - { - foreach ($parameter in $action.Parameter) - { - if ($null -ne $parameter.Nullable) - { - $parameterIsNullable = [System.Convert]::ToBoolean($parameter.Nullable); - } - - $newParameter = [ODataUtils.TypeProperty] @{ - "Name" = $parameter.Name; - "TypeName" = $parameter.Type; - "IsNullable" = $parameterIsNullable - } - - $newAction.Parameters += $newParameter - } - - # IsBindable means it operates on Entity/ies - if ($newAction.IsBindable) - { - $regex = "Collection\((.+)\)" - - if ($newAction.Parameters[0].TypeName -match $regex) - { - # action operating on a collection of entities - $insideTypeName = Convert-ODataTypeToCLRType $Matches[1] - - $newAction.EntitySet = $metaData.EntitySets | Where-Object { ($_.Type.Namespace + "." + $_.Type.Name) -eq $insideTypeName } - $newAction.IsSingleInstance = $false - } - else - { - # actions operating on a single instance - $newAction.EntitySet = $metaData.EntitySets | Where-Object { ($_.Type.Namespace + "." + $_.Type.Name) -eq $newAction.Parameters[0].TypeName } - - $newAction.IsSingleInstance = $true - } - } - - $metaData.Actions += $newAction - } - } - } - } - - $metaData -} - -######################################################### -# VerifyMetaData is a helper function used to validate -# the processed metadata to make sure client side proxy -# can be created for the supplied metadata. -######################################################### -function VerifyMetaData -{ - param - ( - [string] $metaDataUri, - [ODataUtils.Metadata] $metaData, - [boolean] $allowClobber, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet, - [string] $progressBarStatus, - [string] $cmdletAdapter, - [Hashtable] $customData, - [Hashtable] $resourceNameMapping - ) - - # $metaDataUri & $cmdletAdapter is already validated at the cmdlet layer. - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "VerifyMetaData") } - if($null -eq $callerPSCmdlet) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "VerifyMetaData") } - if($null -eq $progressBarStatus) { throw ($LocalizedData.ArguementNullError -f "ProgressBarStatus", "VerifyMetaData") } - - Write-Verbose $LocalizedData.VerboseVerifyingMetadata - - if ($metadata.EntitySets.Count -le 0) - { - $errorMessage = ($LocalizedData.NoEntitySets -f $metaDataUri) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetaDataUri" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $metaDataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - if ($metadata.EntityTypes.Count -le 0) - { - $errorMessage = ($LocalizedData.NoEntityTypes -f $metaDataUri) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetaDataUri" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $metaDataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - # All the generated proxy cmdlets would have the following parameters added. - # The ODataAdapter has the default implementation on how to handle the - # scenario when these parameters are used during proxy invocations. - # The default implementation can be overridden using adapter derivation model. - $reservedProperties = @("Filter", "IncludeTotalResponseCount", "OrderBy", "Select", "Skip", "Top", "ConnectionUri", "CertificateThumbprint", "Credential") - $validEntitySets = @() - $sessionCommands = Get-Command -All - - foreach ($entitySet in $metaData.EntitySets) - { - if ($null -eq $entitySet.Type) - { - $errorMessage = ($LocalizedData.EntitySetUndefinedType -f $metaDataUri, $entitySet.Name) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetaDataUri" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $metaDataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - if ($cmdletAdapter -eq "NetworkControllerAdapter" -And $customData -And $customData.Contains($entitySet.Name) -eq $false) - { - continue - } - - $hasConflictingProperty = $false - $hasConflictingCommand = $false - - $entityAndNavigationProperties = (GetAllProperties $entitySet.Type) + (GetAllProperties $entitySet.Type -IncludeOnlyNavigationProperties) - foreach($entityProperty in $entityAndNavigationProperties) - { - if($reservedProperties.Contains($entityProperty.Name)) - { - $hasConflictingProperty = $true - if(!$allowClobber) - { - # Write Error message and skip current Entity Set. - $errorMessage = ($LocalizedData.SkipEntitySetProxyCreation -f $entitySet.Name, $entitySet.Type.Name, $entityProperty.Name) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointDefaultPropertyCollision" $null ([System.Management.Automation.ErrorCategory]::InvalidOperation) $exception $metaDataUri - $callerPSCmdlet.WriteError($errorRecord) - } - else - { - $warningMessage = ($LocalizedData.EntitySetProxyCreationWithWarning -f $entitySet.Name, $entityProperty.Name, $entitySet.Type.Name) - $callerPSCmdlet.WriteWarning($warningMessage) - } - } - } - - foreach($currentCommand in $sessionCommands) - { - # The generated command Noun can be set using ResourceNameMapping - $generatedCommandName = $entitySet.Name - if ($resourceNameMapping -And $resourceNameMapping.Contains($entitySet.Name)) { - $generatedCommandName = $resourceNameMapping[$entitySet.Name] - } - - if(($null -ne $currentCommand.Noun -and $currentCommand.Noun -eq $generatedCommandName) -and - ($currentCommand.Verb -eq "Get" -or - $currentCommand.Verb -eq "Set" -or - $currentCommand.Verb -eq "New" -or - $currentCommand.Verb -eq "Remove")) - { - $hasConflictingCommand = $true - VerifyMetadataHelper $LocalizedData.SkipEntitySetConflictCommandCreation ` - $LocalizedData.EntitySetConflictCommandCreationWithWarning ` - $entitySet.Name $currentCommand.Name $metaDataUri $allowClobber $callerPSCmdlet - } - } - - foreach($currentAction in $metaData.Actions) - { - $actionCommand = "Invoke-" + "$($entitySet.Name)$($currentAction.Verb)" - - foreach($currentCommand in $sessionCommands) - { - if($actionCommand -eq $currentCommand.Name) - { - $hasConflictingCommand = $true - VerifyMetadataHelper $LocalizedData.SkipEntitySetConflictCommandCreation ` - $LocalizedData.EntitySetConflictCommandCreationWithWarning $entitySet.Name ` - $currentCommand.Name $metaDataUri $allowClobber $callerPSCmdlet - } - } - } - - if(!($hasConflictingProperty -or $hasConflictingCommand)-or $allowClobber) - { - $validEntitySets += $entitySet - } - } - - if ($cmdletAdapter -ne "NetworkControllerAdapter") { - - $metaData.EntitySets = $validEntitySets - - $validServiceActions = @() - $hasConflictingServiceActionCommand = $true - foreach($currentAction in $metaData.Actions) - { - $serviceActionCommand = "Invoke-" + "$($currentAction.Verb)" - - foreach($currentCommand in $sessionCommands) - { - if($serviceActionCommand -eq $currentCommand.Name) - { - $hasConflictingServiceActionCommand = $true - VerifyMetadataHelper $LocalizedData.SkipConflictServiceActionCommandCreation ` - $LocalizedData.ConflictServiceActionCommandCreationWithWarning $entitySet.Name ` - $currentCommand.Name $metaDataUri $allowClobber $callerPSCmdlet - } - } - - if(!$hasConflictingServiceActionCommand -or $allowClobber) - { - $validServiceActions += $currentAction - } - } - - $metaData.Actions = $validServiceActions - } - - # Update Progress bar. - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 5 20 1 1 -} - -######################################################### -# GenerateClientSideProxyModule is a helper function used -# to generate a PowerShell module that serves as a client -# side proxy for interacting with the server side -# OData endpoint. The proxy module contains proxy cmdlets -# implemented in CDXML modules and they are exposed -# through module manifest as nested modules. -# One CDXML module is created for each EntitySet -# described in the metadata. Each CDXML module contains -# CRUD & Service Action specific proxy cmdlets targeting -# the underlying EntityType. There is 1:M mapping between -# EntitySet & its underlying EntityTypes (i.e., all -# entities with in the single EntitySet will be of the -# same EntityType but there can be multiple entities -# of the same type with in an EntitySet). -######################################################### -function GenerateClientSideProxyModule -{ - param - ( - [ODataUtils.Metadata] $metaData, - [string] $metaDataUri, - [string] $uri, - [string] $outputModule, - [string] $createRequestMethod, - [string] $updateRequestMethod, - [string] $cmdletAdapter, - [Hashtable] $resourceNameMapping, - [Hashtable] $customData, - [string] $progressBarStatus, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - # $uri, $outputModule, $metaDataUri, $createRequestMethod, $updateRequestMethod, & $cmdletAdapter is already validated at the cmdlet layer. - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateClientSideProxyModule") } - if($null -eq $callerPSCmdlet) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "GenerateClientSideProxyModule") } - if($null -eq $progressBarStatus) { throw ($LocalizedData.ArguementNullError -f "ProgressBarStatus", "GenerateClientSideProxyModule") } - - # This function performs the following set of tasks - # while creating the client side proxy module: - # 1. If the server side endpoint exposes complex types, - # the client side proxy complex types are created - # as C# class in ComplexTypeDefinitions.psm1 - # 2. Creates proxy cmdlets for CRUD operations. - # 3. Creates proxy cmdlets for Service action operations. - # 4. Creates module manifest. - - Write-Verbose ($LocalizedData.VerboseSavingModule -f $outputModule) - - $typeDefinitionFileName = "ComplexTypeDefinitions.psm1" - $complexTypeMapping = GenerateComplexTypeDefinition $metaData $metaDataUri $outputModule $typeDefinitionFileName $cmdletAdapter $callerPSCmdlet - - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 20 20 1 1 - - $complexTypeFileDefinitionPath = Join-Path -Path $outputModule -ChildPath $typeDefinitionFileName - - if(Test-Path -Path $complexTypeFileDefinitionPath) - { - $proxyFile = New-Object -TypeName System.IO.FileInfo -ArgumentList $complexTypeFileDefinitionPath | Get-Item - if($null -ne $callerPSCmdlet) - { - $callerPSCmdlet.WriteObject($proxyFile) - } - } - - $currentEntryCount = 0 - foreach ($entitySet in $metaData.EntitySets) - { - $currentEntryCount += 1 - if ($cmdletAdapter -eq "NetworkControllerAdapter" -And $customData -And $customData.Contains($entitySet.Name) -eq $false) - { - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 40 20 $metaData.EntitySets.Count $currentEntryCount - continue - } - - GenerateCRUDProxyCmdlet $entitySet $metaData $uri $outputModule $createRequestMethod $updateRequestMethod $cmdletAdapter $resourceNameMapping $customData $complexTypeMapping "Export-ODataEndpointProxy" $progressBarStatus 40 20 $metaData.EntitySets.Count $currentEntryCount $callerPSCmdlet - } - - GenerateServiceActionProxyCmdlet $metaData $uri "$outputModule\ServiceActions.cdxml" $complexTypeMapping $progressBarStatus $callerPSCmdlet - - $moduleDirInfo = [System.IO.DirectoryInfo]::new($outputModule) - $moduleManifestName = $moduleDirInfo.Name + ".psd1" - GenerateModuleManifest $metaData $outputModule\$moduleManifestName @($typeDefinitionFileName, 'ServiceActions.cdxml') $resourceNameMapping $progressBarStatus $callerPSCmdlet -} - -######################################################### -# GenerateCRUDProxyCmdlet is a helper function used -# to generate Get, Set, New & Remove proxy cmdlet. -# The proxy cmdlet is generated in the CDXML -# compliant format. -######################################################### -function GenerateCRUDProxyCmdlet -{ - param - ( - [ODataUtils.EntitySet] $entitySet, - [ODataUtils.Metadata] $metaData, - [string] $uri, - [string] $outputModule, - [string] $createRequestMethod, - [string] $UpdateRequestMethod, - [string] $cmdletAdapter, - [Hashtable] $resourceNameMapping, - [Hashtable] $customData, - [Hashtable] $complexTypeMapping, - [string] $progressBarActivityName, - [string] $progressBarStatus, - [double] $previousSegmentWeight, - [double] $currentSegmentWeight, - [int] $totalNumberofEntries, - [int] $currentEntryCount, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - # $uri, $outputModule, $metaDataUri, $createRequestMethod, $updateRequestMethod, & $cmdletAdapter is already validated at the cmdlet layer. - if($null -eq $entitySet) { throw ($LocalizedData.ArguementNullError -f "EntitySet", "GenerateClientSideProxyModule") } - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateClientSideProxyModule") } - if($null -eq $callerPSCmdlet) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "GenerateClientSideProxyModule") } - if($null -eq $progressBarStatus) { throw ($LocalizedData.ArguementNullError -f "ProgressBarStatus", "GenerateClientSideProxyModule") } - - $entitySetName = $entitySet.Name - if(($null -ne $resourceNameMapping) -and - $resourceNameMapping.ContainsKey($entitySetName)) - { - $entitySetName = $resourceNameMapping[$entitySetName] - } - else - { - $entitySetName = $entitySet.Type.Name - } - - $Path = "$OutputModule\$entitySetName.cdxml" - - $xmlWriter = New-Object System.XMl.XmlTextWriter($Path,$Null) - - if ($null -eq $xmlWriter) - { - throw ($LocalizedData.XmlWriterInitializationError -f $entitySet.Name) - } - - $xmlWriter = SaveCDXMLHeader $xmlWriter $uri $entitySet.Name $entitySetName $cmdletAdapter - - # Get the keys depending on whether the url contains variables or not - if ($CmdletAdapter -ne "NetworkControllerAdapter") - { - $keys = (GetAllProperties $entitySet.Type) | Where-Object { $_.IsKey } - } - else - { - $name = $entitySet.Name - $keys = GetKeys $entitySet $customData.$name 'Get' - } - - $navigationProperties = GetAllProperties $entitySet.Type -IncludeOnlyNavigationProperties - - GenerateGetProxyCmdlet $xmlWriter $metaData $keys $navigationProperties $cmdletAdapter $complexTypeMapping - - $nonKeyProperties = (GetAllProperties $entitySet.Type) | Where-Object { -not $_.isKey } - $nullableProperties = $nonKeyProperties | Where-Object { $_.isNullable } - $nonNullableProperties = $nonKeyProperties | Where-Object { -not $_.isNullable } - - $xmlWriter.WriteStartElement('StaticCmdlets') - - $keyProperties = $keys - - # Do operations specifically needed for NetworkController cmdlets - if ($CmdletAdapter -eq "NetworkControllerAdapter") - { - $keyProperties = GetKeys $entitySet $customData.$name 'New' - $additionalProperties = GetNetworkControllerAdditionalProperties $navigationProperties $metaData - $nullableProperties = UpdateNetworkControllerSpecificProperties $nullableProperties $additionalProperties $keyProperties $true - $nonNullableProperties = UpdateNetworkControllerSpecificProperties $nonNullableProperties $additionalProperties $keyProperties $false - } - - GenerateNewProxyCmdlet $xmlWriter $metaData $keyProperties $nonNullableProperties $nullableProperties $navigationProperties $cmdletAdapter $complexTypeMapping - - if ($CmdletAdapter -ne "NetworkControllerAdapter") - { - GenerateSetProxyCmdlet $xmlWriter $keyProperties $nonKeyProperties $complexTypeMapping - } - - if ($CmdletAdapter -eq "NetworkControllerAdapter") - { - $keyProperties = GetKeys $entitySet $customData.$name 'Remove' - } - - GenerateRemoveProxyCmdlet $xmlWriter $metaData $keyProperties $navigationProperties $cmdletAdapter $complexTypeMapping - - $entityActions = $metaData.Actions | Where-Object { ($_.EntitySet.Namespace -eq $entitySet.Namespace) -and ($_.EntitySet.Name -eq $entitySet.Name) } - - if ($entityActions.Length -gt 0) - { - foreach($action in $entityActions) - { - $xmlWriter = GenerateActionProxyCmdlet $xmlWriter $metaData $action $entitySet.Name $true $keys $complexTypeMapping - } - } - - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletAdapterPrivateData') - - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'EntityTypeName') - $xmlWriter.WriteString("$($entitySet.Type.Namespace).$($entitySet.Type.Name)") - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'EntitySetName') - $xmlWriter.WriteString("$($entitySet.Namespace).$($entitySet.Name)") - $xmlWriter.WriteEndElement() - - # Add the customUri to privateData - if ($CmdletAdapter -eq "NetworkControllerAdapter") - { - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', "CustomUriSuffix") - $xmlWriter.WriteString($CustomData.$name) - $xmlWriter.WriteEndElement() - } - - # Add CreateRequestMethod and UpdateRequestMethod to privateData - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'CreateRequestMethod') - $xmlWriter.WriteString("$CreateRequestMethod") - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'UpdateRequestMethod') - $xmlWriter.WriteString("$UpdateRequestMethod") - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() - - SaveCDXMLFooter $xmlWriter - - ProcessStreamHelper ($LocalizedData.VerboseSavedCDXML -f $($entitySetName), $Path) $progressBarActivityName $progressBarStatus $previousSegmentWeight $currentSegmentWeight $totalNumberofEntries $currentEntryCount $Path $callerPSCmdlet -} - -######################################################### -# GenerateGetProxyCmdlet is a helper function used -# to generate Get-* proxy cmdlet. The proxy cmdlet is -# generated in the CDXML compliant format. -######################################################### -function GenerateGetProxyCmdlet -{ - param - ( - [System.XMl.XmlTextWriter] $xmlWriter, - [ODataUtils.Metadata] $metaData, - [object[]] $keys, - [object[]] $navigationProperties, - [string] $cmdletAdapter, - [Hashtable] $complexTypeMapping - ) - - # $cmdletAdapter is already validated at the cmdlet layer. - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "GenerateGetProxyCmdlet") } - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateGetProxyCmdlet") } - - $xmlWriter.WriteStartElement('InstanceCmdlets') - $xmlWriter.WriteStartElement('GetCmdletParameters') - $xmlWriter.WriteAttributeString('DefaultCmdletParameterSet', 'Default') - - # adding key parameters and association parameters to QueryableProperties, each in a different parameter set - # to be used by GET cmdlet - if (($null -ne $keys -and $keys.Length -gt 0) -or (($null -ne $navigationProperties -and $navigationProperties.Length -gt 0) -and $cmdletAdapter -ne "NetworkControllerAdapter")) - { - $xmlWriter.WriteStartElement('QueryableProperties') - $position = 0 - - $keys | Where-Object { $null -ne $_ } | ForEach-Object { - $xmlWriter.WriteStartElement('Property') - $xmlWriter.WriteAttributeString('PropertyName', $_.Name) - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('RegularQuery') - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $_.Name) - $xmlWriter.WriteAttributeString('CmdletParameterSets', 'Default') - $xmlWriter.WriteAttributeString('IsMandatory', $_.IsMandatory.ToString().ToLower()) - $xmlWriter.WriteAttributeString('Position', $position) - if($_.IsMandatory) - { - $xmlWriter.WriteAttributeString('ValueFromPipelineByPropertyName', 'true') - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $position++ - } - - # This behaviour is different for NetworkController specific cmdlets. - if ($CmdletAdapter -ne "NetworkControllerAdapter") - { - $navigationProperties | Where-Object { $null -ne $_ } | ForEach-Object { - $associatedType = GetAssociatedType $metaData $_ - $associatedEntitySet = GetEntitySetForEntityType $metaData $associatedType - $nvgProperty = $_ - - (GetAllProperties $associatedType) | Where-Object { $_.IsKey } | ForEach-Object { - $xmlWriter.WriteStartElement('Property') - $xmlWriter.WriteAttributeString('PropertyName', $associatedEntitySet.Name + ':' + $_.Name + ':Key') - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('RegularQuery') - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', 'Associated' + $nvgProperty.Name + $_.Name) - $xmlWriter.WriteAttributeString('CmdletParameterSets', $nvgProperty.AssociationName) - $xmlWriter.WriteAttributeString('IsMandatory', 'true') - $xmlWriter.WriteAttributeString('ValueFromPipelineByPropertyName', 'true') - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - } - - - # Add Query Parameters (i.e., Top, Skip, OrderBy, Filter) to the generated Get-* cmdlets. - $queryParameters = - @{ - "Filter" = "Edm.String"; - "IncludeTotalResponseCount" = "switch"; - "OrderBy" = "Edm.String"; - "Select" = "Edm.String"; - "Skip" = "Edm.Int32"; - "Top" = "Edm.Int32"; - } - - foreach($currentQueryParameter in $queryParameters.Keys) - { - $xmlWriter.WriteStartElement('Property') - $xmlWriter.WriteAttributeString('PropertyName', "QueryOption:" + $currentQueryParameter) - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $queryParameters[$currentQueryParameter] - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('RegularQuery') - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $currentQueryParameter) - - if($queryParameters[$currentQueryParameter] -eq "Edm.String") - { - $xmlWriter.WriteStartElement('ValidateNotNullOrEmpty') - $xmlWriter.WriteEndElement() - } - - if($queryParameters[$currentQueryParameter] -eq "Edm.Int32") - { - $minValue = 1 - # For Skip Query parameter we want to support 0 as the - # minimum skip value in order to support client side paging. - if($currentQueryParameter -eq 'Skip') - { - $minValue = 0 - } - $xmlWriter.WriteStartElement('ValidateRange') - $xmlWriter.WriteAttributeString('Min', $minValue) - $xmlWriter.WriteAttributeString('Max', [int]::MaxValue) - $xmlWriter.WriteEndElement() - } - - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - } - - $xmlWriter.WriteEndElement() - } - - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('GetCmdlet') - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Get') - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() -} - -######################################################### -# GenerateNewProxyCmdlet is a helper function used -# to generate New-* proxy cmdlet. The proxy cmdlet is -# generated in the CDXML compliant format. -######################################################### -function GenerateNewProxyCmdlet -{ - param - ( - [System.XMl.XmlTextWriter] $xmlWriter, - [ODataUtils.Metadata] $metaData, - [object[]] $keyProperties, - [object[]] $nonNullableProperties, - [object[]] $nullableProperties, - [object[]] $navigationProperties, - [string] $cmdletAdapter, - [Hashtable] $complexTypeMapping - ) - - # $cmdletAdapter is already validated at the cmdlet layer. - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "GenerateNewProxyCmdlet") } - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateNewProxyCmdlet") } - - $xmlWriter.WriteStartElement('Cmdlet') - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'New') - $xmlWriter.WriteAttributeString('DefaultCmdletParameterSet', 'Default') - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', 'Create') - $xmlWriter.WriteAttributeString('CmdletParameterSet', 'Default') - - AddParametersNode $xmlWriter $keyProperties $nonNullableProperties $nullableProperties $null $true $true $complexTypeMapping - $xmlWriter.WriteEndElement() - - # This behaviour is different for NetworkControllerCmdlets - if ($CmdletAdapter -ne "NetworkControllerAdapter") - { - $navigationProperties | Where-Object { $null -ne $_ } | ForEach-Object { - $associatedType = GetAssociatedType $metaData $_ - $associatedEntitySet = GetEntitySetForEntityType $metaData $associatedType - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', "Association:Create:$($associatedEntitySet.Name)") - $xmlWriter.WriteAttributeString('CmdletParameterSet', $_.Name) - - $associatedKeys = ((GetAllProperties $associatedType) | Where-Object { $_.isKey }) - - AddParametersNode $xmlWriter $associatedKeys $keyProperties $null "Associated$($_.Name)" $true $true $complexTypeMapping - $xmlWriter.WriteEndElement() - } - } - - $xmlWriter.WriteEndElement() -} - -######################################################### -# GenerateRemoveProxyCmdlet is a helper function used -# to generate Remove-* proxy cmdlet. The proxy cmdlet is -# generated in the CDXML compliant format. -######################################################### -function GenerateRemoveProxyCmdlet -{ - param - ( - - [System.XMl.XmlTextWriter] $xmlWriter, - [ODataUtils.Metadata] $metaData, - [object[]] $keyProperties, - [object[]] $navigationProperties, - [string] $cmdletAdapter, - [Hashtable] $complexTypeMapping - ) - - # $metaData, $cmdletAdapter & $cmdletAdapter are already validated at the cmdlet layer. - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "GenerateRemoveProxyCmdlet") } - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateRemoveProxyCmdlet") } - - $xmlWriter.WriteStartElement('Cmdlet') - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Remove') - $xmlWriter.WriteAttributeString('DefaultCmdletParameterSet', 'Default') - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', 'Delete') - $xmlWriter.WriteAttributeString('CmdletParameterSet', 'Default') - - # This behaviour is different for NetworkControllerCmdlets - if ($CmdletAdapter -eq "NetworkControllerAdapter") - { - # Add etag for NetworkControllerCmdlets - $otherProperties = @([ODataUtils.TypeProperty] @{ - "Name" = "Etag"; - "TypeName" = "Edm.String"; - "IsNullable" = $true; - }) - - AddParametersNode $xmlWriter $keyProperties $null $otherProperties $null $true $true $complexTypeMapping - } - else - { - AddParametersNode $xmlWriter $keyProperties $null $null $null $true $true $complexTypeMapping - } - - $xmlWriter.WriteEndElement() - - # This behaviour is different for NetworkControllerCmdlets - if ($CmdletAdapter -ne "NetworkControllerAdapter") - { - $navigationProperties | Where-Object { $null -ne $_ } | ForEach-Object { - - $associatedType = GetAssociatedType $metaData $_ - $associatedEntitySet = GetEntitySetForEntityType $metaData $associatedType - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', "Association:Delete:$($associatedEntitySet.Name)") - $xmlWriter.WriteAttributeString('CmdletParameterSet', $_.Name) - - $associatedType = GetAssociatedType $metaData $_ - $associatedKeys = ((GetAllProperties $associatedType) | Where-Object { $_.isKey }) - - AddParametersNode $xmlWriter $associatedKeys $keyProperties $null "Associated$($_.Name)" $true $true $complexTypeMapping - $xmlWriter.WriteEndElement() - } - } - $xmlWriter.WriteEndElement() -} - -######################################################### -# GenerateActionProxyCmdlet is a helper function used -# to generate Invoke-* proxy cmdlet. These proxy cmdlets -# support Instance/Service level actions. They are -# generated in the CDXML compliant format. -######################################################### -function GenerateActionProxyCmdlet -{ - param - ( - [System.Xml.XmlWriter] $xmlWriter, - [ODataUtils.Metadata] $metaData, - [ODataUtils.Action] $action, - [string] $noun, - [bool] $isInstanceAction, - [ODataUtils.TypeProperty] $keys, - [Hashtable] $complexTypeMapping - ) - - # $metaData is already validated at the cmdlet layer. - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "GenerateActionProxyCmdlet") } - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateActionProxyCmdlet") } - if($null -eq $action) { throw ($LocalizedData.ArguementNullError -f "Action", "GenerateActionProxyCmdlet") } - if($null -eq $noun) { throw ($LocalizedData.ArguementNullError -f "Noun", "GenerateActionProxyCmdlet") } - - $xmlWriter.WriteStartElement('Cmdlet') - - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Invoke') - $xmlWriter.WriteAttributeString('Noun', "$($noun)$($action.Verb)") - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', "Action:$($action.Verb):$($action.EntitySet.Name)") - - $xmlWriter.WriteStartElement('Parameters') - - $keys | Where-Object { $null -ne $_ } | ForEach-Object { - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $_.Name + ':Key') - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $_.Name) - $xmlWriter.WriteAttributeString('IsMandatory', 'true') - $xmlWriter.WriteAttributeString('ValueFromPipelineByPropertyName', 'true') - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - - $i = -1 - foreach ($parameter in $action.Parameters) - { - $i++ - - # for Instance actions, first parameter is Entity Set which we refer to using keys - if ($isInstanceAction -and ($i -eq 0)) - { - continue - } - - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $parameter.Name) - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $parameter.TypeName - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $parameter.Name) - if (-not $parameter.IsNullable) - { - $xmlWriter.WriteAttributeString('IsMandatory', 'true') - $xmlWriter.WriteAttributeString('ValueFromPipelineByPropertyName', 'true') - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - - # Add -Force parameter to Service Action cmdlets. - AddParametersNode $xmlWriter $null $null $null $null $true $false $complexTypeMapping - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() - - $xmlWriter -} - -######################################################### -# GenerateServiceActionProxyCmdlet is a helper function -# used to generate Invoke-* proxy cmdlet. These proxy -# cmdlets support all Service-level actions. They are -# generated in the CDXML compliant format. -######################################################### -function GenerateServiceActionProxyCmdlet -{ - param - ( - [Parameter(Mandatory=$true)] - [ODataUtils.Metadata] $metaData, - [Parameter(Mandatory=$true)] - [string] $uri, - [Parameter(Mandatory=$true)] - [string] $path, - [Hashtable] $complexTypeMapping, - [string] $progressBarStatus, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - # $uri is already validated at the cmdlet layer. - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateServiceActionProxyCmdlet") } - - $xmlWriter = New-Object System.XMl.XmlTextWriter($path,$Null) - - if ($null -eq $xmlWriter) - { - throw $LocalizedData.XmlWriterInitializationError -f "ServiceActions" - } - - $xmlWriter = SaveCDXMLHeader $xmlWriter $uri 'ServiceActions' 'ServiceActions' - - $actions = $metaData.Actions | Where-Object { $null -eq $_.EntitySet } - - if ($actions.Length -gt 0) - { - $xmlWriter.WriteStartElement('StaticCmdlets') - - foreach ($action in $actions) - { - $xmlWriter = GenerateActionProxyCmdlet $xmlWriter $metaData $action '' $false $null $complexTypeMapping - } - - $xmlWriter.WriteEndElement() - } - - $xmlWriter.WriteStartElement('CmdletAdapterPrivateData') - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'Namespace') - $xmlWriter.WriteString("$($EntitySet.Namespace)") - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - SaveCDXMLFooter $xmlWriter - - ProcessStreamHelper ($LocalizedData.VerboseSavedServiceActions -f $path) "Export-ODataEndpointProxy" $progressBarStatus 60 20 1 1 $path $callerPSCmdlet -} - -######################################################### -# GenerateModuleManifest is a helper function used -# to generate a wrapper module manifest file. The -# generated module manifest is persisted to the disk at -# the specified OutPutModule path. When the module -# manifest is imported, the following commands will -# be imported: -# 1. Get, Set, New & Remove proxy cmdlets. -# 2. If the server side Odata endpoint exposes complex -# types, then the corresponding client side proxy -# complex types imported. -# 3. Service Action proxy cmdlets. -######################################################### -function GenerateModuleManifest -{ - param - ( - [ODataUtils.Metadata] $metaData, - [String] $modulePath, - [string[]] $additionalModules, - [Hashtable] $resourceNameMapping, - [string] $progressBarStatus, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateModuleManifest") } - if($null -eq $modulePath) { throw ($LocalizedData.ArguementNullError -f "ModulePath", "GenerateModuleManifest") } - if($null -eq $progressBarStatus) { throw ($LocalizedData.ArguementNullError -f "ProgressBarStatus", "GenerateModuleManifest") } - - $NestedModules = @() - foreach ($entitySet in $metaData.EntitySets) - { - $entitySetName = $entitySet.Name - if(($null -ne $resourceNameMapping) -and - $resourceNameMapping.ContainsKey($entitySetName)) - { - $entitySetName = $resourceNameMapping[$entitySetName] - } - else - { - $entitySetName = $entitySet.Type.Name - } - - $NestedModules += "$OutputModule\$($entitySetName).cdxml" - } - - New-ModuleManifest -Path $modulePath -NestedModules ($AdditionalModules + $NestedModules) - - ProcessStreamHelper ($LocalizedData.VerboseSavedModuleManifest -f $modulePath) "Export-ODataEndpointProxy" $progressBarStatus 80 20 1 1 $modulePath $callerPSCmdlet -} - -######################################################### -# GetBaseType is a helper function used to fetch the -# base type of the given type. -######################################################### -function GetBaseType -{ - param - ( - [System.Xml.XmlElement] $metadataEntityDefinition, - [ODataUtils.Metadata] $metaData - ) - - if ($null -ne $metadataEntityDefinition -and - $null -ne $metaData -and - $null -ne $metadataEntityDefinition.BaseType) - { - $baseType = $metaData.EntityTypes | Where-Object {$_.Namespace+"."+$_.Name -eq $metadataEntityDefinition.BaseType} - if ($null -eq $baseType) - { - $baseType = $metaData.ComplexTypes | Where-Object {$_.Namespace+"."+$_.Name -eq $metadataEntityDefinition.BaseType} - } - } - - if ($null -ne $baseType) - { - $baseType[0] - } -} - -######################################################### -# AddDerivedTypes is a helper function used to process -# derived types of a newly added type, that were -# previously waiting in the queue. -######################################################### -function AddDerivedTypes -{ - param - ( - [ODataUtils.EntityType] $baseType, - [Hashtable]$entityAndComplexTypesQueue, - [ODataUtils.Metadata] $metaData, - [string] $namespace - ) - - # $metaData is already validated at the cmdlet layer. - if($null -eq $baseType) { throw ($LocalizedData.ArguementNullError -f "BaseType", "AddDerivedTypes") } - if($null -eq $entityAndComplexTypesQueue) { throw ($LocalizedData.ArguementNullError -f "EntityAndComplexTypesQueue", "AddDerivedTypes") } - if($null -eq $namespace) { throw ($LocalizedData.ArguementNullError -f "Namespace", "AddDerivedTypes") } - - $baseTypeFullName = $baseType.Namespace + '.' + $baseType.Name - - if ($entityAndComplexTypesQueue.ContainsKey($baseTypeFullName)) - { - foreach ($type in $entityAndComplexTypesQueue[$baseTypeFullName]) - { - if ($type.type -eq 'EntityType') - { - $newType = ParseMetadataTypeDefinition ($type.value) $baseType $metaData $namespace $true - $metaData.EntityTypes += $newType - } - else - { - $newType = ParseMetadataTypeDefinition ($type.value) $baseType $metaData $namespace $false - $metaData.ComplexTypes += $newType - } - - AddDerivedTypes $newType $entityAndComplexTypesQueue $metaData $namespace - } - } -} - -######################################################### -# ParseMetadataTypeDefinition is a helper function used -# to parse types definitions element of metadata xml. -######################################################### -function ParseMetadataTypeDefinition -{ - param - ( - [Parameter(Mandatory=$true)] - [System.Xml.XmlElement] $metadataEntityDefinition, - [ODataUtils.EntityType] $baseType, - [ODataUtils.Metadata] $metaData, - [string] $namespace, - [bool] $isEntity - ) - - # $metaData is already validated at the cmdlet layer. - if($null -eq $metadataEntityDefinition) { throw ($LocalizedData.ArguementNullError -f "MetadataEntityDefinition", "ParseMetadataTypeDefinition") } - if($null -eq $namespace) { throw ($LocalizedData.ArguementNullError -f "Namespace", "ParseMetadataTypeDefinition") } - - $newEntityType = [ODataUtils.EntityType] @{ - "Namespace" = $namespace; - "Name" = $metadataEntityDefinition.Name; - "IsEntity" = $isEntity; - "BaseType" = $baseType; - } - - # properties defined on EntityType - $newEntityType.EntityProperties = $metadataEntityDefinition.Property | ForEach-Object { - if ($null -ne $_) - { - if ($null -ne $_.Nullable) - { - $newPropertyIsNullable = [System.Convert]::ToBoolean($_.Nullable) - } - else - { - $newPropertyIsNullable = $true - } - - [ODataUtils.TypeProperty] @{ - "Name" = $_.Name; - "TypeName" = $_.Type; - "IsNullable" = $newPropertyIsNullable; - } - } - } - - # navigation properties defined on EntityType - $newEntityType.NavigationProperties = $metadataEntityDefinition.NavigationProperty | ForEach-Object { - if ($null -ne $_) - { - ($AssociationNamespace, $AssociationName) = SplitNamespaceAndName $_.Relationship - [ODataUtils.NavigationProperty] @{ - "Name" = $_.Name; - "FromRole" = $_.FromRole; - "ToRole" = $_.ToRole; - "AssociationNamespace" = $AssociationNamespace; - "AssociationName" = $AssociationName; - } - } - } - - foreach ($entityTypeKey in $metadataEntityDefinition.Key.PropertyRef) - { - ((GetAllProperties $newEntityType) | Where-Object { $_.Name -eq $entityTypeKey.Name }).IsKey = $true - } - - $newEntityType -} - -######################################################### -# GetAllProperties is a helper function used to fetch -# the entity properties or navigation properties of -# the entity type as well as that of complete base -# type hierarchy. -######################################################### -function GetAllProperties -{ - param - ( - [ODataUtils.EntityType] $entityType, - [switch] $IncludeOnlyNavigationProperties - ) - - if($null -eq $entityType) { throw ($LocalizedData.ArguementNullError -f "EntityType", "GetAllProperties") } - - $requestedProperties = @() - - # Populate EntityType property from current EntityType as well - # as from the corresponding base types recursively if - # $IncludeOnlyNavigationProperties switch parameter is used then follow - # the same routine for navigation properties. - $currentEntityType = $entityType - while($null -ne $currentEntityType) - { - if($IncludeOnlyNavigationProperties.IsPresent) - { - $chosenProperties = $currentEntityType.NavigationProperties - } - else - { - $chosenProperties = $currentEntityType.EntityProperties - } - - $requestedProperties += $chosenProperties - $currentEntityType = $currentEntityType.BaseType - } - - return $requestedProperties -} - -######################################################### -# SplitNamespaceAndName is a helper function used -# to split Namespace and actual Name. -# e.g. "a.b.c" is namespace "a.b" and name "c" -######################################################### -function SplitNamespaceAndName -{ - param - ( - [string] $fullyQualifiedName - ) - - if($null -eq $fullyQualifiedName) { throw ($LocalizedData.ArguementNullError -f "FUllyQualifiedName", "SplitNamespaceAndName") } - - $sa = $fullyQualifiedName -split "(.*)\.(.*)" - - if ($sa.Length -gt 1) - { - # return Namespace - $sa[1] - - # return Name - $sa[2] - } - else - { - # return Namespace - "" - - # return Name - $sa[0] - } -} - -######################################################### -# GetEntitySetForEntityType is a helper function used -# to fetch EntitySet for a given EntityType by -# searching the inheritance hierarchy in the -# supplied metadata. -######################################################### -function GetEntitySetForEntityType -{ - param - ( - [ODataUtils.Metadata] $metaData, - [ODataUtils.EntityType] $entityType - ) - - # $metaData is already validated at the cmdlet layer. - if($null -eq $entityType) { throw ($LocalizedData.ArguementNullError -f "EntityType", "GetEntitySetForEntityType") } - - $result = $metaData.EntitySets | Where-Object { ($_.Type.Namespace -eq $entityType.Namespace) -and ($_.Type.Name -eq $entityType.Name) } - - if (($result.Count -eq 0) -and ($null -ne $entityType.BaseType)) - { - GetEntitySetForEntityType $metaData $entityType.BaseType - } - elseif ($result.Count -gt 1) - { - throw ($LocalizedData.WrongCountEntitySet -f (($entityType.Namespace + "." + $entityType.Name), $result.Count)) - } - - $result -} - -######################################################### -# ProcessStreamHelper is a helper function that performs -# the following utility tasks: -# 1. Writes verbose messages to the stream. -# 2. Writes FileInfo objects for the proxy modules -# saved to the disk. This is done to keep the user -# experience in consistent with Export-PSSession. -# 3. Updates progress bar. -######################################################### -function ProcessStreamHelper -{ - param - ( - [string] $verboseMessage, - [string] $progressBarActivityName, - [string] $status, - [double] $previousSegmentWeight, - [double] $currentSegmentWeight, - [int] $totalNumberofEntries, - [int] $currentEntryCount, - [string] $path, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - Write-Verbose -Message $verboseMessage - ProgressBarHelper $progressBarActivityName $status $previousSegmentWeight $currentSegmentWeight $totalNumberofEntries $currentEntryCount - $proxyFile = New-Object -TypeName System.IO.FileInfo -ArgumentList $path | Get-Item - if($null -ne $callerPSCmdlet) - { - $callerPSCmdlet.WriteObject($proxyFile) - } -} - -######################################################### -# GetAssociatedType is a helper function used -# to fetch associated instance's EntityType -# for a given Navigation property in the -# supplied metadata. -######################################################### -function GetAssociatedType -{ - param - ( - [ODataUtils.Metadata] $Metadata, - [ODataUtils.NavigationProperty] $navProperty - ) - - # $metaData is already validated at the cmdlet layer. - if($null -eq $navProperty) { throw ($LocalizedData.ArguementNullError -f "NavigationProperty", "GetAssociatedType") } - - $associationName = $navProperty.AssociationName - $association = $Metadata.Associations | Where-Object { $_.Name -eq $associationName } - $associationType = $association.Type - - if ($associationType.Count -lt 1) - { - throw ($LocalizedData.AssociationNotFound -f $associationName) - } - elseif ($associationType.Count -gt 1) - { - throw ($LocalizedData.TooManyMatchingAssociationTypes -f $associationType.Count, $associationName) - } - - if ($associationType.NavPropertyName1 -eq $navProperty.ToRole) - { - $associatedType = $associationType.EndType1 - } - elseif ($associationType.NavPropertyName2 -eq $navProperty.ToRole) - { - $associatedType = $associationType.EndType2 - } - else - { - throw ($LocalizedData.ZeroMatchingAssociationTypes -f $navProperty.ToRole, $association.Name) - } - - # return associated EntityType - $associatedType -} - -######################################################### -# AddParametersNode is a helper function used -# to add parameters to the generated proxy cmdlet, -# based on mandatoryProperties and otherProperties. -# PrefixForKeys is used by associations to append a -# prefix to PowerShell parameter name. -######################################################### -function AddParametersNode -{ - param - ( - [Parameter(Mandatory=$true)] - [System.Xml.XmlWriter] $xmlWriter, - [ODataUtils.TypeProperty[]] $keyProperties, - [ODataUtils.TypeProperty[]] $mandatoryProperties, - [ODataUtils.TypeProperty[]] $otherProperties, - [string] $prefixForKeys, - [boolean] $addForceParameter, - [boolean] $addParametersElement, - [Hashtable] $complexTypeMapping - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "AddParametersNode") } - - if(($keyProperties.Length -gt 0) -or - ($mandatoryProperties.Length -gt 0) -or - ($otherProperties.Length -gt 0) -or - ($addForceParameter)) - { - if($addParametersElement) - { - $xmlWriter.WriteStartElement('Parameters') - } - - $pos = 0 - - if ($null -ne $keyProperties) - { - $pos = AddParametersCDXML $xmlWriter $keyProperties $pos $true $prefixForKeys ":Key" $complexTypeMapping - } - - if ($null -ne $mandatoryProperties) - { - $pos = AddParametersCDXML $xmlWriter $mandatoryProperties $pos $true $null $null $complexTypeMapping - } - - if ($null -ne $otherProperties) - { - $pos = AddParametersCDXML $xmlWriter $otherProperties $pos $false $null $null $complexTypeMapping - } - - if($addForceParameter) - { - $forceParameter = [ODataUtils.TypeProperty] @{ - "Name" = "Force"; - "TypeName" = "switch"; - "IsNullable" = $false - } - - $pos = AddParametersCDXML $xmlWriter $forceParameter $pos $false $null $null $complexTypeMapping - } - - if($addParametersElement) - { - $xmlWriter.WriteEndElement() - } - } -} - -######################################################### -# AddParametersNode is a helper function used -# to add Parameter node to CDXML based on properties. -# Prefix is appended to PS parameter names, used for -# associations. Suffix is appended to all parameter -# names, for ex. to differentiate keys. returns new $pos -######################################################### -function AddParametersCDXML -{ - param - ( - [Parameter(Mandatory=$true)] - [System.Xml.XmlWriter] $xmlWriter, - [ODataUtils.TypeProperty[]] $properties, - [Parameter(Mandatory=$true)] - [int] $pos, - [bool] $isMandatory, - [string] $prefix, - [string] $suffix, - [Hashtable] $complexTypeMapping - ) - - $properties | Where-Object { $null -ne $_ } | ForEach-Object { - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $_.Name + $suffix) - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $prefix + $_.Name) - $xmlWriter.WriteAttributeString('IsMandatory', ($isMandatory).ToString().ToLowerInvariant()) - $xmlWriter.WriteAttributeString('Position', $pos) - if($isMandatory) - { - $xmlWriter.WriteAttributeString('ValueFromPipelineByPropertyName', 'true') - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $pos++ - } - - $pos -} - -######################################################### -# GenerateComplexTypeDefinition is a helper function used -# to generate complex type definition from the metadata. -######################################################### -function GenerateComplexTypeDefinition -{ - param - ( - [ODataUtils.Metadata] $metaData, - [string] $metaDataUri, - [string] $OutputModule, - [string] $typeDefinitionFileName, - [string] $cmdletAdapter, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - #metadataUri, $OutputModule & $cmdletAdapter are already validated at the cmdlet layer. - if($null -eq $typeDefinationFileName) { throw ($LocalizedData.ArguementNullError -f "TypeDefinationFileName", "GenerateComplexTypeDefination") } - if($null -eq $metaData) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateComplexTypeDefination") } - if($null -eq $callerPSCmdlet) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "GenerateComplexTypeDefination") } - - $Path = "$OutputModule\$typeDefinitionFileName" - - # We are currently generating classes for EntityType & ComplexType - # definition exposed in the metadata. - $typesToBeGenerated = $metaData.EntityTypes+$metadata.ComplexTypes - - if($null -ne $typesToBeGenerated -and $typesToBeGenerated.Count -gt 0) - { - $complexTypeMapping = @{} - $entityTypeNameSpaceMapping = @{} - - foreach ($entityType in $typesToBeGenerated) - { - if ($null -ne $entityType) - { - $entityTypeFullName = $entityType.Namespace + '.' + $entityType.Name - if(!$complexTypeMapping.ContainsKey($entityTypeFullName)) - { - $complexTypeMapping.Add($entityTypeFullName, $entityType.Name) - } - - if(!$entityTypeNameSpaceMapping.ContainsKey($entityType.Namespace)) - { - $entityTypes = @() - $entityTypeNameSpaceMapping.Add($entityType.Namespace, $entityTypes) - } - - $entityTypeNameSpaceMapping[$entityType.Namespace] += $entityType - } - } - - if($entityTypeNameSpaceMapping.Count -gt 0) - { -$output = @" -`$typeDefinitions = @" -using System; -using System.Management.Automation; - -"@ - - foreach($currentNameSpace in $entityTypeNameSpaceMapping.Keys) - { - $entityTypes = $entityTypeNameSpaceMapping[$currentNameSpace] - - $output += "`r`nnamespace $(ValidateComplexTypeIdentifier $currentNameSpace $true $metaDataUri $callerPSCmdlet)`r`n{" - - foreach ($entityType in $entityTypes) - { - $entityTypeFullName = (ValidateComplexTypeIdentifier $entityType.Namespace $true $metaDataUri $callerPSCmdlet) + '.' + $entityType.Name - Write-Verbose ($LocalizedData.VerboseAddingTypeDefinationToGeneratedModule -f $entityTypeFullName, "$OutputModule\$typeDefinationFileName") - - if($null -ne $entityType.BaseType) - { - $entityBaseFullName = (ValidateComplexTypeIdentifier $entityType.BaseType.Namespace $true $metaDataUri $callerPSCmdlet) + '.' + (ValidateComplexTypeIdentifier $entityType.BaseType.Name $false $metaDataUri $callerPSCmdlet) - $output += "`r`n public class $(ValidateComplexTypeIdentifier $entityType.Name $false $metaDataUri $callerPSCmdlet) : $($entityBaseFullName)`r`n {" - } - else - { - $output += "`r`n public class $(ValidateComplexTypeIdentifier $entityType.Name $false $metaDataUri $callerPSCmdlet)`r`n {" - } - - $properties = $null - - for($index = 0; $index -lt $entityType.EntityProperties.Count; $index++) - { - $property = $entityType.EntityProperties[$index] - $typeName = Convert-ODataTypeToCLRType $property.TypeName $complexTypeMapping - $properties += "`r`n public $typeName $(ValidateComplexTypeIdentifier $property.Name $false $metaDataUri $callerPSCmdlet);" - } - - # Navigation properties are treated like any other property for NetworkController scenario. - if ($cmdletAdapter -eq "NetworkControllerAdapter") - { - for($index = 0; $index -lt $entityType.NavigationProperties.Count; $index++) - { - $property = $entityType.NavigationProperties[$index] - $navigationTypeName = GetNavigationPropertyTypeName $property $metaData - $typeName = Convert-ODataTypeToCLRType $navigationTypeName $complexTypeMapping - $properties += "`r`n public $typeName $(ValidateComplexTypeIdentifier $property.Name $false $metaDataUri $callerPSCmdlet);" - } - } - - $output += $properties - $output += "`r`n }`r`n" - } - - $output += "}`r`n" - } - $output += """@`r`n" - - $output += "Add-Type -TypeDefinition `$typeDefinitions `r`n" - $output | Out-File -FilePath $Path - Write-Verbose ($LocalizedData.VerboseSavedTypeDefinationModule -f $typeDefinationFileName, $OutputModule) - } - } - - return $complexTypeMapping -} - -# Creating a single instance of CSharpCodeProvider that would be used -# for Identifier validation in the ValidateComplexTypeIdentifier helper method. -$cSharpCodeProvider = [Microsoft.CSharp.CSharpCodeProvider]::new() - -######################################################### -# ValidateComplexTypeIdentifier is a helper function to -# make sure that the type names defined in the -# metadata are valid C# Identifier names. This validation -# is performed to make sure that there are no security -# threat from importing the generated complex type -# (which is created using the metadata file). -# This method return the identifier name if its a -# valid identifier, else a terminating error in thrown. -######################################################### -function ValidateComplexTypeIdentifier -{ - param - ( - [string] $identifierName, - [bool] $isNameSpaceName, - [string] $metaDataUri, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - if($null -eq $callerPSCmdletl) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "ValidateComplexTypeIdentifier") } - - if($isNameSpaceName) - { - $independentIdentifiers = $identifierName.Split('.') - $result = $true - foreach($currentIdentifier in $independentIdentifiers) - { - if(![System.CodeDom.Compiler.CodeGenerator]::IsValidLanguageIndependentIdentifier($currentIdentifier)) - { - $result = $false - break - } - } - } - else - { - $result = $cSharpCodeProvider.IsValidIdentifier($identifierName) - } - - if(!$result) - { - $errorMessage = ($LocalizedData.InValidIdentifierInMetadata -f $metaDataUri, $identifierName) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidIdentifier" $errorMessage ([System.Management.Automation.ErrorCategory]::InvalidData) $null $identifierName - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - else - { - return $identifierName - } -} - -######################################################### -# GetKeys is a helper function used to -# return the keys for the entity if customUri -# is specified. -######################################################### -function GetKeys -{ - param - ( - [ODataUtils.EntitySet] $entitySet, - [string] $customUri, - [string] $actionName - ) - - # Get the original keys - $key = (GetAllProperties $entitySet.Type) | Where-Object { $_.IsKey } - - # Get the keys with delimiters - $keys = $customUri -split "/" | ForEach-Object { - if ($_ -match '{*}') - { - [ODataUtils.TypeProperty] @{ - "Name" = $_.Substring($_.IndexOf('{')+1,$_.IndexOf('}')-$_.IndexOf('{')-1); - "TypeName" = "Edm.String"; - "IsNullable" = $false; - "IsMandatory" = $true; - } - } - elseif ($_ -match '\[*\]') - { - if ($ActionName -eq 'Get') { - [ODataUtils.TypeProperty] @{ - "Name" = $_.Substring($_.IndexOf('[')+1,$_.IndexOf(']')-$_.IndexOf('[')-1); - "TypeName" = "Edm.String"; - "IsNullable" = $false; - "IsMandatory" = $false; - } - } - else { - [ODataUtils.TypeProperty] @{ - "Name" = $_.Substring($_.IndexOf('[')+1,$_.IndexOf(']')-$_.IndexOf('[')-1); - "TypeName" = "Edm.String"; - "IsNullable" = $false; - "IsMandatory" = $true; - } - } - } - } - - # Now combine the two keys and avoid duplication - # Make a list of names already present in the new keys - # Foreach old key check if that key is present in the new keyList - # Else add the key to new key list - $keyParams = $keys | ForEach-Object {$_.Name} - - if ($null -eq $keyParams -Or $keyParams.Count -eq 0) { - $keys = $key - } - else { - if ($keyParams.Count -eq 1) { - $keys = @($keys) - } - - $key | ForEach-Object { - if ($keyParams.Contains($_.Name) -eq $false) - { - $keys += $_ - } - } - } - - $keys -} - -######################################################### -# GetNetworkControllerAdditionalProperties is a helper -# function used to fetch network controller specific -# additional properties. -######################################################### -function GetNetworkControllerAdditionalProperties -{ - param - ( - $navigationProperties, - $metaData - ) - - # Additional properties contains the types present as navigation properties - - $additionalProperties = $navigationProperties | Where-Object { $null -ne $_ } | ForEach-Object { - $typeName = GetNavigationPropertyTypeName $_ $metaData - - if ($_.Name -eq "Properties") { - $isNullable = $false - } - else { - $isNullable = $true - } - - [ODataUtils.TypeProperty] @{ - "Name" = $_.Name; - "TypeName" = $typeName - "IsNullable" = $isNullable; - } - } - - # Add etag to the additionalProperties - - if ($null -ne $additionalProperties) - { - if ($additionalProperties.Count -eq 1) { - $additionalProperties = @($additionalProperties) - } - - $additionalProperties += [ODataUtils.TypeProperty] @{ - "Name" = "Etag"; - "TypeName" = "Edm.String"; - "IsNullable" = $true; - } - } - else - { - $additionalProperties = [ODataUtils.TypeProperty] @{ - "Name" = "Etag"; - "TypeName" = "Edm.String"; - "IsNullable" = $true; - } - } - - $additionalProperties -} - -######################################################### -# UpdateNetworkControllerSpecificProperties is a -# helper function used to append additionalProperties -# to nullable/nonNullable Properties. This is network controller -# specific logic. -######################################################### -function UpdateNetworkControllerSpecificProperties -{ - param - ( - $nullableProperties, - $additionalProperties, - $keyProperties, - $isNullable - ) - - if ($isNullable) { - $additionalProperties = $additionalProperties | Where-Object { $_.isNullable } - } - else { - $additionalProperties = $additionalProperties | Where-Object { -not $_.isNullable } - } - - if ($null -eq $nullableProperties) - { - $nullableProperties = $additionalProperties - } - else { - if ($nullableProperties.Count -eq 1) { - $nullableProperties = @($nullableProperties) - } - if ($null -ne $additionalProperties) { - $nullableProperties += $additionalProperties - } - } - - if ($null -ne $nullableProperties -And $null -ne $keyProperties) - { - if ($keyProperties.Count -eq 1) { - $keyProperties = @($keyProperties) - } - - $keys = $keyProperties | ForEach-Object {$_.Name} - - if ($keys.Count -eq 1) { - $keys = @($keys) - } - - $nullableProperties = $nullableProperties | Where-Object {$keys.Contains($_.Name) -eq $false} - } - - $nullableProperties -} - -######################################################### -# GetNavigationPropertyTypeName is a -# helper function used to fetch the type corresponding -# to navigation property in this metadata. This is -# network controller specific logic. -######################################################### -function GetNavigationPropertyTypeName -{ - param - ( - $navigationProperty, - $metaData - ) - - foreach($association in $metaData.Associations) - { - if ($association.Name -ne $navigationProperty.AssociationName -Or $association.Namespace -ne $navigationProperty.AssociationNamespace) - { - continue - } - - # Now get the type for this association - - if ($association.Type.NavPropertyName1 -eq $navigationProperty.Name) - { - $type = $association.Type.EndType1 - $multiplicity = $association.Type.Multiplicity1 - } - elseif ($associationType.NavPropertyName2 -eq $navigationProperty.Name) - { - $type = $association.Type.EndType2 - $multiplicity = $association.Type.Multiplicity2 - } - - break - } - - $fullName = $type.Namespace + '.' + $type.Name - - # Check the multiplicity and convert to array if needed - if ($multiplicity -eq "*") - { - $fullName = "Collection($fullName)" - } - - $fullName -} diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtils.psd1 b/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtils.psd1 deleted file mode 100644 index 4f1b1e47012f..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtils.psd1 +++ /dev/null @@ -1,240 +0,0 @@ -# -# Module manifest for module 'Microsoft.PowerShell.ODataUtils' -# -# Generated on: 8/15/2013 -# - -@{ - -# Script module or binary module file associated with this manifest. -RootModule = 'Microsoft.PowerShell.ODataUtils.psm1' - -# Version number of this module. -ModuleVersion = '1.0' - -# ID used to uniquely identify this module -GUID = 'fa1606d1-94cb-4264-bfb6-def714420084' - -# Author of this module -Author = 'Microsoft Corporation' - -# Company or vendor of this module -CompanyName = 'Microsoft Corporation' - -# Copyright statement for this module -Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.' - -# Description of the functionality provided by this module -# Description = '' - -# Minimum version of the Windows PowerShell engine required by this module -# PowerShellVersion = '' - -# Name of the Windows PowerShell host required by this module -# PowerShellHostName = '' - -# Minimum version of the Windows PowerShell host required by this module -# PowerShellHostVersion = '' - -# Minimum version of Microsoft .NET Framework required by this module -# DotNetFrameworkVersion = '' - -# Minimum version of the common language runtime (CLR) required by this module -# CLRVersion = '' - -# Processor architecture (None, X86, Amd64) required by this module -# ProcessorArchitecture = '' - -# Modules that must be imported into the global environment prior to importing this module -# RequiredModules = @() - -# Assemblies that must be loaded prior to importing this module -# RequiredAssemblies = @() - -# Script files (.ps1) that are run in the caller's environment prior to importing this module. -# ScriptsToProcess = @() - -# Type files (.ps1xml) to be loaded when importing this module -# TypesToProcess = @() - -# Format files (.ps1xml) to be loaded when importing this module -# FormatsToProcess = @() - -# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -# NestedModules = @() - -# Functions to export from this module -FunctionsToExport = @('Export-ODataEndpointProxy') - -# Cmdlets to export from this module -CmdletsToExport = '' - -# Variables to export from this module -VariablesToExport = '' - -# Aliases to export from this module -AliasesToExport = '' - -# List of all modules packaged with this module -# ModuleList = @() - -# List of all files packaged with this module -# FileList = @() - -# Private data to pass to the module specified in RootModule/ModuleToProcess -# PrivateData = '' - -# HelpInfo URI of this module -HelpInfoURI = 'https://go.microsoft.com/fwlink/?LinkId=509916' - -# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. -# DefaultCommandPrefix = '' - -} - - -# SIG # Begin signature block -# MIIavwYJKoZIhvcNAQcCoIIasDCCGqwCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB -# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR -# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU5qxxE9NAWfUb5Y4oxi1pHiiU -# j+GgghWCMIIEwzCCA6ugAwIBAgITMwAAAHQNgGQOfWd9owAAAAAAdDANBgkqhkiG -# 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G -# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw -# HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTUwMzIwMTczMjA1 -# WhcNMTYwNjIwMTczMjA1WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp -# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw -# b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO -# OjdEMkUtMzc4Mi1CMEY3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT -# ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4NFrifjVvo5Y -# gN/jD+4M6zszXn3GnmZHP9AerBSCDRiftpwnIvG2hpREQXSJkW8X9t+Y5jbLX3iS -# 6XJ+S7kExWIUc3HGf2NBW+tk8r1cVWJGzA9ewQnEr9nxvyV94BegUO4lqkXl48Z+ -# vxBZqcGPPtn77GQbY1u1p7jq681X6xtD9WWRv1D1+cEGvH2qzDfnBqmgzLH1M8wN -# ssh1ZgDRbTCTR8+OomdEXhoTf/McHucPncG8SPyBgW1UauJpE8bO9ZdnMmxIyhHC -# VjrW3Dpi9PwQl2RIC4pc8RbClfDLYBukA5sMyfe7kr8Ac2czHKJ673VKGUZaDH6a -# W6A6HVQ16wIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFCUsOGYFtEU5DmC29u69PuDd -# r4wNMB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw -# SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz -# L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG -# AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv -# c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI -# hvcNAQEFBQADggEBAEEG50j6xJHcMBMNInjC0iPTszPL+yYh1978CncY+4Nyzu/U -# LIaP4xXj1RICZ1xbN9MDe02RW0FTZgn9457fLHgJORo2HYqBocllfJx7kbIPSptB -# 3cdEC2EFyUwu8rRrKKoIR+4IrGZUF1aQiMbpddAhEDh5yT+7VTDFpjmmU7/NXFbS -# ThcUvGISy+lL8MWR3J2EypjWDttWFGht21OLMM+6J2V1oDFvk6N1EGDqqu7uduvl -# jAup0655zzS+SR8i0MT1o+/zrjDcjohGI4ygqjyXrwfbdug2VN+Ls4mewOospGBr -# 8d/DthI6rzM4elFxNTXm5AjiUZaC+b7hG4N8e2cwggTsMIID1KADAgECAhMzAAAA -# ymzVMhI1xOFVAAEAAADKMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNVBAYTAlVTMRMw -# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN -# aWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNp -# Z25pbmcgUENBMB4XDTE0MDQyMjE3MzkwMFoXDTE1MDcyMjE3MzkwMFowgYMxCzAJ -# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k -# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx -# HjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJKoZIhvcNAQEB -# BQADggEPADCCAQoCggEBAJZxXe0GRvqEy51bt0bHsOG0ETkDrbEVc2Cc66e2bho8 -# P/9l4zTxpqUhXlaZbFjkkqEKXMLT3FIvDGWaIGFAUzGcbI8hfbr5/hNQUmCVOlu5 -# WKV0YUGplOCtJk5MoZdwSSdefGfKTx5xhEa8HUu24g/FxifJB+Z6CqUXABlMcEU4 -# LYG0UKrFZ9H6ebzFzKFym/QlNJj4VN8SOTgSL6RrpZp+x2LR3M/tPTT4ud81MLrs -# eTKp4amsVU1Mf0xWwxMLdvEH+cxHrPuI1VKlHij6PS3Pz4SYhnFlEc+FyQlEhuFv -# 57H8rEBEpamLIz+CSZ3VlllQE1kYc/9DDK0r1H8wQGcCAwEAAaOCAWAwggFcMBMG -# A1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBQfXuJdUI1Whr5KPM8E6KeHtcu/ -# gzBRBgNVHREESjBIpEYwRDENMAsGA1UECxMETU9QUjEzMDEGA1UEBRMqMzE1OTUr -# YjQyMThmMTMtNmZjYS00OTBmLTljNDctM2ZjNTU3ZGZjNDQwMB8GA1UdIwQYMBaA -# FMsR6MrStBZYAck3LjMWFrlMmgofMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j -# cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvZFNpZ1BDQV8w -# OC0zMS0yMDEwLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6 -# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29kU2lnUENBXzA4LTMx -# LTIwMTAuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQB3XOvXkT3NvXuD2YWpsEOdc3wX -# yQ/tNtvHtSwbXvtUBTqDcUCBCaK3cSZe1n22bDvJql9dAxgqHSd+B+nFZR+1zw23 -# VMcoOFqI53vBGbZWMrrizMuT269uD11E9dSw7xvVTsGvDu8gm/Lh/idd6MX/YfYZ -# 0igKIp3fzXCCnhhy2CPMeixD7v/qwODmHaqelzMAUm8HuNOIbN6kBjWnwlOGZRF3 -# CY81WbnYhqgA/vgxfSz0jAWdwMHVd3Js6U1ZJoPxwrKIV5M1AHxQK7xZ/P4cKTiC -# 095Sl0UpGE6WW526Xxuj8SdQ6geV6G00DThX3DcoNZU6OJzU7WqFXQ4iEV57MIIF -# vDCCA6SgAwIBAgIKYTMmGgAAAAAAMTANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZIm -# iZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQD -# EyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTAwODMx -# MjIxOTMyWhcNMjAwODMxMjIyOTMyWjB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMK -# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 -# IENvcnBvcmF0aW9uMSMwIQYDVQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBD -# QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJyWVwZMGS/HZpgICBC -# mXZTbD4b1m/My/Hqa/6XFhDg3zp0gxq3L6Ay7P/ewkJOI9VyANs1VwqJyq4gSfTw -# aKxNS42lvXlLcZtHB9r9Jd+ddYjPqnNEf9eB2/O98jakyVxF3K+tPeAoaJcap6Vy -# c1bxF5Tk/TWUcqDWdl8ed0WDhTgW0HNbBbpnUo2lsmkv2hkL/pJ0KeJ2L1TdFDBZ -# +NKNYv3LyV9GMVC5JxPkQDDPcikQKCLHN049oDI9kM2hOAaFXE5WgigqBTK3S9dP -# Y+fSLWLxRT3nrAgA9kahntFbjCZT6HqqSvJGzzc8OJ60d1ylF56NyxGPVjzBrAlf -# A9MCAwEAAaOCAV4wggFaMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMsR6MrS -# tBZYAck3LjMWFrlMmgofMAsGA1UdDwQEAwIBhjASBgkrBgEEAYI3FQEEBQIDAQAB -# MCMGCSsGAQQBgjcVAgQWBBT90TFO0yaKleGYYDuoMW+mPLzYLTAZBgkrBgEEAYI3 -# FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBQOrIJgQFYnl+UlE/wq4QpTlVnk -# pDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp -# L2NybC9wcm9kdWN0cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEE -# SDBGMEQGCCsGAQUFBzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl -# cnRzL01pY3Jvc29mdFJvb3RDZXJ0LmNydDANBgkqhkiG9w0BAQUFAAOCAgEAWTk+ -# fyZGr+tvQLEytWrrDi9uqEn361917Uw7LddDrQv+y+ktMaMjzHxQmIAhXaw9L0y6 -# oqhWnONwu7i0+Hm1SXL3PupBf8rhDBdpy6WcIC36C1DEVs0t40rSvHDnqA2iA6VW -# 4LiKS1fylUKc8fPv7uOGHzQ8uFaa8FMjhSqkghyT4pQHHfLiTviMocroE6WRTsgb -# 0o9ylSpxbZsa+BzwU9ZnzCL/XB3Nooy9J7J5Y1ZEolHN+emjWFbdmwJFRC9f9Nqu -# 1IIybvyklRPk62nnqaIsvsgrEA5ljpnb9aL6EiYJZTiU8XofSrvR4Vbo0HiWGFzJ -# NRZf3ZMdSY4tvq00RBzuEBUaAF3dNVshzpjHCe6FDoxPbQ4TTj18KUicctHzbMrB -# 7HCjV5JXfZSNoBtIA1r3z6NnCnSlNu0tLxfI5nI3EvRvsTxngvlSso0zFmUeDord -# EN5k9G/ORtTTF+l5xAS00/ss3x+KnqwK+xMnQK3k+eGpf0a7B2BHZWBATrBC7E7t -# s3Z52Ao0CW0cgDEf4g5U3eWh++VHEK1kmP9QFi58vwUheuKVQSdpw5OPlcmN2Jsh -# rg1cnPCiroZogwxqLbt2awAdlq3yFnv2FoMkuYjPaqhHMS+a3ONxPdcAfmJH0c6I -# ybgY+g5yjcGjPa8CQGr/aZuW4hCoELQ3UAjWwz0wggYHMIID76ADAgECAgphFmg0 -# AAAAAAAcMA0GCSqGSIb3DQEBBQUAMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX -# BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290 -# IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNzA0MDMxMjUzMDlaFw0yMTA0MDMx -# MzAzMDlaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD -# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xITAf -# BgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQTCCASIwDQYJKoZIhvcNAQEB -# BQADggEPADCCAQoCggEBAJ+hbLHf20iSKnxrLhnhveLjxZlRI1Ctzt0YTiQP7tGn -# 0UytdDAgEesH1VSVFUmUG0KSrphcMCbaAGvoe73siQcP9w4EmPCJzB/LMySHnfL0 -# Zxws/HvniB3q506jocEjU8qN+kXPCdBer9CwQgSi+aZsk2fXKNxGU7CG0OUoRi4n -# rIZPVVIM5AMs+2qQkDBuh/NZMJ36ftaXs+ghl3740hPzCLdTbVK0RZCfSABKR2YR -# JylmqJfk0waBSqL5hKcRRxQJgp+E7VV4/gGaHVAIhQAQMEbtt94jRrvELVSfrx54 -# QTF3zJvfO4OToWECtR0Nsfz3m7IBziJLVP/5BcPCIAsCAwEAAaOCAaswggGnMA8G -# A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM0+NlSRnAK7UD7dvuzK7DDNbMPMAsG -# A1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADCBmAYDVR0jBIGQMIGNgBQOrIJg -# QFYnl+UlE/wq4QpTlVnkpKFjpGEwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcG -# CgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3Qg -# Q2VydGlmaWNhdGUgQXV0aG9yaXR5ghB5rRahSqClrUxzWPQHEy5lMFAGA1UdHwRJ -# MEcwRaBDoEGGP2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1 -# Y3RzL21pY3Jvc29mdHJvb3RjZXJ0LmNybDBUBggrBgEFBQcBAQRIMEYwRAYIKwYB -# BQUHMAKGOGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z -# b2Z0Um9vdENlcnQuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEB -# BQUAA4ICAQAQl4rDXANENt3ptK132855UU0BsS50cVttDBOrzr57j7gu1BKijG1i -# uFcCy04gE1CZ3XpA4le7r1iaHOEdAYasu3jyi9DsOwHu4r6PCgXIjUji8FMV3U+r -# kuTnjWrVgMHmlPIGL4UD6ZEqJCJw+/b85HiZLg33B+JwvBhOnY5rCnKVuKE5nGct -# xVEO6mJcPxaYiyA/4gcaMvnMMUp2MT0rcgvI6nA9/4UKE9/CCmGO8Ne4F+tOi3/F -# NSteo7/rvH0LQnvUU3Ih7jDKu3hlXFsBFwoUDtLaFJj1PLlmWLMtL+f5hYbMUVbo -# nXCUbKw5TNT2eb+qGHpiKe+imyk0BncaYsk9Hm0fgvALxyy7z0Oz5fnsfbXjpKh0 -# NbhOxXEjEiZ2CzxSjHFaRkMUvLOzsE1nyJ9C/4B5IYCeFTBm6EISXhrIniIh0EPp -# K+m79EjMLNTYMoBMJipIJF9a6lbvpt6Znco6b72BJ3QGEe52Ib+bgsEnVLaxaj2J -# oXZhtG6hE6a/qkfwEm/9ijJssv7fUciMI8lmvZ0dhxJkAj0tr1mPuOQh5bWwymO0 -# eFQF1EEuUKyUsKV4q7OglnUa2ZKHE3UiLzKoCG6gW4wlv6DvhMoh1useT8ma7kng -# 9wFlb4kLfchpyOZu6qeXzjEp/w7FW1zYTRuh2Povnj8uVRZryROj/TGCBKcwggSj -# AgEBMIGQMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD -# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xIzAh -# BgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBAhMzAAAAymzVMhI1xOFV -# AAEAAADKMAkGBSsOAwIaBQCggcAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw -# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFFNt -# DhScbWHVDFMkTLRd2qRP8wFeMGAGCisGAQQBgjcCAQwxUjBQoCaAJABXAGkAbgBk -# AG8AdwBzACAAUABvAHcAZQByAFMAaABlAGwAbKEmgCRodHRwOi8vd3d3Lm1pY3Jv -# c29mdC5jb20vcG93ZXJzaGVsbCAwDQYJKoZIhvcNAQEBBQAEggEAddyT//E7Ysbi -# U9kfhQrYkjrhhZCKOzQPVAZSNxWx246MveRe1aj3A+Kr868dYH3x8or8g7MpeJig -# 0WOx4O+mw4fUCdTT6fLqo+W8Q+5qNpWjpfpP5eq7firhhh5D8jB1h7tJWI7fkvHN -# VwadYG4t4BxGIFgsn6YIgPn8ZipmOLb8zvCaDPpg9Xr5U5YKKUrA3sgiuW+zf0aK -# r506K+pfuC56XItbX25VEvf+hjazJr2UasFTweV4mCgKHoAG1UluKUZaX8B+KaKB -# DGMUJ3pCAqyt9RCTSQC9xZxWyK+g0byzn2dpCNxWDXHI7SxCs8ejBhp5yYtlBXl7 -# vkGAXdlJ9aGCAigwggIkBgkqhkiG9w0BCQYxggIVMIICEQIBATCBjjB3MQswCQYD -# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe -# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3Nv -# ZnQgVGltZS1TdGFtcCBQQ0ECEzMAAAB0DYBkDn1nfaMAAAAAAHQwCQYFKw4DAhoF -# AKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1 -# MDUxMTE4MTE1M1owIwYJKoZIhvcNAQkEMRYEFJl30ao3ese0x5O4lPs3SVZVIOdq -# MA0GCSqGSIb3DQEBBQUABIIBAESrx9oY0vI7nyBV0AwzpSYTA/jQF/+MGVokP7ak -# 5i7x25UMc7+RRMROW9VxhzYpzPtotmF8H4rfZsJLxPRlbFF2pu+8MKiNAKiP851m -# tsD1Cw8AN7T31LG8Syk3yKtEvsvnc3yzZy6sXUbkn02yjHNp0PMsrQJNw9ALRc/p -# s3mHzZTqYkmFeHUHzsRa97ByExmjPnP4vcfK2HdZ+oq2EiLjGICooqimt2ys/BPy -# 7nYZaeHaKaNJtnOQHM2BqN38OcH7X7K4IzxCNceXEION6gZE6wqvp+dkvpN5wasL -# OkQhubomAuN/S2TGKwjx3H45G1dpl3LXqihqtqF/Sed7MZs= -# SIG # End signature block diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtils.psm1 b/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtils.psm1 deleted file mode 100644 index 9d5e52547263..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtils.psm1 +++ /dev/null @@ -1,231 +0,0 @@ -Import-LocalizedData LocalizedData -FileName Microsoft.PowerShell.ODataUtilsStrings.psd1 - - -# This module doesn't support Arm because of Add-Type cmdlet -$ProcessorArchitecture = (Get-WmiObject -query "Select Architecture from Win32_Processor").Architecture - -# 0 = x86 -# 1 = MIPS -# 2 = Alpha -# 3 = PowerPC -# 5 = ARM -# 6 = Itanium -# 9 = x64 -if ($ProcessorArchitecture -eq 5) -{ - throw $LocalizedData.ArchitectureNotSupported -f "ARM" -} - -. "$PSScriptRoot\Microsoft.PowerShell.ODataUtilsHelper.ps1" - -######################################################### -# Generates PowerShell module containing client side -# proxy cmdlets that can be used to interact with an -# OData based server side endpoint. -######################################################### -function Export-ODataEndpointProxy -{ - [CmdletBinding( - DefaultParameterSetName='CDXML', - SupportsShouldProcess=$true, - HelpUri="https://go.microsoft.com/fwlink/?LinkId=510069")] - [OutputType([System.IO.FileInfo])] - param - ( - [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] - [ValidateNotNullOrEmpty()] - [string] $Uri, - - [Parameter(Position=1, Mandatory=$true, ValueFromPipelineByPropertyName=$true)] - [ValidateNotNullOrEmpty()] - [string] $OutputModule, - - [Parameter(Position=2, ValueFromPipelineByPropertyName=$true)] - [ValidateNotNullOrEmpty()] - [string] $MetadataUri, - - [Parameter(Position=3, ValueFromPipelineByPropertyName=$true)] - [PSCredential] $Credential, - - [Parameter(Position=4, ValueFromPipelineByPropertyName=$true)] - [ValidateSet('Put', 'Post', 'Patch')] - [string] $CreateRequestMethod='Post', - - [Parameter(Position=5, ValueFromPipelineByPropertyName=$true)] - [ValidateSet('Put', 'Post', 'Patch')] - [string] $UpdateRequestMethod='Patch', - - [Parameter(Position=6, ValueFromPipelineByPropertyName=$true)] - [ValidateSet('ODataAdapter', 'NetworkControllerAdapter', 'ODataV4Adapter')] - [string] $CmdletAdapter='ODataAdapter', - - [Parameter(Position=7, ValueFromPipelineByPropertyName=$true)] - [Hashtable] $ResourceNameMapping, - - [parameter (Position=8,ValueFromPipelineByPropertyName=$true)] - [switch] $Force, - - [Parameter(Position=9, ValueFromPipelineByPropertyName=$true)] - [Hashtable] $CustomData, - - [parameter (Position=10,ValueFromPipelineByPropertyName=$true)] - [switch] $AllowClobber, - - [parameter (Position=11,ValueFromPipelineByPropertyName=$true)] - [switch] $AllowUnsecureConnection, - - [parameter (Position=12,ValueFromPipelineByPropertyName=$true)] - [ValidateNotNull()] - [Hashtable] $Headers - ) - - BEGIN - { - if (!$MetadataUri) - { - $Uri = $Uri.TrimEnd('/') - $MetadataUri = $Uri + '/$metadata' - $PSBoundParameters["MetadataUri"] = $MetadataUri - } - - # Validate to make sure that a valid URI is supplied as input. - try - { - $connectionUri = [System.Uri]::new($Uri) - } - catch - { - $errorMessage = ($LocalizedData.InValidUri -f $Uri) - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidUriFormat" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $Uri - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - - # Block Redfish-support for in-box version of the module and advise user to use a version from PS Gallery instead. - # According to Redfish specification DSP0266v1.0.1 Redfish Service Metadata Document and Redfish Service Root URIs (used by Export-ODataEndpointProxy) are required to start with '/redfish/v1' (section "6.3 Redfish-Defined URIs and Relative URI Rules"). - # We use this as indicator of whether Export-ODataEndpointProxy was attempted against a Redfish endpoint. - if($connectionUri.AbsolutePath.StartsWith('/redfish/',[StringComparison]::OrdinalIgnoreCase)) - { - $errorMessage = $LocalizedData.RedfishNotEnabled - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyRedfishNotEnabled" $errorMessage ([System.Management.Automation.ErrorCategory]::NotEnabled) $exception $Uri - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - - if($connectionUri.Scheme -eq "http" -and !$AllowUnsecureConnection.IsPresent) - { - $errorMessage = ($LocalizedData.AllowUnsecureConnectionMessage -f $PSCmdlet.MyInvocation.MyCommand.Name, $Uri, "Uri") - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyUnSecureConnection" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $Uri - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - - $OutputModuleExists = Test-Path -Path $OutputModule -PathType Container - - if($OutputModuleExists -and ($Force -eq $false)) - { - $errorMessage = ($LocalizedData.ModuleAlreadyExistsAndForceParameterIsNotSpecified -f $OutputModule) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyOutputModuleExists" $errorMessage ([System.Management.Automation.ErrorCategory]::ResourceExists) $null $OutputModule - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - - $isWhatIf = $psboundparameters.ContainsKey("WhatIf") - - if(!$OutputModuleExists) - { - if(!$isWhatIf) - { - $OutputModule = (New-Item -Path $OutputModule -ItemType Directory).FullName - } - } - else - { - $resolvedOutputModulePath = Resolve-Path -Path $OutputModule -ErrorAction Stop -Verbose - if($resolvedOutputModulePath.Count -gt 1) - { - $errorMessage = ($LocalizedData.OutputModulePathIsNotUnique -f $OutputModule) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyOutputModulePathIsNotUnique" $errorMessage ([System.Management.Automation.ErrorCategory]::InvalidArgument) $null $OutputModule - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - - # Make sure that the path specified is a valid file system directory path. - if([system.IO.Directory]::Exists($resolvedOutputModulePath)) - { - $OutputModule = $resolvedOutputModulePath - } - else - { - $errorMessage = ($LocalizedData.OutputModulePathIsNotFileSystemPath -f $OutputModule) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyPathIsNotFileSystemPath" $errorMessage ([System.Management.Automation.ErrorCategory]::InvalidArgument) $null $OutputModule - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - } - - $rootDir = [System.IO.Directory]::GetDirectoryRoot($OutputModule) - - if($rootDir -eq $OutputModule) - { - $errorMessage = ($LocalizedData.InvalidOutputModulePath -f $OutputModule) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidOutputModulePath" $errorMessage ([System.Management.Automation.ErrorCategory]::InvalidArgument) $null $OutputModule - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - - if(!$isWhatIf) - { - $progressBarStatus = ($LocalizedData.ProgressBarMessage -f $Uri) - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 0 100 100 1 - } - - # Add parameters to $PSBoundParameters, which were not passed by user, but the default value is set - $parametersWithDefaultValue = @("CreateRequestMethod", "UpdateRequestMethod", "CmdletAdapter") - - foreach ($parameterWithDefaultValue in $parametersWithDefaultValue) - { - if (!$PSBoundParameters.ContainsKey($parameterWithDefaultValue)) - { - $PSBoundParameters.Add($parameterWithDefaultValue, (Get-Variable $parameterWithDefaultValue).Value) - } - } - } - - END - { - if($pscmdlet.ShouldProcess($Uri)) - { - try - { - $PSBoundParameters.Add("ProgressBarStatus", $progressBarStatus) - $PSBoundParameters.Add("PSCmdlet", $PSCmdlet) - - # Import module based on selected CmdletAdapter - $adapterToImport = $CmdletAdapter - - # NetworkControllerAdapter relies on ODataAdapter - if ($CmdletAdapter -eq 'NetworkControllerAdapter') - { - $adapterToImport = 'ODataAdapter' - } - - Write-Debug ($LocalizedData.SelectedAdapter -f $adapterPSScript) - - $adapterPSScript = "$PSScriptRoot\Microsoft.PowerShell." + $adapterToImport + ".ps1" - - . $adapterPSScript - ExportODataEndpointProxy @PSBoundParameters - } - catch - { - $errorMessage = ($LocalizedData.InValidMetadata -f $Uri) - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidInput" $null ([System.Management.Automation.ErrorCategory]::InvalidData) $exception $Uri - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - finally - { - Write-Progress -Activity "Export-ODataEndpointProxy" -Completed - } - } - } -} - -Export-ModuleMember -Function @('Export-ODataEndpointProxy') diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtilsHelper.ps1 b/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtilsHelper.ps1 deleted file mode 100644 index 473d39909e25..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataUtilsHelper.ps1 +++ /dev/null @@ -1,782 +0,0 @@ -# Base class definitions used by the actual Adapter modules -$global:BaseClassDefinitions = @" -using System; - -namespace ODataUtils -{ - public class TypeProperty - { - public String Name; - - // OData Type Name, e.g. Edm.Int32 - public String TypeName; - - public bool IsKey; - public bool IsMandatory; - public bool? IsNullable; - } - - public class NavigationProperty - { - public String Name; - - public String FromRole; - public String ToRole; - public String AssociationNamespace; - public String AssociationName; - } - - public class EntityTypeBase - { - public String Namespace; - public String Name; - public TypeProperty[] EntityProperties; - public bool IsEntity; - public EntityTypeBase BaseType; - } - - public class AssociationType - { - public String Namespace; - - public EntityTypeBase EndType1; - public String Multiplicity1; - public String NavPropertyName1; - - public EntityTypeBase EndType2; - public String Multiplicity2; - public String NavPropertyName2; - } - - public class EntitySet - { - public String Namespace; - public String Name; - public EntityTypeBase Type; - } - - public class AssociationSet - { - public String Namespace; - public String Name; - public AssociationType Type; - } - - public class Action - { - public String Namespace; - public String Verb; - public EntitySet EntitySet; - public Boolean IsSideEffecting; - public Boolean IsBindable; - public Boolean IsSingleInstance; - public TypeProperty[] Parameters; - } - - public class MetadataBase - { - // Desired destination namespace - public String Namespace; - } - - public class CmdletParameter - { - public CmdletParameter() - { - } - - public CmdletParameter(String type, String name) - { - this.Type = type; - this.Name = name; - this.Qualifiers = new String[] { "Parameter(ValueFromPipelineByPropertyName=`$true)" }; - } - - public String[] Qualifiers; - public String Type; - public String Name; - } - - public class CmdletParameters - { - public CmdletParameter[] Parameters; - } - - public class ReferentialConstraint - { - public String Property; - public String ReferencedProperty; - } - - public class OnDelete - { - public String Action; - } - - public class NavigationPropertyV4 - { - public String Name; - public String Type; - public bool Nullable; - public String Partner; - public bool ContainsTarget; - public ReferentialConstraint[] ReferentialConstraints; - public OnDelete OnDelete; - } - - public class NavigationPropertyBinding - { - public String Path; - public String Target; - } - - public class EntityTypeV4 : EntityTypeBase - { - public String Alias; - public NavigationPropertyV4[] NavigationProperties; - public String BaseTypeStr; - } - - public class SingletonType - { - public String Namespace; - public String Alias; - public String Name; - public String Type; - public NavigationPropertyBinding[] NavigationPropertyBindings; - } - - public class EntitySetV4 - { - public String Namespace; - public String Alias; - public String Name; - public EntityTypeV4 Type; - } - - public class EnumMember - { - public String Name; - public String Value; - } - - public class EnumType - { - public String Namespace; - public String Alias; - public String Name; - public String UnderlyingType; - public bool IsFlags; - public EnumMember[] Members; - } - - public class ActionV4 - { - public String Namespace; - public String Alias; - public String Name; - public String Action; - public EntitySetV4 EntitySet; - public TypeProperty[] Parameters; - } - - public class FunctionV4 - { - public String Namespace; - public String Alias; - public String Name; - public bool Function; - public String EntitySet; - public String ReturnType; - public Parameter[] Parameters; - } - - public class Parameter - { - public String Name; - public String Type; - public bool Nullable; - } - - public class ReferenceInclude - { - public String Namespace; - public String Alias; - } - - public class Reference - { - public String Uri; - } - - public class MetadataV4 : MetadataBase - { - public string ODataVersion; - public string Uri; - public string MetadataUri; - public string Alias; - public Reference[] References; - public string DefaultEntityContainerName; - public EntitySetV4[] EntitySets; - public EntityTypeV4[] EntityTypes; - public SingletonType[] SingletonTypes; - public EntityTypeV4[] ComplexTypes; - public EntityTypeV4[] TypeDefinitions; - public EnumType[] EnumTypes; - public ActionV4[] Actions; - public FunctionV4[] Functions; - } - - public class ReferencedMetadata - { - public System.Collections.ArrayList References; - } - - public class ODataEndpointProxyParameters - { - public String Uri; - public String MetadataUri; - public System.Management.Automation.PSCredential Credential; - public String OutputModule; - - public bool Force; - public bool AllowClobber; - public bool AllowUnsecureConnection; - } - - public class EntityType : EntityTypeBase - { - public NavigationProperty[] NavigationProperties; - } - - public class Metadata : MetadataBase - { - public String DefaultEntityContainerName; - public EntitySet[] EntitySets; - public EntityType[] EntityTypes; - public EntityType[] ComplexTypes; - public AssociationSet[] Associations; - public Action[] Actions; - } -} -"@ - -######################################################### -# GetMetaData is a helper function used to fetch metadata -# from the specified file or web URL. -######################################################### -function GetMetaData -{ - param - ( - [string] $metaDataUri, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet, - [PSCredential] $credential, - [Hashtable] $headers - ) - - # $metaDataUri is already validated at the cmdlet layer. - if($null -eq $callerPSCmdletl) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "GetMetaData") } - Write-Verbose ($LocalizedData.VerboseReadingMetadata -f $metaDataUri) - - try - { - $uri = [System.Uri]::new($metadataUri) - - # By default, proxy generation is supported on secured Uri (i.e., https). - # However if the user trusts the unsecure http uri, then they can override - # the security check by specifying -AllowSecureConnection parameter during - # proxy generation. - if($uri.Scheme -eq "http" -and !$AllowUnsecureConnection.IsPresent) - { - $errorMessage = ($LocalizedData.AllowUnsecureConnectionMessage -f $callerPSCmdlet.MyInvocation.MyCommand.Name, $uri, "MetaDataUri") - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyUnSecureConnection" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $uri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - } - catch - { - $errorMessage = ($LocalizedData.InValidMetadata -f $MetadataUri) - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetadataUriFormat" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - if($uri.IsFile) - { - if ($null -ne $credential) - { - $fileExists = Test-Path -Path $metaDataUri -PathType Leaf -Credential $credential -ErrorAction Stop - } - else - { - $fileExists = Test-Path -Path $metaDataUri -PathType Leaf -ErrorAction Stop - } - - if($fileExists) - { - $metaData = Get-Content -Path $metaDataUri -ErrorAction Stop - } - else - { - $errorMessage = ($LocalizedData.MetadataUriDoesNotExist -f $MetadataUri) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyMetadataFileDoesNotExist" $errorMessage ([System.Management.Automation.ErrorCategory]::InvalidArgument) $null $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - } - else - { - try - { - $cmdParams = @{'Uri'= $metaDataUri ; 'UseBasicParsing'=$true; 'ErrorAction'= 'Stop'} - - if ($null -ne $credential) - { - $cmdParams.Add('Credential', $credential) - } - - if ($null -ne $headers) - { - $cmdParams.Add('Headers', $headers) - } - - $webResponse = Invoke-WebRequest @cmdParams - } - catch - { - $errorMessage = ($LocalizedData.MetadataUriDoesNotExist -f $MetadataUri) - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyMetadataUriDoesNotExist" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - if($null -ne $webResponse) - { - if ($webResponse.StatusCode -eq 200) - { - $metaData = $webResponse.Content - - if ($null -eq $metadata) - { - $errorMessage = ($LocalizedData.EmptyMetadata -f $MetadataUri) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyMetadataIsEmpty" $errorMessage ([System.Management.Automation.ErrorCategory]::InvalidArgument) $null $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - } - else - { - $errorMessage = ($LocalizedData.InvalidEndpointAddress -f $MetadataUri, $webResponse.StatusCode) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidEndpointAddress" $errorMessage ([System.Management.Automation.ErrorCategory]::InvalidArgument) $null $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - } - } - - if($null -ne $metaData) - { - try - { - [xml] $metadataXML = $metaData - } - catch - { - $errorMessage = ($LocalizedData.InValidMetadata -f $MetadataUri) - $exception = [System.InvalidOperationException]::new($errorMessage, $_.Exception) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetadata" $null ([System.Management.Automation.ErrorCategory]::InvalidData) $exception $MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - } - - return $metadataXML -} - -######################################################### -# VerifyMetadataHelper is a helper function used to -# validate if Error/Warning message has to be displayed -# during command collision. -######################################################### -function VerifyMetadataHelper -{ - param - ( - [string] $localizedDataErrorString, - [string] $localizedDataWarningString, - [string] $entitySetName, - [string] $currentCommandName, - [string] $metaDataUri, - [boolean] $allowClobber, - [System.Management.Automation.PSCmdlet] $callerPSCmdlet - ) - - if($null -eq $localizedDataErrorString) { throw ($LocalizedData.ArguementNullError -f "localizedDataErrorString", "VerifyMetadataHelper") } - if($null -eq $localizedDataWarningString) { throw ($LocalizedData.ArguementNullError -f "localizedDataWarningString", "VerifyMetadataHelper") } - - if(!$allowClobber) - { - # Write Error message and skip current Entity Set. - $errorMessage = ($localizedDataErrorString -f $entitySetName, $currentCommandName) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointDefaultPropertyCollision" $null ([System.Management.Automation.ErrorCategory]::InvalidOperation) $exception $metaDataUri - $callerPSCmdlet.WriteError($errorRecord) - } - else - { - $warningMessage = ($localizedDataWarningString -f $entitySetName, $currentCommandName) - $callerPSCmdlet.WriteWarning($warningMessage) - } -} - -######################################################### -# CreateErrorRecordHelper is a helper function used to -# create an error record. -######################################################### -function CreateErrorRecordHelper -{ - param - ( - [string] $errorId, - [string] $errorMessage, - [System.Management.Automation.ErrorCategory] $errorCategory, - [Exception] $exception, - [object] $targetObject - ) - - if($null -eq $exception) - { - $exception = New-Object System.IO.IOException $errorMessage - } - - $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $targetObject - return $errorRecord -} - -######################################################### -# ProgressBarHelper is a helper function used to -# used to display progress message. -######################################################### -function ProgressBarHelper -{ - param - ( - [string] $cmdletName, - [string] $status, - [double] $previousSegmentWeight, - [double] $currentSegmentWeight, - [int] $totalNumberofEntries, - [int] $currentEntryCount - ) - - if($null -eq $cmdletName) { throw ($LocalizedData.ArguementNullError -f "CmdletName", "ProgressBarHelper") } - if($null -eq $status) { throw ($LocalizedData.ArguementNullError -f "Status", "ProgressBarHelper") } - - if($currentEntryCount -gt 0 -and - $totalNumberofEntries -gt 0 -and - $previousSegmentWeight -ge 0 -and - $currentSegmentWeight -gt 0) - { - $entryDefaultWeight = $currentSegmentWeight/[double]$totalNumberofEntries - $percentComplete = $previousSegmentWeight + ($entryDefaultWeight * $currentEntryCount) - Write-Progress -Activity $cmdletName -Status $status -PercentComplete $percentComplete - } -} - -######################################################### -# Convert-ODataTypeToCLRType is a helper function used to -# Convert OData type to its CLR equivalent. -######################################################### -function Convert-ODataTypeToCLRType -{ - param - ( - [string] $typeName, - [Hashtable] $complexTypeMapping - ) - - if($null -eq $typeName) { throw ($LocalizedData.ArguementNullError -f "TypeName", "Convert-ODataTypeToCLRType ") } - - switch ($typeName) - { - "Edm.Binary" {"Byte[]"} - "Edm.Boolean" {"Boolean"} - "Edm.Byte" {"Byte"} - "Edm.DateTime" {"DateTime"} - "Edm.Decimal" {"Decimal"} - "Edm.Double" {"Double"} - "Edm.Single" {"Single"} - "Edm.Guid" {"Guid"} - "Edm.Int16" {"Int16"} - "Edm.Int32" {"Int32"} - "Edm.Int64" {"Int64"} - "Edm.SByte" {"SByte"} - "Edm.String" {"String"} - "Edm.PropertyPath" {"String"} - "switch" {"switch"} - "Edm.DateTimeOffset" {"DateTimeOffset"} - default - { - if($null -ne $complexTypeMapping -and - $complexTypeMapping.Count -gt 0 -and - $complexTypeMapping.ContainsKey($typeName)) - { - $typeName - } - else - { - $regex = "Collection\((.+)\)" - if ($typeName -match $regex) - { - $insideTypeName = Convert-ODataTypeToCLRType $Matches[1] $complexTypeMapping - "$insideTypeName[]" - } - else - { - "PSObject" - } - } - } - } -} - -######################################################### -# SaveCDXMLHeader is a helper function used -# to save CDXML headers common to all -# PSODataUtils modules. -######################################################### -function SaveCDXMLHeader -{ - param - ( - [System.Xml.XmlWriter] $xmlWriter, - [string] $uri, - [string] $className, - [string] $defaultNoun, - [string] $cmdletAdapter - ) - - # $uri & $cmdletAdapter are already validated at the cmdlet layer. - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "SaveCDXMLHeader") } - if($null -eq $defaultNoun) { throw ($LocalizedData.ArguementNullError -f "DefaultNoun", "SaveCDXMLHeader") } - - if ($className -eq 'ServiceActions' -Or $cmdletAdapter -eq "NetworkControllerAdapter") - { - $entityName = '' - } - else - { - $entityName = $className - } - - if ($uri[-1] -ne '/') - { - $fullName = "$uri/$entityName" - } - else - { - $fullName = "$uri$entityName" - } - - $xmlWriter.Formatting = 'Indented' - $xmlWriter.Indentation = 2 - $xmlWriter.IndentChar = ' ' - - $xmlWriter.WriteStartDocument() - - $today=Get-Date - $xmlWriter.WriteComment("This module was autogenerated by PSODataUtils on $today.") - - $xmlWriter.WriteStartElement('PowerShellMetadata') - $xmlWriter.WriteAttributeString('xmlns', 'http://schemas.microsoft.com/cmdlets-over-objects/2009/11') - - $xmlWriter.WriteStartElement('Class') - $xmlWriter.WriteAttributeString('ClassName', $fullName) - $xmlWriter.WriteAttributeString('ClassVersion', '1.0.0') - - $DotNetAdapter = 'Microsoft.PowerShell.Cmdletization.OData.ODataCmdletAdapter' - - if ($CmdletAdapter -eq "NetworkControllerAdapter") { - $DotNetAdapter = 'Microsoft.PowerShell.Cmdletization.OData.NetworkControllerCmdletAdapter' - } - elseif ($CmdletAdapter -eq "ODataV4Adapter") { - $DotNetAdapter = 'Microsoft.PowerShell.Cmdletization.OData.ODataV4CmdletAdapter' - } - - $xmlWriter.WriteAttributeString('CmdletAdapter', $DotNetAdapter + ', Microsoft.PowerShell.Cmdletization.OData, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35') - - $xmlWriter.WriteElementString('Version', '1.0') - $xmlWriter.WriteElementString('DefaultNoun', $defaultNoun) - - $xmlWriter -} - -######################################################### -# SaveCDXMLFooter is a helper function used -# to save CDXML closing attributes corresponding -# to SaveCDXMLHeader function. -######################################################### -function SaveCDXMLFooter -{ - param - ( - [System.Xml.XmlWriter] $xmlWriter - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "SaveCDXMLFooter") } - - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndDocument() - - $xmlWriter.Flush() - $xmlWriter.Close() -} - -######################################################### -# AddParametersNode is a helper function used -# to add parameters to the generated proxy cmdlet, -# based on mandatoryProperties and otherProperties. -# PrefixForKeys is used by associations to append a -# prefix to PowerShell parameter name. -######################################################### -function AddParametersNode -{ - param - ( - [Parameter(Mandatory=$true)] - [System.Xml.XmlWriter] $xmlWriter, - [ODataUtils.TypeProperty[]] $keyProperties, - [ODataUtils.TypeProperty[]] $mandatoryProperties, - [ODataUtils.TypeProperty[]] $otherProperties, - [string] $prefixForKeys, - [boolean] $addForceParameter, - [boolean] $addParametersElement, - [Hashtable] $complexTypeMapping - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "AddParametersNode") } - - if(($keyProperties.Length -gt 0) -or - ($mandatoryProperties.Length -gt 0) -or - ($otherProperties.Length -gt 0) -or - ($addForceParameter)) - { - if($addParametersElement) - { - $xmlWriter.WriteStartElement('Parameters') - } - - $pos = 0 - - if ($null -ne $keyProperties) - { - $pos = AddParametersCDXML $xmlWriter $keyProperties $pos $true $prefixForKeys ":Key" $complexTypeMapping - } - - if ($null -ne $mandatoryProperties) - { - $pos = AddParametersCDXML $xmlWriter $mandatoryProperties $pos $true $null $null $complexTypeMapping - } - - if ($null -ne $otherProperties) - { - $pos = AddParametersCDXML $xmlWriter $otherProperties $pos $false $null $null $complexTypeMapping - } - - if($addForceParameter) - { - $forceParameter = [ODataUtils.TypeProperty] @{ - "Name" = "Force"; - "TypeName" = "switch"; - "IsNullable" = $false - } - - $pos = AddParametersCDXML $xmlWriter $forceParameter $pos $false $null $null $complexTypeMapping - } - - if($addParametersElement) - { - $xmlWriter.WriteEndElement() - } - } -} - -######################################################### -# AddParametersCDXML is a helper function used -# to add Parameter node to CDXML based on properties. -# Prefix is appended to PS parameter names, used for -# associations. Suffix is appended to all parameter -# names, for ex. to differentiate keys. returns new $pos -######################################################### -function AddParametersCDXML -{ - param - ( - [Parameter(Mandatory=$true)] - [System.Xml.XmlWriter] $xmlWriter, - [ODataUtils.TypeProperty[]] $properties, - [Parameter(Mandatory=$true)] - [int] $pos, - [bool] $isMandatory, - [string] $prefix, - [string] $suffix, - [Hashtable] $complexTypeMapping - ) - - $properties | Where-Object { $null -ne $_ } | ForEach-Object { - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $_.Name + $suffix) - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $prefix + $_.Name) - $xmlWriter.WriteAttributeString('IsMandatory', ($isMandatory).ToString().ToLowerInvariant()) - $xmlWriter.WriteAttributeString('Position', $pos) - if($isMandatory) - { - $xmlWriter.WriteAttributeString('ValueFromPipelineByPropertyName', 'true') - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $pos++ - } - - $pos -} - -######################################################### -# GenerateSetProxyCmdlet is a helper function used -# to generate Set-* proxy cmdlet. The proxy cmdlet is -# generated in the CDXML compliant format. -######################################################### -function GenerateSetProxyCmdlet -{ - param - ( - [System.XMl.XmlTextWriter] $xmlWriter, - [object[]] $keyProperties, - [object[]] $nonKeyProperties, - [Hashtable] $complexTypeMapping - ) - - # $cmdletAdapter is already validated at the cmdlet layer. - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "GenerateSetProxyCmdlet") } - - $xmlWriter.WriteStartElement('Cmdlet') - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Set') - $xmlWriter.WriteAttributeString('DefaultCmdletParameterSet', 'Default') - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', 'Update') - $xmlWriter.WriteAttributeString('CmdletParameterSet', 'Default') - - AddParametersNode $xmlWriter $keyProperties $null $nonKeyProperties $null $true $true $complexTypeMapping - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() -} diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataV4Adapter.ps1 b/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataV4Adapter.ps1 deleted file mode 100644 index 9ecd112b2e8a..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/Microsoft.PowerShell.ODataV4Adapter.ps1 +++ /dev/null @@ -1,2668 +0,0 @@ -Import-LocalizedData LocalizedData -FileName Microsoft.PowerShell.ODataUtilsStrings.psd1 - -# Add .NET classes used by the module -Add-Type -TypeDefinition $global:BaseClassDefinitions - -######################################################### -# Generates PowerShell module containing client side -# proxy cmdlets that can be used to interact with an -# OData based server side endpoint. -######################################################### -function ExportODataEndpointProxy -{ - param - ( - [string] $Uri, - [string] $OutputModule, - [string] $MetadataUri, - [PSCredential] $Credential, - [string] $CreateRequestMethod, - [string] $UpdateRequestMethod, - [string] $CmdletAdapter, - [Hashtable] $ResourceNameMapping, - [switch] $Force, - [Hashtable] $CustomData, - [switch] $AllowClobber, - [switch] $AllowUnsecureConnection, - [Hashtable] $Headers, - [string] $ProgressBarStatus, - [System.Management.Automation.PSCmdlet] $PSCmdlet - ) - - # Record of all metadata XML files which have been opened for parsing - # used to avoid parsing the same file twice, if referenced in multiple - # metadata files - $script:processedFiles = @() - - # Record of all referenced and parsed metadata files (including entry point metadata) - $script:GlobalMetadata = New-Object System.Collections.ArrayList - - # The namespace name might have invalid characters or might be conflicting with class names in inheritance scenarios - # We will be normalizing these namespaces and saving them into $normalizedNamespaces, where key is the original namespace and value is normalized namespace - $script:normalizedNamespaces = @{} - - # This information will be used during recursive referenced metadata files loading - $ODataEndpointProxyParameters = [ODataUtils.ODataEndpointProxyParameters] @{ - "MetadataUri" = $MetadataUri; - "Uri" = $Uri; - "Credential" = $Credential; - "OutputModule" = $OutputModule; - "Force" = $Force; - "AllowClobber" = $AllowClobber; - "AllowUnsecureConnection" = $AllowUnsecureConnection; - } - - # Recursively fetch all metadatas (referenced by entry point metadata) - $GlobalMetadata = GetTypeInfo -callerPSCmdlet $pscmdlet -MetadataUri $MetadataUri -ODataEndpointProxyParameters $ODataEndpointProxyParameters -Headers $Headers - # Now that we are done with recursive metadata references parsing we can get rid of this variable - $script:GlobalMetadata = $null - - VerifyMetadata $GlobalMetadata $AllowClobber.IsPresent $PSCmdlet $ProgressBarStatus - - # Get Uri Resource path key format. It can be either 'EmbeddedKey' or 'SeparateKey'. - # If not provided, default value will be set to 'EmbeddedKey'. - $UriResourcePathKeyFormat = 'EmbeddedKey' - if ($CustomData -and $CustomData.ContainsKey("UriResourcePathKeyFormat")) - { - $UriResourcePathKeyFormat = $CustomData."UriResourcePathKeyFormat" - } - - GenerateClientSideProxyModule $GlobalMetadata $ODataEndpointProxyParameters $OutputModule $CreateRequestMethod $UpdateRequestMethod $CmdletAdapter $ResourceNameMapping $CustomData $UriResourcePathKeyFormat $ProgressBarStatus $script:normalizedNamespaces -} - -######################################################### -# GetTypeInfo is a helper method used to get all the types -# from metadata files in a recursive manner -######################################################### -function GetTypeInfo -{ - param - ( - [System.Management.Automation.PSCmdlet] $callerPSCmdlet, - [string] $MetadataUri, - [ODataUtils.ODataEndpointProxyParameters] $ODataEndpointProxyParameters, - [Hashtable] $Headers - ) - - if($null -eq $callerPSCmdlet) { throw ($LocalizedData.ArguementNullError -f "callerPSCmdlet", "GetTypeInfo") } - - $metadataSet = New-Object System.Collections.ArrayList - $metadataXML = GetMetaData $MetadataUri $callerPSCmdlet $ODataEndpointProxyParameters.Credential $Headers $ODataEndpointProxyParameters.AllowUnsecureConnection - $script:processedFiles += $MetadataUri - - # parses all referenced metadata XML files recursively - foreach ($reference in $metadataXML.Edmx.Reference) - { - if (-not $script:processedFiles.Contains($reference.Uri)) - { - $tmpMetadataSet = $null - $tmpMetadataSet = GetTypeInfo -callerPSCmdlet $callerPSCmdlet -MetadataUri $reference.Uri -ODataEndpointProxyParameters $ODataEndpointProxyParameters - AddMetadataToMetadataSet -Metadatas $metadataSet -NewMetadata $tmpMetadataSet - } - } - - $metadatas = ParseMetadata -MetadataXML $metadataXML -ODataVersion $metadataXML.Edmx.Version -MetadataUri $MetadataUri -Uri $ODataEndpointProxyParameters.Uri -MetadataSet $script:GlobalMetadata - AddMetadataToMetadataSet -Metadatas $script:GlobalMetadata -NewMetadata $metadatas - AddMetadataToMetadataSet -Metadatas $metadataSet -NewMetadata $metadatas - - return $metadataSet -} - -function AddMetadataToMetadataSet -{ - param - ( - [System.Collections.ArrayList] $Metadatas, - $NewMetadata - ) - - if($null -eq $NewMetadata) { throw ($LocalizedData.ArguementNullError -f "NewMetadata", "AddMetadataToMetadataSet") } - - if ($NewMetadata.GetType().Name -eq 'MetadataV4') - { - $Metadatas.Add($NewMetadata) | Out-Null - } - else - { - $Metadatas.AddRange($NewMetadata) | Out-Null - } -} - -######################################################### -# Normalization of Namespace name will be required in following scenarios: -# 1. Namespace name contains combination of dots and numbers -# 2. Namespace name collides with Class name (EntityType, EntitySet, etc.) -# If normalization is needed, all dots will be replaced with underscores and Ns suffix added -# User will receive warning notifying her about the namespace name change -######################################################### -function NormalizeNamespace -{ - param - ( - [string] $MetadataNamespace, - [string] $MetadataUri, - [Hashtable] $NormalizedNamespaces, - [boolean] $DoesNamespaceConflictsWithClassName - ) - - $doesNamespaceContainsInvalidChars = $false - - # Check if namespace name contains invalid combination if dots and numbers - if ($MetadataNamespace -match '\.[0-9]' -or $MetadataNamespace -match '[0-9]\.') - { - # Normalization needed - $doesNamespaceContainsInvalidChars = $true - } - - # Normalize if needed - if ($doesNamespaceContainsInvalidChars -or $DoesNamespaceConflictsWithClassName) - { - if ($NormalizedNamespaces.ContainsKey($MetadataNamespace)) - { - # It's possible we've already attempted to normalize that namespace. In that case we'll update normalized name. - $NormalizedNamespaces[$MetadataNamespace] = NormalizeNamespaceHelper $NormalizedNamespaces[$MetadataNamespace] $doesNamespaceContainsInvalidChars $DoesNamespaceConflictsWithClassName - } - else - { - $NormalizedNamespaces.Add($MetadataNamespace, (NormalizeNamespaceHelper $MetadataNamespace $doesNamespaceContainsInvalidChars $DoesNamespaceConflictsWithClassName)) - } - } - - # Print warning - if ($doesNamespaceContainsInvalidChars) - { - # Normalization needed - $warningMessage = ($LocalizedData.InValidSchemaNamespaceContainsInvalidChars -f $MetadataUri, $MetadataNamespace, $NormalizedNamespaces[$MetadataNamespace]) - Write-Warning $warningMessage - } - if ($DoesNamespaceConflictsWithClassName) - { - # Collision between namespace name and type name detected (example: namespace TaskService { class Service : Service.BasicService { ... } ... }) - # Normalization needed - $warningMessage = ($LocalizedData.InValidSchemaNamespaceConflictWithClassName -f $MetadataUri, $MetadataNamespace, $NormalizedNamespaces[$MetadataNamespace]) - Write-Warning $warningMessage - } -} - -function NormalizeNamespaceCollisionWithClassName -{ - param - ( - [string] $InheritingType, - [string] $BaseTypeName, - [string] $MetadataUri - ) - - if (![string]::IsNullOrEmpty($BaseTypeName)) - { - $dotNetNamespace = '' - if ($BaseTypeName.LastIndexOf(".") -gt 0) - { - # BaseTypeStr contains Namespace and TypeName. Extract Namespace name. - $dotNetNamespace = $BaseTypeName.SubString(0, $BaseTypeName.LastIndexOf(".")) - } - - if (![string]::IsNullOrEmpty($dotNetNamespace) -and $InheritingType -eq $dotNetNamespace) - { - # Collision between namespace name and type name detected (example: namespace TaskService { class Service : Service.BasicService { ... } ... }) - # Normalization needed - NormalizeNamespace $dotNetNamespace $MetadataUri $script:normalizedNamespaces $true - break - } - } -} - -######################################################### -# This helper method is used by functions, -# writing directly to CDXML files or to .Net namespace/class definitions ComplexTypes file -######################################################### -function GetNamespace -{ - param - ( - [string] $Namespace, - $NormalizedNamespaces, - [boolean] $isClassNameIncluded = $false - ) - - $dotNetNamespace = $Namespace - $dotNetClassName = '' - - # Extract only namespace name - if ($isClassNameIncluded) - { - if ($Namespace.LastIndexOf(".") -gt 0) - { - # For example, from following namespace (Namespace.TypeName) Service.1.0.0.Service we'll extract only namespace name, which is Service.1.0.0 - $dotNetNamespace = $Namespace.SubString(0, $Namespace.LastIndexOf(".")) - $dotNetClassName = $Namespace.SubString($Namespace.LastIndexOf(".") + 1, $Namespace.Length - $Namespace.LastIndexOf(".") - 1) - } - } - - # Check if the namespace has to be normalized. - if ($NormalizedNamespaces.ContainsKey($dotNetNamespace)) - { - $dotNetNamespace = $NormalizedNamespaces.Get_Item($dotNetNamespace) - } - - if (![string]::IsNullOrEmpty($dotNetClassName)) - { - return ($dotNetNamespace + "." + $dotNetClassName) - } - else - { - return $dotNetNamespace - } -} - -function NormalizeNamespaceHelper -{ - param - ( - [string] $Namespace, - [boolean] $DoesNamespaceContainsInvalidChars, - [boolean] $DoesNamespaceConflictsWithClassName - ) - - # For example, following namespace: Service.1.0.0 - # Will change to: Service_1_0_0 - # Ns postfix in Namespace name will allow to differentiate between this namespace - # and a colliding type name from different namespace - $updatedNs = $Namespace - if ($DoesNamespaceContainsInvalidChars) - { - $updatedNs = $updatedNs.Replace('.', '_') - } - if ($DoesNamespaceConflictsWithClassName) - { - $updatedNs = $updatedNs + "Ns" - } - - $updatedNs -} - -######################################################### -# Processes EntityTypes (OData V4 schema) from plain text -# xml metadata into our custom structure -######################################################### -function ParseEntityTypes -{ - param - ( - [System.Xml.XmlElement] $SchemaXML, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - [hashtable] $EntityAndComplexTypesQueue, - [string] $CustomNamespace, - [AllowEmptyString()] - [string] $Alias - ) - - if($null -eq $SchemaXML) { throw ($LocalizedData.ArguementNullError -f "SchemaXML", "ParseEntityTypes") } - - foreach ($entityType in $SchemaXML.EntityType) - { - $baseType = $null - - if ($null -ne $entityType.BaseType) - { - # add it to the processing queue - $baseType = GetBaseType $entityType $Metadata $SchemaXML.Namespace $GlobalMetadata - if ($null -eq $baseType) - { - $EntityAndComplexTypesQueue[$entityType.BaseType] += @(@{type='EntityType'; value=$entityType}) - } - - # Check if Namespace has to be normalized because of the collision with the inheriting Class name - NormalizeNamespaceCollisionWithClassName -InheritingType $entityType.Name -BaseTypeName $entityType.BaseType -MetadataUri $Metadata.Uri - } - - [ODataUtils.EntityTypeV4] $newType = ParseMetadataTypeDefinition $entityType $baseType $Metadata $schema.Namespace $Alias $true $entityType.BaseType - $Metadata.EntityTypes += $newType - AddDerivedTypes $newType $entityAndComplexTypesQueue $Metadata $SchemaXML.Namespace - } -} - -######################################################### -# Processes ComplexTypes from plain text xml metadata -# into our custom structure -######################################################### -function ParseComplexTypes -{ - param - ( - [System.Xml.XmlElement] $SchemaXML, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - [hashtable] $EntityAndComplexTypesQueue, - [string] $CustomNamespace, - [AllowEmptyString()] - [string] $Alias - ) - - if($null -eq $SchemaXMLl) { throw ($LocalizedData.ArguementNullError -f "SchemaXML", "ParseComplexTypes") } - - foreach ($complexType in $SchemaXML.ComplexType) - { - $baseType = $null - - if ($null -ne $complexType.BaseType) - { - # add it to the processing queue - $baseType = GetBaseType $complexType $metadata $SchemaXML.Namespace $GlobalMetadata - if ($null -eq $baseType -and $null -ne $entityAndComplexTypesQueue -and $entityAndComplexTypesQueue.ContainsKey($complexType.BaseType)) - { - $entityAndComplexTypesQueue[$complexType.BaseType] += @(@{type='ComplexType'; value=$complexType}) - continue - } - - # Check if Namespace has to be normalized because of the collision with the inheriting Class name - NormalizeNamespaceCollisionWithClassName -InheritingType $complexType.Name -BaseTypeName $complexType.BaseType -MetadataUri $Metadata.Uri - } - - [ODataUtils.EntityTypeV4] $newType = ParseMetadataTypeDefinition $complexType $baseType $Metadata $schema.Namespace -Alias $Alias $false $complexType.BaseType - $Metadata.ComplexTypes += $newType - AddDerivedTypes $newType $entityAndComplexTypesQueue $metadata $schema.Namespace - } -} - -######################################################### -# Processes TypeDefinition from plain text xml metadata -# into our custom structure -######################################################### -function ParseTypeDefinitions -{ - param - ( - [System.Xml.XmlElement] $SchemaXML, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - [string] $CustomNamespace, - [AllowEmptyString()] - [string] $Alias - ) - - if($null -eq $SchemaXML) { throw ($LocalizedData.ArguementNullError -f "SchemaXML", "ParseTypeDefinitions") } - - - foreach ($typeDefinition in $SchemaXML.TypeDefinition) - { - $newType = [ODataUtils.EntityTypeV4] @{ - "Namespace" = $Metadata.Namespace; - "Alias" = $Metadata.Alias; - "Name" = $typeDefinition.Name; - "BaseTypeStr" = $typeDefinition.UnderlyingType; - } - $Metadata.TypeDefinitions += $newType - } -} - -######################################################### -# Processes EnumTypes from plain text xml metadata -# into our custom structure -######################################################### -function ParseEnumTypes -{ - param - ( - [System.Xml.XmlElement] $SchemaXML, - [ODataUtils.MetadataV4] $Metadata - ) - - if($null -eq $SchemaXML) { throw ($LocalizedData.ArguementNullError -f "SchemaXML", "ParseEnumTypes") } - - foreach ($enum in $SchemaXML.EnumType) - { - $newEnumType = [ODataUtils.EnumType] @{ - "Namespace" = $Metadata.Namespace; - "Alias" = $Metadata.Alias; - "Name" = $enum.Name; - "UnderlyingType" = $enum.UnderlyingType; - "IsFlags" = $enum.IsFlags; - "Members" = @() - } - - if (!$newEnumType.UnderlyingType) - { - # If no type specified set the default type which is Edm.Int32 - $newEnumType.UnderlyingType = "Edm.Int32" - } - - if ($null -eq $newEnumType.IsFlags) - { - # If no value is specified for IsFlags, its value defaults to false. - $newEnumType.IsFlags = $false - } - - $enumValue = 0 - $currentEnumValue = 0 - - # Now parse EnumType elements - foreach ($element in $enum.Member) - { - - if ($element.Value -eq "" -and $newEnumType.IsFlags -eq $true) - { - # When IsFlags set to true each edm:Member element MUST specify a non-negative integer Value in the value attribute - $errorMessage = ($LocalizedData.InValidMetadata) - $detailedErrorMessage = "When IsFlags set to true each edm:Member element MUST specify a non-negative integer Value in the value attribute in " + $newEnumType.Name + " EnumType" - $exception = [System.InvalidOperationException]::new($errorMessage, $detailedErrorMessage) - $errorRecord = CreateErrorRecordHelper "InValidMetadata" $null ([System.Management.Automation.ErrorCategory]::InvalidData) $detailedErrorMessage nu - $PSCmdlet.ThrowTerminatingError($errorRecord) - } - elseif (($null -eq $element.Value) -or ($element.Value.GetType().Name -eq "Int32" -and $element.Value -eq "")) - { - # If no values are specified, the members are assigned consecutive integer values in the order of their appearance, - # starting with zero for the first member. - $currentEnumValue = $enumValue - } - else - { - $currentEnumValue = $element.Value - } - - $tmp = [ODataUtils.EnumMember] @{ - "Name" = $element.Name; - "Value" = $currentEnumValue; - } - - $newEnumType.Members += $tmp - $enumValue++ - } - - $Metadata.EnumTypes += $newEnumType - } -} - -######################################################### -# Processes SingletonTypes from plain text xml metadata -# into our custom structure -######################################################### -function ParseSingletonTypes -{ - param - ( - [System.Xml.XmlElement] $SchemaEntityContainerXML, - [ODataUtils.MetadataV4] $Metadata - ) - - if($null -eq $SchemaEntityContainerXML) { throw ($LocalizedData.ArguementNullError -f "SchemaEntityContainerXML", "ParseSingletonTypes") } - - foreach ($singleton in $SchemaEntityContainerXML.Singleton) - { - $navigationPropertyBindings = @() - - foreach ($navigationPropertyBinding in $singleton.NavigationPropertyBinding) - { - $tmp = [ODataUtils.NavigationPropertyBinding] @{ - "Path" = $navigationPropertyBinding.Path; - "Target" = $navigationPropertyBinding.Target; - } - - $navigationPropertyBindings += $tmp - } - - $newSingletonType = [ODataUtils.SingletonType] @{ - "Namespace" = $Metadata.Namespace; - "Alias" = $Metadata.Alias; - "Name" = $singleton.Name; - "Type" = $singleton.Type; - "NavigationPropertyBindings" = $navigationPropertyBindings; - } - - $Metadata.SingletonTypes += $newSingletonType - } -} - -######################################################### -# Processes EntitySets from plain text xml metadata -# into our custom structure -######################################################### -function ParseEntitySets -{ - param - ( - [System.Xml.XmlElement] $SchemaEntityContainerXML, - [ODataUtils.MetadataV4] $Metadata, - [string] $Namespace, - [AllowEmptyString()] - [string] $Alias - ) - - if($null -eq $SchemaEntityContainerXML) { throw ($LocalizedData.ArguementNullError -f "SchemaEntityContainerXML", "ParseEntitySets") } - - $entityTypeToEntitySetMapping = @{}; - foreach ($entitySet in $SchemaEntityContainerXML.EntitySet) - { - $entityType = $metadata.EntityTypes | Where-Object { $_.Name -eq $entitySet.EntityType.Split('.')[-1] } - $entityTypeName = $entityType.Name - - if($entityTypeToEntitySetMapping.ContainsKey($entityTypeName)) - { - $existingEntitySetName = $entityTypeToEntitySetMapping[$entityTypeName] - throw ($LocalizedData.EntityNameConflictError -f $entityTypeName, $existingEntitySetName, $entitySet.Name, $entityTypeName ) - } - else - { - $entityTypeToEntitySetMapping.Add($entityTypeName, $entitySet.Name) - } - - $newEntitySet = [ODataUtils.EntitySetV4] @{ - "Namespace" = $Namespace; - "Alias" = $Alias; - "Name" = $entitySet.Name; - "Type" = $entityType; - } - - $Metadata.EntitySets += $newEntitySet - } -} - -######################################################### -# Processes Actions from plain text xml metadata -# into our custom structure -######################################################### -function ParseActions -{ - param - ( - [System.Object[]] $SchemaActionsXML, - [ODataUtils.MetadataV4] $Metadata - ) - - if($null -eq $SchemaActionsXML) { throw ($LocalizedData.ArguementNullError -f "SchemaActionsXML", "ParseActions") } - - foreach ($action in $SchemaActionsXML) - { - # HttpMethod is only used for legacy Service Operations - if ($null -eq $action.HttpMethod) - { - $newAction = [ODataUtils.ActionV4] @{ - "Namespace" = $Metadata.Namespace; - "Alias" = $Metadata.Alias; - "Name" = $action.Name; - "Action" = $Metadata.Namespace + '.' + $action.Name; - } - - # Actions are always SideEffecting, otherwise it's an OData function - foreach ($parameter in $action.Parameter) - { - if ($null -ne $parameter.Nullable) - { - $parameterIsNullable = [System.Convert]::ToBoolean($parameter.Nullable); - } - else - { - $parameterIsNullable = $true - } - - $newParameter = [ODataUtils.TypeProperty] @{ - "Name" = $parameter.Name; - "TypeName" = $parameter.Type; - "IsNullable" = $parameterIsNullable; - } - - $newAction.Parameters += $newParameter - } - - if ($null -ne $action.EntitySet) - { - $newAction.EntitySet = $metadata.EntitySets | Where-Object { $_.Name -eq $action.EntitySet } - } - - $Metadata.Actions += $newAction - } - } -} - -######################################################### -# Processes Functions from plain text xml metadata -# into our custom structure -######################################################### -function ParseFunctions -{ - param - ( - [System.Object[]] $SchemaFunctionsXML, - [ODataUtils.MetadataV4] $Metadata - ) - - if($null -eq $SchemaFunctionsXML) { throw ($LocalizedData.ArguementNullError -f "SchemaFunctionsXML", "ParseFunctions") } - - foreach ($function in $SchemaFunctionsXML) - { - # HttpMethod is only used for legacy Service Operations - if ($null -eq $function.HttpMethod) - { - $newFunction = [ODataUtils.FunctionV4] @{ - "Namespace" = $Metadata.Namespace; - "Alias" = $Metadata.Alias; - "Name" = $function.Name; - "Function" = $Metadata.Namespace + '.' + $function.Name; - "EntitySet" = $function.EntitySetPath; - "ReturnType" = $function.ReturnType; - } - - # Future TODO - consider removing this hack once all the service we run against fix this issue - # Hack - sometimes service does not return ReturnType, however this information can be found in InnerXml - if ($newFunction.ReturnType -eq '' -or $newFunction.ReturnType -eq 'System.Xml.XmlElement') - { - try - { - [xml] $innerXML = '' + $function.InnerXml + '' - $newFunction.Returntype = $innerXML.Params.ReturnType.Type - } - catch - { - # Do nothing - } - } - - # Keep only EntityType name - $newFunction.ReturnType = $newFunction.ReturnType.Replace('Collection(', '') - $newFunction.ReturnType = $newFunction.ReturnType.Replace(')', '') - - # Actions are always SideEffecting, otherwise it's an OData function - foreach ($parameter in $function.Parameter) - { - if ($null -ne $parameter.Nullable) - { - $parameterIsNullable = [System.Convert]::ToBoolean($parameter.Nullable); - } - - $newParameter = [ODataUtils.Parameter] @{ - "Name" = $parameter.Name; - "Type" = $parameter.Type; - "Nullable" = $parameterIsNullable; - } - - $newFunction.Parameters += $newParameter - } - - $Metadata.Functions += $newFunction - } - } -} - -######################################################### -# Processes plain text xml metadata (OData V4 schema version) into our custom structure -# MetadataSet contains all parsed so far referenced Metadatas (for base class lookup) -######################################################### -function ParseMetadata -{ - param - ( - [xml] $MetadataXML, - [string] $ODataVersion, - [string] $MetadataUri, - [string] $Uri, - [System.Collections.ArrayList] $MetadataSet - ) - - if($null -eq $MetadataXML) { throw ($LocalizedData.ArguementNullError -f "MetadataXML", "ParseMetadata") } - - # This is a processing queue for those types that require base types that haven't been defined yet - $entityAndComplexTypesQueue = @{} - [System.Collections.ArrayList] $metadatas = [System.Collections.ArrayList]::new() - - foreach ($schema in $MetadataXML.Edmx.DataServices.Schema) - { - if ($null -eq $schema) - { - Write-Error $LocalizedData.EmptySchema - continue - } - - [ODataUtils.MetadataV4] $metadata = [ODataUtils.MetadataV4]::new() - $metadata.ODataVersion = $ODataVersion - $metadata.MetadataUri = $MetadataUri - $metadata.Uri = $Uri - $metadata.Namespace = $schema.Namespace - $metadata.Alias = $schema.Alias - - ParseEntityTypes -SchemaXML $schema -metadata $metadata -GlobalMetadata $MetadataSet -EntityAndComplexTypesQueue $entityAndComplexTypesQueue -CustomNamespace $CustomNamespace -Alias $metadata.Alias - ParseComplexTypes -SchemaXML $schema -metadata $metadata -GlobalMetadata $MetadataSet -EntityAndComplexTypesQueue $entityAndComplexTypesQueue -CustomNamespace $CustomNamespace -Alias $metadata.Alias - ParseTypeDefinitions -SchemaXML $schema -metadata $metadata -GlobalMetadata $MetadataSet -CustomNamespace $CustomNamespace -Alias $metadata.Alias - ParseEnumTypes -SchemaXML $schema -metadata $metadata - - foreach ($entityContainer in $schema.EntityContainer) - { - if ($entityContainer.IsDefaultEntityContainer) - { - $metadata.DefaultEntityContainerName = $entityContainer.Name - } - - ParseSingletonTypes -SchemaEntityContainerXML $entityContainer -Metadata $metadata - ParseEntitySets -SchemaEntityContainerXML $entityContainer -Metadata $metadata -Namespace $schema.Namespace -Alias $schema.Alias - } - - if ($schema.Action) - { - ParseActions -SchemaActionsXML $schema.Action -Metadata $metadata - } - - if ($schema.Function) - { - ParseFunctions -SchemaFunctionsXML $schema.Function -Metadata $metadata - } - - # In this call we check if the Namespace or Alias have to be normalized because it has invalid combination of dots and numbers. - # Note: In ParseEntityTypes and ParseComplexTypes we check for scenario where namespace/alias collide with inheriting class name. - NormalizeNamespace $metadata.Namespace $metadata.Uri $script:normalizedNamespaces $false - NormalizeNamespace $metadata.Alias $metadata.Uri $script:normalizedNamespaces $false - - $metadatas.Add($metadata) | Out-Null - } - - $metadatas -} - -######################################################### -# Verifies processed metadata for correctness -######################################################### -function VerifyMetadata -{ - param - ( - [System.Collections.ArrayList] $metadataSet, - [boolean] $allowClobber, - $callerPSCmdlet, - [string] $progressBarStatus - ) - - if($null -eq $callerPSCmdlet) { throw ($LocalizedData.ArguementNullError -f "PSCmdlet", "VerifyMetaData") } - if($null -eq $progressBarStatus) { throw ($LocalizedData.ArguementNullError -f "ProgressBarStatus", "VerifyMetaData") } - - Write-Verbose $LocalizedData.VerboseVerifyingMetadata - - $reservedProperties = @("Filter", "OrderBy", "Skip", "Top", "ConnectionUri", "CertificateThumbPrint", "Credential") - $validEntitySets = @() - $sessionCommands = Get-Command -All - - - foreach ($metadata in $metadataSet) - { - foreach ($entitySet in $metadata.EntitySets) - { - if ($null -eq $entitySet.Type) - { - $errorMessage = ($LocalizedData.EntitySetUndefinedType -f $metadata.MetadataUri, $entitySet.Name) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointProxyInvalidMetaDataUri" $null ([System.Management.Automation.ErrorCategory]::InvalidArgument) $exception $metadata.MetadataUri - $callerPSCmdlet.ThrowTerminatingError($errorRecord) - } - - $hasConflictingProperty = $false - $hasConflictingCommand = $false - $entityAndNavigationProperties = $entitySet.Type.EntityProperties + $entitySet.Type.NavigationProperties - foreach($entityProperty in $entityAndNavigationProperties) - { - if($reservedProperties.Contains($entityProperty.Name)) - { - $hasConflictingProperty = $true - if(!$allowClobber) - { - # Write Error message and skip current Entity Set. - $errorMessage = ($LocalizedData.SkipEntitySetProxyCreation -f $entitySet.Name, $entitySet.Type.Name, $entityProperty.Name) - $exception = [System.InvalidOperationException]::new($errorMessage) - $errorRecord = CreateErrorRecordHelper "ODataEndpointDefaultPropertyCollision" $null ([System.Management.Automation.ErrorCategory]::InvalidOperation) $exception $metadata.MetadataUri - $callerPSCmdlet.WriteError($errorRecord) - } - else - { - $warningMessage = ($LocalizedData.EntitySetProxyCreationWithWarning -f $entitySet.Name, $entityProperty.Name, $entitySet.Type.Name) - $callerPSCmdlet.WriteWarning($warningMessage) - } - } - } - - foreach($currentCommand in $sessionCommands) - { - if(($null -ne $currentCommand.Noun -and $currentCommand.Noun -eq $entitySet.Name) -and - ($currentCommand.Verb -eq "Get" -or - $currentCommand.Verb -eq "Set" -or - $currentCommand.Verb -eq "New" -or - $currentCommand.Verb -eq "Remove")) - { - $hasConflictingCommand = $true - VerifyMetadataHelper $LocalizedData.SkipEntitySetConflictCommandCreation ` - $LocalizedData.EntitySetConflictCommandCreationWithWarning ` - $entitySet.Name $currentCommand.Name $metadata.MetadataUri $allowClobber $callerPSCmdlet - } - } - - foreach($currentAction in $metadata.Actions) - { - $actionCommand = "Invoke-" + "$($entitySet.Name)$($currentAction.Verb)" - - foreach($currentCommand in $sessionCommands) - { - if($actionCommand -eq $currentCommand.Name) - { - $hasConflictingCommand = $true - VerifyMetadataHelper $LocalizedData.SkipEntitySetConflictCommandCreation ` - $LocalizedData.EntitySetConflictCommandCreationWithWarning $entitySet.Name ` - $currentCommand.Name $metadata.MetadataUri $allowClobber $callerPSCmdlet - } - } - } - - if(!($hasConflictingProperty -or $hasConflictingCommand)-or $allowClobber) - { - $validEntitySets += $entitySet - } - } - - $metadata.EntitySets = $validEntitySets - - $validServiceActions = @() - $hasConflictingServiceActionCommand - foreach($currentAction in $metadata.Actions) - { - $serviceActionCommand = "Invoke-" + "$($currentAction.Verb)" - - foreach($currentCommand in $sessionCommands) - { - if($serviceActionCommand -eq $currentCommand.Name) - { - $hasConflictingServiceActionCommand = $true - VerifyMetadataHelper $LocalizedData.SkipConflictServiceActionCommandCreation ` - $LocalizedData.ConflictServiceActionCommandCreationWithWarning $entitySet.Name ` - $currentCommand.Name $metadata.MetadataUri $allowClobber $callerPSCmdlet - } - } - - if(!$hasConflictingServiceActionCommand -or $allowClobber) - { - $validServiceActions += $currentAction - } - } - - $metadata.Actions = $validServiceActions - } - - # Update Progress bar. - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 5 20 1 1 -} - -######################################################### -# Takes xml definition of a class from metadata document, -# plus existing metadata structure and finds its base class -######################################################### -function GetBaseType -{ - param - ( - [System.Xml.XmlElement] $MetadataEntityDefinition, - [ODataUtils.MetadataV4] $Metadata, - [string] $Namespace, - [System.Collections.ArrayList] $GlobalMetadata - ) - - if ($null -ne $metadataEntityDefinition -and - $null -ne $metaData -and - $null -ne $MetadataEntityDefinition.BaseType) - { - $baseType = $Metadata.EntityTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $MetadataEntityDefinition.BaseType -or $_.Alias + "." + $_.Name -eq $MetadataEntityDefinition.BaseType } - if ($null -eq $baseType) - { - $baseType = $Metadata.ComplexTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $MetadataEntityDefinition.BaseType -or $_.Alias + "." + $_.Name -eq $MetadataEntityDefinition.BaseType } - } - - if ($null -eq $baseType) - { - # Look in other metadatas, since the class can be defined in referenced metadata - foreach ($referencedMetadata in $GlobalMetadata) - { - if ($null -ne ($baseType = $referencedMetadata.EntityTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $MetadataEntityDefinition.BaseType -or $_.Alias + "." + $_.Name -eq $MetadataEntityDefinition.BaseType }) -or - $null -ne ($baseType = $referencedMetadata.ComplexTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $MetadataEntityDefinition.BaseType -or $_.Alias + "." + $_.Name -eq $MetadataEntityDefinition.BaseType })) - { - # Found base class - break - } - } - } - } - - if ($null -ne $baseType) - { - $baseType[0] - } -} - -######################################################### -# Takes base class name and global metadata structure -# and finds its base class -######################################################### -function GetBaseTypeByName -{ - param - ( - [String] $BaseTypeStr, - [System.Collections.ArrayList] $GlobalMetadata - ) - - if ($null -ne $BaseTypeStr) - { - - # Look for base class definition in all referenced metadatas (including entry point) - foreach ($referencedMetadata in $GlobalMetadata) - { - if ($null -ne ($baseType = $referencedMetadata.EntityTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $BaseTypeStr -or $_.Alias + "." + $_.Name -eq $BaseTypeStr }) -or - $null -ne ($baseType = $referencedMetadata.ComplexTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $BaseTypeStr -or $_.Alias + "." + $_.Name -eq $BaseTypeStr })) - { - # Found base class - break - } - } - } - - if ($null -ne $baseType) - { - $baseType[0] - } - else - { - $null - } -} - -######################################################### -# Processes derived types of a newly added type, -# that were previously waiting in the queue -######################################################### -function AddDerivedTypes { - param( - [ODataUtils.EntityTypeV4] $baseType, - $entityAndComplexTypesQueue, - [ODataUtils.MetadataV4] $metadata, - [string] $namespace - ) - - if($null -eq $baseType) { throw ($LocalizedData.ArguementNullError -f "BaseType", "AddDerivedTypes") } - if($null -eq $entityAndComplexTypesQueue) { throw ($LocalizedData.ArguementNullError -f "EntityAndComplexTypesQueue", "AddDerivedTypes") } - if($null -eq $namespace) { throw ($LocalizedData.ArguementNullError -f "Namespace", "AddDerivedTypes") } - - $baseTypeFullName = $baseType.Namespace + '.' + $baseType.Name - $baseTypeShortName = $baseType.Alias + '.' + $baseType.Name - - if ($entityAndComplexTypesQueue.ContainsKey($baseTypeFullName) -or $entityAndComplexTypesQueue.ContainsKey($baseTypeShortName)) - { - $types = $entityAndComplexTypesQueue[$baseTypeFullName] + $entityAndComplexTypesQueue[$baseTypeShortName] - - foreach ($type in $types) - { - if ($type.type -eq 'EntityType') - { - $newType = ParseMetadataTypeDefinition ($type.value) $baseType $metadata $namespace $true - $metadata.EntityTypes += $newType - } - else - { - $newType = ParseMetadataTypeDefinition ($type.value) $baseType $metadata $namespace $false - $metadata.ComplexTypes += $newType - } - - AddDerivedTypes $newType $entityAndComplexTypesQueue $metadata $namespace - } - } -} - -######################################################### -# Parses types definitions element of metadata xml -######################################################### -function ParseMetadataTypeDefinitionHelper -{ - param - ( - [System.Xml.XmlElement] $metadataEntityDefinition, - [ODataUtils.EntityTypeV4] $baseType, - [string] $baseTypeStr, - [ODataUtils.MetadataV4] $metadata, - [string] $namespace, - [AllowEmptyString()] - [string] $alias, - [bool] $isEntity - ) - - if($null -eq $metadataEntityDefinition) { throw ($LocalizedData.ArguementNullError -f "MetadataEntityDefinition", "ParseMetadataTypeDefinition") } - if($null -eq $namespace) { throw ($LocalizedData.ArguementNullError -f "Namespace", "ParseMetadataTypeDefinition") } - - [ODataUtils.EntityTypeV4] $newEntityType = CreateNewEntityType -metadataEntityDefinition $metadataEntityDefinition -baseType $baseType -baseTypeStr $baseTypeStr -namespace $namespace -alias $alias -isEntity $isEntity - - if ($null -ne $baseType) - { - # Add properties inherited from BaseType - ParseMetadataBaseTypeDefinitionHelper $newEntityType $baseType - } - - # properties defined on EntityType - $newEntityType.EntityProperties += $metadataEntityDefinition.Property | ForEach-Object { - if ($null -ne $_) - { - if ($null -ne $_.Nullable) - { - $newPropertyIsNullable = [System.Convert]::ToBoolean($_.Nullable) - } - else - { - $newPropertyIsNullable = $true - } - - [ODataUtils.TypeProperty] @{ - "Name" = $_.Name; - "TypeName" = $_.Type; - "IsNullable" = $newPropertyIsNullable; - } - } - } - - # odataId property will be inherited from base type, if it exists. - # Otherwise, it should be added to current type - if ($null -eq $baseType) - { - # @odata.Id property (renamed to odataId) is required for dynamic Uri creation - # This property is only available when user executes auto-generated cmdlet with -AllowAdditionalData, - # but ODataAdapter needs it to construct Uri to access navigation properties. - # Thus, we need to fetch this info for scenario when -AllowAdditionalData isn't used. - $newEntityType.EntityProperties += [ODataUtils.TypeProperty] @{ - "Name" = "odataId"; - "TypeName" = "Edm.String"; - "IsNullable" = $True; - } - } - - # Property name can't be identical to entity type name. - # If such property exists, "Property" suffix will be added to its name. - foreach ($property in $newEntityType.EntityProperties) - { - if ($property.Name -eq $newEntityType.Name) - { - $property.Name += "Property" - } - } - - if ($null -ne $metadataEntityDefinition -and $null -ne $metadataEntityDefinition.Key) - { - foreach ($entityTypeKey in $metadataEntityDefinition.Key.PropertyRef) - { - ($newEntityType.EntityProperties | Where-Object { $_.Name -eq $entityTypeKey.Name }).IsKey = $true - } - } - - $newEntityType -} - -######################################################### -# Add base class entity and navigation properties to inheriting class -######################################################### -function ParseMetadataBaseTypeDefinitionHelper -{ - param - ( - [ODataUtils.EntityTypeV4] $EntityType, - [ODataUtils.EntityTypeV4] $BaseType - ) - - if ($null -ne $EntityType -and $null -ne $BaseType) - { - # Add properties inherited from BaseType - $EntityType.EntityProperties += $BaseType.EntityProperties - $EntityType.NavigationProperties += $BaseType.NavigationProperties - } -} - -######################################################### -# Create new EntityType object -######################################################### -function CreateNewEntityType -{ - param - ( - [System.Xml.XmlElement] $metadataEntityDefinition, - [ODataUtils.EntityTypeV4] $baseType, - [string] $baseTypeStr, - [string] $namespace, - [AllowEmptyString()] - [string] $alias, - [bool] $isEntity - ) - $newEntityType = [ODataUtils.EntityTypeV4] @{ - "Namespace" = $namespace; - "Alias" = $alias; - "Name" = $metadataEntityDefinition.Name; - "IsEntity" = $isEntity; - "BaseType" = $baseType; - "BaseTypeStr" = $baseTypeStr; - } - - $newEntityType -} - -######################################################### -# Parses navigation properties from metadata xml -######################################################### -function ParseMetadataTypeDefinitionNavigationProperties -{ - param - ( - [System.Xml.XmlElement] $metadataEntityDefinition, - [ODataUtils.EntityTypeV4] $entityType - ) - - # navigation properties defined on EntityType - $newEntityType.NavigationProperties = @{} - $newEntityType.NavigationProperties.Clear() - - foreach ($navigationProperty in $metadataEntityDefinition.NavigationProperty) - { - $tmp = [ODataUtils.NavigationPropertyV4] @{ - "Name" = $navigationProperty.Name; - "Type" = $navigationProperty.Type; - "Nullable" = $navigationProperty.Nullable; - "Partner" = $navigationProperty.Partner; - "ContainsTarget" = $navigationProperty.ContainsTarget; - "OnDelete" = $navigationProperty.OnDelete; - } - - $referentialConstraints = @{} - foreach ($constraint in $navigationProperty.ReferentialConstraints) - { - $tmp = [ODataUtils.ReferencedConstraint] @{ - "Property" = $constraint.Property; - "ReferencedProperty" = $constraint.ReferencedProperty; - } - } - - $newEntityType.NavigationProperties += $tmp - } -} - -######################################################### -# Parses types definitions element of metadata xml for OData V4 schema -######################################################### -function ParseMetadataTypeDefinition -{ - param - ( - [System.Xml.XmlElement] $metadataEntityDefinition, - [ODataUtils.EntityTypeV4] $baseType, - [ODataUtils.MetadataV4] $metadata, - [string] $namespace, - [AllowEmptyString()] - [string] $alias, - [bool] $isEntity, - [string] $baseTypeStr - ) - - if($null -eq $metadataEntityDefinition) { throw ($LocalizedData.ArguementNullError -f "MetadataEntityDefinition", "ParseMetadataTypeDefinition") } - if($null -eq $namespace) { throw ($LocalizedData.ArguementNullError -f "Namespace", "ParseMetadataTypeDefinition") } - - [ODataUtils.EntityTypeV4] $newEntityType = ParseMetadataTypeDefinitionHelper -metadataEntityDefinition $metadataEntityDefinition -baseType $baseType -baseTypeStr $baseTypeStr -metadata $metadata -namespace $namespace -alias $alias -isEntity $isEntity - ParseMetadataTypeDefinitionNavigationProperties -metadataEntityDefinition $metadataEntityDefinition -entityType $newEntityType - - $newEntityType -} - -######################################################### -# Create psd1 and cdxml files required to auto-generate -# cmdlets for given service. -######################################################### -function GenerateClientSideProxyModule -{ - param - ( - [System.Collections.ArrayList] $GlobalMetadata, - [ODataUtils.ODataEndpointProxyParameters] $ODataEndpointProxyParameters, - [string] $OutputModule, - [string] $CreateRequestMethod, - [string] $UpdateRequestMethod, - [string] $CmdletAdapter, - [Hashtable] $resourceNameMappings, - [Hashtable] $CustomData, - [string] $UriResourcePathKeyFormat, - [string] $progressBarStatus, - $NormalizedNamespaces - ) - - if($null -eq $progressBarStatus) { throw ($LocalizedData.ArguementNullError -f "ProgressBarStatus", "GenerateClientSideProxyModule") } - - Write-Verbose ($LocalizedData.VerboseSavingModule -f $OutputModule) - - # Save ComplexTypes for all metadata schemas in single file - $typeDefinitionFileName = "ComplexTypeDefinitions.psm1" - $complexTypeMapping = GenerateComplexTypeDefinition $GlobalMetadata $OutputModule $typeDefinitionFileName $NormalizedNamespaces - - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 20 20 1 1 - - $actions = @() - $functions = @() - - $currentEntryCount = 0 - foreach ($Metadata in $GlobalMetadata) - { - foreach ($entitySet in $Metadata.EntitySets) - { - $currentEntryCount += 1 - SaveCDXML $entitySet $Metadata $GlobalMetadata $Metadata.Uri $OutputModule $CreateRequestMethod $UpdateRequestMethod $CmdletAdapter $resourceNameMappings $CustomData $complexTypeMapping $UriResourcePathKeyFormat $NormalizedNamespaces - - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 40 20 $Metadata.EntitySets.Count $currentEntryCount - } - - $currentEntryCount = 0 - foreach ($singleton in $Metadata.SingletonTypes) - { - $currentEntryCount += 1 - SaveCDXMLSingletonCmdlets $singleton $Metadata $GlobalMetadata $Metadata.Uri $OutputModule $CreateRequestMethod $UpdateRequestMethod $CmdletAdapter $resourceNameMappings $CustomData $complexTypeMapping $NormalizedNamespaces - - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 40 20 $Metadata.Singletons.Count $currentEntryCount - } - - $actions += $Metadata.Actions | Where-Object { $_.EntitySet -eq '' -or $null -eq $_.EntitySet } - $functions += $Metadata.Functions | Where-Object { $_.EntitySet -eq '' -or $null -eq $_.EntitySet} - } - - if ($actions.Count -gt 0 -or $functions.Count -gt 0) - { - # Save Service Actions for all metadata schemas in single file - SaveServiceActionsCDXML $GlobalMetadata $ODataEndpointProxyParameters "$OutputModule\ServiceActions.cdxml" $complexTypeMapping $progressBarStatus $CmdletAdapter - } - - $moduleDirInfo = [System.IO.DirectoryInfo]::new($OutputModule) - $moduleManifestName = $moduleDirInfo.Name + ".psd1" - - if ($actions.Count -gt 0 -or $functions.Count -gt 0) - { - $additionalModules = @($typeDefinitionFileName, 'ServiceActions.cdxml') - } - else - { - $additionalModules = @($typeDefinitionFileName) - } - - GenerateModuleManifest $GlobalMetadata $OutputModule\$moduleManifestName $additionalModules $resourceNameMappings $progressBarStatus -} - -######################################################### -# Generates CDXML module for a specific OData EntitySet -######################################################### -function SaveCDXML -{ - param - ( - [ODataUtils.EntitySetV4] $EntitySet, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - [string] $Uri, - [string] $OutputModule, - [string] $CreateRequestMethod, - [string] $UpdateRequestMethod, - [string] $CmdletAdapter, - [Hashtable] $resourceNameMappings, - [Hashtable] $CustomData, - [Hashtable] $complexTypeMapping, - [string] $UriResourcePathKeyFormat, - $normalizedNamespaces - ) - - if($null -eq $EntitySet) { throw ($LocalizedData.ArguementNullError -f "EntitySet", "GenerateClientSideProxyModule") } - if($null -eq $Metadata) { throw ($LocalizedData.ArguementNullError -f "metadata", "GenerateClientSideProxyModule") } - - $entitySetName = $EntitySet.Name - if(($null -ne $resourceNameMappings) -and - $resourceNameMappings.ContainsKey($entitySetName)) - { - $entitySetName = $resourceNameMappings[$entitySetName] - } - else - { - $entitySetName = $EntitySet.Type.Name - } - - $Path = "$OutputModule\$entitySetName.cdxml" - - $xmlWriter = New-Object System.XMl.XmlTextWriter($Path,$Null) - - if ($null -eq $xmlWriter) - { - throw ($LocalizedData.XmlWriterInitializationError -f $EntitySet.Name) - } - - $xmlWriter = SaveCDXMLHeader $xmlWriter $Uri $EntitySet.Name $entitySetName $CmdletAdapter - - # Get the keys - $keys = $EntitySet.Type.EntityProperties | Where-Object { $_.IsKey } - - $navigationProperties = $EntitySet.Type.NavigationProperties - - SaveCDXMLInstanceCmdlets $xmlWriter $Metadata $GlobalMetadata $EntitySet.Type $keys $navigationProperties $CmdletAdapter $complexTypeMapping $false - - $nonKeyProperties = $EntitySet.Type.EntityProperties | Where-Object { -not $_.isKey } - $nullableProperties = $nonKeyProperties | Where-Object { $_.isNullable } - $nonNullableProperties = $nonKeyProperties | Where-Object { -not $_.isNullable } - - $xmlWriter.WriteStartElement('StaticCmdlets') - - $keyProperties = $keys - - SaveCDXMLNewCmdlet $xmlWriter $Metadata $GlobalMetadata $keyProperties $nonNullableProperties $nullableProperties $navigationProperties $CmdletAdapter $complexTypeMapping - - GenerateSetProxyCmdlet $xmlWriter $keyProperties $nonKeyProperties $complexTypeMapping - - SaveCDXMLRemoveCmdlet $xmlWriter $Metadata $GlobalMetadata $keyProperties $navigationProperties $CmdletAdapter $complexTypeMapping - - $entityActions = $Metadata.Actions | Where-Object { ($_.EntitySet.Namespace -eq $EntitySet.Namespace) -and ($_.EntitySet.Name -eq $EntitySet.Name) } - - if ($entityActions.Length -gt 0) - { - foreach($action in $entityActions) - { - $xmlWriter = SaveCDXMLAction $xmlWriter $Metadata $action $EntitySet.Name $true $keys $complexTypeMapping - } - } - - $entityFunctions = $Metadata.Functions | Where-Object { ($_.EntitySet.Namespace -eq $EntitySet.Namespace) -and ($_.EntitySet.Name -eq $EntitySet.Name) } - - if ($entityFunctions.Length -gt 0) - { - foreach($function in $entityFunctions) - { - $xmlWriter = SaveCDXMLFunction $xmlWriter $Metadata $function $EntitySet.Name $true $keys $complexTypeMapping - } - } - - $xmlWriter.WriteEndElement() - - $normalizedDotNetNamespace = GetNamespace $EntitySet.Type.Namespace $normalizedNamespaces - $normalizedDotNetAlias = GetNamespace $EntitySet.Alias $normalizedNamespaces - $normalizedDotNetEntitySetNamespace = $normalizedDotNetNamespace - - $xmlWriter.WriteStartElement('CmdletAdapterPrivateData') - - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'EntityTypeName') - $xmlWriter.WriteString("$($normalizedDotNetNamespace).$($EntitySet.Type.Name)") - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'EntityTypeAliasName') - if (!$EntitySet.Alias) - { - $xmlWriter.WriteString("") - } - else - { - $xmlWriter.WriteString("$($normalizedDotNetAlias).$($EntitySet.Type.Name)") - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'EntitySetName') - $xmlWriter.WriteString("$($normalizedDotNetEntitySetNamespace).$($EntitySet.Name)") - $xmlWriter.WriteEndElement() - - # Add URI resource path format (webservice.svc/ResourceName/ResourceId vs webservice.svc/ResourceName(QueryKeyName=ResourceId)) - if ($null -ne $UriResourcePathKeyFormat -and $UriResourcePathKeyFormat -ne [string]::Empty) - { - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'UriResourcePathKeyFormat') - $xmlWriter.WriteString("$UriResourcePathKeyFormat") - $xmlWriter.WriteEndElement() - } - - # Add information about navigation properties and their types - # Used in scenario where user requests navigation property in -Select query - foreach ($navProperty in $navigationProperties) - { - if ($navProperty) - { - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', $navProperty.Name + 'NavigationProperty') - $xmlWriter.WriteString($navProperty.Type) - $xmlWriter.WriteEndElement() - } - } - - # Add CreateRequestMethod and UpdateRequestMethod to privateData - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'CreateRequestMethod') - $xmlWriter.WriteString("$CreateRequestMethod") - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'UpdateRequestMethod') - $xmlWriter.WriteString("$UpdateRequestMethod") - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() - - SaveCDXMLFooter $xmlWriter - - Write-Verbose ($LocalizedData.VerboseSavedCDXML -f $($entitySetName), $Path) -} - -######################################################### -# Save Singleton Cmdlets to CDXML -######################################################### -function SaveCDXMLSingletonCmdlets -{ - param - ( - [ODataUtils.SingletonType] $Singleton, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - [string] $Uri, - [string] $OutputModule, - [string] $CreateRequestMethod, - [string] $UpdateRequestMethod, - [string] $CmdletAdapter, - [Hashtable] $resourceNameMappings, - [Hashtable] $CustomData, - [Hashtable] $complexTypeMapping, - $normalizedNamespaces - ) - - if($null -eq $Singleton) { throw ($LocalizedData.ArguementNullError -f "Singleton", "SaveCDXMLSingletonCmdlets") } - if($null -eq $Metadata) { throw ($LocalizedData.ArguementNullError -f "Metadata", "SaveCDXMLSingletonCmdlets") } - - $singletonName = $singleton.Name - $singletonType = $singleton.Type - - $Path = "$OutputModule\$singletonName" + "Singleton" + ".cdxml" - - $xmlWriter = New-Object System.XMl.XmlTextWriter($Path,$Null) - - if ($null -eq $xmlWriter) - { - throw ($LocalizedData.XmlWriterInitializationError -f $singletonName) - } - - # Get associated EntityType - $associatedEntityType = $Metadata.EntityTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $singletonType -or $_.Alias + "." + $_.Name -eq $singletonType} - - if ($null -eq $associatedEntityType) - { - # Look in other metadatas, since the class can be defined in referenced metadata - foreach ($referencedMetadata in $GlobalMetadata) - { - if ($null -ne ($associatedEntityType = $referencedMetadata.EntityTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $singletonType -or $_.Alias + "." + $_.Name -eq $singletonType })) - { - # Found associated class - break - } - } - } - - if ($null -ne $associatedEntityType) - { - $xmlWriter = SaveCDXMLHeader $xmlWriter $Uri $singletonName $singletonName $CmdletAdapter - - if ($null -eq $associatedEntityType.BaseType -and $null -ne $associatedEntityType.BaseTypeStr -and $associatedEntityType.BaseTypeStr -ne '') - { - $associatedEntitybaseType = GetBaseTypeByName $associatedEntityType.BaseTypeStr $GlobalMetadata - - # Make another pass on base class to make sure its properties were added to associated entity type - ParseMetadataBaseTypeDefinitionHelper $associatedEntityType $associatedEntitybaseType - } - - # Get the keys depending on whether the url contains variables or not - $keys = $associatedEntityType.EntityProperties | Where-Object { $_.IsKey } - - $navigationProperties = $associatedEntityType.NavigationProperties - - SaveCDXMLInstanceCmdlets $xmlWriter $Metadata $GlobalMetadata $associatedEntityType $keys $navigationProperties $CmdletAdapter $complexTypeMapping $true - - $nonKeyProperties = $associatedEntityType.EntityProperties | Where-Object { -not $_.isKey } - $nullableProperties = $nonKeyProperties | Where-Object { $_.isNullable } - $nonNullableProperties = $nonKeyProperties | Where-Object { -not $_.isNullable } - - $xmlWriter.WriteStartElement('StaticCmdlets') - - $keyProperties = $keys - - GenerateSetProxyCmdlet $xmlWriter $keyProperties $nonKeyProperties $complexTypeMapping - - $entityActions = $Metadata.Actions | Where-Object { $_.EntitySet.Name -eq $associatedEntityType.Name } - - if ($entityActions.Length -gt 0) - { - foreach($action in $entityActions) - { - $xmlWriter = SaveCDXMLAction $xmlWriter $Metadata $action $EntitySet.Name $true $keys $complexTypeMapping - } - } - - $entityFunctions = $Metadata.Functions | Where-Object { $_.EntitySet.Name -eq $associatedEntityType.Name } - - if ($entityFunctions.Length -gt 0) - { - foreach($function in $entityFunctions) - { - $xmlWriter = SaveCDXMLFunction $xmlWriter $Metadata $function $associatedEntityType.Name $true $keys $complexTypeMapping - } - } - - $xmlWriter.WriteEndElement() - - $normalizedDotNetNamespace = GetNamespace $associatedEntityType.Namespace $normalizedNamespaces - $normalizedDotNetAlias = GetNamespace $associatedEntityType.Alias $normalizedNamespaces - - $xmlWriter.WriteStartElement('CmdletAdapterPrivateData') - - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'EntityTypeAliasName') - if (!$associatedEntityType.Alias) - { - $xmlWriter.WriteString("") - } - else - { - $xmlWriter.WriteString("$($normalizedDotNetAlias).$($associatedEntityType.Name)") - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'EntityTypeName') - $xmlWriter.WriteString("$($normalizedDotNetNamespace).$($associatedEntityType.Name)") - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'IsSingleton') - $xmlWriter.WriteString("True") - $xmlWriter.WriteEndElement() - - # Add information about navigation properties and their types - # Used in scenario where user requests navigation property in -Select query - foreach ($navProperty in $navigationProperties) - { - if ($navProperty) - { - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', $navProperty.Name + 'NavigationProperty') - $xmlWriter.WriteString($navProperty.Type) - $xmlWriter.WriteEndElement() - } - } - - # Add UpdateRequestMethod to privateData - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'UpdateRequestMethod') - $xmlWriter.WriteString("$UpdateRequestMethod") - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() - - SaveCDXMLFooter $xmlWriter - - Write-Verbose ($LocalizedData.VerboseSavedCDXML -f $($associatedEntityType.Name), $Path) - } -} - -######################################################### -# Saves InstanceCmdlets node to CDXML -######################################################### -function SaveCDXMLInstanceCmdlets -{ - param - ( - [System.XMl.XmlTextWriter] $xmlWriter, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - [ODataUtils.EntityTypeV4] $EntityType, - $keys, - $navigationProperties, - $CmdletAdapter, - [Hashtable] $complexTypeMapping, - [bool] $isSingleton - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "SaveCDXMLInstanceCmdlets") } - if($null -eq $Metadata) { throw ($LocalizedData.ArguementNullError -f "Metadata", "SaveCDXMLInstanceCmdlets") } - - $xmlWriter.WriteStartElement('InstanceCmdlets') - $xmlWriter.WriteStartElement('GetCmdletParameters') - # adding key parameters and association parameters to QueryableProperties, each in a different parameter set - # to be used by GET cmdlet - if (($keys.Length -gt 0) -or ($navigationProperties.Length -gt 0)) - { - $queryableNavProperties = @{} - - if ($isSingleton -eq $false) - { - foreach ($navProperty in $navigationProperties) - { - if ($null -ne $navProperty) - { - $associatedType = GetAssociatedType $Metadata $GlobalMetadata $navProperty - $associatedTypeKeyProperties = $associatedType.EntityProperties | Where-Object { $_.IsKey } - - # Make sure associated parameter (based on navigation property) has EntitySet or Singleton, which makes it accessible from the service root - # Otherwise the Uri for associated navigation property won't be valid - if ($associatedTypeKeyProperties.Length -gt 0 -and (ShouldBeAssociatedParameter $GlobalMetadata $EntityType $associatedType $isSingleton)) - { - $queryableNavProperties.Add($navProperty, $associatedTypeKeyProperties) - } - } - } - } - - $defaultCmdletParameterSet = 'Default' - if ($isSingleton -eq $true -and $queryableNavProperties.Count -gt 0) - { - foreach($item in $queryableNavProperties.GetEnumerator()) - { - $defaultCmdletParameterSet = $item.Key.Name - break - } - } - $xmlWriter.WriteAttributeString('DefaultCmdletParameterSet', $defaultCmdletParameterSet) - - - $xmlWriter.WriteStartElement('QueryableProperties') - - $position = 0 - - if ($isSingleton -eq $false) - { - $keys | Where-Object { $null -ne $_ } | ForEach-Object { - $xmlWriter.WriteStartElement('Property') - $xmlWriter.WriteAttributeString('PropertyName', $_.Name) - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('RegularQuery') - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $_.Name) - $xmlWriter.WriteAttributeString('CmdletParameterSets', 'Default') - $xmlWriter.WriteAttributeString('IsMandatory', $_.IsMandatory.ToString().ToLower()) - $xmlWriter.WriteAttributeString('Position', $position) - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $position++ - } - } - - if ($queryableNavProperties.Count -gt 0) - { - foreach($item in $queryableNavProperties.GetEnumerator()) - { - $xmlWriter.WriteStartElement('Property') - $xmlWriter.WriteAttributeString('PropertyName', $item.Key.Name + ':' + $item.Value.Name + ':Key') - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $item.Value.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('RegularQuery') - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', 'Associated' + $item.Key.Name + $item.Value.Name) - $xmlWriter.WriteAttributeString('CmdletParameterSets', $item.Key.Name) - $xmlWriter.WriteAttributeString('IsMandatory', 'false') - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - } - - if ($isSingleton -eq $false) - { - # Add Query Parameters (i.e., Top, Skip, OrderBy, Filter) to the generated Get-* cmdlets. - $queryParameters = - @{ - "Filter" = "Edm.String"; - "IncludeTotalResponseCount" = "switch"; - "OrderBy" = "Edm.String"; - "Select" = "Edm.String"; - "Skip" = "Edm.Int32"; - "Top" = "Edm.Int32"; - } - } - else - { - $queryParameters = - @{ - "Select" = "Edm.String"; - } - } - - foreach($currentQueryParameter in $queryParameters.Keys) - { - $xmlWriter.WriteStartElement('Property') - $xmlWriter.WriteAttributeString('PropertyName', "QueryOption:" + $currentQueryParameter) - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $queryParameters[$currentQueryParameter] - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('RegularQuery') - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $currentQueryParameter) - - if($queryParameters[$currentQueryParameter] -eq "Edm.String") - { - $xmlWriter.WriteStartElement('ValidateNotNullOrEmpty') - $xmlWriter.WriteEndElement() - } - - if($queryParameters[$currentQueryParameter] -eq "Edm.Int32") - { - $xmlWriter.WriteStartElement('ValidateRange') - $xmlWriter.WriteAttributeString('Min', "1") - $xmlWriter.WriteAttributeString('Max', [int]::MaxValue) - $xmlWriter.WriteEndElement() - } - - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - - - $xmlWriter.WriteEndElement() - } - - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('GetCmdlet') - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Get') - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() -} - -# Helper Method -# Returns true if navigation property of $AssociatedType has corresponding EntitySet or Singleton -# If yes, then it should become an associated parameter in CDXML -function ShouldBeAssociatedParameter -{ - param - ( - [System.Collections.ArrayList] $GlobalMetadata, - [ODataUtils.EntityTypeV4] $EntityType, - [ODataUtils.EntityTypeV4] $AssociatedType - ) - - # Check if associated type has navigation property, which links back to current type - $associatedTypeNavProperties = $AssociatedType.NavigationProperties | Where-Object { - $_.Type -eq ($EntityType.Namespace + "." + $EntityType.Name) -or - $_.Type -eq ($EntityType.Alias + "." + $EntityType.Name) -or - $_.Type -eq ("Collection(" + $EntityType.Namespace + "." + $EntityType.Name + ")") -or - $_.Type -eq ("Collection(" + $EntityType.Alias + "." + $EntityType.Name + ")") - } - - if ($associatedTypeNavProperties.Length -lt 1) - { - return $false - } - - # Now check if associated parameter type (i.e, type of navigation property) has corresponding EntitySet or Singleton, - # which makes it accessible from the service root. - # Otherwise the Uri for associated navigation property won't be valid - foreach ($currentMetadata in $GlobalMetadata) - { - # Look for EntitySet with given type - foreach ($currentEntitySet in $currentMetadata.EntitySets) - { - if ($currentEntitySet.Type.Namespace -eq $EntityType.Namespace -and - $currentEntitySet.Type.Name -eq $EntityType.Name) - { - return $true - } - } - - # Look for Singleton with given type - foreach ($currentSingleton in $currentMetadata.Singletons) - { - if ($currentSingleton.Type.Namespace -eq $EntityType.Namespace -and - $currentSingleton.Type.Name -eq $EntityType.Name) - { - return $true - } - } - } - - return $false -} - -######################################################### -# Saves NewCmdlet node to CDXML -######################################################### -function SaveCDXMLNewCmdlet -{ - param - ( - [System.XMl.XmlTextWriter] $xmlWriter, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - $keyProperties, - $nonNullableProperties, - $nullableProperties, - $navigationProperties, - $CmdletAdapter, - $complexTypeMapping - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "SaveCDXMLNewCmdlet") } - if($null -eq $Metadata) { throw ($LocalizedData.ArguementNullError -f "Metadata", "SaveCDXMLNewCmdlet") } - - $xmlWriter.WriteStartElement('Cmdlet') - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'New') - $xmlWriter.WriteAttributeString('DefaultCmdletParameterSet', 'Default') - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', 'Create') - $xmlWriter.WriteAttributeString('CmdletParameterSet', 'Default') - - AddParametersNode $xmlWriter $keyProperties $nonNullableProperties $nullableProperties $null $true $true $complexTypeMapping - - $xmlWriter.WriteEndElement() - - $navigationProperties | Where-Object { $null -ne $_ } | ForEach-Object { - $associatedType = GetAssociatedType $Metadata $GlobalMetadata $_ - $associatedEntitySet = GetEntitySetForEntityType $Metadata $associatedType - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', "Association:Create:$($associatedEntitySet.Name)") - $xmlWriter.WriteAttributeString('CmdletParameterSet', $_.Name) - - $associatedKeys = ($associatedType.EntityProperties | Where-Object { $_.isKey }) - - AddParametersNode $xmlWriter $associatedKeys $keyProperties $null "Associated$($_.Name)" $true $true $complexTypeMapping - - $xmlWriter.WriteEndElement() - } - - $xmlWriter.WriteEndElement() -} - -######################################################### -# Get corresponding EntityType for given EntitySet -######################################################### -function GetEntitySetForEntityType { - param( - [ODataUtils.MetadataV4] $Metadata, - [ODataUtils.EntityTypeV4] $entityType - ) - - if($null -eq $entityType) { throw ($LocalizedData.ArguementNullError -f "EntityType", "GetEntitySetForEntityType") } - - $result = $Metadata.EntitySets | Where-Object { ($_.Type.Namespace -eq $entityType.Namespace) -and ($_.Type.Name -eq $entityType.Name) } - - if (($result.Count -eq 0) -and ($null -ne $entityType.BaseType)) - { - GetEntitySetForEntityType $Metadata $entityType.BaseType - } - elseif ($result.Count -gt 1) - { - throw ($LocalizedData.WrongCountEntitySet -f (($entityType.Namespace + "." + $entityType.Name), $result.Count)) - } - - $result -} - -######################################################### -# Saves RemoveCmdlet node to CDXML -######################################################### -function SaveCDXMLRemoveCmdlet -{ - param - ( - [System.XMl.XmlTextWriter] $xmlWriter, - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - $keyProperties, - $navigationProperties, - $CmdletAdapter, - $complexTypeMapping - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "SaveCDXMLRemoveCmdlet") } - if($null -eq $Metadata) { throw ($LocalizedData.ArguementNullError -f "Metadata", "SaveCDXMLRemoveCmdlet") } - - $xmlWriter.WriteStartElement('Cmdlet') - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Remove') - $xmlWriter.WriteAttributeString('DefaultCmdletParameterSet', 'Default') - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', 'Delete') - $xmlWriter.WriteAttributeString('CmdletParameterSet', 'Default') - - AddParametersNode $xmlWriter $keyProperties $nul $null $null $true $true $complexTypeMapping - - $xmlWriter.WriteEndElement() - - $navigationProperties | Where-Object { $null -ne $_ } | ForEach-Object { - - $associatedType = GetAssociatedType $Metadata $GlobalMetadata $_ - $associatedEntitySet = GetEntitySetForEntityType $Metadata $associatedType - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', "Association:Delete:$($associatedEntitySet.Name)") - $xmlWriter.WriteAttributeString('CmdletParameterSet', $_.Name) - - $associatedType = GetAssociatedType $Metadata $GlobalMetadata $_ - $associatedKeys = ($associatedType.EntityProperties | Where-Object { $_.isKey }) - - AddParametersNode $xmlWriter $associatedKeys $keyProperties $null "Associated$($_.Name)" $true $true $complexTypeMapping - - $xmlWriter.WriteEndElement() - } - $xmlWriter.WriteEndElement() -} - -######################################################### -# Gets associated instance's EntityType for a given navigation property -######################################################### -function GetAssociatedType { - param( - [ODataUtils.MetadataV4] $Metadata, - [System.Collections.ArrayList] $GlobalMetadata, - [ODataUtils.NavigationPropertyV4] $navProperty - ) - - $associationType = $navProperty.Type - $associationType = $associationType.Replace($Metadata.Namespace + ".", "") - $associationType = $associationType.Replace($Metadata.Alias + ".", "") - $associationType = $associationType.Replace("Collection(", "") - $associationType = $associationType.Replace(")", "") - - $associatedType = $Metadata.EntityTypes | Where-Object { $_.Name -eq $associationType } - - if (!$associatedType -and $null -ne $GlobalMetadata) - { - $associationFullTypeName = $navProperty.Type.Replace("Collection(", "").Replace(")", "") - - foreach ($referencedMetadata in $GlobalMetadata) - { - if ($null -ne ($associatedType = $referencedMetadata.EntityTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $associationFullTypeName -or $_.Alias + "." + $_.Name -eq $associationFullTypeName }) -or - $null -ne ($associatedType = $referencedMetadata.ComplexTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $associationFullTypeName -or $_.Alias + "." + $_.Name -eq $associationFullTypeName }) -or - $null -ne ($associatedType = $referencedMetadata.EnumTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $associationFullTypeName -or $_.Alias + "." + $_.Name -eq $associationFullTypeName })) - { - # Found associated class - break - } - } - } - - if ($associatedType.Count -lt 1) - { - throw ($LocalizedData.AssociationNotFound -f $associationType) - } - elseif ($associatedType.Count -gt 1) - { - throw ($LocalizedData.TooManyMatchingAssociationTypes -f $associatedType.Count, $associationType) - } - - # return associated EntityType - $associatedType -} - -######################################################### -# Saves CDXML for Instance/Service level actions -######################################################### -function SaveCDXMLAction -{ - param - ( - [System.Xml.XmlWriter] $xmlWriter, - [ODataUtils.ActionV4] $action, - [AllowEmptyString()] - [string] $noun, - [bool] $isInstanceAction, - [ODataUtils.TypeProperty] $keys, - [Hashtable] $complexTypeMapping - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "SaveCDXMLAction") } - if($null -eq $action) { throw ($LocalizedData.ArguementNullError -f "action", "SaveCDXMLAction") } - - $xmlWriter.WriteStartElement('Cmdlet') - - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Invoke') - $xmlWriter.WriteAttributeString('Noun', "$($noun)$($action.Name)") - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - $xmlWriter.WriteAttributeString('MethodName', "Action:$($action.Name):$($action.EntitySet.Name)") - - $xmlWriter.WriteStartElement('Parameters') - - $keys | Where-Object { $null -ne $_ } | ForEach-Object { - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $_.Name + ':Key') - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $_.Name) - $xmlWriter.WriteAttributeString('IsMandatory', 'true') - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - - $i = -1 - foreach ($parameter in $action.Parameters) - { - $i++ - - # for Instance actions, first parameter is Entity Set which we refer to using keys - if ($isInstanceAction -and ($i -eq 0)) - { - continue - } - - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $parameter.Name) - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $parameter.TypeName - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $parameter.Name) - if (-not $parameter.IsNullable) - { - $xmlWriter.WriteAttributeString('IsMandatory', 'true') - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - - # Add -Force parameter to Service Action cmdlets. - AddParametersNode $xmlWriter $null $null $null $null $true $false $complexTypeMapping - - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() - - $xmlWriter -} - -######################################################### -# Saves CDXML for Instance/Service level functions -######################################################### -function SaveCDXMLFunction -{ - param - ( - [System.Xml.XmlWriter] $xmlWriter, - [ODataUtils.FunctionV4] $function, - [AllowEmptyString()] - [string] $noun, - [bool] $isInstanceAction, - [ODataUtils.TypeProperty] $keys, - [Hashtable] $complexTypeMapping - ) - - if($null -eq $xmlWriter) { throw ($LocalizedData.ArguementNullError -f "xmlWriter", "SaveCDXMLFunction") } - if($null -eq $function) { throw ($LocalizedData.ArguementNullError -f "function", "SaveCDXMLFunction") } - - $xmlWriter.WriteStartElement('Cmdlet') - - $xmlWriter.WriteStartElement('CmdletMetadata') - $xmlWriter.WriteAttributeString('Verb', 'Invoke') - $xmlWriter.WriteAttributeString('Noun', "$($noun)$($function.Name)") - $xmlWriter.WriteAttributeString('ConfirmImpact', 'Medium') - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Method') - if (!$function.EntitySet) - { - $xmlWriter.WriteAttributeString('MethodName', "Action:$($function.Name):$($function.ReturnType)") - } - else - { - $xmlWriter.WriteAttributeString('MethodName', "Action:$($function.Name):$($function.EntitySet)") - } - - $xmlWriter.WriteStartElement('Parameters') - - $keys | Where-Object { $null -ne $_ } | ForEach-Object { - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $_.Name + ':Key') - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $_.TypeName $complexTypeMapping - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $_.Name) - $xmlWriter.WriteAttributeString('IsMandatory', 'true') - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - - $i = -1 - foreach ($parameter in $function.Parameters) - { - $i++ - - # for Instance actions, first parameter is Entity Set which we refer to using keys - if ($isInstanceAction -and ($i -eq 0)) - { - continue - } - - $xmlWriter.WriteStartElement('Parameter') - $xmlWriter.WriteAttributeString('ParameterName', $parameter.Name) - - $xmlWriter.WriteStartElement('Type') - $PSTypeName = Convert-ODataTypeToCLRType $parameter.Type - $xmlWriter.WriteAttributeString('PSType', $PSTypeName) - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('CmdletParameterMetadata') - $xmlWriter.WriteAttributeString('PSName', $parameter.Name) - if (-not $parameter.IsNullable) - { - $xmlWriter.WriteAttributeString('IsMandatory', 'true') - } - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - } - - # Add -Force parameter to Service Function cmdlets. - AddParametersNode $xmlWriter $null $null $null $null $true $false $complexTypeMapping - - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteEndElement() - - $xmlWriter -} - -######################################################### -# Saves CDXML for Service-level actions and functions -######################################################### -function SaveServiceActionsCDXML -{ - param - ( - [System.Collections.ArrayList] $GlobalMetadata, - [ODataUtils.ODataEndpointProxyParameters] $ODataEndpointProxyParameters, - [string] $Path, - [Hashtable] $complexTypeMapping, - [string] $progressBarStatus, - [string] $CmdletAdapter - ) - - $xmlWriter = New-Object System.XMl.XmlTextWriter($Path,$Null) - - if ($null -eq $xmlWriter) - { - throw $LocalizedData.XmlWriterInitializationError -f "ServiceActions" - } - - $xmlWriter = SaveCDXMLHeader $xmlWriter $ODataEndpointProxyParameters.Uri 'ServiceActions' 'ServiceActions' -CmdletAdapter $CmdletAdapter - - $actions = @() - $functions = @() - - foreach ($Metadata in $GlobalMetadata) - { - $actions += $Metadata.Actions | Where-Object { $_.EntitySet -eq [string]::Empty -or $null -eq $_.EntitySet } - $functions += $Metadata.Functions | Where-Object { $_.EntitySet -eq [string]::Empty -or $null -eq $_.EntitySet} - } - - if ($actions.Length -gt 0 -or $functions.Length -gt 0) - { - $xmlWriter.WriteStartElement('StaticCmdlets') - } - - # Save actions - if ($actions.Length -gt 0) - { - foreach ($action in $actions) - { - if ($null -ne $action) - { - $xmlWriter = SaveCDXMLAction $xmlWriter $action '' $false $null $complexTypeMapping - } - } - } - - # Save functions - if ($functions.Length -gt 0) - { - foreach ($function in $functions) - { - if ($null -ne $function) - { - $xmlWriter = SaveCDXMLFunction $xmlWriter $function '' $false $null $complexTypeMapping - } - } - } - - if ($actions.Length -gt 0 -or $functions.Length -gt 0) - { - $xmlWriter.WriteEndElement() - } - - $xmlWriter.WriteStartElement('CmdletAdapterPrivateData') - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'Namespace') - $xmlWriter.WriteString("$($EntitySet.Namespace)") - $xmlWriter.WriteEndElement() - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'Alias') - if (!$EntitySet.Alias) - { - $xmlWriter.WriteString("") - } - else - { - $xmlWriter.WriteString("$($EntitySet.Alias)") - } - $xmlWriter.WriteEndElement() - - $xmlWriter.WriteStartElement('Data') - $xmlWriter.WriteAttributeString('Name', 'CreateRequestMethod') - $xmlWriter.WriteString("Post") - $xmlWriter.WriteEndElement() - $xmlWriter.WriteEndElement() - - SaveCDXMLFooter $xmlWriter - - Write-Verbose ($LocalizedData.VerboseSavedServiceActions -f $Path) - - # Write progress bar message - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 60 20 1 1 -} - -######################################################### -# GenerateModuleManifest is a helper function used -# to generate a wrapper module manifest file. The -# generated module manifest is persisted to the disk at -# the specified OutputModule path. When the module -# manifest is imported, the following commands will -# be imported: -# 1. Get, Set, New & Remove proxy cmdlets for entity -# sets and singletons. -# 2. If the server side Odata endpoint exposes complex -# types, enum types, type definitions, then the corresponding -# client side proxy types imported. -# 3. Service Action/Function proxy cmdlets. -######################################################### -function GenerateModuleManifest -{ - param - ( - [System.Collections.ArrayList] $GlobalMetadata, - [String] $ModulePath, - [string[]] $AdditionalModules, - [Hashtable] $resourceNameMappings, - [string] $progressBarStatus - ) - - if($null -eq $progressBarStatus) { throw ($LocalizedData.ArguementNullError -f "progressBarStatus", "GenerateModuleManifest") } - - $NestedModules = @() - - foreach ($Metadata in $GlobalMetadata) - { - foreach ($entitySet in $Metadata.EntitySets) - { - $entitySetName = $entitySet.Name - if(($null -ne $resourceNameMappings) -and - $resourceNameMappings.ContainsKey($entitySetName)) - { - $entitySetName = $resourceNameMappings[$entitySetName] - } - else - { - $entitySetName = $entitySet.Type.Name - } - - $NestedModules += "$OutputModule\$($entitySetName).cdxml" - } - - foreach ($singleton in $Metadata.SingletonTypes) - { - $singletonName = $singleton.Name - $NestedModules += "$OutputModule\$($singletonName)" + "Singleton" + ".cdxml" - } - } - - New-ModuleManifest -Path $ModulePath -NestedModules ($AdditionalModules + $NestedModules) - - Write-Verbose ($LocalizedData.VerboseSavedModuleManifest -f $ModulePath) - - # Update the Progress Bar. - ProgressBarHelper "Export-ODataEndpointProxy" $progressBarStatus 80 20 1 1 -} - -######################################################### -# This is a helper function used to generate complex -# type definition from the metadata. -######################################################### -function GenerateComplexTypeDefinition -{ - param - ( - [System.Collections.ArrayList] $GlobalMetadata, - [string] $OutputModule, - [string] $typeDefinationFileName, - $normalizedNamespaces - ) - - $Path = "$OutputModule\$typeDefinationFileName" - $date = Get-Date - - $output = @" -# This module was generated by PSODataUtils on $date. - -`$typeDefinitions = @" -using System; -using System.Management.Automation; -using System.ComponentModel; - -"@ - # We are currently generating classes for EntityType & ComplexType - # definition exposed in the metadata. - - $complexTypeMapping = @{} - - # First, create complex type mappings for all metadata files at once - foreach ($metadata in $GlobalMetadata) - { - $typesToBeGenerated = $metadata.EntityTypes+$metadata.ComplexTypes - $enumTypesToBeGenerated = $metadata.EnumTypes - $typeDefinitionsToBeGenerated = $metadata.TypeDefinitions - - foreach ($entityType in $typesToBeGenerated) - { - if ($null -ne $entityType) - { - $entityTypeFullName = $entityType.Namespace + '.' + $entityType.Name - if(!$complexTypeMapping.ContainsKey($entityTypeFullName)) - { - $complexTypeMapping.Add($entityTypeFullName, $entityType.Name) - } - - # In short name we use Alias instead of Namespace - # We will add short name to $complexTypeMapping to enable Alias based search - if ($null -ne $entityType.Alias -and $entityType.Alias -ne "") - { - $entityTypeShortName = $entityType.Alias + '.' + $entityType.Name - if(!$complexTypeMapping.ContainsKey($entityTypeShortName)) - { - $complexTypeMapping.Add($entityTypeShortName, $entityType.Name) - } - } - } - } - - foreach ($enumType in $enumTypesToBeGenerated) - { - if ($null -ne $enumType) - { - $enumTypeFullName = $enumType.Namespace + '.' + $enumType.Name - if(!$complexTypeMapping.ContainsKey($enumTypeFullName)) - { - $complexTypeMapping.Add($enumTypeFullName, $enumType.Name) - } - - if (($null -ne $enumType.Alias -and $enumType.Alias -ne "") -or ($null -ne $metadata.Alias -and $metadata.Alias -ne [string]::Empty)) - { - if ($null -ne $enumType.Alias -and $enumType.Alias -ne "") - { - $alias = $enumType.Alias - } - else - { - $alias = $metadata.Alias - } - - $enumTypeShortName = $alias + '.' + $enumType.Name - if(!$complexTypeMapping.ContainsKey($enumTypeShortName)) - { - $complexTypeMapping.Add($enumTypeShortName, $enumType.Name) - } - } - } - } - - foreach ($typeDefinition in $typeDefinitionsToBeGenerated) - { - if ($null -ne $typeDefinition) - { - $typeDefinitionFullName = $typeDefinition.Namespace + '.' + $typeDefinition.Name - if(!$complexTypeMapping.ContainsKey($typeDefinitionFullName)) - { - $complexTypeMapping.Add($typeDefinitionFullName, $typeDefinition.Name) - } - - # In short name we use Alias instead of Namespace - # We will add short name to $complexTypeMapping to enable Alias based search - if ($typeDefinition.Alias) - { - $typeDefinitionShortName = $typeDefinition.Alias + '.' + $typeDefinition.Name - if(!$complexTypeMapping.ContainsKey($typeDefinitionShortName)) - { - $complexTypeMapping.Add($typeDefinitionShortName, $typeDefinition.Name) - } - } - } - } - } - - # Now classes definitions will be generated - foreach ($metadata in $GlobalMetadata) - { - $typesToBeGenerated = $metadata.EntityTypes+$metadata.ComplexTypes - $enumTypesToBeGenerated = $metadata.EnumTypes - $typeDefinitionsToBeGenerated = $metadata.TypeDefinitions - - if($typesToBeGenerated.Count -gt 0 -or $enumTypesToBeGenerated.Count -gt 0) - { - if ($null -ne $metadata.Alias -and $metadata.Alias -ne [string]::Empty) - { - # Check if this namespace has to be normalized in the .Net namespace/class definitions file. - $dotNetAlias = GetNamespace $metadata.Alias $normalizedNamespaces - - $output += @" - -namespace $($dotNetAlias) -{ -"@ - } - else - { - # Check if this namespace has to be normalized in the .Net namespace/class definitions file. - $dotNetNamespace = GetNamespace $metadata.Namespace $normalizedNamespaces - - $output += @" - -namespace $($dotNetNamespace) -{ -"@ - } - - foreach ($typeDefinition in $typeDefinitionsToBeGenerated) - { - if ($null -ne $typeDefinition) - { - Write-Verbose ($LocalizedData.VerboseAddingTypeDefinationToGeneratedModule -f $typeDefinitionFullName, "$OutputModule\$typeDefinationFileName") - - $output += "`n public class $($typeDefinition.Name)`n {" - $typeName = Convert-ODataTypeToCLRType $typeDefinition.BaseTypeStr $complexTypeMapping - $dotNetPropertyNamespace = GetNamespace $typeName $normalizedNamespaces $true - $output += "`n public $dotNetPropertyNamespace value;" - $output += @" -`n } -"@ - } - } - - $DotNETKeywords = ("abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "in", "int", "interface", "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "volatile", "while", "add", "alias", "ascending", "async", "await", "descending", "dynamic", "from", "get", "global", "group", "into", "join", "let", "orderby", "partial", "partial", "remove", "select", "set", "value", "var", "where", "yield") - - foreach ($enumType in $enumTypesToBeGenerated) - { - if ($null -ne $enumType) - { - $enumTypeFullName = $enumType.Namespace + '.' + $enumType.Name - - Write-Verbose ($LocalizedData.VerboseAddingTypeDefinationToGeneratedModule -f $enumTypeFullName, "$OutputModule\$typeDefinationFileName") - - $output += "`n public enum $($enumType.Name)`n {" - - $properties = $null - - for($index = 0; $index -lt $enumType.Members.Count; $index++) - { - $memberName = $enumType.Members[$index].Name - $formattedMemberName = [System.Text.RegularExpressions.Regex]::Replace($memberName, "[^0-9a-zA-Z]", "_"); - $memberValue = $enumType.Members[$index].Value - - if ($DotNETKeywords -contains $formattedMemberName) - { - # If member name is a known keyword in .Net, add '@' prefix - $formattedMemberName = '@' + $formattedMemberName - } - - if ($formattedMemberName -match "^[0-9]*$") - { - # If member name is a numeric value, add 'm_' prefix - $formattedMemberName = 'm_' + $formattedMemberName - } - - if ($memberName -ne $formattedMemberName -or $formattedMemberName -like '@*' -or $formattedMemberName -like 'm_*') - { - # Add Description attribute to preserve original value - $properties += "`n [Description(`"$($memberName)`")]$formattedMemberName" - } - else - { - $properties += "`n $memberName" - } - - if ($memberValue) - { - $properties += " = $memberValue," - } - else - { - $properties += "," - } - } - - $output += $properties - $output += @" -`n } -"@ - } - } - - foreach ($entityType in $typesToBeGenerated) - { - if ($null -ne $entityType) - { - $entityTypeFullName = $entityType.Namespace + '.' + $entityType.Name - - Write-Verbose ($LocalizedData.VerboseAddingTypeDefinationToGeneratedModule -f $entityTypeFullName, "$OutputModule\$typeDefinationFileName") - - if ($null -ne $entityType.BaseTypeStr -and $entityType.BaseTypeStr -ne '' -and $null -eq $entityType.BaseType) - { - # This class inherits from another class, but we were not able to find base class during Parsing. - # We'll make another attempt. - foreach ($referencedMetadata in $GlobalMetadata) - { - if ($null -ne ($baseType = $referencedMetadata.EntityTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $entityType.BaseTypeStr -or $_.Alias + "." + $_.Name -eq $entityType.BaseTypeStr }) -or - $null -ne ($baseType = $referencedMetadata.ComplexTypes | Where-Object { $_.Namespace + "." + $_.Name -eq $entityType.BaseTypeStr -or $_.Alias + "." + $_.Name -eq $entityType.BaseTypeStr })) - { - # Found base class - $entityType.BaseType = $baseType - break - } - } - } - - if($null -ne $entityType.BaseType) - { - if ((![string]::IsNullOrEmpty($entityType.BaseType.Alias) -and $entityType.BaseType.Alias -eq $entityType.Alias) -or - (![string]::IsNullOrEmpty($entityType.BaseType.Namespace) -and $entityType.BaseType.Namespace -eq $entityType.Namespace)) - { - $fullBaseTypeName = $entityType.BaseType.Name - } - else - { - # Base type can be defined in different namespace. For that reason we include namespace or alias. - if (![string]::IsNullOrEmpty($entityType.BaseType.Alias)) - { - # Check if derived alias has to be normalized. - $normalizedDotNetAlias = GetNamespace $entityType.BaseType.Alias $normalizedNamespaces - $fullBaseTypeName = $normalizedDotNetAlias + "." + $entityType.BaseType.Name - } - else - { - # Check if derived namespace has to be normalized. - $normalizedDotNetNamespace = GetNamespace $entityType.BaseType.Namespace $normalizedNamespaces - $fullBaseTypeName = $normalizedDotNetNamespace + "." + $entityType.BaseType.Name - } - } - - $output += "`n public class $($entityType.Name) : $($fullBaseTypeName)`n {" - } - else - { - $output += "`n public class $($entityType.Name)`n {" - } - - $properties = $null - - for($index = 0; $index -lt $entityType.EntityProperties.Count; $index++) - { - $property = $entityType.EntityProperties[$index] - $typeName = Convert-ODataTypeToCLRType $property.TypeName $complexTypeMapping - - if ($typeName.StartsWith($metadata.Namespace + ".")) - { - $dotNetPropertyNamespace = $typeName.Replace($metadata.Namespace + ".", "") - } - elseif ($typeName.StartsWith($metadata.Alias + ".")) - { - $dotNetPropertyNamespace = $typeName.Replace($metadata.Alias + ".", "") - } - else - { - $dotNetPropertyNamespace = GetNamespace $typeName $normalizedNamespaces $true - } - - $properties += "`n public $dotNetPropertyNamespace $($property.Name);" - } - - $output += $properties - $output += @" -`n } -"@ - } - } - - $output += "`n}`n" - } - } - $output += """@`n" - $output += "Add-Type -TypeDefinition `$typeDefinitions -IgnoreWarnings`n" - $output | Out-File -FilePath $Path - Write-Verbose ($LocalizedData.VerboseSavedTypeDefinationModule -f $typeDefinationFileName, $OutputModule) - - return $complexTypeMapping -} \ No newline at end of file diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/en-US/Microsoft.PowerShell.ODataUtilsStrings.psd1 b/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/en-US/Microsoft.PowerShell.ODataUtilsStrings.psd1 deleted file mode 100644 index 971b8333595f..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.ODataUtils/en-US/Microsoft.PowerShell.ODataUtilsStrings.psd1 +++ /dev/null @@ -1,55 +0,0 @@ -# Localized PSODataUtils.psd1 - -ConvertFrom-StringData @' -###PSLOC -SelectedAdapter=Dot sourcing '{0}'. -ArchitectureNotSupported=This module is not supported on your processor architecture ({0}). -ArguementNullError=Failed to generate proxy as '{0}' is pointing to $null in '{1}'. -EmptyMetadata=Read metadata was empty. Url: {0}. -InvalidEndpointAddress=Invalid endpoint address ({0}). Web response with status code '{1}' was obtained while accessing this endpoint address. -NoEntitySets=Metadata from URI '{0}' does not contain Entity Sets. No output will be written. -NoEntityTypes=Metadata from URI '{0}' does not contain Entity Types. No output will be written. -MetadataUriDoesNotExist=Metadata specified at the URI '{0}' does not exist. No output will be written. -InValidIdentifierInMetadata=Metadata specified at URI '{0}' contains an invalid Identifier '{1}'. Only valid C# identifiers are supported in the generated complex types during the proxy creation. -InValidMetadata=Failed to process metadata specified at URI '{0}'. No output will be written. -InValidXmlInMetadata=Metadata specified at URI '{0}' contains an invalid XML. No output will be written. -ODataVersionNotFound=Metadata specified at URI '{0}' does not contain the OData Version. No output will be written. -ODataVersionNotSupported=The OData version '{0}' specified in the metadata located at the URI '{1}' is not supported. Only OData versions between '{2}' and '{3}' are supported by '{4}' during proxy generation. No output will be written. -InValidSchemaNamespace=Metadata specified at URI '{0}' is invalid. NULL or Empty values are not supported for Namespace attribute in the schema. -InValidSchemaNamespaceConflictWithClassName=Metadata specified at URI '{0}' contains invalid Namespace {1} name, which conflicts with another type name. To avoid compilation error {1} will be changed to {2}. -InValidSchemaNamespaceContainsInvalidChars=Metadata specified at URI '{0}' contains invalid Namespace name {1} with a combination of dots and numbers in it, which is not allowed in .Net. To avoid compilation error {1} will be changed to {2}. -InValidUri=URI '{0}' is invalid. No output will be written. -RedfishNotEnabled=This version of Microsoft.PowerShell.ODataUtils doesn’t support Redfish, please run: ‘update-module Microsoft.PowerShell.ODataUtils’ to get Redfish support. -EntitySetUndefinedType=Metadata from URI '{0}' does not contain the Type for Entity Set '{1}'. No output will be written. -XmlWriterInitializationError=There was an error initiating XmlWriter for writing the {0} CDXML module. -EmptySchema=Edmx.DataServices.Schema node should not be null. -VerboseReadingMetadata=Reading metadata from uri {0}. -VerboseParsingMetadata=Parsing metadata... -VerboseVerifyingMetadata=Verifying metadata... -VerboseSavingModule=Saving output module to path {0}. -VerboseSavedCDXML=Saved CDXML module for {0} to {1}. -VerboseSavedServiceActions=Saved Service Actions CDXML module for to {0}. -VerboseSavedModuleManifest=Saved module manifest at {0}. -AssociationNotFound=Association {0} not found in Metadata.Associations. -TooManyMatchingAssociationTypes=Found {0} {1} associations in Metadata.Associations. Expected only one. -ZeroMatchingAssociationTypes=Navigation property {0} not found on association {1}. -WrongCountEntitySet=Expected one EntitySet for EntityType {0}, but got {1}. -EntityNameConflictError=Proxy creation is not supported when multiple EntitySets are mapped to the same EntityType. The metadata located at the URI '{0}' contains EntitySets '{1}' and '{2}' that are mapped to the same EntityType '{3}'. -VerboseSavedTypeDefinationModule=Saved Type definition module '{0}' at '{1}'. -VerboseAddingTypeDefinationToGeneratedModule=Adding Type definition for '{0}' to '{1}' module. -OutputPathNotFound=Could not find a part of the path '{0}'. -ModuleAlreadyExistsAndForceParameterIsNotSpecified=The directory '{0}' already exists. Use the -Force parameter if you want to overwrite the directory and files within the directory. -InvalidOutputModulePath=Path '{0}' specified to -OutputModule parameter does not contain the module name. -OutputModulePathIsNotUnique=Path '{0}' specified to -OutputModule parameter resolves to multiple paths in the file system. Provide a unique file system path to -OutputModule parameter. -OutputModulePathIsNotFileSystemPath=Path '{0}' specified to -OutputModule parameter is not a file system. Provide a unique file system path to -OutputModule parameter. -SkipEntitySetProxyCreation=CDXML module creation has been skipped for the Entity Set '{0}' because its Entity Type '{1}' contains a property '{2}' that collides with one of the default properties of the generated cmdlets. -EntitySetProxyCreationWithWarning=CDXML module creation for the Entity Set '{0}' succeeded but contains a property '{1}' in the Entity Type '{2}' that collides with one of the default properties of the generated cmdlets. -SkipEntitySetConflictCommandCreation=CDXML module creation has been skipped for the Entity Set '{0}' because the exported command '{1}' conflicts with the inbox command. -EntitySetConflictCommandCreationWithWarning=CDXML module creation for the Entity Set '{0}' succeeded but contains a command '{1}' that collides with the inbox command. -SkipConflictServiceActionCommandCreation=CDXML module creation has been skipped for the Service Action '{0}' because the exported command '{1}' conflicts with the inbox command. -ConflictServiceActionCommandCreationWithWarning=CDXML module creation for the Service Action '{0}' succeeded but contains a command '{1}' that collides with the inbox command. -AllowUnsecureConnectionMessage=The cmdlet '{0}' is trying to establish an Unsecure connection with the OData endpoint through the URI '{1}'. Either supply a secure URI to the -{2} parameter or use -AllowUnsecureConnection switch parameter if you intend to use the current URI. -ProgressBarMessage=Creating proxy for the OData endpoint at the URI '{0}'. -###PSLOC - -'@ \ No newline at end of file diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Windows-Full/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 deleted file mode 100644 index 4a48f4ec1e73..000000000000 --- a/src/Modules/Windows-Full/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 +++ /dev/null @@ -1,32 +0,0 @@ -@{ -GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59" -Author="Microsoft Corporation" -CompanyName="Microsoft Corporation" -Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="3.1.0.0" -PowerShellVersion="3.0" -CLRVersion="4.0" -CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide", - "Out-File", "Out-Printer", "Out-String", - "Out-GridView", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json", - "Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent", - "Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event", "New-Guid", - "New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertTo-Html", "ConvertFrom-StringData", - "Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression", - "Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture", - "Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData", - "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date", - "Start-Sleep", "Tee-Object", "Measure-Command", "Update-List", "Update-TypeData", "Update-FormatData", - "Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object", - "Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable", - "Clear-Variable", "Export-Clixml", "Import-Clixml", "Import-PowerShellDataFile", "ConvertTo-Xml", "Select-Xml", "Write-Debug", - "Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint", "Get-PSBreakpoint", - "Remove-PSBreakpoint", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack", - "Send-MailMessage", "Get-TraceSource", "Set-TraceSource", "Trace-Command", "Show-Command", "Unblock-File", "Get-FileHash", - "Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug", "Get-RunspaceDebug", "Wait-Debugger", - "ConvertFrom-String", "Convert-String" , "Get-Uptime", "New-TemporaryFile", "Get-Verb", "Format-Hex" -FunctionsToExport= "ConvertFrom-SddlString" -AliasesToExport= "CFS", "fhx" -NestedModules="Microsoft.PowerShell.Commands.Utility.dll","Microsoft.PowerShell.Utility.psm1" -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855960' -} diff --git a/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.Format.ps1xml b/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.Format.ps1xml deleted file mode 100644 index 09820341fbe3..000000000000 --- a/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.Format.ps1xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - ScheduledJobTrigger - - Microsoft.PowerShell.ScheduledJob.ScheduledJobTrigger - - - - - - 10 - left - - - - 15 - left - - - - 22 - left - - - - 23 - left - - - - 10 - left - - - - - - - Id - - - Frequency - - - At - - - DaysOfWeek - - - Enabled - - - - - - - - ScheduledJobDefinition - - Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition - - - - - - 10 - left - - - - 15 - left - - - - 15 - left - - - - 40 - left - - - - 10 - left - - - - - - - Id - - - Name - - - $_.JobTriggers.Count - - - Command - - - Enabled - - - - - - - - diff --git a/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.psd1 b/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.psd1 deleted file mode 100644 index a8ed0ab830de..000000000000 --- a/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.psd1 +++ /dev/null @@ -1,33 +0,0 @@ -@{ - -ModuleToProcess = 'Microsoft.PowerShell.ScheduledJob.dll' - -ModuleVersion = '1.1.0.0' - -GUID = '50cdb55f-5ab7-489f-9e94-4ec21ff51e59' - -Author = 'Microsoft Corporation' - -CompanyName = 'Microsoft Corporation' - -Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.' - -PowerShellVersion = '3.0' - -CLRVersion = '4.0' - -TypesToProcess = 'PSScheduledJob.types.ps1xml' - -FormatsToProcess="PSScheduledJob.Format.ps1xml" - -CmdletsToExport = 'New-JobTrigger', 'Add-JobTrigger', 'Remove-JobTrigger', - 'Get-JobTrigger', 'Set-JobTrigger', 'Enable-JobTrigger', - 'Disable-JobTrigger', 'New-ScheduledJobOption', 'Get-ScheduledJobOption', - 'Set-ScheduledJobOption', 'Register-ScheduledJob', 'Get-ScheduledJob', - 'Set-ScheduledJob', 'Unregister-ScheduledJob', 'Enable-ScheduledJob', - 'Disable-ScheduledJob' -AliasesToExport = @() -FunctionsToExport = @() - -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=390816' -} diff --git a/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.types.ps1xml b/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.types.ps1xml deleted file mode 100644 index f8822f2c9d6a..000000000000 --- a/src/Modules/Windows-Full/PSScheduledJob/PSScheduledJob.types.ps1xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Microsoft.Management.Infrastructure.CimInstance - - Microsoft.PowerShell.ScheduledJob.JobTriggerToCimInstanceConverter, Microsoft.PowerShell.ScheduledJob, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 - - - diff --git a/src/Modules/Windows-Core+Full/CimCmdlets/CimCmdlets.psd1 b/src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 similarity index 91% rename from src/Modules/Windows-Core+Full/CimCmdlets/CimCmdlets.psd1 rename to src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 index 049f89c7d10b..2a4048fc1182 100644 --- a/src/Modules/Windows-Core+Full/CimCmdlets/CimCmdlets.psd1 +++ b/src/Modules/Windows/CimCmdlets/CimCmdlets.psd1 @@ -1,18 +1,18 @@ @{ GUID="{Fb6cc51d-c096-4b38-b78d-0fed6277096a}" -Author="Microsoft Corporation" +Author="PowerShell" CompanyName="Microsoft Corporation" Copyright="Copyright (c) Microsoft Corporation. All rights reserved." -ModuleVersion="1.0.0.0" +ModuleVersion="7.0.0.0" +CompatiblePSEditions = @("Core") PowerShellVersion="3.0" -CLRVersion="4.0" RootModule="Microsoft.Management.Infrastructure.CimCmdlets" RequiredAssemblies="Microsoft.Management.Infrastructure.CimCmdlets.dll","Microsoft.Management.Infrastructure.Dll" +FunctionsToExport = @() CmdletsToExport= "Get-CimAssociatedInstance", "Get-CimClass", "Get-CimInstance", "Get-CimSession", "Invoke-CimMethod", "New-CimInstance","New-CimSession","New-CimSessionOption","Register-CimIndicationEvent","Remove-CimInstance", "Remove-CimSession","Set-CimInstance", "Export-BinaryMiLog","Import-BinaryMiLog" AliasesToExport = "gcim","scim","ncim", "rcim","icim","gcai","rcie","ncms","rcms","gcms","ncso","gcls" -FunctionsToExport = @() HelpInfoUri="https://go.microsoft.com/fwlink/?linkid=855946" } diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml b/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml similarity index 100% rename from src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml rename to src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml b/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml similarity index 100% rename from src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml rename to src/Modules/Windows/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml b/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml similarity index 96% rename from src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml rename to src/Modules/Windows/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml index 150f184c1648..dbe1d96dae01 100644 --- a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml +++ b/src/Modules/Windows/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml @@ -1,8 +1,8 @@  + - + + + + - 64 - - - - true - - 1048985600 - - + + +