Notices: This section not yet converted to new layout. Download stats are rolling back out.

posh-dynargs

0.1.0.5

Package test results are passing.

This package was approved by moderator gep13 on 7/4/2019.

posh-dynargs

A PowerShell module that enables dynamic tab completion for project-specific commands.

posh-dynargs enables tab completion for commands whose arguments change depending on the current directory. It also generates helper functions for those commands, adding capabilities such as logging, timing, and audio alerts.

To install posh-dynargs, run the following command from the command line or from PowerShell:

C:\> choco install poshdynargs

To upgrade posh-dynargs, run the following command from the command line or from PowerShell:

C:\> choco upgrade poshdynargs

Files

Hide
  • src\en-US\about_posh-dynargs.help.txt Show
    TOPIC
        posh-dynargs
    
    SHORT DESCRIPTION
        posh-dynargs enables tab completion for commands whose arguments change
        depending on the current directory. It also generates helper functions for
        those commands, adding capabilities such as logging, timing, and audio
        alerts.
    
    LONG DESCRIPTION
        Many projects rely on commands like build, ci, make, test, etc. Each of
        these commands has its own set of possible arguments, often dozens of them,
        and their usage and interface can vary between projects and certainly
        between organizations.
    
        posh-dynargs makes tab completion possible for these disparate commands.
        Possible arguments are determined on the fly, so even when arguments change
        or new ones are added, they are instantly tab completable.
        See TAB COMPLETION.
    
        Additionally, a helper function of the same name is generated for each
        command. Apart from making it possible to invoke the command without the
        leading .\ or ./, it enables additional features such as logging the output.
        See HELPER FUNCTIONS.
    
        A project that wants to use posh-dynargs only has to include a file called
        .argument-completer-registry.json at the root of the project. This file is
        a registry that describes the completable commands, how to find their
        arguments, and how to customize the helper functions.
        See ARGUMENT COMPLETER REGISTRY.
    
    TAB COMPLETION
        To enable tab completion for a project-specific command, add it to the
        argument completer registry, including a few hints regarding where to find
        and parse the arguments to be completed.
    
        KNOWN SCRIPT TYPES
        posh-dynargs knows how to extract arguments from Cake scripts, PSake
        scripts, and Make files. In those cases, you only have to register the
        location and type of the script. posh-dynargs figures out the rest.
    
        For a Cake script, for example, the registry entry might look like this:
        {
            "name": "build",
            "argsPath": "./build/ci.cake",
            "type": "cake",
            "funcDefaults": {
                "logOutput": true,
                "talk": true,
            }
        }
    
        This entry tells posh-dynargs that the command to invoke is "build", and
        it is dealing with a Cake script that lives at ./build/ci.cake. It will
        parse the script for possible arguments the second you enter build{TAB}. On
        a reasonably performant computer, this is nearly instantaneous.
    
        CUSTOM SCRIPTS
        You likely have other scripts that posh-dynargs doesn't know how to parse.
        In such a case, register it as a custom command and provide a regex to guide
        posh-dynargs to the correct arguments.
    
        Here's a sample registry entry for a custom command called "scrape":
        {
            "name": "scrape",
            "argsPath": "./tools/scrape.ps1",
            "type": "custom",
            "regex": "^Task ([A-Z][^ ]+)"
        },
    
        BINARY COMMANDS
        What about binary commands that aren't parsable? Those commands typically
        ship with a switch like --help from which we can extract the arguments to
        complete. posh-dynargs can execute this help command and cache the help
        text to make future tab completion faster (and safer).
    
        Sample registry entry for an unparsable binary command:
        {
            "name": "test",
            "helpCommand": "--help",
            "type": "custom",
            "regex": "(--[a-z]+=?)"
        }
    
        DANGER, WILL ROBINSON
        Executing the "help command" adds a security risk to posh-dynargs, because
        we leave the relative safety of simply parsing text and begin executing
        code. The following precautions have been taken to help mitigate this risk:
    
        * Only allow executing the registered command
        * Only allow executing a whitelisted set of help arguments:
           * help
           * --help
           * -h
           * --list
           * -l
           * /?
           * -?
        * Additionally, before executing the command, the user is prompted with a
        frightening message, to which they must respond "yes", or the expression
        will not be executed:
    
            >>> DANGER! OK to run `./test --help`? (yes/no) :
    
        So where do we add these argument completer registry entries? You will
        create a file at the root of your project called
        .argument-completer-registry.json. See ARGUMENT COMPLETER REGISTRY.
    
        LEADING DASH POWERSHELL BUG
        As of January, 2019, there is a PowerShell bug that prevents arguments with
        a leading dash from being completed. E.g. "build -stuff" would fail. The
        workaround used by posh-dynargs is to preface those arguments with a
        leading colon ":". Rather than running "build -stuff", you would run
        "build :-stuff". The helper function then strips off the leading colon.
        This is undesirable. Hopefully the bug will be fixed soon.
    
        ISSUE: https://github.com/PowerShell/PowerShell-Docs/issues/1979
    
    HELPER FUNCTIONS
        A helper function of the same name is generated for for each command. Apart
        from making it possible to invoke the command without the leading .\ or ./,
        it enables the following additional features:
    
        * Logging of command output.
        * An audible prompt when the command finishes.
           Great for long-running commands.
        * Timing the command.
    
        Each of these features is optional and configurable in the argument
        completer registry, using options supplied to funcDefaults.
        See ARGUMENT COMPLETER REGISTRY for the full syntax.
    
    ARGUMENT COMPLETER REGISTRY
        The argument completer file is called .argument-completer-registry.json and
        should be placed at the root of the project.
    
        This JSON file is a registry of the project's completable commands. It
        controls how each command's arguments are discovered. It also configures
        options for the generated helper functions.
    
        SAMPLE .argument-completer-registry.json
        {
            "completableCommands": [
                {
                    "name": "build",
                    "argsPath": "./build/ci.cake",
                    "type": "cake",
                    "funcDefaults": {
                        "logOutput": true,
                        "talk": true,
                        "useTimer": true,
                        "useGlobal": false,
                    }
                },
                {
                    "name": "scrape",
                    "argsPath": "./tools/scrape.ps1",
                    "type": "custom",
                    "regex": "^Task ([A-Z][^ ]+)"
                },
                {
                    "name": "test",
                    "helpCommand": "--help",
                    "type": "custom",
                    "regex": "(--[a-z]+=?)"
                }
            ]
        }
    
        DESCRIPTION OF ATTRIBUTES
    
        name:        The name of the command to be completed.
    
        argsPath:    The path to the script containing the arguments to be parsed.
    
        helpCommand: For compiled tools. Parse the arguments from the tool's help
                     output. Supply something like "--help" or "-h".
                     The help text output will be cached in $env:TEMP.
    
        type:        The type of script being parsed. Natively-supported types are
                     "cake", "make", and "psake".
    
        regex:       (For custom types) The regular expression used to extract the
                     task names from "argsPath" or the output of "helpCommand".
                     The first capturing group must contain the task name.
    
        funcDefaults:  Sets defaults for the generated helper function.
    
            logOutput: true or false. If true, log command output to the TEMP
                       directory. Note that you will lose color output.
    
            talk:      true or false. If true, audibly communicate a failed or
                       successful command invocation.
    
            useTimer:  true or false. If true, display elapsed time when the
                       command finishes.
    
            useGlobal: true or false. If true, invoke the command found in your
                       PATH rather than the local directory.
    
        DISCUSSION
        In the above file sample we can assume that there is an executable .\build,
        a .\scrape, and a .\test in the same directory alongside
        .argument-completer-registry.json. This simple registry tells the argument
        completer where the actual script is located and how to parse it.
    
        For example, the "build" command above will execute the Cake script located
        in ./build/ci.cake. The "type" is listed as "cake". The argument completer
        knows how to parse Cake files and extract the arguments, which are then
        used for tab completion.
    
        When you are in this directory and you type build, PowerShell will find the
        registered argument completer and invoke the associated script block. The
        script block will load ./.argument-completer-registry.json and find the
        "build" command. Then it parses the Cake script using the path provided in
        the .json file, and uses that to provide tab completion. This happens every
        time you run the build command, but it happens extremely fast. There is
        typically no lag.
    
    USAGE
        You need to import the posh-dynargs module into your PowerShell session to
        use it. This is done with the command "Import-Module posh-dynargs". Once
        imported, run "Add-PoshDynargsToProfile" so that posh-dynargs is imported
        every time PowerShell starts.
    
    PERFORMANCE
        posh-dynargs piggybacks on top of the PowerShell prompt. Every time prompt
        is invoked, Register-LocalArgumentCompleters is also invoked.
    
        Register-LocalArgumentCompleters will process .argument-completer-registry.json
        if it exists. This involves registering each argument completer and creating
        a helper function. If you experience a slowdown, it will be here. Once
        registered, the process will not repeat until the directory changes.
    
        To enable timing of the Register-LocalArgumentCompleters function, set
        $PoshDynargsSettings.EnableTiming = $true
    
    UNDER THE HOOD
        As noted in PERFORMANCE, posh-dynargs works by attaching itself to
        PowerShell's prompt function. Every time the prompt function is invoked,
        a so is the main posh-dynargs function.
    
        How does this work?
        (I'm not happy with the current implementation, and it's likely to change.)
        If you're using posh-git, the function is attached to and executed with
        $GitPromptSettings.DefaultPromptPrefix. If you aren't using posh-git, the prompt is replaced with a custom one
        which just so happens to run Register-LocalArgumentCompleters.
    
    BASED ON WORK BY:
        Ty Walls, https://www.tygertec.com/
        Keith Dahlby, http://solutionizing.net/
        Mark Embling, http://www.markembling.info/
        Jeremy Skinner, http://www.jeremyskinner.co.uk/
    
  • src\posh-dynargs.psd1 Show
    @{
    
    # Script module or binary module file associated with this manifest.
    ModuleToProcess = 'posh-dynargs.psm1'
    
    # Version number of this module.
    ModuleVersion = '0.1.0.5'
    
    # ID used to uniquely identify this module
    GUID = 'dab0538d-eaf9-4e2a-a924-e1781007ac00'
    
    # Author of this module
    Author = 'Ty Walls and contributors'
    
    # Copyright statement for this module
    Copyright = '(c) 2019 Ty Walls and contributors'
    
    # Description of the functionality provided by this module
    Description = 'posh-dynargs enables tab completion for commands whose arguments change depending on the current directory, e.g. a project-specific `build` command. It also generates helper functions for those commands, adding capabilities such as logging, timing, and audible alerts.'
    
    # Minimum version of the Windows PowerShell engine required by this module
    PowerShellVersion = '5.0'
    
    # Functions to export from this module
    FunctionsToExport = @(
        'Register-LocalArgumentCompleters',
        'Add-PoshDynargsToProfile'
    )
    
    # Cmdlets to export from this module
    CmdletsToExport = @()
    
    # Variables to export from this module
    VariablesToExport = @(
        'PoshDynargsSettings'
    )
    
    # Aliases to export from this module
    AliasesToExport = @('??')
    
    # 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.
    PrivateData = @{
    
        PSData = @{
            # Tags applied to this module. These help with module discovery in online galleries.
            Tags = @('prompt', 'tab', 'tab-completion', 'tab-expansion', 'tabexpansion')
    
            # A URL to the license for this module.
            LicenseUri = 'https://github.com/tygerbytes/posh-dynargs/blob/v0.1.0.5/LICENSE.txt'
    
            # A URL to the main website for this project.
            ProjectUri = 'https://github.com/tygerbytes/posh-dynargs'
    
            # ReleaseNotes of this module
            ReleaseNotes = 'https://github.com/tygerbytes/posh-dynargs/blob/v0.1.0.5/CHANGELOG.md'
        }
    
    }
    
    }
    
  • src\posh-dynargs.psm1 Show
    if (Get-Module posh-dynargs) { return }
    
    . $PSScriptRoot\Utils.ps1
    
    function Register-LocalArgumentCompleters() {
        if ($PoshDynargsSettings.EnableTiming) {
            $sw = [System.Diagnostics.Stopwatch]::StartNew()
        }
        $argumentCompleterRegistryPath = ".\.argument-completer-registry.json"
        if (!(Test-Path $argumentCompleterRegistryPath)) { return }
        if ($PoshDynargsSettings.LastRegisteredDirectory -eq $PWD.Path) { return }
    
        $completableCommands = ((Get-Content $argumentCompleterRegistryPath | ConvertFrom-Json).completableCommands).name;
        if ($null -eq $completableCommands) { return }
    
        & $PSScriptRoot\Register-DynamicArgumentCompleters.ps1 -commandsToComplete $completableCommands
        $PoshDynargsSettings.LastRegisteredDirectory = $PWD.Path
    
        # If timing enabled, display elapsed milliseconds
        if ($PoshDynargsSettings.EnableTiming) {
            $sw.Stop()
            $elapsed = $sw.ElapsedMilliseconds
            Write-Host "[${elapsed}ms]" -NoNewline -ForegroundColor DarkGray
        }
    }
    
    $PoshDynargsSettings = @{
        LastRegisteredDirectory = $null;
        EnableTiming = $false;
    }
    
    if ($GitPromptSettings) {
        # Piggyback on the posh-git prompt
        # TODO: Better way to do this?
        if ($GitPromptSettings.DefaultPromptPrefix -and $GitPromptSettings.DefaultPromptPrefix.GetType().Name -ne 'String' ) {
            Write-Host 'posh-dynargs warning: $GitPromptSettings.DefaultPromptPrefix overwritten' -ForegroundColor Yellow
            $GitPromptSettings.DefaultPromptPrefix = $null
        }
        $GitPromptSettings.DefaultPromptPrefix += '$(Register-LocalArgumentCompleters)'
    }
    else {
        # TODO: Don't really want to clobber the existing prompt.
        #       Consider wrapping the existing prompt.
        # TODO: Bypass overriding prompt via environment setting.
        $promptScriptBlock = {
            $origLastExitCode = $global:LASTEXITCODE
    
            Register-LocalArgumentCompleters
    
            $pathInfo = $ExecutionContext.SessionState.Path.CurrentLocation
            $currentPath = if ($pathInfo.Drive) { $pathInfo.Path } else { $pathInfo.ProviderPath }
    
            $global:LASTEXITCODE = $origLastExitCode
    
            "$currentPath> "
        }
    
        Set-Item Function:\prompt -Value $promptScriptBlock
    }
    
    $exportModuleMemberParams = @{
        Function = @(
            'Register-LocalArgumentCompleters',
            'Add-PoshDynargsToProfile'
        );
        Variable = @(
            'PoshDynargsSettings'
        );
    }
    
    Export-ModuleMember @exportModuleMemberParams
    
  • src\Register-DynamicArgumentCompleters.ps1 Show
    param(
        [Parameter(Mandatory=$true)]
        [String[]]$commandsToComplete)
    <#
    
    .SYNOPSIS
    Register tab completion for custom commands that change depending on the current directory.
    
    .PARAMETER commandsToComplete
    An array of strings representing the commands to register for tab completion.
    
    .EXAMPLE
    Register-DynamicArgumentCompleters -commandsToComplete @("build", "ci", "test")
    
    .NOTES
    Just to reiterate, there will be no tab completion without a .argument-completer-registry.json
    file in the directory containing the commands.
    
    #>
    
    Register-ArgumentCompleter -Native -CommandName $commandsToComplete -ScriptBlock {
        param($wordToComplete, $commandAst, $cursorPosition)
    
        # Grab the base command from the abstract syntax tree
        $baseCommand = $commandAst.CommandElements[0].Value
        $leadingDotSlash = $false
        if ($baseCommand -match "^\.[/\\]") {
            # Strip the leading ./ or .\ from the command
            $leadingDotSlash = $true
            $baseCommand = $baseCommand.Substring(2)
        }
    
        $argumentCompleterRegistryPath = ".\.argument-completer-registry.json"
    
        # Get the matching command object from the local "argument completer registry"
        $cmd = ((Get-Content $argumentCompleterRegistryPath | ConvertFrom-Json).completableCommands | Where-Object name -match $baseCommand);
        if ($cmd -eq $null) { return }
    
        $argsRegex = ""
        $switchesRegex = ""
        $argsPath = $cmd.argsPath
        switch ( $cmd.type ) {
            cake {
                $argsRegex = "^Task\(`"([A-Z][^`"]+)`""
                $switchesRegex = "Argument<\w+>\(`"(\w+)`""
            }
            make {
                $argsRegex = "^([a-z_]+):"
            }
            psake {
                $argsRegex = "^Task ([A-Z][^ ]+)"
            }
            default {
                $argsRegex = $cmd.regex
                if ($cmd.helpCommand) {
                    $uniquePath = "global";
                    if (!($cmd.funcDefaults.useGlobal)) {
                        $uniquePath = $(Get-Location) -replace "[:\\/]", ""
                    }
                    $argsPath = "$env:temp/$baseCommand-$uniquePath.txt"
                    if (!(Test-Path $argsPath)) {
                        if (!($cmd.helpCommand -match "^(-h|/\?|--help|help|-\?|--list|-l)$")) {
                            # To avoid command injection, only allow whitelisted "help" arguments
                            return
                        }
                        $expression = "$baseCommand $($cmd.helpCommand)"
                        if (Test-Path "./$baseCommand.*" -Include *.bat,*.cmd,*.ps1) {
                            $expression = "./$expression"
                        }
                        Write-Host " >>> " -ForegroundColor Cyan -NoNewline
                        Write-Host "DANGER! " -ForegroundColor Red -NoNewline
                        Write-Host "OK to run " -NoNewline -ForegroundColor Cyan
                        Write-Host "``$expression``" -ForegroundColor Red -NoNewline
                        Write-Host "? (yes/no)" -NoNewline -ForegroundColor Cyan
                        if ($(Read-Host " ") -ne "yes") { return }
                        # Temporarily disable ansicon, if enabled
                        $ansiconSetting = $env:ANSICON
                        $env:ANSICON = $null
                        Invoke-Expression $expression *>&1 > $argsPath
                        $env:ANSICON = $ansiconSetting
                    }
                }
            }
        }
    
        # Parse the args file registered for the command using the regex registered for the command
        $argumentCandidates = (Select-String $argsPath -Pattern $argsRegex |
            ForEach-Object {
                # The task name must be in the first capturing group
                $_.matches.groups[1].value }) |
                # Attempt to complete the supplied word using the parsed task names
                Where-Object { $_ -like "$wordToComplete*" } |
                Select-Object -Unique
    
        $switchCandidates = $null
        # Workaround [bug](https://github.com/PowerShell/PowerShell-Docs/issues/1979)
        #  Args starting with a hyphen aren't autocompleted. Start with a colon instead.
        $switchFormatString = ":-{0}"
        if ($leadingDotSlash) {
            # But only do the workaround when the wrapper function is invoked
            $switchFormatString = "-{0}"
        }
        if ($switchesRegex) {
            $switchCandidates = (Select-String $argsPath -Pattern $switchesRegex |
                ForEach-Object {
                    $_.matches.groups[1].value }) |
                    ForEach-Object { $switchFormatString -f $_ } |
                    Where-Object { $_ -like "$wordToComplete*" }
        }
    
        ($argumentCandidates + $switchCandidates) |
            Sort-Object |
            ForEach-Object {
                [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
            }
    }
    
    # Create helper functions for each command so that you don't have to use the leading ./ or .\
    $script:helperFunctionTemplateBlock = {
        Param(
        [switch]$Talk, [switch]$NoTalk,
        [switch]$Log,  [switch]$NoLog,
        [switch]$Timer,[switch]$NoTimer)
    
        $commandName = $MyInvocation.MyCommand;
    
        $sw = [Diagnostics.Stopwatch]::StartNew()
        $args = $args -replace ":-", "-"  # <--Lousy "workaround" for args starting with a hyphen
        $outputPath = "$($env:TEMP)\$commandName-$($(Get-Location) -replace "[:\\/]", """).txt"
    
        $defaultOptions = ((Get-Content -ErrorAction Ignore ".\.argument-completer-registry.json" | ConvertFrom-Json).completableCommands | Where-Object name -match $commandName).funcDefaults;
        $options = @{
            log = $(!($NoLog.IsPresent) -and ($defaultOptions.logOutput -or $Log.IsPresent));
            talk = $(!($NoTalk.IsPresent) -and ($defaultOptions.talk -or $Talk.IsPresent));
            timer = $(!($NoTimer.IsPresent) -and ($defaultOptions.useTimer -or $Timer.IsPresent));
            useGlobal = $(!($defaultOptions) -or $defaultOptions.useGlobal);
        }
    
        $cmdToInvoke = "./$commandName $args"
        if ($options.useGlobal) {
            $cmdToInvoke = "$(Get-Command $commandName -All | Where-Object CommandType -eq Application | Select-Object -First 1) $args"
        }
    
        if ($options.log) {
            Invoke-Expression $($cmdToInvoke) | Tee-Object $outputPath
        }
        else {
            Invoke-Expression $($cmdToInvoke)
        }
        $result = $LASTEXITCODE -eq 0
        $message = "`"$commandName $args`" finished {0}" -f $(if($result){"successfully"}else{"with errors"})
        Write-Host "`n$message" -ForegroundColor Cyan
        $sw.Stop()
        if ($options.timer) {
            Write-Host "Total time:" -ForegroundColor Magenta -NoNewline
            $sw.Elapsed
        }
        if ($options.log) {
            Write-Host "View logs at:" -ForegroundColor Green
            Write-Host "`t$outputPath"
        }
        if ($options.talk) {
            Add-Type -AssemblyName System.Speech
            $synth = New-Object -TypeName System.Speech.Synthesis.SpeechSynthesizer
            try {
                $synth.SpeakAsync($message) | Out-Null
            }
            catch {
                Write-Host "[No audio device]: $message" -ForegroundColor Yellow
            }
        }
        Write-Host "`nReturning: " -NoNewline
        $result
    }
    
    Write-Host "`nEnabled " -NoNewLine
    Write-Host "tab completion" -ForegroundColor Green -NoNewLine
    Write-Host " and generated " -NoNewline
    Write-Host "helper functions" -ForegroundColor Green -NoNewLine
    Write-Host " for (" -NoNewLine
    foreach($script:command in $commandsToComplete) {
        Write-Host " $script:command" -ForegroundColor Magenta -NoNewLine
        Set-Item -Path Function:global:$script:command -Value $script:helperFunctionTemplateBlock
    }
    Write-Host " )"
    
  • src\Utils.ps1 Show
    function Test-Administrator {
        # PowerShell 5.x only runs on Windows so use .NET types to determine isAdminProcess
        # Or if we are on v6 or higher, check the $IsWindows pre-defined variable.
        if (($PSVersionTable.PSVersion.Major -le 5) -or $IsWindows) {
            $currentUser = [Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent())
            return $currentUser.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
        }
    
        # Must be Linux or OSX, so use the id util. Root has userid of 0.
        return 0 -eq (id -u)
    }
    
    <#
    .SYNOPSIS
        Configures your PowerShell profile (startup) script to import the posh-dynargs
        module when PowerShell starts.
    .DESCRIPTION
        Checks if your PowerShell profile script is not already importing posh-dynargs
        and if not, adds a command to import the posh-dynargs module. This will cause
        PowerShell to load posh-dynargs whenever PowerShell starts.
    .PARAMETER AllHosts
        By default, this command modifies the CurrentUserCurrentHost profile
        script.  By specifying the AllHosts switch, the command updates the
        CurrentUserAllHosts profile (or AllUsersAllHosts, given -AllUsers).
    .PARAMETER AllUsers
        By default, this command modifies the CurrentUserCurrentHost profile
        script.  By specifying the AllUsers switch, the command updates the
        AllUsersCurrentHost profile (or AllUsersAllHosts, given -AllHosts).
        Requires elevated permissions.
    .PARAMETER Force
        Do not check if the specified profile script is already importing
        posh-dynargs. Just add Import-Module posh-dynargs command.
    .EXAMPLE
        PS C:\> Add-PoshDynargsToProfile
        Updates your profile script for the current PowerShell host to import the
        posh-dynargs module when the current PowerShell host starts.
    .EXAMPLE
        PS C:\> Add-PoshDynargsToProfile -AllHosts
        Updates your profile script for all PowerShell hosts to import the posh-dynargs
        module whenever any PowerShell host starts.
    .INPUTS
        None.
    .OUTPUTS
        None.
    #>
    function Add-PoshDynargsToProfile {
        [CmdletBinding(SupportsShouldProcess)]
        param(
            [Parameter()]
            [switch]
            $AllHosts,
    
            [Parameter()]
            [switch]
            $AllUsers,
    
            [Parameter()]
            [switch]
            $Force
        )
    
        if ($AllUsers -and !(Test-Administrator)) {
            throw 'Adding posh-dynargs to an AllUsers profile requires an elevated host.'
        }
    
        $profileName = $(if ($AllUsers) { 'AllUsers' } else { 'CurrentUser' }) `
                     + $(if ($AllHosts) { 'AllHosts' } else { 'CurrentHost' })
        Write-Verbose "`$profileName = '$profileName'"
    
        $profilePath = $PROFILE.$profileName
        Write-Verbose "`$profilePath = '$profilePath'"
    
        if (!$profilePath) { $profilePath = $PROFILE }
    
        if (!$Force) {
            $importedInProfile = Test-ProfileContainsText 'posh-dynargs'
    
            if ($importedInProfile) {
                Write-Warning "Skipping add of posh-dynargs import to file '$profilePath'."
                Write-Warning "posh-dynargs appears to already be imported in one of your profile scripts."
                Write-Warning "If you want to force the add, use the -Force parameter."
                return
            }
        }
    
        if (!$profilePath) {
            Write-Warning "Skipping add of posh-dynargs import to profile; no profile found."
            Write-Verbose "`$PROFILE              = '$PROFILE'"
            Write-Verbose "CurrentUserCurrentHost = '$($PROFILE.CurrentUserCurrentHost)'"
            Write-Verbose "CurrentUserAllHosts    = '$($PROFILE.CurrentUserAllHosts)'"
            Write-Verbose "AllUsersCurrentHost    = '$($PROFILE.AllUsersCurrentHost)'"
            Write-Verbose "AllUsersAllHosts       = '$($PROFILE.AllUsersAllHosts)'"
            return
        }
    
        # If the profile script exists and is signed, then we should not modify it
        if (Test-Path -LiteralPath $profilePath) {
            $sig = Get-AuthenticodeSignature $profilePath
            if ($null -ne $sig.SignerCertificate) {
                Write-Warning "Skipping add of posh-dynargs import to profile; '$profilePath' appears to be signed."
                Write-Warning "Add the command 'Import-Module posh-dynargs' to your profile and resign it."
                return
            }
        }
    
        $profileContent = "`nImport-Module posh-dynargs.psd1"
    
        # Make sure the PowerShell profile directory exists
        $profileDir = Split-Path $profilePath -Parent
        if (!(Test-Path -LiteralPath $profileDir)) {
            if ($PSCmdlet.ShouldProcess($profileDir, "Create current user PowerShell profile directory")) {
                New-Item $profileDir -ItemType Directory -Force -Verbose:$VerbosePreference > $null
            }
        }
    
        if (!(Test-ProfileContainsText 'posh-git')) {
            Write-Warning "If you plan on integrating posh-dynargs with posh-git, make sure it is imported first."
        }
    
        if ($PSCmdlet.ShouldProcess($profilePath, "Add 'Import-Module posh-dynargs' to profile")) {
            Add-Content -LiteralPath $profilePath -Value $profileContent -Encoding UTF8
        }
    }
    
    function Test-ProfileContainsText {
        param (
            [Parameter(Position=0)]
            [string]
            $Text
        )
    
        # Search the user's profiles to see if any are using posh-dynargs already.
        $importedInProfile = $false
        if (!$importedInProfile) {
            $importedInProfile = Test-ScriptContainsText -ScriptPath $PROFILE -Text $Text
        }
        if (!$importedInProfile) {
            $importedInProfile = Test-ScriptContainsText -ScriptPath $PROFILE.CurrentUserCurrentHost -Text $Text
        }
        if (!$importedInProfile) {
            $importedInProfile = Test-ScriptContainsText -ScriptPath $PROFILE.CurrentUserAllHosts -Text $Text
        }
        if (!$importedInProfile) {
            $importedInProfile = Test-ScriptContainsText -ScriptPath $PROFILE.AllUsersCurrentHost -Text $Text
        }
        if (!$importedInProfile) {
            $importedInProfile = Test-ScriptContainsText -ScriptPath $PROFILE.AllUsersAllHosts -Text $Text
        }
        $importedInProfile
    }
    
    function Test-ScriptContainsText {
        param (
            [Parameter(Position=0)]
            [string]
            $ScriptPath,
            [Parameter(Position=1)]
            [string]
            $Text
        )
    
        if (!$ScriptPath -or !(Test-Path -LiteralPath $ScriptPath)) {
            return $false
        }
    
        $match = (@(Get-Content $ScriptPath -ErrorAction SilentlyContinue) -match $Text).Count -gt 0
        if ($match) { Write-Verbose "$Text found in '$ScriptPath'" }
        $match
    }
    
  • tools\chocolateyBeforeModify.ps1 Show
    $ErrorActionPreference = 'Stop'
    
    $moduleName = 'posh-dynargs'
    Remove-Module -Name $moduleName -Force -ErrorAction SilentlyContinue
    
  • tools\chocolateyInstall.ps1 Show
    $ErrorActionPreference = 'Stop'
    
    $moduleName = 'posh-dynargs'
    
    if ($PSVersionTable.PSVersion.Major -le 4) {
        $PowerShellUpgradeUrl = 'https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell'
        Write-Warning "$moduleName requires PowerShell 5 or later. See '$PowerShellUpgradeUrl' to upgrade."
    }
    
    $libDir = "$($MyInvocation.MyCommand.Definition | Split-Path -Parent | Split-Path -Parent )"
    $sourcePath = Join-Path -Path $libDir -ChildPath "src\*"
    $destinationPath = Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\$moduleName"
    
    if ($PSVersionTable.PSVersion.Major -ge 5) {
        $manifestFile = Join-Path -Path $libDir -ChildPath "src\$moduleName.psd1"
        $manifest = Test-ModuleManifest -Path $manifestFile -WarningAction Ignore -ErrorAction Stop
        $destinationPath = Join-Path -Path $destinationPath -ChildPath $manifest.Version.ToString()
    }
    
    if (Test-Path $destinationPath) {
        Write-Verbose "Destination exists. Deleting '$destinationPath'."
        Remove-Item -Recurse $destinationPath -Force
    }
    
    Write-Verbose "Creating destination directory '$destinationPath' for module."
    New-Item -Path $destinationPath -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
    
    Write-Verbose "Moving '$moduleName' files from '$sourcePath' to '$destinationPath'."
    Move-Item -Path $sourcePath -Destination $destinationPath -Force
    
    Write-Host "`nTo add posh-dynargs to your profile use 'Import-Module posh-dynargs; Add-PoshDynargsToProfile'.`n"
    
  • tools\chocolateyUninstall.ps1 Show
    $ErrorActionPreference = 'Stop'
    
    $moduleName = 'posh-dynargs'
    $sourcePath = Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\$moduleName"
    
    Write-Verbose "Removing all version of '$moduleName' from '$sourcePath'."
    Remove-Item -Path $sourcePath -Recurse -Force -ErrorAction SilentlyContinue
    
  • tools\LICENSE.txt Show
    From: https://github.com/tygerbytes/posh-dynargs/blob/master/LICENSE.txt
    
    MIT License
    
    Copyright (c) 2019 Ty Walls 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.
    
  • tools\VERIFICATION.txt Show
    VERIFICATION
    Verification is intended to assist the Chocolatey moderators and community
    in verifying that this package's contents are trustworthy.
    
    To verify the files using the project source:
    
    1. Please go to the project source location (https://github.com/tygerbytes/posh-dynargs/releases/tag/v0.1.0.5) and download the source files;
    2. Use Get-FileHash -Path <FILE TO VERIFY> to get the file hash value from both the built file (from step 1 above) and the file from the package and compare them;
    

Virus Scan Results

In cases where actual malware is found, the packages are subject to removal. Software sometimes has false positives. Moderators do not necessarily validate the safety of the underlying software, only that a package retrieves software from the official distribution point and/or validate embedded software against official distribution point (where distribution rights allow redistribution).

Chocolatey Pro provides runtime protection from possible malware.

Dependencies

Package Maintainer(s)

Software Author(s)

  • Ty Walls

Tags

Release Notes

https://github.com/tygerbytes/posh-dynargs/blob/v0.1.0.5/CHANGELOG.md

Version History

Version Downloads Last updated Status
posh-dynargs 0.1.0.4 69 Tuesday, January 29, 2019 approved
posh-dynargs 0.1.0.3 57 Monday, January 21, 2019 approved

Discussion for the posh-dynargs Package

Ground rules:

  • This discussion is only about posh-dynargs and the posh-dynargs package. If you have feedback for Chocolatey, please contact the google group.
  • This discussion will carry over multiple versions. If you have a comment about a particular version, please note that in your comments.
  • The maintainers of this Chocolatey Package will be notified about new comments that are posted to this Disqus thread, however, it is NOT a guarantee that you will get a response. If you do not hear back from the maintainers after posting a message below, please follow up by using the link on the left side of this page or follow this link to contact maintainers. If you still hear nothing back, please follow the package triage process.
  • Tell us what you love about the package or posh-dynargs, or tell us what needs improvement.
  • Share your experiences with the package, or extra configuration or gotchas that you've found.
  • If you use a url, the comment will be flagged for moderation until you've been whitelisted. Disqus moderated comments are approved on a weekly schedule if not sooner. It could take between 1-5 days for your comment to show up.

comments powered by Disqus
Chocolatey.org uses cookies to enhance the user experience of the site.
Ok