├── CONTRIBUTING.md ├── Configuration.psd1 ├── LICENSE.md ├── README.md ├── about_tldr.help.txt ├── pages ├── Configuration │ ├── Add-MetadataConverter.md │ ├── ConvertFrom-Metadata.md │ ├── ConvertTo-Metadata.md │ ├── Export-Configuration.md │ ├── Export-Metadata.md │ ├── Get-Metadata.md │ ├── Get-StoragePath.md │ ├── Import-Configuration.md │ ├── Import-Metadata.md │ └── Update-Metadata.md ├── index.json └── tldr │ ├── Get-ShortHelp.md │ └── Set-TldrConfiguration.md ├── tldr.psd1 ├── tldr.psm1 └── update-index.ps1 /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contribution are very welcome! All of our `tldr` pages are written in Markdown and stored right here on GitHub. Just open an issue or send a pull request and we'll merge it as soon as possible. 4 | 5 | *Note*: when submitting a new command, don't forget to check if there's already a pull request in progress. 6 | 7 | ## Guidelines 8 | 9 | Note that `tldr` is focused on concrete, real-world examples. 10 | Here's a few guidelines to get started: 11 | 12 | 1. Focus on the 5 or 6 most common usages. It's OK if the page doesn't cover everything; that's what `Get-Help` is for. 13 | 2. Introduce parameters gradually, starting with the simplest commands and using progressively more complex examples. 14 | 3. Use short but descriptive variable names for the values, e.g. `$SourceFile` or `$Credentials`. 15 | 4. Do not include output in your examples. These should just be command lines. 16 | 5. Be specific to the command you're writing examples for. Avoid explaining general PowerShell concepts that could apply to any command -- we don't need examples that show how to sort, filter, or format the results! 17 | 6. When in doubt, keep in mind most readers are IT professionals, focus on the usefulness of the command, not teaching PowerShell. 18 | 7. Remember to keep descriptions **very** short so they don't wrap. Just explain _what_ the example does, don't explain how -- that _should_ be obvious. 19 | 20 | The best way to be consistent is to have a look at a few existing pages :) 21 | 22 | ## Quick Start 23 | 24 | If your command has existing help (comment or XML based) that shows up in Get-Help, you should be able to generate a page to get you started by just calling `tldr $YourCommand`. 25 | 26 | However, the generated pages practically never match our guidelines, because the typical examples from PowerShell help are simplistic and extremely verbose, and their descriptions are almost ridiculously repetitive. 27 | 28 | You will need to carefully edit the pages to get something useful, and drastically reduce the description (although the generated page will have only the first paragraph of the help descriptions, you will almost always need to shorten it a lot more). 29 | 30 | ## Markdown format 31 | 32 | We're borrowing the [platyPS markdown schema](https://github.com/PowerShell/platyPS/blob/master/platyPS.schema.md), although we don't generally care about all of the things in help, we want to collaborate on a single format. For `tldr`, the only parts that matter are as follows: 33 | 34 | 35 | ```posh 36 | # command-name 37 | 38 | ## Synopsis 39 | The command synopsis. Maximum 1 or 2 lines 40 | 41 | ## Examples 42 | 43 | ### -- EXAMPLE 1 -- 44 | A short description of the example 45 | 46 | ```powershell 47 | example code here 48 | ``` 49 | 50 | ### -- EXAMPLE 2 -- 51 | A short description of this example 52 | 53 | ```powershell 54 | example code here 55 | ``` 56 | 57 | ## Syntax 58 | 59 | ``` 60 | `Verb-Noun [-Switch1] [-Switch2] [[-Param1] ]` 61 | `Verb-Noun [-Switch1] [-Switch3]` 62 | 63 | ``` 64 | 65 | We recommend that user-provided values in examples use the `${Variable}` syntax for parameter values (with the curly braces) to allow clients to properly highlight them. For example: `Compress-Archive -Path ${FileList} -Destination ${OutputFolder}` 66 | 67 | One of the reasons for this format is that it's well suited for command-line clients that need to extract a single description and example. 68 | 69 | Note that the final `## Syntax` block can be missing, but should not be incomplete -- that is, you may leave off the full syntax (for commands that are available on the user's machine, we can generate that), but if you do include it, please include all the parameter sets just as PowerShell would output them from `Get-Command -Syntax` (this will be used if the command is not available on the user's box). 70 | 71 | ## Submitting a pull request 72 | 73 | TL;DR: fork, feature branch, commit, push, pull request. 74 | 75 | Detailed explanation: 76 | 77 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, 78 | and configure the remotes: 79 | 80 | ```bash 81 | # Clone your fork of the repo into the current directory 82 | git clone https://github.com//tldr 83 | # Navigate to the newly cloned directory 84 | cd tldr 85 | # Assign the original repo to a remote called "upstream" 86 | git remote add upstream https://github.com/poshcode/tldr 87 | ``` 88 | 89 | 2. If you cloned a while ago, get the latest changes from upstream: 90 | 91 | ```bash 92 | git checkout master 93 | git pull upstream master 94 | ``` 95 | 96 | 3. Create a new topic branch (sometimes they are called feature branches) off 97 | the main project development branch: 98 | 99 | ```bash 100 | git checkout -b feature/ 101 | ``` 102 | 103 | 4. Please use the following commit message format: 104 | `: type of change`. 105 | 106 | Examples: 107 | 108 | - `Get-ChildItem: Add page` 109 | - `Get-Content: Fix typo` 110 | - `Set-Content: Add -force example` 111 | - `Rename-Item: fix -passthru example` 112 | 113 | 7. Push your topic branch up to your fork: 114 | 115 | ```bash 116 | git push origin feature/ 117 | ``` 118 | 119 | 8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 120 | with a clear title and description. 121 | 122 | 9. Use Git's 123 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 124 | feature to tidy up your commits before making them public. 125 | In many cases it is better to squash commits before submitting a pull request. 126 | 127 | 10. If you are asked to amend your changes before they can be merged in, please 128 | use `git commit --amend` and force push to your remote feature branch. 129 | You _may_ also be asked to squash commits. 130 | 131 | 132 | ## Licensing 133 | 134 | `tldr` is under [MIT license](https://github.com/tldr-pages/tldr/blob/master/LICENSE.md). 135 | 136 | **IMPORTANT**: By submitting a patch, you agree to license your work under the 137 | same license as that used by the project. -------------------------------------------------------------------------------- /Configuration.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Colors = @{ 3 | Name = @{ Foreground = "Yellow" } 4 | Synopsis = @{ Foreground = "DarkYellow" } 5 | Description = @{} 6 | Code = @{ Foreground = "Cyan" } 7 | Variables = @{ Foreground = "DarkCyan" } 8 | } 9 | NoCache = $false 10 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Joel Bennett 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tldr 2 | 3 | The PoshCode *tldr* module is a collection of simplified and community-driven example pages to help you quickly the the gist of commands. 4 | 5 | ## What does tldr mean? 6 | 7 | TL;DR stands for "Too Long; Didn't Read". 8 | It has its origins in internet and email slang, where it is used to indicate parts of a text were skipped as too lengthy to read. 9 | Read more in the [TLDR article on Wikipedia](https://en.wikipedia.org/wiki/TL;DR). 10 | 11 | ## What is tldr? 12 | 13 | It's a help module for people like me... 14 | 15 | When I look at command help, I usually only care about two things: 16 | 17 | 1. The syntax 18 | 2. Some examples 19 | 20 | I'm always frustrated when a command has a lot of description text, causing the syntax block to scroll right off the top of the page in PowerShell. I'm also frustrated when there are pages and pages of examples that don't actually do anything useful (like, how could there be 74 lines of examples for Set-ACL without a single example that doesn't just copy the ACL from another file?). 21 | 22 | You are like me if you would prefer simple syntax blocks and "show me common usage" in your help. Something like this: 23 | 24 | ![tldr screenshot](http://raw.github.com/poshcode/tldr/gh-pages/images/screenshot.png) 25 | 26 | Or maybe you're just frustrated that in 74 lines of the `Get-Help Set-Acl -Examples` there's not a single example that doesn't just copy the ACL from one file to another. 27 | 28 | This module and repository is an ever-growing collection of high-quality real-world examples for the most common PowerShell commands, and some code to generate starter files from the help documentation already available with your commands. 29 | 30 | ### `tldr` is for you if you ever 31 | 32 | * Find a new module and want a quick overview? 33 | * Need a reminder about a command's syntax? 34 | * Can't remember how to pass that one parameter? 35 | * Can't remember the syntax for commands you only use once in a blue moon? 36 | 37 | ## Antecedents 38 | 39 | I've borrowed the idea from a similar linux project, [tldr-pages](http://tldr-pages.github.io/), and so I expect that once we have a little content we should be able to modify [their clients](https://github.com/tldr-pages/tldr#clients), including the interactive web client and android client to point at this repository and get PowerShell examples. 40 | 41 | ## Contributing 42 | 43 | - Your favourite command isn't covered? 44 | - You can think of more examples for an existing command? 45 | 46 | Contributions are most welcome! 47 | Have a look at the [contributing guidelines](CONTRIBUTING.md) 48 | and help us out! 49 | -------------------------------------------------------------------------------- /about_tldr.help.txt: -------------------------------------------------------------------------------- 1 | The PoshCode *tldr* module is a collection of simplified and community-driven example pages to help you quickly the the gist of commands. 2 | 3 | It's a help module for people like me: When I look at command help, I usually only care about two things. 4 | 5 | 1. The syntax 6 | 2. Some examples 7 | 8 | I'm always frustrated when a command has a lot of description text, causing the syntax block to scroll right off the top of the page in PowerShell, or when there are pages and pages of examples that repeat the same refrain, and don't exercise the use case I need. 9 | 10 | You are like me if you would prefer simple syntax blocks and "show me common usage" in your help. Something like this: 11 | 12 | ![tldr screenshot](http://raw.github.com/poshcode/tldr/gh-pages/images/screenshot.png) 13 | 14 | Or maybe you're just frustrated that in 74 lines of the `Get-Help Set-Acl -Examples` there's not a single example that doesn't just copy the ACL from one file to another. 15 | 16 | This module and repository is an ever-growing collection of high-quality real-world examples for the most common PowerShell commands, and some code to generate starter files from the help documentation already available with your commands. 17 | 18 | * Just found a new module and want a quick overview? 19 | * A little rusty on a command? 20 | * Can't remember how to pass that one parameter? 21 | * Can't remember the syntax for commands you only use once in a blue moon? 22 | 23 | ### `tldr` is for you. 24 | 25 | 26 | 27 | # tldr 28 | 29 | The PoshCode *tldr* module is a collection of simplified and community-driven example pages to help you quickly the the gist of commands. 30 | 31 | ## What does tldr mean? 32 | 33 | TL;DR stands for "Too Long; Didn't Read". 34 | It has its origins in internet and email slang, where it is used to indicate parts of a text were skipped as too lengthy to read. 35 | Read more in the [TLDR article on Wikipedia](https://en.wikipedia.org/wiki/TL;DR). 36 | 37 | ## What is tldr? 38 | 39 | Found a new module? Or just a little rusty on one? 40 | Or maybe you can't always remember the syntax for `Set-ACL` or `Get-OdbcDsn`? 41 | 42 | Maybe it doesn't help that the parameter explanations in `Get-Help Set-Acl -Full` start with this: 43 | 44 | ``` 45 | -AclObject 46 | Specifies an ACL with the desired property values. Set-Acl changes the ACL of item specified by the Path or InputObject 47 | parameter to match the values in the specified security object. 48 | 49 | You can save the output of a Get-Acl command in a variable and then use the AclObject parameter to pass the variable, or type 50 | a Get-Acl command. 51 | 52 | Required? true 53 | Position? 2 54 | Default value 55 | Accept pipeline input? true (ByValue) 56 | Accept wildcard characters? false 57 | ``` 58 | 59 | Or maybe you're just frustrated that in 74 lines of the `Get-Help Set-Acl -Examples` there's not a single example that doesn't just copy the ACL from one file to another. 60 | 61 | I figured people like me would prefer simple syntax blocks and "show me common usage" help pages. How about something like this: 62 | 63 | ![tldr screenshot](http://raw.github.com/poshcode/tldr/gh-pages/images/screenshot.png) 64 | 65 | So, this module and repository is an ever-growing collection of examples 66 | for the most common PowerShell commands, and some code to generate starter files from the help documentation already available for the command. 67 | 68 | ## Antecedents 69 | 70 | I've borrowed the idea from a similar linux project, [tldr-pages](http://tldr-pages.github.io/), and so I expect that once we have a little content you should be able to use [their clients](https://github.com/tldr-pages/tldr#clients), including the interactive web client and android client, with only slight modifications. 71 | 72 | ## Contributing 73 | 74 | - Your favourite command isn't covered? 75 | - You can think of more examples for an existing command? 76 | 77 | Contributions are most welcome! 78 | Have a look at the [contributing guidelines](https://github.com/tldr-pages/tldr/blob/master/CONTRIBUTING.md) 79 | and help us out! 80 | -------------------------------------------------------------------------------- /pages/Configuration/Add-MetadataConverter.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Add-MetadataConverter.md -------------------------------------------------------------------------------- /pages/Configuration/ConvertFrom-Metadata.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/ConvertFrom-Metadata.md -------------------------------------------------------------------------------- /pages/Configuration/ConvertTo-Metadata.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/ConvertTo-Metadata.md -------------------------------------------------------------------------------- /pages/Configuration/Export-Configuration.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Export-Configuration.md -------------------------------------------------------------------------------- /pages/Configuration/Export-Metadata.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Export-Metadata.md -------------------------------------------------------------------------------- /pages/Configuration/Get-Metadata.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Get-Metadata.md -------------------------------------------------------------------------------- /pages/Configuration/Get-StoragePath.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Get-StoragePath.md -------------------------------------------------------------------------------- /pages/Configuration/Import-Configuration.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Import-Configuration.md -------------------------------------------------------------------------------- /pages/Configuration/Import-Metadata.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Import-Metadata.md -------------------------------------------------------------------------------- /pages/Configuration/Update-Metadata.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/Configuration/Update-Metadata.md -------------------------------------------------------------------------------- /pages/index.json: -------------------------------------------------------------------------------- 1 | [{"Name":"Import-Configuration","Module":"Configuration","Updated":"2016-04-18T21:29:45Z"},{"Name":"Get-ShortHelp","Module":"tldr","Updated":"2016-04-18T21:29:45Z"}] 2 | -------------------------------------------------------------------------------- /pages/tldr/Get-ShortHelp.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/tldr/Get-ShortHelp.md -------------------------------------------------------------------------------- /pages/tldr/Set-TldrConfiguration.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoshCode/tldr/02b0487bf71d697b28a0e1a7eb6db9ba2d3f53ab/pages/tldr/Set-TldrConfiguration.md -------------------------------------------------------------------------------- /tldr.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | # Script module or binary module file associated with this manifest. 3 | RootModule = 'tldr.psm1' 4 | 5 | # Version number of this module. 6 | ModuleVersion = '2.0' 7 | 8 | # ID used to uniquely identify this module 9 | GUID = 'e345813b-77db-4fbe-ae0d-fc2ed6ef6cf3' 10 | 11 | # Author of this module 12 | Author = 'Joel Bennett' 13 | 14 | # Company or vendor of this module 15 | CompanyName = 'PoshCode.org' 16 | 17 | # Copyright statement for this module 18 | Copyright = '(c) 2015 Joel Bennett. All rights reserved.' 19 | 20 | # Description of the functionality provided by this module 21 | Description = 'Simplified, community-driven, example-centric help pages for PowerShell' 22 | 23 | # Minimum version of the Windows PowerShell engine required by this module 24 | # PowerShellVersion = '' 25 | 26 | # Name of the Windows PowerShell host required by this module 27 | # PowerShellHostName = '' 28 | 29 | # Minimum version of the Windows PowerShell host required by this module 30 | # PowerShellHostVersion = '' 31 | 32 | # Minimum version of Microsoft .NET Framework required by this module 33 | # DotNetFrameworkVersion = '' 34 | 35 | # Minimum version of the common language runtime (CLR) required by this module 36 | # CLRVersion = '' 37 | 38 | # Processor architecture (None, X86, Amd64) required by this module 39 | # ProcessorArchitecture = '' 40 | 41 | # Modules that must be imported into the global environment prior to importing this module 42 | # RequiredModules = @() 43 | 44 | # Assemblies that must be loaded prior to importing this module 45 | # RequiredAssemblies = @() 46 | 47 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 48 | # ScriptsToProcess = @() 49 | 50 | # Type files (.ps1xml) to be loaded when importing this module 51 | # TypesToProcess = @() 52 | 53 | # Format files (.ps1xml) to be loaded when importing this module 54 | # FormatsToProcess = @() 55 | 56 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 57 | # NestedModules = @() 58 | 59 | # Functions to export from this module 60 | FunctionsToExport = 'Get-ShortHelp','Set-TldrConfiguration', 'New-TldrDocument' 61 | 62 | # Cmdlets to export from this module 63 | # CmdletsToExport = '*' 64 | 65 | # Variables to export from this module 66 | # VariablesToExport = '*' 67 | 68 | # Aliases to export from this module 69 | AliasesToExport = 'tldr' 70 | 71 | # DSC resources to export from this module 72 | # DscResourcesToExport = @() 73 | 74 | # List of all modules packaged with this module 75 | # ModuleList = @() 76 | 77 | # List of all files packaged with this module 78 | # FileList = @() 79 | 80 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 81 | PrivateData = @{ 82 | PSData = @{ 83 | # Tags applied to this module. These help with module discovery in online galleries. 84 | Tags = @('tldr','man','help') 85 | 86 | # A URL to the license for this module. 87 | LicenseUri = 'https://GitHub.com/PoshCode/tldr/blob/master/LICENSE.md' 88 | 89 | # A URL to the main website for this project. 90 | ProjectUri = 'https://GitHub.com/PoshCode/tldr' 91 | 92 | # A URL to an icon representing this module. 93 | # IconUri = '' 94 | 95 | # ReleaseNotes of this module 96 | ReleaseNotes = 'Using platyPS schema (2.0) for markdown' 97 | } # End of PSData hashtable 98 | } # End of PrivateData hashtable 99 | 100 | # HelpInfo URI of this module 101 | # HelpInfoURI = '' 102 | 103 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 104 | # DefaultCommandPrefix = '' 105 | } 106 | -------------------------------------------------------------------------------- /tldr.psm1: -------------------------------------------------------------------------------- 1 | #requires -Module @{ModuleName="Configuration"; ModuleVersion="0.3"} 2 | 3 | $PagesUrl = "https://github.com/PoshCode/tldr/raw/master/pages/" 4 | $OnlineUrl = "https://github.com/PoshCode/tldr/blob/master/pages/" 5 | 6 | function GetStoragePath { 7 | Configuration\Get-StoragePath 8 | } 9 | 10 | function ImportConfiguration { 11 | #.Synopsis 12 | # Read the colors from the configuration file 13 | $Config = Configuration\Import-Configuration 14 | 15 | [bool]$script:NoCache = $Config.NoCache 16 | $script:NameColors = $Config.Colors.Name 17 | $script:SynopsisColors = $Config.Colors.Synopsis 18 | $script:DescriptionColors = $Config.Colors.Description 19 | $script:CodeColors = $Config.Colors.Code 20 | $script:VariableColors = $Config.Colors.Variables 21 | } 22 | 23 | function Set-TldrConfiguration { 24 | #.Synopsis 25 | # Change options in the configuration files 26 | #.Description 27 | # Imports your current configuration, changes the specified options, and stores them 28 | #.Example 29 | # Set-TldrConfiguration -NameColors @{ Foreground = "Blue" } 30 | # 31 | # Set the color used for printing section names to a blue foreground 32 | #.Example 33 | # Set-TldrConfiguration -CodeColors @{ Foreground = "Blue"; Background = "Black" } -VariableColors @{ Foreground = "DarkGray"; Background = "Black"} 34 | # 35 | # Set the colors used for printing code snippets 36 | param( 37 | # If set, local caching will be ignored, 38 | # results will always be fetched from the ${OnlineUrl} 39 | [bool]$NoCache, 40 | # A hashtable of Foreground and Background colors for the Name 41 | [hashtable]$NameColors, 42 | # A hashtable of Foreground and Background colors for the Synopsis 43 | [hashtable]$SynopsisColors, 44 | # A hashtable of Foreground and Background colors for the Description 45 | [hashtable]$DescriptionColors, 46 | # A hashtable of Foreground and Background colors for the Examples 47 | [hashtable]$CodeColors, 48 | # A hashtable of Foreground and Background colors to highlight Variables 49 | [hashtable]$VariableColors 50 | ) 51 | $Config = Configuration\Import-Configuration 52 | 53 | if($PSBoundParameters.ContainsKey("NoCache")) { 54 | $Config.NoCache = $NoCache 55 | $null = $PSBoundParameters.Remove("NoCache") 56 | } 57 | 58 | # Enumerate all those color values 59 | foreach($key in $PSBoundParameters.Keys) { 60 | foreach($color in $PSBoundParameters[$key].Keys) { 61 | if($color -notin "Foreground","Background") { 62 | throw "Invalid key '$Color' in ${key}: should be 'Foreground' or 'Background'" 63 | } 64 | if(!($PSBoundParameters[$key][$color] -as [ConsoleColor] -is [ConsoleColor])) { 65 | throw "Invalid value '$($PSBoundParameters[$key][$color])' for $key.$color, must be a ConsoleColor" 66 | } 67 | $Config.Colors[($key -replace "Colors$")] = $PSBoundParameters[$key] 68 | } 69 | } 70 | 71 | $Config | Configuration\Export-Configuration -Verbose 72 | 73 | # Update the script-scope variables without re-reading the config (again) 74 | [bool]$script:NoCache = $Config.NoCache 75 | $script:NameColors = $Config.Colors.Name 76 | $script:SynopsisColors = $Config.Colors.Synopsis 77 | $script:DescriptionColors = $Config.Colors.Description 78 | $script:CodeColors = $Config.Colors.Code 79 | $script:VariableColors = $Config.Colors.Variables 80 | } 81 | 82 | function Get-ShortHelp { 83 | #.Synopsis 84 | # Get the short example-based help for a command 85 | #.Example 86 | # tldr tldr 87 | # Invokes Get-ShortHelp via it's standard alias, on itself. 88 | #.Example 89 | # Get-Command -Module tldr | Get-ShortHelp 90 | # Invokes Get-ShortHelp for each of the commands in the tldr module. 91 | [CmdletBinding(DefaultParameterSetName="Text")] 92 | param( 93 | # The name of a command to fetch some examples for 94 | [Alias("Command")] 95 | [Parameter(Position=0, ParameterSetName="Text", ValueFromPipelineByPropertyName=$true)] 96 | [string]$Name = "*", 97 | 98 | # A Module name (to make the results more specific) 99 | [Parameter(ParameterSetName="Text", ValueFromPipelineByPropertyName=$true)] 100 | [string]$Module, 101 | 102 | # Show the web version of the file 103 | [Switch]$Online, 104 | 105 | # Don't consider (or create new) local copies 106 | # You can set the default for this option in the configuration using Set-TldrConfiguration 107 | [Switch]$NoCache = $script:NoCache, 108 | 109 | # If set, generates a new tldr file from the help 110 | [switch]$Regenerate 111 | ) 112 | begin { 113 | $index = 0 114 | } 115 | process { 116 | Write-Verbose "NoCache:$NoCache" 117 | Write-Progress "Fetching Help for $Name" "Loading help cache" 118 | 119 | # Cache initial data ... 120 | if(!$StoragePath) { 121 | Write-Verbose "Load StoragePath" 122 | $Script:StoragePath = GetStoragePath 123 | } 124 | if(!$HelpCache){ 125 | Write-Progress "Fetching Help for $Name" "No active cache - loading from ${PagesUrl}index.json" 126 | Write-Verbose "Load online help index" 127 | $Script:HelpCache = Invoke-RestMethod ${PagesUrl}index.json 128 | } 129 | 130 | $null = $PSBoundParameters.Remove("Regenerate") 131 | $null = $PSBoundParameters.Remove("NoCache") 132 | $null = $PSBoundParameters.Remove("Online") 133 | Write-Progress "Fetching Help for $Name" "Testing if command exists locally" 134 | $Command = Resolve-Command @PSBoundParameters 135 | 136 | # Find the command if it's available on the local system 137 | $FullName = $Name 138 | 139 | if($Command) { 140 | $Name = $Command.Name 141 | $Module = $Command.ModuleName 142 | } else { 143 | Write-Verbose "Command Not Found (checking online index anyway)" 144 | # If we didn't find the command, we can still show help 145 | # We support two syntaxes, because Get-Command does: 146 | # Get-ShortHelp Get-Service -Module Microsoft.PowerShell.Management 147 | # Get-ShortHelp Microsoft.PowerShell.Management\Get-Service 148 | $Module, $Name = $Name -split "[\\/](?=[^\\/]+$)",2 149 | if(!$Name) { 150 | $Name = $Module 151 | $Module = $Null 152 | } 153 | } 154 | 155 | # TODO: if the online version is (newer?), fetch that one 156 | $Best = $HelpCache | Where { $_.Name -eq $Name -and ($Module -eq $Null -or $Module -eq $_.Module)} 157 | if($Best) { 158 | Write-Verbose "Found online help for $($Best.Module)/$($Best.Name) last updated $($Best.Updated)" 159 | } 160 | 161 | if($Online) { 162 | if($Best) { 163 | Write-Progress "Fetching Help for $Name" "Loading online version of help into browser" 164 | foreach($page in $Best) { 165 | Start-Process "${OnlineUrl}$($page.Module)/$($page.Name).md" 166 | } 167 | return 168 | } else { 169 | Write-Error "There's no online documentation for $Module\$Name" 170 | return 171 | } 172 | } 173 | 174 | # Use syntax from the actual command, if available 175 | if($Command) { 176 | Write-Verbose "Loading syntax from PowerShell" 177 | $Syntax = Get-Command $Command -Syntax 178 | } 179 | if(($index++) -and !$passthru) { 180 | Write-Host "- - - -" 181 | } 182 | 183 | if(!$Regenerate -and (!$NoCache -and ($HelpFile = Find-TldrDocument $Name $Module))) { 184 | # If they did not Module-qualify the name, and the command doesn't exist locally 185 | # It's possible that we have multiple matches online or locally or both 186 | foreach($filePath in @($HelpFile)) { 187 | Write-Verbose "Found $filePath for $Module\$Name" 188 | # Write the output right now, before we try to update ... 189 | Write-Help -Name $Name -Path $HelpFile -Syntax $Syntax 190 | 191 | # If it's ok to cache the latest, we might want to update 192 | if($Best) { 193 | $FileInfo = Get-Item $FilePath 194 | foreach($page in @($Best)) { 195 | if($page.Module -eq $Module -or $page.Module -eq $FileInfo.Directory.Name) { 196 | # FINALLY! If the online version is newer, update now 197 | if($FileInfo.LastWriteTime -lt $Best.Updated) { 198 | $Url ="${PagesUrl}$($Best.Module)/($Best.Name).md" 199 | Write-Warning "Newer help content found online, updating $filePath with $Url" 200 | Invoke-WebRequest $Url -OutFile $filePath -ErrorAction Stop 201 | } 202 | } 203 | } 204 | } 205 | } 206 | return 207 | } 208 | 209 | # If we don't have a local copy (or we're ignoring it) but there is one online... 210 | if(!$Regenerate -and (($NoCache -or !$HelpFile) -and $Best)) { 211 | Write-Progress "Fetching Help for $Name" "Loading latest help file from remote server" 212 | 213 | foreach($page in @($Best)) { 214 | if($NoCache) { 215 | $HelpFile = [IO.Path]::GetTempFileName() 216 | } else { 217 | $null = mkdir (join-Path $Script:StoragePath $Page.Module) -force 218 | $HelpFile = Join-Path ${Script:StoragePath} "$($Page.Module)\$($Page.Name).md" 219 | } 220 | $Url = "${PagesUrl}$($Page.Module)/$($Page.Name).md" 221 | Write-Verbose "NoCache:$NoCache - Downloading $Url for to $HelpFile" 222 | Invoke-WebRequest $Url -OutFile "$HelpFile" -ErrorAction Stop 223 | Write-Help -Name $Name -Path $HelpFile -Syntax $Syntax 224 | if($NoCache) { 225 | Remove-Item $HelpFile 226 | } 227 | } 228 | return 229 | } 230 | 231 | # Found the real help, and they asked to regenerate or there's no HelpFile 232 | if(($Help = Get-Help $Command) -and ($Regenerate -or !$HelpFile)) { 233 | $HelpFile = New-TldrDocument $Command 234 | Write-Warning "Generated tldr page for $Name from built-in help:" 235 | Write-Warning "$HelpFile" 236 | 237 | Write-Help -Name $Name -Path $HelpFile -Syntax $Syntax 238 | return 239 | } 240 | 241 | Write-Error "Cannot find help for $Name!" 242 | } 243 | } 244 | 245 | function Resolve-Command { 246 | [OutputType([System.Management.Automation.CommandInfo])] 247 | [CmdletBinding()] 248 | param( 249 | # The name of a command to fetch some examples for 250 | [Alias("Command")] 251 | [string]$Name = "*", 252 | 253 | # A Module name to filter the results 254 | [string]$Module 255 | ) 256 | $Command = Get-Command @PSBoundParameters -Type "Alias", "Function", "Filter", "Cmdlet", "ExternalScript", "Script", "Workflow", "Configuration" 257 | if($Command -is [System.Management.Automation.AliasInfo]) { 258 | $Command = Get-Command $Command.Definition 259 | } 260 | return $Command 261 | } 262 | 263 | function Find-TldrDocument { 264 | param( 265 | # The name of a command to fetch some examples for 266 | [Alias("Command")] 267 | [string]$Name = "*", 268 | 269 | # A Module name to filter the results 270 | [string]$Module 271 | ) 272 | 273 | # And append that to the search path if it exists 274 | if($Module) { 275 | $local:StoragePath = Join-Path $StoragePath $Module 276 | if(Test-Path $local:StoragePath) { 277 | Remove-Variable StoragePath -Scope Local 278 | } 279 | } 280 | 281 | Get-ChildItem $StoragePath -Recurse -Filter "${Name}.md" | Convert-Path 282 | } 283 | 284 | function New-TldrDocument { 285 | #.Synopsis 286 | # Generates a new tldr help document from the command's built-in help. Called automatically by tldr when custom-written help doesn't already exist. 287 | #.Description 288 | # Generates a new tldr help document from the command's built-in help, using just the synopsys and snippets from the examples. 289 | # 290 | # Note that only the lines which appear to be commands, plus the first line of commentary are actually pulled from the examples. Depending on how well the help was written, examples may need a lot of editing to make them useful with that little commentary. 291 | #.Example 292 | # Get-Command Get-ShortHelp | New-TldrDocument 293 | # 294 | # Regenerates the short tldr help file for the Get-ShortHelp command 295 | #.Example 296 | # Get-Command -Module Configuration | New-TldrDocument .\pages 297 | # 298 | # Regenerates the short tldr help files for all the commands in the Configuration module into the .\pages\Configuration folder, organized such that you can edit them and upload them to the tldr project. 299 | 300 | [CmdletBinding(SupportsShouldProcess=$true)] 301 | param( 302 | # The command we're generating help for 303 | [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)] 304 | [System.Management.Automation.CommandInfo]$CommandInfo, 305 | 306 | # The folder to generate tldr help files into (will be grouped into subfolders by module) 307 | $StoragePath 308 | ) 309 | begin { 310 | if(!$StoragePath) { $Script:StoragePath = GetStoragePath } 311 | 312 | $prefix = "PS C:\\>" # Stupid prefix is sometimes in the code, sometimes not 313 | } 314 | process { 315 | $ErrorActionPreference = "Stop" 316 | $Help = Get-Help $CommandInfo 317 | 318 | $Module = $Help.ModuleName 319 | $Name = $Help.Name 320 | $Synopsis = $Help.Synopsis 321 | $Syntax = $Help.Syntax | Out-String -stream -width 1e4 | Where-Object { $_ } 322 | 323 | $local:ModulePath = Join-Path $StoragePath $Module 324 | $HelpFile = Join-Path $ModulePath "${Name}.md" 325 | 326 | if($PSCmdlet.ShouldProcess("Generated the file '$($HelpFile)'", 327 | "Generate the file '$($HelpFile)'?", 328 | "Generating Help Files")) { 329 | Write-Progress "Generating HelpFile:" "$HelpFile" 330 | $null = mkdir $ModulePath -force 331 | 332 | "# $Name`n`n" | Out-File $HelpFile 333 | "## Synopsis`n`n$Synopsis`n" | Out-File $HelpFile -Append 334 | "## Examples`n" | Out-File $HelpFile -Append 335 | 336 | $index = 1 337 | if($Help.Examples.example.Count -eq 0) { 338 | Write-Warning "No examples in help for $Name" 339 | } 340 | foreach($example in $Help.Examples.example) { 341 | $code = $example.code -split "[\r\n]+" 342 | # We always want the first line, *maybe* other lines with the prompt prefix 343 | $code = @($code[0]) + @($code[1..1e3] -match $prefix) -replace $prefix 344 | 345 | # We really aren't interested in those long-winded explanations, but keep the first paragraph 346 | 347 | $intro = if([string]::IsNullOrWhiteSpace($example.introduction.Text) -or $example.introduction.Text.Trim() -eq 'PS C:\>') { 348 | @($example.remarks[0].Text -split '(?<=\.) ')[0] 349 | } else { 350 | $example.introduction.Text 351 | } 352 | "### EXAMPLE {0}`n" -f $index++ | Out-File $HelpFile -Append 353 | "$intro`n" | Out-File $HelpFile -Append 354 | "``````powershell`n$code`n```````n" | Out-File $HelpFile -Append 355 | } 356 | 357 | "`n## Syntax`n" | Out-File $HelpFile -Append 358 | foreach($syn in $syntax) { 359 | "``````powershell`n$syn`n```````n" | Out-File $HelpFile -Append 360 | } 361 | } 362 | 363 | Get-Item $HelpFile 364 | } 365 | end { 366 | Write-Warning "Please consider editing the generated file(s) to match the tldr guidelines and sharing it for others to use.`nSee also: Get-Help about_tldr`n`n" 367 | } 368 | } 369 | 370 | function Write-Help { 371 | #.Synopsis 372 | # Output Markdown-formatted tldr help files to the host, colorfully 373 | #.Notes 374 | # Changed in 2.0 to use the platyPS schema 375 | [CmdletBinding()] 376 | param( 377 | [Parameter()] 378 | [Alias("Name")] 379 | $CommandName, 380 | 381 | [Parameter()] 382 | [Alias("File","Path","PSPath")] 383 | $HelpFile, 384 | 385 | [Parameter()] 386 | $Syntax = $(Get-Command $CommandName -Syntax) 387 | ) 388 | ImportConfiguration 389 | 390 | # Syntax: 391 | # $Syntax| Out-String -stream -width 1e4 | Where-Object { $_ } 392 | Write-Debug "HelpFile: $HelpFile" 393 | 394 | $help = Get-Content $HelpFile -Raw 395 | 396 | ## indent all the code (we want to print it that way anyway) 397 | $help = [regex]::replace($help,'(?s)\n```.*?\n```',{ $args[0] -replace '(?m)(^(?!```).*)',' $1' }) 398 | 399 | # foreach command name (matches '# Command Name' without throwing it out 400 | foreach($command in $help -split '(?m)^(?=#\s+.*$)') { 401 | $Name = [regex]::Match($command,'^#\s+(.*)(?m:$)').Groups[1].Value 402 | 403 | if(!$CommandName -or $CommandName -eq $Name) { 404 | Write-Host "`n$Name" @NameColors 405 | # split each section on the headline: '## whatever' 406 | foreach($helpBlock in $command -split '(?m)^(?=##\s+.*$)') { 407 | $global:match = [regex]::Match($helpBlock,'(?m)^##\s+(?.*?)$').Groups['name'].Value 408 | $blockName = $match 409 | switch($blockName.trim()) { 410 | "Synopsis" { 411 | Write-Host " " ($helpBlock -replace "^(.*?)(?m:$)").Split(("`r","`n")).where{$_}[0] @SynopsisColors 412 | } 413 | "Examples" { 414 | Write-Host "`nExamples:".ToUpper() @NameColors 415 | # We throw out the "EXAMPLE" junk header 416 | foreach($example in $helpBlock -split '(?m)^###\s+.*$') { 417 | if($example -match '(?s)(?.*)```(?:powershell)?(?.*)```(?.*)') { 418 | $intro = if(![string]::IsNullOrWhiteSpace($matches['intro'])) { 419 | $matches['intro'] 420 | } elseif($matches['remarks']) { 421 | $matches['remarks'] 422 | } 423 | 424 | Write-Host ($intro -split "\n").where{![string]::IsNullOrWhiteSpace($_)}[0] @DescriptionColors 425 | $matches['code'] | Write-Code 426 | } 427 | } 428 | } 429 | default { 430 | Write-Debug "$($helpBlock.Split(@("`r","`n")).where{$_}[0]) not wanted" 431 | } 432 | } 433 | } 434 | } 435 | } 436 | 437 | if($Syntax) { 438 | Write-Host "Syntax:".ToUpper() @NameColors 439 | $Syntax | Out-String -stream -width 1e4 | Where-Object { $_ } | Write-Code -VariablePattern "(?=\<.*?\>)|(?<=\<.*?\>)" 440 | } 441 | } 442 | 443 | filter Write-Code { 444 | [CmdletBinding()] 445 | param( 446 | [Parameter(ValueFromPipeline)] 447 | $Code, 448 | 449 | $VariablePattern = "(?=\$\{.*?\})|(?<=\$\{.*?\})|(?=\$\w+)|(?<=\$\w+)" 450 | ) 451 | $Code = ($Code -split "[\r\n]+").where{![string]::IsNullOrWhiteSpace($_)} -join "`n" 452 | 453 | $Code = $Code -replace '(?m)^( {4})?PS C:\\>(.*)', '$1$2' 454 | $Code = $Code -replace '(?m)^(\S+.*)', ' $1' 455 | 456 | switch -regex ($Code -split $VariablePattern) { 457 | $VariablePattern { Write-Host $_ @VariableColors -NoNewLine} 458 | default { Write-Host $_ @CodeColors -NoNewLine} 459 | } 460 | Write-Host "`n" 461 | } 462 | 463 | Set-Alias tldr Get-ShortHelp 464 | -------------------------------------------------------------------------------- /update-index.ps1: -------------------------------------------------------------------------------- 1 | push-location $PSScriptRoot 2 | &{ 3 | Get-ChildItem (Join-Path $PSScriptRoot pages) -File -Recurse -Filter *.md | 4 | Select-Object @{name="Name"; expr={$_.BaseName}}, 5 | @{name="Module"; expr={$_.Directory.Name}}, 6 | @{name="Updated"; expr={ 7 | $last = [DateTimeOffset]$(git log -n 1 --pretty=format:%ai HEAD -- $_.FullName) 8 | # To shrink this, remove useless nanoseconds, and always use Zulu time: 9 | ("{0:o}" -f $last.UtcDateTime) -replace "\.0000000" 10 | }} 11 | } | ConvertTo-Json -Compress | Set-Content (Join-Path (Join-Path $PSScriptRoot pages) index.json) 12 | 13 | pop-location --------------------------------------------------------------------------------