OhMyPsh.psm1
## Pre-Loaded Module code ## param( [parameter(Position=0)] [string]$UserProfilePath ) if (-not [string]::IsNullOrEmpty($UserProfilePath)) { if ((Test-Path -Path $UserProfilePath -PathType:Container)) { $Script:UserProfilePath = Resolve-Path -Path $UserProfilePath } else { throw "Invalid OhMyPsh profile path: $UserProfilePath" } } else { if ((Get-Variable 'PROFILE' -ErrorAction:SilentlyContinue) -eq $null) { throw 'No profile variable found!' } $Script:UserProfilePath = Split-Path $PROFILE } $OMPProfileExportFile = Join-Path $UserProfilePath '.OhMyPsh.config.json' $IsConEmuConsole = if ($null -ne $env:ConEmuANSI) {$true} else {$false} # Backup some basic host settings. these never get updated and are used for restore purposes. $Script:HostState = @{ Title = $Host.UI.RawUI.WindowTitle Background = $Host.UI.RawUI.BackgroundColor Foreground = $Host.UI.RawUI.ForegroundColor Prompt = $function:prompt TabExpansion = $function:TabExpansion TabExpansion2 = $function:TabExpansion2 PSDefaultParameterValues = $Global:PSDefaultParameterValues.Clone() Aliases = Join-Path $UserProfilePath '.OhMyPsh.aliasbackup.ps1' Modules = (Get-Module).Name Colors = @{ BackgroundColor = $Host.UI.RawUI.BackgroundColor ForegroundColor = $Host.UI.RawUI.ForegroundColor ErrorForegroundColor = $Host.PrivateData.ErrorForegroundColor WarningForegroundColor = $Host.PrivateData.WarningForegroundColor DebugForegroundColor = $Host.PrivateData.DebugForegroundColor VerboseForegroundColor = $Host.PrivateData.VerboseForegroundColor ProgressForegroundColor = $Host.PrivateData.ProgressForegroundColor ErrorBackgroundColor = $Host.PrivateData.ErrorBackgroundColor WarningBackgroundColor = $Host.PrivateData.WarningBackgroundColor DebugBackgroundColor = $Host.PrivateData.DebugBackgroundColor VerboseBackgroundColor = $Host.PrivateData.VerboseBackgroundColor ProgressBackgroundColor = $Host.PrivateData.ProgressBackgroundColor } } if (get-module psreadline) { $Script:PSReadlineState = Get-PSReadlineOption } else { $Script:PSReadlineState = $null } if (-not $Script:ModulePath) { $ModulePath = Split-Path $script:MyInvocation.MyCommand.Path } # Backup original aliases Get-Alias | Where {($_.Options -split ',') -notcontains 'ReadOnly'} | Export-Alias -Path $Script:HostState['Aliases'] -As Script -Force ## PRIVATE MODULE FUNCTIONS AND DATA ## function Get-CallerPreference { <# .Synopsis Fetches "Preference" variable values from the caller's scope. .DESCRIPTION Script module functions do not automatically inherit their caller's variables, but they can be obtained through the $PSCmdlet variable in Advanced Functions. This function is a helper function for any script module Advanced Function; by passing in the values of $ExecutionContext.SessionState and $PSCmdlet, Get-CallerPreference will set the caller's preference variables locally. .PARAMETER Cmdlet The $PSCmdlet object from a script module Advanced Function. .PARAMETER SessionState The $ExecutionContext.SessionState object from a script module Advanced Function. This is how the Get-CallerPreference function sets variables in its callers' scope, even if that caller is in a different script module. .PARAMETER Name Optional array of parameter names to retrieve from the caller's scope. Default is to retrieve all Preference variables as defined in the about_Preference_Variables help file (as of PowerShell 4.0) This parameter may also specify names of variables that are not in the about_Preference_Variables help file, and the function will retrieve and set those as well. .EXAMPLE Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState Imports the default PowerShell preference variables from the caller into the local scope. .EXAMPLE Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState -Name 'ErrorActionPreference','SomeOtherVariable' Imports only the ErrorActionPreference and SomeOtherVariable variables into the local scope. .EXAMPLE 'ErrorActionPreference','SomeOtherVariable' | Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState Same as Example 2, but sends variable names to the Name parameter via pipeline input. .INPUTS String .OUTPUTS None. This function does not produce pipeline output. .LINK about_Preference_Variables #> [CmdletBinding(DefaultParameterSetName = 'AllVariables')] param ( [Parameter(Mandatory = $true)] [ValidateScript({ $_.GetType().FullName -eq 'System.Management.Automation.PSScriptCmdlet' })] $Cmdlet, [Parameter(Mandatory = $true)] [System.Management.Automation.SessionState]$SessionState, [Parameter(ParameterSetName = 'Filtered', ValueFromPipeline = $true)] [string[]]$Name ) begin { $filterHash = @{} } process { if ($null -ne $Name) { foreach ($string in $Name) { $filterHash[$string] = $true } } } end { # List of preference variables taken from the about_Preference_Variables help file in PowerShell version 4.0 $vars = @{ 'ErrorView' = $null 'FormatEnumerationLimit' = $null 'LogCommandHealthEvent' = $null 'LogCommandLifecycleEvent' = $null 'LogEngineHealthEvent' = $null 'LogEngineLifecycleEvent' = $null 'LogProviderHealthEvent' = $null 'LogProviderLifecycleEvent' = $null 'MaximumAliasCount' = $null 'MaximumDriveCount' = $null 'MaximumErrorCount' = $null 'MaximumFunctionCount' = $null 'MaximumHistoryCount' = $null 'MaximumVariableCount' = $null 'OFS' = $null 'OutputEncoding' = $null 'ProgressPreference' = $null 'PSDefaultParameterValues' = $null 'PSEmailServer' = $null 'PSModuleAutoLoadingPreference' = $null 'PSSessionApplicationName' = $null 'PSSessionConfigurationName' = $null 'PSSessionOption' = $null 'ErrorActionPreference' = 'ErrorAction' 'DebugPreference' = 'Debug' 'ConfirmPreference' = 'Confirm' 'WhatIfPreference' = 'WhatIf' 'VerbosePreference' = 'Verbose' 'WarningPreference' = 'WarningAction' } foreach ($entry in $vars.GetEnumerator()) { if (([string]::IsNullOrEmpty($entry.Value) -or -not $Cmdlet.MyInvocation.BoundParameters.ContainsKey($entry.Value)) -and ($PSCmdlet.ParameterSetName -eq 'AllVariables' -or $filterHash.ContainsKey($entry.Name))) { $variable = $Cmdlet.SessionState.PSVariable.Get($entry.Key) if ($null -ne $variable) { if ($SessionState -eq $ExecutionContext.SessionState) { Set-Variable -Scope 1 -Name $variable.Name -Value $variable.Value -Force -Confirm:$false -WhatIf:$false } else { $SessionState.PSVariable.Set($variable.Name, $variable.Value) } } } } if ($PSCmdlet.ParameterSetName -eq 'Filtered') { foreach ($varName in $filterHash.Keys) { if (-not $vars.ContainsKey($varName)) { $variable = $Cmdlet.SessionState.PSVariable.Get($varName) if ($null -ne $variable) { if ($SessionState -eq $ExecutionContext.SessionState) { Set-Variable -Scope 1 -Name $variable.Name -Value $variable.Value -Force -Confirm:$false -WhatIf:$false } else { $SessionState.PSVariable.Set($variable.Name, $variable.Value) } } } } } } } Function Invoke-OMPPersonalFunction { <# .SYNOPSIS Dot sources a personal function file in the global context and tags it to ohmypsh. .DESCRIPTION Dot sources a personal function file in the global context and tags it to ohmypsh. .PARAMETER Path Path for the file to import. .PARAMETER Tag Tag to place on the function (in the form of a noteproperty). .EXAMPLE TBD .NOTES Author: Zachary Loeber Version History 1.0.0 - Initial release #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] [string]$Path, [Parameter(Position = 1, Mandatory = $true)] [string]$Tag ) Begin { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState Write-Verbose "Attempting to load the file $Path" } Process { if (Test-Path $Path) { $errmsg = $null # Load the script, replace any root level functions with its global equivalent. Then invoke. $script = (Get-Content $Path -Raw) -replace '^function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)', 'function Global:$1' try { $sb = [Scriptblock]::create(".{$script}") Invoke-Command -NoNewScope -ScriptBlock $sb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg))) { throw "Unable to load script file $Path" } } catch { throw "Unable to load script file $Path" } # Next look for any globally defined functions and tag them with a noteproperty to track ([System.Management.Automation.Language.Parser]::ParseInput($script, [ref]$null, [ref]$null)).FindAll({ $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $false) | Foreach-Object { if (($_.Name).StartsWith('Global:')) { $globalfunc = Get-ChildItem -Path "Function:\$($_.Name -replace 'Global:','')" -ErrorAction:SilentlyContinue if ($GlobalFunc -ne $null) { Write-Verbose "Function exported into the global session: $($_.Name -replace 'Global:','')" try { $globalfunc | Add-Member -MemberType 'NoteProperty' -Name 'ohmypsh' -Value $Tag -Force } catch { # Do nothing as the member probably already existed. } } } } } else { throw "Invalid Path: $Path" } } } function New-DynamicParameter { <# .SYNOPSIS Helper function to simplify creating dynamic parameters .DESCRIPTION Helper function to simplify creating dynamic parameters. Example use cases: Include parameters only if your environment dictates it Include parameters depending on the value of a user-specified parameter Provide tab completion and intellisense for parameters, depending on the environment Please keep in mind that all dynamic parameters you create, will not have corresponding variables created. Use New-DynamicParameter with 'CreateVariables' switch in your main code block, ('Process' for advanced functions) to create those variables. Alternatively, manually reference $PSBoundParameters for the dynamic parameter value. This function has two operating modes: 1. All dynamic parameters created in one pass using pipeline input to the function. This mode allows to create dynamic parameters en masse, with one function call. There is no need to create and maintain custom RuntimeDefinedParameterDictionary. 2. Dynamic parameters are created by separate function calls and added to the RuntimeDefinedParameterDictionary you created beforehand. Then you output this RuntimeDefinedParameterDictionary to the pipeline. This allows more fine-grained control of the dynamic parameters, with custom conditions and so on. .NOTES Credits to jrich523 and ramblingcookiemonster for their initial code and inspiration: https://github.com/RamblingCookieMonster/PowerShell/blob/master/New-DynamicParam.ps1 http://ramblingcookiemonster.wordpress.com/2014/11/27/quick-hits-credentials-and-dynamic-parameters/ http://jrich523.wordpress.com/2013/05/30/powershell-simple-way-to-add-dynamic-parameters-to-advanced-function/ Credit to BM for alias and type parameters and their handling .PARAMETER Name Name of the dynamic parameter .PARAMETER Type Type for the dynamic parameter. Default is string .PARAMETER Alias If specified, one or more aliases to assign to the dynamic parameter .PARAMETER Mandatory If specified, set the Mandatory attribute for this dynamic parameter .PARAMETER Position If specified, set the Position attribute for this dynamic parameter .PARAMETER HelpMessage If specified, set the HelpMessage for this dynamic parameter .PARAMETER DontShow If specified, set the DontShow for this dynamic parameter. This is the new PowerShell 4.0 attribute that hides parameter from tab-completion. http://www.powershellmagazine.com/2013/07/29/pstip-hiding-parameters-from-tab-completion/ .PARAMETER ValueFromPipeline If specified, set the ValueFromPipeline attribute for this dynamic parameter .PARAMETER ValueFromPipelineByPropertyName If specified, set the ValueFromPipelineByPropertyName attribute for this dynamic parameter .PARAMETER ValueFromRemainingArguments If specified, set the ValueFromRemainingArguments attribute for this dynamic parameter .PARAMETER ParameterSetName If specified, set the ParameterSet attribute for this dynamic parameter. By default parameter is added to all parameters sets. .PARAMETER AllowNull If specified, set the AllowNull attribute of this dynamic parameter .PARAMETER AllowEmptyString If specified, set the AllowEmptyString attribute of this dynamic parameter .PARAMETER AllowEmptyCollection If specified, set the AllowEmptyCollection attribute of this dynamic parameter .PARAMETER ValidateNotNull If specified, set the ValidateNotNull attribute of this dynamic parameter .PARAMETER ValidateNotNullOrEmpty If specified, set the ValidateNotNullOrEmpty attribute of this dynamic parameter .PARAMETER ValidateRange If specified, set the ValidateRange attribute of this dynamic parameter .PARAMETER ValidateLength If specified, set the ValidateLength attribute of this dynamic parameter .PARAMETER ValidatePattern If specified, set the ValidatePattern attribute of this dynamic parameter .PARAMETER ValidateScript If specified, set the ValidateScript attribute of this dynamic parameter .PARAMETER ValidateSet If specified, set the ValidateSet attribute of this dynamic parameter .PARAMETER ParameterDefaultValue If specified, set a default value for the parameter. .PARAMETER Dictionary If specified, add resulting RuntimeDefinedParameter to an existing RuntimeDefinedParameterDictionary. Appropriate for custom dynamic parameters creation. If not specified, create and return a RuntimeDefinedParameterDictionary Aappropriate for a simple dynamic parameter creation. .EXAMPLE Create one dynamic parameter. This example illustrates the use of New-DynamicParameter to create a single dynamic parameter. The Drive's parameter ValidateSet is populated with all available volumes on the computer for handy tab completion / intellisense. Usage: Get-FreeSpace -Drive <tab> function Get-FreeSpace { [CmdletBinding()] Param() DynamicParam { # Get drive names for ValidateSet attribute $DriveList = ([System.IO.DriveInfo]::GetDrives()).Name # Create new dynamic parameter New-DynamicParameter -Name Drive -ValidateSet $DriveList -Type ([array]) -Position 0 -Mandatory } Process { # Dynamic parameters don't have corresponding variables created, # you need to call New-DynamicParameter with CreateVariables switch to fix that. New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object {$Drive -contains $_.Name} $DriveInfo | ForEach-Object { if(!$_.TotalFreeSpace) { $FreePct = 0 } else { $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), 2) } New-Object -TypeName psobject -Property @{ Drive = $_.Name DriveType = $_.DriveType 'Free(%)' = $FreePct } } } } .EXAMPLE Create several dynamic parameters not using custom RuntimeDefinedParameterDictionary (requires piping). In this example two dynamic parameters are created. Each parameter belongs to the different parameter set, so they are mutually exclusive. The Drive's parameter ValidateSet is populated with all available volumes on the computer. The DriveType's parameter ValidateSet is populated with all available drive types. Usage: Get-FreeSpace -Drive <tab> or Usage: Get-FreeSpace -DriveType <tab> Parameters are defined in the array of hashtables, which is then piped through the New-Object to create PSObject and pass it to the New-DynamicParameter function. Because of piping, New-DynamicParameter function is able to create all parameters at once, thus eliminating need for you to create and pass external RuntimeDefinedParameterDictionary to it. function Get-FreeSpace { [CmdletBinding()] Param() DynamicParam { # Array of hashtables that hold values for dynamic parameters $DynamicParameters = @( @{ Name = 'Drive' Type = [array] Position = 0 Mandatory = $true ValidateSet = ([System.IO.DriveInfo]::GetDrives()).Name ParameterSetName = 'Drive' }, @{ Name = 'DriveType' Type = [array] Position = 0 Mandatory = $true ValidateSet = [System.Enum]::GetNames('System.IO.DriveType') ParameterSetName = 'DriveType' } ) # Convert hashtables to PSObjects and pipe them to the New-DynamicParameter, # to create all dynamic paramters in one function call. $DynamicParameters | ForEach-Object {New-Object PSObject -Property $_} | New-DynamicParameter } Process { # Dynamic parameters don't have corresponding variables created, # you need to call New-DynamicParameter with CreateVariables switch to fix that. New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters if($Drive) { $Filter = {$Drive -contains $_.Name} } elseif($DriveType) { $Filter = {$DriveType -contains $_.DriveType} } $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object $Filter $DriveInfo | ForEach-Object { if(!$_.TotalFreeSpace) { $FreePct = 0 } else { $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), 2) } New-Object -TypeName psobject -Property @{ Drive = $_.Name DriveType = $_.DriveType 'Free(%)' = $FreePct } } } } .EXAMPLE Create several dynamic parameters, with multiple Parameter Sets, not using custom RuntimeDefinedParameterDictionary (requires piping). In this example three dynamic parameters are created. Two of the parameters are belong to the different parameter set, so they are mutually exclusive. One of the parameters belongs to both parameter sets. The Drive's parameter ValidateSet is populated with all available volumes on the computer. The DriveType's parameter ValidateSet is populated with all available drive types. The DriveType's parameter ValidateSet is populated with all available drive types. The Precision's parameter controls number of digits after decimal separator for Free Space percentage. Usage: Get-FreeSpace -Drive <tab> -Precision 2 or Usage: Get-FreeSpace -DriveType <tab> -Precision 2 Parameters are defined in the array of hashtables, which is then piped through the New-Object to create PSObject and pass it to the New-DynamicParameter function. If parameter with the same name already exist in the RuntimeDefinedParameterDictionary, a new Parameter Set is added to it. Because of piping, New-DynamicParameter function is able to create all parameters at once, thus eliminating need for you to create and pass external RuntimeDefinedParameterDictionary to it. function Get-FreeSpace { [CmdletBinding()] Param() DynamicParam { # Array of hashtables that hold values for dynamic parameters $DynamicParameters = @( @{ Name = 'Drive' Type = [array] Position = 0 Mandatory = $true ValidateSet = ([System.IO.DriveInfo]::GetDrives()).Name ParameterSetName = 'Drive' }, @{ Name = 'DriveType' Type = [array] Position = 0 Mandatory = $true ValidateSet = [System.Enum]::GetNames('System.IO.DriveType') ParameterSetName = 'DriveType' }, @{ Name = 'Precision' Type = [int] # This will add a Drive parameter set to the parameter Position = 1 ParameterSetName = 'Drive' }, @{ Name = 'Precision' # Because the parameter already exits in the RuntimeDefinedParameterDictionary, # this will add a DriveType parameter set to the parameter. Position = 1 ParameterSetName = 'DriveType' } ) # Convert hashtables to PSObjects and pipe them to the New-DynamicParameter, # to create all dynamic paramters in one function call. $DynamicParameters | ForEach-Object {New-Object PSObject -Property $_} | New-DynamicParameter } Process { # Dynamic parameters don't have corresponding variables created, # you need to call New-DynamicParameter with CreateVariables switch to fix that. New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters if($Drive) { $Filter = {$Drive -contains $_.Name} } elseif($DriveType) { $Filter = {$DriveType -contains $_.DriveType} } if(!$Precision) { $Precision = 2 } $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object $Filter $DriveInfo | ForEach-Object { if(!$_.TotalFreeSpace) { $FreePct = 0 } else { $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), $Precision) } New-Object -TypeName psobject -Property @{ Drive = $_.Name DriveType = $_.DriveType 'Free(%)' = $FreePct } } } } .Example Create dynamic parameters using custom dictionary. In case you need more control, use custom dictionary to precisely choose what dynamic parameters to create and when. The example below will create DriveType dynamic parameter only if today is not a Friday: function Get-FreeSpace { [CmdletBinding()] Param() DynamicParam { $Drive = @{ Name = 'Drive' Type = [array] Position = 0 Mandatory = $true ValidateSet = ([System.IO.DriveInfo]::GetDrives()).Name ParameterSetName = 'Drive' } $DriveType = @{ Name = 'DriveType' Type = [array] Position = 0 Mandatory = $true ValidateSet = [System.Enum]::GetNames('System.IO.DriveType') ParameterSetName = 'DriveType' } # Create dictionary $DynamicParameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Add new dynamic parameter to dictionary New-DynamicParameter @Drive -Dictionary $DynamicParameters # Add another dynamic parameter to dictionary, only if today is not a Friday if((Get-Date).DayOfWeek -ne [DayOfWeek]::Friday) { New-DynamicParameter @DriveType -Dictionary $DynamicParameters } # Return dictionary with dynamic parameters $DynamicParameters } Process { # Dynamic parameters don't have corresponding variables created, # you need to call New-DynamicParameter with CreateVariables switch to fix that. New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters if($Drive) { $Filter = {$Drive -contains $_.Name} } elseif($DriveType) { $Filter = {$DriveType -contains $_.DriveType} } $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object $Filter $DriveInfo | ForEach-Object { if(!$_.TotalFreeSpace) { $FreePct = 0 } else { $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), 2) } New-Object -TypeName psobject -Property @{ Drive = $_.Name DriveType = $_.DriveType 'Free(%)' = $FreePct } } } } #> [CmdletBinding(PositionalBinding = $false, DefaultParameterSetName = 'DynamicParameter')] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateNotNullOrEmpty()] [string]$Name, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [System.Type]$Type = [int], [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [string[]]$Alias, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$Mandatory, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [int]$Position, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [string]$HelpMessage, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$DontShow, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$ValueFromPipeline, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$ValueFromPipelineByPropertyName, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$ValueFromRemainingArguments, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [string]$ParameterSetName = '__AllParameterSets', [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$AllowNull, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$AllowEmptyString, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$AllowEmptyCollection, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$ValidateNotNull, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [switch]$ValidateNotNullOrEmpty, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateCount(2, 2)] [int[]]$ValidateCount, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateCount(2, 2)] [int[]]$ValidateRange, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateCount(2, 2)] [int[]]$ValidateLength, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateNotNullOrEmpty()] [string]$ValidatePattern, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateNotNullOrEmpty()] [scriptblock]$ValidateScript, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateNotNullOrEmpty()] [string[]]$ValidateSet, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateNotNullOrEmpty()] $ParameterDefaultValue, [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')] [ValidateNotNullOrEmpty()] [ValidateScript( { if (!($_ -is [System.Management.Automation.RuntimeDefinedParameterDictionary])) { Throw 'Dictionary must be a System.Management.Automation.RuntimeDefinedParameterDictionary object' } $true })] $Dictionary = $false, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CreateVariables')] [switch]$CreateVariables, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CreateVariables')] [ValidateNotNullOrEmpty()] [ValidateScript( { # System.Management.Automation.PSBoundParametersDictionary is an internal sealed class, # so one can't use PowerShell's '-is' operator to validate type. if ($_.GetType().Name -ne 'PSBoundParametersDictionary') { Throw 'BoundParameters must be a System.Management.Automation.PSBoundParametersDictionary object' } $true })] $BoundParameters ) Begin { Write-Verbose 'Creating new dynamic parameters dictionary' $InternalDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary Write-Verbose 'Getting common parameters' function _temp { [CmdletBinding()] Param() } $CommonParameters = (Get-Command _temp).Parameters.Keys } Process { if ($CreateVariables) { Write-Verbose 'Creating variables from bound parameters' Write-Debug 'Picking out bound parameters that are not in common parameters set' $BoundKeys = $BoundParameters.Keys | Where-Object { $CommonParameters -notcontains $_ } foreach ($Parameter in $BoundKeys) { Write-Debug "Setting existing variable for dynamic parameter '$Parameter' with value '$($BoundParameters.$Parameter)'" Set-Variable -Name $Parameter -Value $BoundParameters.$Parameter -Scope 1 -Force } } else { Write-Verbose 'Looking for cached bound parameters' Write-Debug 'More info: https://beatcracker.wordpress.com/2014/12/18/psboundparameters-pipeline-and-the-valuefrompipelinebypropertyname-parameter-attribute' $StaleKeys = @() $StaleKeys = $PSBoundParameters.GetEnumerator() | ForEach-Object { if ($_.Value.PSobject.Methods.Name -match '^Equals$') { # If object has Equals, compare bound key and variable using it if (!$_.Value.Equals((Get-Variable -Name $_.Key -ValueOnly -Scope 0))) { $_.Key } } else { # If object doesn't has Equals (e.g. $null), fallback to the PowerShell's -ne operator if ($_.Value -ne (Get-Variable -Name $_.Key -ValueOnly -Scope 0)) { $_.Key } } } if ($StaleKeys) { [string[]]"Found $($StaleKeys.Count) cached bound parameters:" + $StaleKeys | Write-Debug Write-Verbose 'Removing cached bound parameters' $StaleKeys | ForEach-Object {[void]$PSBoundParameters.Remove($_)} } # Since we rely solely on $PSBoundParameters, we don't have access to default values for unbound parameters Write-Verbose 'Looking for unbound parameters with default values' Write-Debug 'Getting unbound parameters list' $UnboundParameters = (Get-Command -Name ($PSCmdlet.MyInvocation.InvocationName)).Parameters.GetEnumerator() | # Find parameters that are belong to the current parameter set Where-Object { $_.Value.ParameterSets.Keys -contains $PsCmdlet.ParameterSetName } | Select-Object -ExpandProperty Key | # Find unbound parameters in the current parameter set Where-Object { $PSBoundParameters.Keys -notcontains $_ } # Even if parameter is not bound, corresponding variable is created with parameter's default value (if specified) Write-Debug 'Trying to get variables with default parameter value and create a new bound parameter''s' $tmp = $null foreach ($Parameter in $UnboundParameters) { $DefaultValue = Get-Variable -Name $Parameter -ValueOnly -Scope 0 if (!$PSBoundParameters.TryGetValue($Parameter, [ref]$tmp) -and $DefaultValue) { $PSBoundParameters.$Parameter = $DefaultValue Write-Debug "Added new parameter '$Parameter' with value '$DefaultValue'" } } if ($Dictionary) { Write-Verbose 'Using external dynamic parameter dictionary' $DPDictionary = $Dictionary } else { Write-Verbose 'Using internal dynamic parameter dictionary' $DPDictionary = $InternalDictionary } Write-Verbose "Creating new dynamic parameter: $Name" # Shortcut for getting local variables $GetVar = {Get-Variable -Name $_ -ValueOnly -Scope 0} # Strings to match attributes and validation arguments $AttributeRegex = '^(Mandatory|Position|ParameterSetName|DontShow|HelpMessage|ValueFromPipeline|ValueFromPipelineByPropertyName|ValueFromRemainingArguments)$' $ValidationRegex = '^(AllowNull|AllowEmptyString|AllowEmptyCollection|ValidateCount|ValidateLength|ValidatePattern|ValidateRange|ValidateScript|ValidateSet|ValidateNotNull|ValidateNotNullOrEmpty)$' $AliasRegex = '^Alias$' Write-Debug 'Creating new parameter''s attirubutes object' $ParameterAttribute = New-Object -TypeName System.Management.Automation.ParameterAttribute Write-Debug 'Looping through the bound parameters, setting attirubutes...' switch -regex ($PSBoundParameters.Keys) { $AttributeRegex { Try { $ParameterAttribute.$_ = . $GetVar Write-Debug "Added new parameter attribute: $_" } Catch { $_ } continue } } if ($DPDictionary.Keys -contains $Name) { Write-Verbose "Dynamic parameter '$Name' already exist, adding another parameter set to it" $DPDictionary.$Name.Attributes.Add($ParameterAttribute) } else { Write-Verbose "Dynamic parameter '$Name' doesn't exist, creating" Write-Debug 'Creating new attribute collection object' $AttributeCollection = New-Object -TypeName Collections.ObjectModel.Collection[System.Attribute] Write-Debug 'Looping through bound parameters, adding attributes' switch -regex ($PSBoundParameters.Keys) { $ValidationRegex { Try { $ParameterOptions = New-Object -TypeName "System.Management.Automation.${_}Attribute" -ArgumentList (. $GetVar) -ErrorAction Stop $AttributeCollection.Add($ParameterOptions) Write-Debug "Added attribute: $_" } Catch { $_ } continue } $AliasRegex { Try { $ParameterAlias = New-Object -TypeName System.Management.Automation.AliasAttribute -ArgumentList (. $GetVar) -ErrorAction Stop $AttributeCollection.Add($ParameterAlias) Write-Debug "Added alias: $_" continue } Catch { $_ } } } Write-Debug 'Adding attributes to the attribute collection' $AttributeCollection.Add($ParameterAttribute) Write-Debug 'Finishing creation of the new dynamic parameter' $Parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter -ArgumentList @($Name, $Type, $AttributeCollection) if ($null -ne $ParameterDefaultValue) { $Parameter.Value = $ParameterDefaultValue } Write-Debug 'Adding dynamic parameter to the dynamic parameter dictionary' $DPDictionary.Add($Name, $Parameter) } } } End { if (!$CreateVariables -and !$Dictionary) { Write-Verbose 'Writing dynamic parameter dictionary to the pipeline' $DPDictionary } } } Function Read-HostContinue { param ( [Parameter(Position=0)] [String]$PromptTitle = '', [Parameter(Position=1)] [string]$PromptQuestion = 'Continue?', [Parameter(Position=2)] [string]$YesDescription = 'Do this.', [Parameter(Position=3)] [string]$NoDescription = 'Do not do this.', [Parameter(Position=4)] [switch]$DefaultToNo, [Parameter(Position=5)] [switch]$Force ) if ($Force) { (-not $DefaultToNo) return } $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", $YesDescription $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", $NoDescription if ($DefaultToNo) { $ConsolePrompt = [System.Management.Automation.Host.ChoiceDescription[]]($no,$yes) } else { $ConsolePrompt = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) } if (($host.ui.PromptForChoice($PromptTitle, $PromptQuestion , $ConsolePrompt, 0)) -eq 0) { $true } else { $false } } ## PUBLIC MODULE FUNCTIONS AND DATA ## Function Add-OMPAutoLoadModule { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Add-OMPAutoLoadModule.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string]$Name, [Parameter(Position = 1)] [switch]$NoProfileUpdate ) try { Import-OMPModule -Name $Name $Script:OMPProfile['AutoLoadModules'] = @($Script:OMPProfile['AutoLoadModules'] + $Name | Sort-Object -Unique) if (-not $NoProfileUpdate) { Export-OMPProfile } } catch { throw "Unable to add module $($Name)" } } Function Add-OMPPersonalFunction { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Add-OMPPersonalFunction.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string]$Path, [Parameter(Position = 1)] [switch]$Recurse, [Parameter(Position = 2)] [switch]$NoProfileUpdate ) $PathsAdded = $false if (Test-Path $Path) { if ($Recurse) { $Paths = @((Get-ChildItem -Path $Path -File -Filter '*.ps1').FullName) } else { $Paths = $($Path) } Foreach ($ScriptPath in $Paths) { Write-Verbose "Checking if the following is a valid candidate for being added: $ScriptPath" if ($Script:OMPProfile['PersonalFunctions'] -notcontains $ScriptPath){ try { Invoke-OMPPersonalFunction -Path $ScriptPath -Tag 'personalfunction' $PathsAdded = $true $Script:OMPProfile['PersonalFunctions'] += $ScriptPath } catch { Write-Warning "Unable to load $ScriptPath" } } } } try { if ((-not $NoProfileUpdate) -and $PathsAdded) { Write-Verbose "Profile being updated" Export-OMPProfile } } catch { throw "Unable to add module $($Name)" } } Function Add-OMPPlugin { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Add-OMPPlugin.md #> [CmdletBinding()] param ( [Parameter()] [switch]$Force, [Parameter()] [switch]$NoProfileUpdate, [Parameter()] [switch]$UpdateConfig, [Parameter()] [switch]$DebugOutput ) dynamicparam { # Create dictionary $DynamicParameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $ValidPlugins = @() Foreach ($PPath in $Script:OMPProfile['OMPPluginRootPaths']) { $ValidPlugins += (Get-ChildItem $PPath -Directory).Name } $ValidPlugins = $ValidPlugins | Sort-Object | Select-Object -Unique $NewParamSettings = @{ Name = 'Name' Position = 0 Type = 'string' ValidateSet = $ValidPlugins HelpMessage = "The plugin to add to your profile and optionally load." ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true } # Add new dynamic parameter to dictionary New-DynamicParameter @NewParamSettings -Dictionary $DynamicParameters # Return dictionary with dynamic parameters $DynamicParameters } begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } Process { # Pull in the dynamic parameters first New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters $PluginPath = $null Foreach ($PPath in $Script:OMPProfile['OMPPluginRootPaths']) { if (Test-Path (Join-Path $PPath $Name)) { if ($null -eq $PluginPath) { Write-Verbose "$($FunctionName): Loading the plugin found in $PPath" $PluginPath = $PPath } else { Write-Warning "$($FunctionName): More than one root plugin folder paths contain the plugin named $Name, ignoring the plugin found in $PPath" } } } if ($null -eq $PluginPath) { Write-Warning "Unable to locate $Name in any plugin paths!" return } $LoadedPlugins = $Script:OMPState['PluginsLoaded'] if (($LoadedPlugins -notcontains $Name) -or $Force) { $Preload = $null $PostLoad = $null $LoadScript = Join-Path $PluginPath "$Name\Load.ps1" if (-not (Test-Path $LoadScript)) { Write-Error "Unable to find the plugin load file: $LoadScript" } Write-Verbose "Executing plugin load script: $LoadScript" # pull in the preload and postload definitions $errmsg = $null $sb = [Scriptblock]::create(".{$(Get-Content -Path $LoadScript -Raw)}") Invoke-Command -NoNewScope -ScriptBlock $sb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg)) -and $DebugOutput) { Write-Warning "Unable to load plugin $Name" Write-Warning "Error: $($errmsg | Select *)" if (-not $Force) { return } } # Run preload plugin code $errmsg = $null $Preloadsb = [Scriptblock]::create(".{$Preload}") Invoke-Command -NoNewScope -ScriptBlock $Preloadsb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg)) -and $Debug) { Write-Warning "Unable to load plugin preload code for $Name" Write-Warning "Error: $($errmsg | Select *)" if (-not $Force) { return } } # Dot source any file in the plugin src directory of this plugin and track global functions $FullPluginSrcPath = Join-Path $PluginPath "$Name\src" Write-Verbose "Plugin $Name source file repo is $FullPluginSrcPath" Get-ChildItem -Path $FullPluginSrcPath -Recurse -Filter "*.ps1" -File | Sort-Object Name | ForEach-Object { Write-Verbose "Dot sourcing plugin script file: $($_.Name)" # First dot source the ps1 . $_.FullName # Next look for any globally defined functions and tag them with a noteproperty to track ([System.Management.Automation.Language.Parser]::ParseInput((Get-Content -Path $_.FullName -Raw), [ref]$null, [ref]$null)).FindAll({ $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $false) | Foreach-Object { if (($_.Name).StartsWith('Global:')) { $globalfunc = Get-ChildItem -Path "Function:\$($_.Name -replace 'Global:','')" if ($GlobalFunc -ne $null) { Write-Verbose "Plugin function exported into the global session: $($_.Name -replace 'Global:','')" $globalfunc | Add-Member -MemberType 'NoteProperty' -Name 'ohmypsh' -Value "$Name" -Force } } } } # Run postload plugin code $errmsg = $null $Postloadsb = [Scriptblock]::create(".{$Postload}") Invoke-Command -NoNewScope -ScriptBlock $Postloadsb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg)) -and $Debug) { $errmsg Write-Warning "Unable to load plugin postload code for $Name" Write-Warning "Error: $($errmsg | Select *)" if (-not $Force) { return } } # Finally run any config plugin code if ((Test-OMPProfileSetting -Name "pluginconfig_$Name") -and (-not $UpdateConfig)) { $Config = Get-OMPProfileSetting -Name "pluginconfig_$Name" } else { # If not already in the profile config add the plugin config variable if (Test-OMPProfileSetting -Name "pluginconfig_$Name") { Set-OMPProfileSetting -Name "pluginconfig_$Name" -Value ([string]$Config) } else { Add-OMPProfileSetting -Name "pluginconfig_$Name" -Value ([string]$Config) } } $errmsg = $null $Configsb = [Scriptblock]::create(".{$Config}") Invoke-Command -NoNewScope -ScriptBlock $Configsb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg)) -and $Debug) { $errmsg Write-Warning "Unable to load plugin configuration code for $Name" Write-Warning "Error: $($errmsg | Select *)" if (-not $Force) { return } } # If we made it this far then update our loaded plugins list $LoadedPlugins += $Name $Script:OMPState['PluginsLoaded'] = @($LoadedPlugins | Sort-Object -Unique) if (-not $NoProfileUpdate) { try { # update the profile plugins list as well $ProfPlugins = $Script:OMPProfile['Plugins'] $ProfPlugins += $Name $Script:OMPProfile['Plugins'] = @($ProfPlugins | Sort-Object -Unique) Export-OMPProfile } catch { throw "Unable to update or save the profile!" } } } else { Write-Output "$Name already is loaded in this session. Use the -Force parameter to load it again anyways.." } } } Function Add-OMPProfileSetting { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Add-OMPProfileSetting.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string]$Name, [Parameter(Position = 1)] $Value, [Parameter(Position = 2)] [switch]$NoProfileUpdate ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $ExistingSettings = @(($Script:OMPProfile).Keys) Write-Verbose "Existing settings: $($ExistingSettings -join ', ')" if ($ExistingSettings -notcontains $Name) { try { $Script:OMPProfile[$Name] = $Value } catch { Write-Error "Unable to add profile setting $Name" } if (-not $NoProfileUpdate) { try { Export-OMPProfile } catch { throw "Unable to update or save the profile!" } } } else { Write-Output "$Name already exists as a setting. Doing nothing." } } Function Export-OMPProfile { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Export-OMPProfile.md #> [CmdletBinding()] Param ( [Parameter()] [string]$Path = $Script:OMPProfileExportFile ) try { $Script:OMPProfile | ConvertTo-Json | Out-File $Path -Encoding:utf8 -Force } catch { throw "Unable to save $Path" } } function Get-OMPGitBranchName { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPGitBranchName.md #> $currentBranch = '' try { git branch | foreach { if ($_ -match "^\* (.*)") { $currentBranch += $matches[1] } } } catch { # do nothing but git likely isn't available } return $currentBranch } function Get-OMPGitStatus { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPGitStatus.md #> $deleted = 0 $modified = 0 $added = 0 $untracked = 0 try { $gitstatus = git status --porcelain --short $deleted = ($gitstatus | select-string '^D\s').count $modified = ($gitstatus | select-string '^M\s').count $added = ($gitstatus | select-string '^A\s').count $untracked = ($gitstatus | select-string '^\?\?\s').count } catch {} return @{ "untracked" = $untracked "added" = $added "modified" = $modified "deleted" = $deleted } } function Get-OMPHostState { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPHostState.md #> [CmdletBinding()] param( ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } process { } end { $Script:HostState Write-Verbose "$($FunctionName): End." } } function Get-OMPIPAddress { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPIPAddress.md #> [CmdletBinding()] param( ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } process { } end { # Retreive IP address informaton from dot net core only functions (should run on both linux and windows properly) $NetworkInterfaces = @([System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() | Where-Object {($_.OperationalStatus -eq 'Up')}) $NetworkInterfaces | Foreach-Object { $_.GetIPProperties() | Where-Object {$_.GatewayAddresses} | Foreach-Object { $Gateway = $_.GatewayAddresses.Address.IPAddressToString $DNSAddresses = @($_.DnsAddresses | Foreach-Object {$_.IPAddressToString}) $_.UnicastAddresses | Where-Object {$_.Address -notlike '*::*'} | Foreach-Object { New-Object PSObject -Property @{ IP = $_.Address Prefix = $_.PrefixLength Gateway = $Gateway DNS = $DNSAddresses } } } } Write-Verbose "$($FunctionName): End." } } function Get-OMPLoadedFunction { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPLoadedFunction.md #> [CmdletBinding()] param ( [Parameter()] [string]$Name = '*' ) Process { Get-ChildItem -Path "Function:\$Name" -Recurse | Where-Object { $null -ne $_.ohmypsh } | Select Name,ohmypsh } } function GET-OMPOSPlatform { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPOSPlatform.md #> [CmdletBinding()] param( [Parameter()] [Switch]$IncludeLinuxDetails ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } process {} end { $ThisIsCoreCLR = if ($IsCoreCLR) {$True} else {$False} $ThisIsLinux = if ($IsLinux) {$True} else {$False} #$Runtime::IsOSPlatform($OSPlatform::Linux) $ThisIsOSX = if ($IsOSX) {$True} else {$False} #$Runtime::IsOSPlatform($OSPlatform::OSX) $ThisIsWindows = if ($IsWindows) {$True} else {$False} #$Runtime::IsOSPlatform($OSPlatform::Windows) if (-not ($ThisIsLinux -or $ThisIsOSX)) { $ThisIsWindows = $true } if ($ThisIsLinux) { if ($IncludeLinuxDetails) { $LinuxInfo = Get-Content /etc/os-release | ConvertFrom-StringData $IsUbuntu = $LinuxInfo.ID -match 'ubuntu' if ($IsUbuntu -and $LinuxInfo.VERSION_ID -match '14.04') { return 'Ubuntu 14.04' } if ($IsUbuntu -and $LinuxInfo.VERSION_ID -match '16.04') { return 'Ubuntu 16.04' } if ($LinuxInfo.ID -match 'centos' -and $LinuxInfo.VERSION_ID -match '7') { return 'CentOS' } } return 'Linux' } elseif ($ThisIsOSX) { return 'OSX' } elseif ($ThisIsWindows) { return 'Windows' } else { return 'Unknown' } Write-Verbose "$($FunctionName): End." } } function Get-OMPPlugin { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPPlugin.md #> [CmdletBinding()] [OutputType('OMP.PluginStatus')] param ( [Parameter(Position = 0, ValueFromPipeline = $true)] [String]$Name ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." #Configure a default display set $defaultDisplaySet = 'Name','Loaded' #Create the default property display set $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet) } process { $AllPlugins = @() Foreach ($PluginPath in $Script:OMPProfile['OMPPluginRootPaths']) { if ([string]::IsNullOrEmpty($Name)) { $SearchPath = $PluginPath (Get-ChildItem $SearchPath -Directory).FullName | ForEach-Object { $AllPlugins += $_ } } else { if (Test-Path (Join-Path $PluginPath $Name)) { $AllPlugins = (Join-Path $PluginPath $Name) } } } if ($AllPlugins.Count -eq 0) { throw "Plugin not found in any path!" } $AllPlugins | ForEach-Object { $pluginmanifest = Join-Path $_ 'manifest.json' $manifest = $null if (Test-Path $pluginmanifest) { try { Write-Verbose "$($FunctionName): Manifest file found - $pluginmanifest" $manifest = Get-Content -Path $pluginmanifest -Raw | ConvertFrom-Json Write-Verbose "$($FunctionName): Manifest file loaded." } catch { Write-Verbose "$($FunctionName): Manifest file NOT loaded." } } $object = [pscustomobject]@{ Name = Split-Path $_ -Leaf Loaded = if ($Script:OMPState['PluginsLoaded'] -contains (Split-Path $_ -Leaf)) {$true} else {$false} Path = $_ Version = $manifest.Version Description = $manifest.Description Platform = $manifest.Platform } $object.PSTypeNames.Insert(0,'OMP.PluginStatus') $object | Add-Member MemberSet PSStandardMembers $PSStandardMembers $object } } } function Get-OMPPowerShellProfile { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPPowerShellProfile.md #> [CmdletBinding()] param( [Parameter()] [ValidateSet('AllUsersAllHosts','AllUsersCurrentHost','CurrentUserAllHosts','CurrentUserCurrentHost')] [string]$ProfileType = 'CurrentUserCurrentHost' ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } end { if (Test-Path $PROFILE.$ProfileType) { Get-Content $PROFILE.$ProfileType } else { Write-Warning "$($FunctionName): Profile does not exist - $($PROFILE.$ProfileType)" } Write-Verbose "$($FunctionName): End." } } function Get-OMPPowerShellProfileState { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPPowerShellProfileState.md #> [CmdletBinding()] param( ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." $ProfileTypes = @('AllUsersAllHosts','AllUsersCurrentHost','CurrentUserAllHosts','CurrentUserCurrentHost') } end { $order = 0 Foreach ($PType in $Profiletypes) { $order++ New-Object -TypeName psobject -Property @{ Name = $PType Exists = if (test-path $PROFILE.$Ptype) {$true} else {$false} Path = $PROFILE.$Ptype Order = $order } | Select Order, Name, Exists, Path } Write-Verbose "$($FunctionName): End." } } Function Get-OMPProfilePath { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPProfilePath.md #> [CmdletBinding()] param () $Script:OMPProfileExportFile } Function Get-OMPProfileSetting { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPProfileSetting.md #> [CmdletBinding()] param ( [Parameter(Position = 0, ValueFromPipeline = $true)] [ValidateScript({ (($Script:OMPProfile).Keys -contains $_ ) -or ([string]::IsNullOrEmpty($_)) })] [String]$Name ) process { if ([string]::IsNullOrEmpty($Name)) { $Script:OMPProfile } else { $Script:OMPProfile[$Name] } } } Function Get-OMPPromptColor { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPPromptColor.md #> [CmdletBinding()] param () [psobject]@{ BackgroundColor = $Host.UI.RawUI.BackgroundColor ForegroundColor = $Host.UI.RawUI.ForegroundColor ErrorForegroundColor = $Host.PrivateData.ErrorForegroundColor WarningForegroundColor = $Host.PrivateData.WarningForegroundColor DebugForegroundColor = $Host.PrivateData.DebugForegroundColor VerboseForegroundColor = $Host.PrivateData.VerboseForegroundColor ProgressForegroundColor = $Host.PrivateData.ProgressForegroundColor ErrorBackgroundColor = $Host.PrivateData.ErrorBackgroundColor WarningBackgroundColor = $Host.PrivateData.WarningBackgroundColor DebugBackgroundColor = $Host.PrivateData.DebugBackgroundColor VerboseBackgroundColor = $Host.PrivateData.VerboseBackgroundColor ProgressBackgroundColor = $Host.PrivateData.ProgressBackgroundColor } } function Get-OMPState { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPState.md #> [CmdletBinding()] param( ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } process {} end { $Script:OMPState Write-Verbose "$($FunctionName): End." } } function Get-OMPSystemUpTime { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPSystemUpTime.md #> [CmdletBinding()] param( [switch]$FromSleep ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." function Test-EventLogSource { param( [Parameter(Mandatory = $true)] [string] $SourceName ) try { [System.Diagnostics.EventLog]::SourceExists($SourceName) } catch { $false } } } process {} end { switch ( Get-OMPOSPlatform -ErrorVariable null ) { 'Linux' { # Add me! } 'OSX' { # Add me! } Default { if (-not $FromSleep) { $os = Get-WmiObject win32_operatingsystem $Uptime = (Get-Date) - ($os.ConvertToDateTime($os.lastbootuptime)) } elseif (Test-EventLogSource 'Microsoft-Windows-Power-Troubleshooter') { try { $LastPowerEvent = (Get-EventLog -LogName system -Source 'Microsoft-Windows-Power-Troubleshooter' -Newest 1 -ErrorAction:Stop).TimeGenerated } catch { $error.Clear() } if ($LastPowerEvent -ne $null) { $Uptime = ( (Get-Date) - $LastPowerEvent ) } } if ($Uptime -ne $null) { $Display = "" + $Uptime.Days + " days / " + $Uptime.Hours + " hours / " + $Uptime.Minutes + " minutes" Write-Output $Display } } } Write-Verbose "$($FunctionName): End." } } function Get-OMPTheme { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Get-OMPTheme.md #> [CmdletBinding()] [OutputType('OMP.ThemeStatus')] param ( [Parameter(Position = 0, ValueFromPipeline = $true)] [ValidateScript({ (@((Get-ChildItem (Join-Path $Script:ModulePath 'Themes') -File -Filter '*.ps1').Name | ForEach-Object {$_ -replace '.ps1',''}) -contains $_) -or ([string]::IsNullOrEmpty($_)) })] [String]$Name ) Begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." #Configure a default display set $defaultDisplaySet = 'Name','Loaded' #Create the default property display set $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet) } Process { if ([string]::IsNullOrEmpty($Name)) { $Themes = @((Get-ChildItem (Join-Path $Script:ModulePath 'Themes') -File -Filter '*.ps1').Name | ForEach-Object {$_ -replace '.ps1',''}) } else { $Themes = @((Get-ChildItem (Join-Path $Script:ModulePath "Themes\$Name.ps1") -File -Filter '*.ps1').Name | ForEach-Object {$_ -replace '.ps1',''}) } $Themes | ForEach-Object { $ThemePath = Join-Path $Script:ModulePath "Themes\$($_).ps1" $object = New-Object -TypeName PSObject -Property @{ 'Name' = $_ 'Loaded' = if ($Script:OMPProfile['Theme'] -eq $_) {$true} else {$false} 'Path' = $ThemePath 'Content' = Get-Content $ThemePath } $object.PSTypeNames.Insert(0,'OMP.ThemeStatus') $object | Add-Member MemberSet PSStandardMembers $PSStandardMembers $object } } End { Write-Verbose "$($FunctionName): End." } } Function Import-OMPModule { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Import-OMPModule.md #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string[]]$Name, [Parameter()] [string]$Prefix ) Begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." $AllModules = @() $ImportSplat = @{} if (-not [string]::IsNullOrEmpty($Prefix)) { $ImportSplat.Prefix = $Prefix } if ($Force) { $ImportSplat.Force = $true } } Process { $AllModules += $Name } End { Foreach ($Module in $AllModules) { if ( $null -eq (Get-Module $Module -ListAvailable) ) { if ($Script:OMPProfile['AutoInstallModules']) { Write-Verbose "$($FunctionName): Attempting to install missing module: $($Module)" try { Import-Module PowerShellGet -Force $null = Install-Module $Module -Scope:CurrentUser Write-Verbose "$($FunctionName): Module Installed - $($Module)" } catch { throw "Unable to find or install the following module requirement: $($Module)" } } else { throw "$($Module) was not found and automatic installation of modules is disabled in this profile!" } } # If we made it this far and the module isn't loaded, try to do so now. We have to import globaly for it to show up in the calling user's session. if (-not (get-module $Module)) { Write-Verbose "$($FunctionName): Attempting to import module - $Module" Import-Module $Module -Global -force @ImportSplat } else { Write-Verbose "$($FunctionName): $Module is already loaded" return } # check if it loaded properly if (-not (get-module $Module)) { throw "$($Module) was not able to load!" } else { Write-Verbose "$($FunctionName): Module Imported - $Module" } } } } Function Import-OMPProfile { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Import-OMPProfile.md #> [CmdletBinding()] Param ( [Parameter()] [string]$Path = $Script:OMPProfileExportFile ) try { $LoadedProfile = Get-Content $Path | ConvertFrom-Json } catch { throw "Unable to load $Path" } $ProfileSettings = ($LoadedProfile | Get-Member -Type 'NoteProperty').Name ForEach ($Key in $ProfileSettings) { if (@($Script:OMPProfile.Keys) -contains $Key) { Write-Verbose "Updating profile setting '$key' from $Path" $Script:OMPProfile[$Key] = $LoadedProfile.$Key } else { Write-Verbose "Adding profile setting '$key' from $Path" ($Script:OMPProfile).$Key = $LoadedProfile.$Key } } $MissingSettings = @($Script:OMPProfile.Keys | Where-Object {$ProfileSettings -notcontains $_}) if ($MissingSettings.Count -gt 0) { Write-Verbose "There were $($MissingSettings.Count) settings missing from the saved profile. Re-exporting to bring profile up to date." try { Export-OMPProfile -Path $Script:OMPProfileExportFile } catch { throw "Unable to export profile to $($Script:OMPProfileExportFile)" } } } Function Invoke-OMPPluginShutdown { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Invoke-OMPPluginShutdown.md #> [CmdletBinding()] param ( [Parameter(Position = 0, ValueFromPipeline = $true)] [string]$Name ) Begin { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState Write-Verbose "Attempting to shutdown the plugin $Name" } Process { Foreach ($Plugin in (Get-OMPPlugin -Name $Name | Where {$_.Loaded})) { $LoadScript = Join-Path $Plugin.Path "Load.ps1" $Shutdown = $null if (-not (Test-Path $LoadScript)) { Write-Error "Unable to find the plugin load file: $LoadScript" return } Write-Verbose "Executing plugin load script: $LoadScript" # pull in the entire load script $errmsg = $null $sb = [Scriptblock]::create(".{$(Get-Content -Path $LoadScript -Raw)}") Invoke-Command -NoNewScope -ScriptBlock $sb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg))) { Write-Warning "Unable to load plugin $($Plugin.Name)" Write-Warning "Error: $($errmsg | Select *)" return } # Run shutdown plugin code $errmsg = $null if ($Shutdown -ne $null) { $Shutdownsb = [Scriptblock]::create(".{$Shutdown}") Invoke-Command -NoNewScope -ScriptBlock $Shutdownsb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg))) { Write-Warning "Unable to run shutdown plugin code for $($Plugin.Name)" Write-Warning "Error: $($errmsg | Select *)" return } } } } } Function New-OMPPlugin { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/New-OMPPlugin.md #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Name, [Parameter()] [string]$Path ) if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." $TemplatePath = Join-Path $Script:ModulePath 'templates\plugin' if ([string]::IsNullOrEmpty($Path)) { $PluginDestPath = Join-Path $Script:ModulePath "plugins\$Name" } else { if (Test-Path $Path) { $PluginDestPath = Join-Path $Path $Name if ((Get-OMPProfileSetting).OMPPluginRootPaths -notcontains $Path) { Write-Warning "$($FunctionName): $Path exists but is not in the OMPPluginRootPaths list for your profile. This plugin will be created regardless but will not be usable." } } else { throw "$Path does not exist!" } } Write-Verbose "$($FunctionName): New Plugin Path = $PluginDestPath" if (Test-Path $TemplatePath) { if (-not (Test-Path $PluginDestPath)) { $null = Copy-Item -Path $TemplatePath -Destination $PluginDestPath -Recurse Write-Output "The following plugin template has been created: $PluginDestPath" Write-Output "Modify the $PluginDestPath\src\Plugin.ps1 file to suit your needs." Write-Output "When ready to do so, test your plugin with Add-OMPPlugin -Name $Name -NoProfileUpdate" } else { Write-Error "The plugin name already exists: $PluginDestPath" } } else { Write-Error "The source plugin template path doesn't exist: $TemplatePath" } } Function New-OMPPluginManifest { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/New-OMPPluginManifest.md #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Name, [Parameter()] [string]$Path, [Parameter()] [string]$Version = '0.0.1', [Parameter()] [string]$Description = '' ) if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." if ([string]::IsNullOrEmpty($Path)) { $ManifestFile = Join-Path $Script:ModulePath "plugins\$Name\manifest.json" } else { if (Test-Path $Path) { if (-not $Path.EndsWith('manifest.json')) { $ManifestFile = Join-Path $Path 'manifest.json' } else { $ManifestFile = $Path } } else { throw "$Path does not exist!" } } Write-Verbose "$($FunctionName): Manifest file to output = $Manifestfile" try { [psobject]@{ Name = $Name Version = $Version Description = $Description } | ConvertTo-Json | Out-File $ManifestFile -Encoding:utf8 } catch { throw } } Function Optimize-OMPProfile { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Optimize-OMPProfile.md #> [CmdletBinding()] Param() if ((Test-OMPIsElevated) -and ((Get-OMPOSPlatform) -eq 'Windows')) { Write-Output 'Optimizing assemblies for PowerShell profile.' $env:path = (@($env:path -split ';') + [Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory() | Sort-Object -Unique) -join ';' [AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object { if (-not $_.location) { continue } $Name = Split-Path $_.location -leaf Write-Output "NGENing : $Name" ngen install $_.location | ForEach-Object {"`t$_"} } } else { Write-Warning "Not able to optimize assemblies either because this prompt is not eleveted or the platform is not Windows." } } Function Remove-OMPAutoLoadModule { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Remove-OMPAutoLoadModule.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string]$Name, [Parameter(Position = 1)] [switch]$NoProfileUpdate ) try { Remove-OMPModule -Name $Name -ErrorAction:SilentlyContinue $Script:OMPProfile['AutoLoadModules'] = @($Script:OMPProfile['AutoLoadModules'] | Where-Object {$_ -ne $Name} | Sort-Object -Unique) if (-not $NoProfileUpdate) { Export-OMPProfile } } catch { # Do nothing } } Function Remove-OMPModule { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Remove-OMPModule.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string[]]$Name, [Parameter(Position = 1)] [switch]$PluginSafe ) Begin { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $AllModules = @() $PluginSafeArg = @{} if ($PluginSafe) { $PluginSafeArg.PluginSafe = $true } } Process { $AllModules += (Get-Module $Name).Name } End { Foreach ($Module in $AllModules) { # Recursively remove dependant modules first... $ModulesDependOnMe = @(Get-Module | Where {$_.RequiredModules -contains $Module}) if ($ModulesDependOnMe.Count -gt 0) { Write-Verbose "Found $($ModulesDependOnMe.Count) other modules dependant upon $Module" $ModulesDependOnMe | ForEach-Object { Write-Verbose "Recursively attempting to remove $($_) first..." Remove-OMPModule -Name $_ @PluginSafeArg } } # if pluginsafe removal then only remove modules new since OMP started and not in our autoload module list. if ($PluginSafe) { $WasAlreadyLoaded = ($Script:OMPState['ModulesAlreadyLoaded'] -contains $Module) $IsAutoLoaded = ($Script:OMPProfile['AutoLoadModules' -contains $Module]) if (-not ($WasAlreadyLoaded -or $IsAutoLoaded)) { try { Write-Verbose "Attempting to remove module: $Module" Remove-Module -Name $Module -Force } catch { throw "Unable to remove module $($Name)" } } else { Write-Output "Refraining from unloading module as it is defined for autoloading in the profile or was loaded before OhMyPsh started." } } else { try { Write-Verbose "Attempting to remove module: $Module" Remove-Module -Name $Module -Force } catch { throw "Unable to remove module $($Name)" } } } } } Function Remove-OMPPersonalFunction { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Remove-OMPPersonalFunction.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string]$Path, [Parameter(Position = 1)] [switch]$NoProfileUpdate ) try { $Script:OMPProfile['PersonalFunctions'] = @($Script:OMPProfile['PersonalFunctions'] | Where-Object {$_ -ne $Path} | Sort-Object -Unique) if (-not $NoProfileUpdate) { Export-OMPProfile } } catch { throw "Unable to remove personal function path: $Path" } } Function Remove-OMPPlugin { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Remove-OMPPlugin.md #> [CmdletBinding()] param ( [Parameter()] [switch]$Force, [Parameter()] [switch]$NoProfileUpdate ) dynamicparam { # Create dictionary $DynamicParameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $NewParamSettings = @{ Name = 'Name' Position = 0 Type = 'string' HelpMessage = 'The plugin to remove.' ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true } $NewParamSettings.ValidateSet = @($Script:OMPState['PluginsLoaded']) if ((@($Script:OMPState['PluginsLoaded']).Count -gt 0) -and (-not $force)) { $NewParamSettings.ValidateSet = (Get-OMPProfileSetting).Plugins } # Add new dynamic parameter to dictionary New-DynamicParameter @NewParamSettings -Dictionary $DynamicParameters # Return dictionary with dynamic parameters $DynamicParameters } begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } process { # Pull in the dynamic parameters first New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters $LoadedPlugins = $Script:OMPState['PluginsLoaded'] if (-not [string]::IsNullOrEmpty($Name)) { if ((@($Script:OMPState['PluginsLoaded']) -contains $Name) -or $Force) { $Unload = $null $PluginPath = (Get-OMPPlugin | Where {$_.Name -eq $Name}).Path $UnloadScript = Join-Path $PluginPath 'Load.ps1' if (Test-Path $UnloadScript) { Write-Verbose "Executing plugin unload script: $UnloadScript" # pull in the unload definition $sb = [Scriptblock]::create(".{$(Get-Content -Path $UnloadScript -Raw)}") Invoke-Command -NoNewScope -ScriptBlock $sb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg))) { Write-Warning "Unable to unload plugin - $Name" Write-Warning "Error: $($errmsg | Select *)" throw } # Run unload plugin code $Unloadsb = [Scriptblock]::create(".{$Unload}") Invoke-Command -NoNewScope -ScriptBlock $Unloadsb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg))) { Write-Warning "Unable to unload plugin - $Name" Write-Warning "Error: $($errmsg | Select *)" throw } } else { Write-Verbose "No unload file found for plugin - $Name" } # If we made it this far then update our loaded plugins list to remove the plugin $Script:OMPState['PluginsLoaded'] = @($LoadedPlugins | Where-Object {$_ -ne $Name} | Sort-Object -Unique) if (-not $NoProfileUpdate) { try { $Script:OMPProfile['Plugins'] = @($Script:OMPProfile['Plugins'] | Where-Object {$_ -ne $Name} | Sort-Object -Unique) Export-OMPProfile } catch { throw "Unable to update or save the profile!" } } } else { Write-Output "$Name is not loaded in this session. Use the -Force parameter to try to unload it regardless." } } } } Function Remove-OMPProfileSetting { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Remove-OMPProfileSetting.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string]$Name, [Parameter(Position = 1)] [switch]$NoProfileUpdate ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $ExistingSettings = @(($Script:OMPProfile).Keys) if (($ExistingSettings -contains $Name) -and ($Script:OMPProfileCoreSettings -notcontains $Name)) { try { ($Script:OMPProfile).Remove($Name) } catch { Write-Error "Unable to remove profile setting $Name" } if (-not $NoProfileUpdate) { try { Export-OMPProfile } catch { throw "Unable to update or save the profile!" } } } else { Write-Output "$Name either doesn't exist or is a core profile property" } } function Reset-OMPConsoleOverride { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Reset-OMPConsoleOverride.md #> [CmdletBinding()] param( ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." function linksto($path, $target) { if(!(isshortcut $path)) { return $false } $path = "$(resolve-path $path)" $shell = new-object -com wscript.shell -strict $shortcut = $shell.createshortcut($path) $result = $shortcut.targetpath -eq $target [Runtime.Interopservices.Marshal]::ReleaseComObject($shortcut) > $null return $result } function isshortcut($path) { if(!(test-path $path)) { return $false } if($path -notmatch '\.lnk$') { return $false } return $true } # based on code from coapp: # https://github.com/coapp/coapp/tree/master/toolkit/Shell $cs = @" using System; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; namespace concfg { public static class Shortcut { public static void RmProps(string path) { var NT_CONSOLE_PROPS_SIG = 0xA0000002; var STGM_READ = 0; var lnk = new ShellLinkCoClass(); var data = (IShellLinkDataList)lnk; var file = (IPersistFile)lnk; file.Load(path, STGM_READ); data.RemoveDataBlock(NT_CONSOLE_PROPS_SIG); file.Save(path, true); Marshal.ReleaseComObject(data); Marshal.ReleaseComObject(file); Marshal.ReleaseComObject(lnk); } } [ComImport, Guid("00021401-0000-0000-C000-000000000046")] class ShellLinkCoClass { } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("45e2b4ae-b1c3-11d0-b92f-00a0c90312e1")] interface IShellLinkDataList { void _VtblGap1_2(); // AddDataBlock, CopyDataBlock [PreserveSig] Int32 RemoveDataBlock(UInt32 dwSig); void _VtblGap2_2(); // GetFlag, SetFlag } } "@ add-type -typedef $cs -lang csharp function rmprops($path) { if(!(isshortcut $path)) { return $false } $path = "$(resolve-path $path)" try { [concfg.shortcut]::rmprops($path) } catch [UnauthorizedAccessException] { return $false } $true } $pspath = "$pshome\powershell.exe" $pscorepath = "$pshome\pwsh.exe" function cleandir($dir) { if(!(test-path $dir)) { return } gci $dir | % { if($_.psiscontainer) { cleandir $_.fullname } else { $path = $_.fullname if((linksto $path $pspath) -or (linksto $path $pscorepath)) { if(!(rmprops $path)) { write-host "warning: admin permission is required to remove console props from $path" -f darkyellow } } } } } } process { } end { if(test-path hkcu:console) { gci hkcu:console | % { write-host "removing $($_.name)" rm "registry::$($_.name)" } } $dirs = @( "~\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar", "~\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Windows PowerShell", "\ProgramData\Microsoft\Windows\Start Menu\Programs" ) $dirs | % { cleandir $_ } Write-Verbose "$($FunctionName): End." } } Function Restore-OMPConsoleColor { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Restore-OMPConsoleColor.md #> [CmdletBinding()] param () Write-Verbose 'Restoring original console colors (this does not include psreadline configurations)' $OriginalColors = $Script:HostState['colors'] Set-OMPConsoleColor @OriginalColors } Function Restore-OMPConsolePrompt { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Restore-OMPConsolePrompt.md #> [CmdletBinding()] param () #if ($null -ne $Script:OldPrompt) { Write-Verbose 'Restoring original Prompt function' Set-Item Function:\prompt $Script:HostState['Prompt'] #} } Function Restore-OMPConsoleTitle { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Restore-OMPConsoleTitle.md #> [CmdletBinding()] param () Write-Verbose 'Restoring original console title' $Global:Host.UI.RawUI.WindowTitle = $Script:HostState['Title'] } Function Restore-OMPOriginalAlias { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Restore-OMPOriginalAlias.md #> [CmdletBinding()] param () # I cannot figure out a way to import these automatically back into the users session when the module unloads # so for now tell the user how to do so themselves if so desired. $Path = $Script:HostState['Aliases'] if ((Test-Path $Path)) { Write-Output '' Write-Output "Original aliases stored in $Path" Write-Output 'To restore these into your session run the following: ' Write-Output '' Write-Output ". $Path" Write-Output '' } } Function Restore-OMPOriginalPSDefaultParameter { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Restore-OMPOriginalPSDefaultParameter.md #> [CmdletBinding()] param () Write-Verbose 'Restoring original PSDefaultParameters variable' $Global:PSDefaultParameterValues = $Script:HostState['PSDefaultParameterValues'].Clone() } Function Restore-OMPOriginalTabCompletion { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Restore-OMPOriginalTabCompletion.md #> [CmdletBinding()] param () Write-Verbose 'Restoring original TabExpansion function' Set-Item function:\TabExpansion $Script:HostState['TabExpansion'] Write-Verbose 'Restoring original TabExpansion2 function' Set-Item function:\TabExpansion2 $Script:HostState['TabExpansion2'] } Function Restore-OMPPSReadline { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Restore-OMPPSReadline.md #> [CmdletBinding()] param () Write-Verbose 'Restoring original psreadline settings and colors' if ($null -ne $Script:PSReadlineState) { $TokenKinds = @( 'Comment', 'Keyword', 'String', 'Operator', 'Variable', 'Command', 'Parameter', 'Type', 'Number', 'Member') $PSReadlineSplat = @{} Foreach ($ReadlineOption in ($Script:PSReadlineState | Get-Member -MemberType:Property).Name) { if ($ReadlineOption -match '^(.*)(ForegroundColor|BackgroundColor)$') { $Token = $Matches[1] $ParamName = $Matches[2] if ($TokenKinds -contains $Token) { Write-Output "Restoring $ParamName for $Token to $(($Script:PSReadlineState).$ReadlineOption)" $Psreadlinesplat = @{ TokenKind = $Token $ParamName = ($Script:PSReadlineState).$ReadlineOption } Set-PSReadlineOption @Psreadlinesplat } } else { $PSReadlineSplat.$ReadlineOption = ($Script:PSReadlineState).$ReadlineOption } } Set-PSReadlineOption @PSReadlineSplat } Set-OMPConsoleColor @OriginalColors } function Set-OMPConsoleColor { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Set-OMPConsoleColor.md #> [CmdletBinding()] param( $BackgroundColor, $ForegroundColor, $ErrorForegroundColor, $WarningForegroundColor, $DebugForegroundColor, $VerboseForegroundColor, $ProgressForegroundColor, $ErrorBackgroundColor, $WarningBackgroundColor, $DebugBackgroundColor, $VerboseBackgroundColor, $ProgressBackgroundColor ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." $PsreadlineIsLoaded = if (get-module psreadline) {$true} else {$false} } process { if ($PsreadlineIsLoaded) { Write-Verbose "$($FunctionName): Psreadline is loaded, setting psreadline options." $PSReadlineOptions = Get-PSReadlineOption } else { Write-Verbose "$($FunctionName): Psreadline is not loaded, setting default host console colors." } if ($null -ne $BackgroundColor) { Write-Verbose "$($FunctionName): Setting the BackgroundColor" if ($PsreadlineIsLoaded) { $PSReadlineOptions.CommandBackgroundColor = $BackgroundColor } $Host.UI.RawUI.BackgroundColor = [System.ConsoleColor]$BackgroundColor } if ($null -ne $ForegroundColor) { Write-Verbose "$($FunctionName): Setting the ForegroundColor" if ($PsreadlineIsLoaded) { $PSReadlineOptions.CommandForegroundColor = $ForegroundColor } $Host.UI.RawUI.ForegroundColor = [System.ConsoleColor]$ForegroundColor } if (($host.PrivateData | get-member -Type:Property).Count -gt 0) { if ($null -ne $ErrorForegroundColor) { Write-Verbose "$($FunctionName): Setting the ErrorForegroundColor" if ($PsreadlineIsLoaded) { $PSReadlineOptions.ErrorForegroundColor = $ErrorForegroundColor } $Host.PrivateData.ErrorForegroundColor = [System.ConsoleColor]$ErrorForegroundColor } if ($null -ne $WarningForegroundColor) { Write-Verbose "$($FunctionName): Setting the WarningforegroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.WarningForegroundColor = $WarningForegroundColor #} $Host.PrivateData.WarningForegroundColor = [System.ConsoleColor]$WarningForegroundColor } if ($null -ne $DebugForegroundColor) { Write-Verbose "$($FunctionName): Setting the DebugForegroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.DebugForegroundColor = $DebugForegroundColor #} $Host.PrivateData.DebugForegroundColor = [System.ConsoleColor]$DebugForegroundColor } if ($null -ne $VerboseForegroundColor) { Write-Verbose "$($FunctionName): Setting the VerboseForegroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.VerboseForegroundColor = $VerboseForegroundColor #} $Host.PrivateData.VerboseForegroundColor = [System.ConsoleColor]$VerboseForegroundColor } if ($null -ne $ProgressForegroundColor) { Write-Verbose "$($FunctionName): Setting the ProgressForegroundColor" # if ($PsreadlineIsLoaded) { # $PSReadlineOptions.ProgressForegroundColor = $ProgressForegroundColor # } $Host.PrivateData.ProgressForegroundColor = [System.ConsoleColor]$ProgressForegroundColor } if ($null -ne $ErrorBackgroundColor) { Write-Verbose "$($FunctionName): Setting the ErrorBackgroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.ErrorBackgroundColor = $ErrorBackgroundColor #} $Host.PrivateData.ErrorBackgroundColor = [System.ConsoleColor]$ErrorBackgroundColor } if ($null -ne $WarningBackgroundColor) { Write-Verbose "$($FunctionName): Setting the WarningBackgroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.WarningBackgroundColor = $WarningBackgroundColor #} $Host.PrivateData.WarningBackgroundColor = [System.ConsoleColor]$WarningBackgroundColor } if ($null -ne $DebugBackgroundColor) { Write-Verbose "$($FunctionName): Setting the DebugBackgroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.DebugBackgroundColor = $DebugBackgroundColor #} $Host.PrivateData.DebugBackgroundColor = [System.ConsoleColor]$DebugBackgroundColor } if ($null -ne $VerboseBackgroundColor) { Write-Verbose "$($FunctionName): Setting the VerboseBackgroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.VerboseBackgroundColor = $VerboseBackgroundColor #} $Host.PrivateData.VerboseBackgroundColor = [System.ConsoleColor]$VerboseBackgroundColor } if ($null -ne $ProgressBackgroundColor) { Write-Verbose "$($FunctionName): Setting the ProgressBackgroundColor" #if ($PsreadlineIsLoaded) { # $PSReadlineOptions.ProgressBackgroundColor = $ProgressBackgroundColor #} $Host.PrivateData.ProgressBackgroundColor = [System.ConsoleColor]$ProgressBackgroundColor } } } end { Write-Verbose "$($FunctionName): End." } } function Set-OMPGitOutput { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Set-OMPGitOutput.md #> [CmdletBinding()] param ( [Parameter(Position = 0)] [ValidateSet('psgit','posh-git','script')] [string]$Name = 'script' ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } end { switch ($Name) { 'psgit' { Write-Verbose "$($FunctionName): Setting to psgit, attempting to unload posh-git if loaded." Remove-OMPAutoLoadModule 'posh-git' -ErrorAction:SilentlyContinue if (get-module 'posh-git') { Remove-Module 'posh-git' -ErrorAction:SilentlyContinue } try { Import-OMPModule 'psgit' Add-OMPAutoLoadModule 'psgit' Set-OMPProfileSetting -Name:OMPGitOutput -Value:$Name } catch { Write-Warning "$($FunctionName): Unable to load psgit module! Leaving current OMP git output setting in place." } } 'posh-git' { Write-Verbose "$($FunctionName): Setting to posh-git, attempting to unload psgit if loaded." Remove-OMPAutoLoadModule 'psgit' -ErrorAction:SilentlyContinue if (get-module 'psgit') { Remove-Module 'psgit' -ErrorAction:SilentlyContinue } try { Import-OMPModule 'posh-git' Add-OMPAutoLoadModule 'posh-git' Set-OMPProfileSetting -Name:OMPGitOutput -Value:$Name } catch { Write-Warning "$(FunctionName): Unable to load posh-git module! Leaving current OMP git output setting in place." } } Default { Write-Verbose "$($FunctionName): Setting to script, leaving git modules as they are" Remove-OMPAutoLoadModule 'psgit' Remove-OMPAutoLoadModule 'posh-git' if (get-module 'psgit') { Remove-Module 'psgit' -ErrorAction:SilentlyContinue } if (get-module 'posh-git') { Remove-Module 'posh-git' -ErrorAction:SilentlyContinue } Set-OMPProfileSetting -Name:OMPGitOutput -Value:$Name } } Write-Verbose "$($FunctionName): End." } } Function Set-OMPProfileSetting { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Set-OMPProfileSetting.md #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] $Value ) dynamicparam { # Create dictionary $DynamicParameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $ValidOMPProfileSettings = ($Script:OMPProfile).keys $NewParamSettings = @{ Name = 'Name' Type = 'string' ValidateSet = $ValidOMPProfileSettings HelpMessage = "The setting to update the value of." } # Add new dynamic parameter to dictionary New-DynamicParameter @NewParamSettings -Dictionary $DynamicParameters # Return dictionary with dynamic parameters $DynamicParameters } begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } process { # Pull in the dynamic parameters first New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters try { Write-Verbose "$($FunctionName): Attempting to update the $Name Setting to be $Value." Write-Verbose "$($FunctionName): Original value of $($Name) - $($Script:OMPProfile[$Name])" $Script:OMPProfile[$Name] = $Value } catch { throw "Unable to update profile setting $Name" } } End { try { Export-OMPProfile } catch { throw "Unable to update or save the profile!" } } } Function Set-OMPTheme { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Set-OMPTheme.md #> [CmdletBinding()] param ( [Parameter()] [switch]$NoProfileUpdate, [Parameter()] [switch]$Safe ) dynamicparam { # Create dictionary $DynamicParameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $ThemesPath = Join-Path $Script:ModulePath "themes" $ValidThemes = @(Get-ChildItem -Path $ThemesPath -File -Filter '*.ps1').BaseName $NewParamSettings = @{ Name = 'Name' Position = 0 Type = 'string' ValidateSet = $ValidThemes HelpMessage = 'The theme to load. Will be applied immediately' ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true } if ($null -ne $Script:OMPProfile['Theme']) { $NewParamSettings.ParameterDefaultValue = $Script:OMPProfile['Theme'] } # Add new dynamic parameter to dictionary New-DynamicParameter @NewParamSettings -Dictionary $DynamicParameters # Return dictionary with dynamic parameters $DynamicParameters } begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." $errmsg = $null } Process { if ($PSBoundParameters.ContainsKey('Name')) { try { if ($null -ne $PSBoundParameters['Name']) { # Pull in the dynamic parameters first New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters } } catch {} } if ([string]::IsNullOrEmpty($Name)) { Write-Output 'No theme specified, restoring the original PowerShell prompt and removing current theme' Restore-OMPConsolePrompt Restore-OMPConsoleTitle Restore-OMPConsoleColor } else { $ThemeScriptPath = (Join-Path $Script:ModulePath "themes\$Name.ps1") if (Test-Path $ThemeScriptPath) { Restore-OMPConsolePrompt Restore-OMPConsoleTitle Restore-OMPConsoleColor Write-Verbose "Loading theme file: $ThemeScriptPath" $script = (Get-Content $ThemeScriptPath -Raw) try { $sb = [Scriptblock]::create(".{$script}") Invoke-Command -NoNewScope -ScriptBlock $sb -ErrorVariable errmsg 2>$null if (-not ([string]::IsNullOrEmpty($errmsg))) { Write-Verbose "Errors occurred loading $ThemeScriptPath. Errors returned were $errmsg" if ($Safe) { Write-Warning "Errors were found on the error stream when loading the theme and the safe option was set, NOT saving this theme as the theme for this profile." return } } Set-OMPProfileSetting -Name 'Theme' -Value $Name } catch { Write-Warning "Unable to load theme file $ThemeScriptPath" Write-Warning "Errors reported - $errmsg" throw } } else { Throw "Theme with the name $Name was not found (somehow)!" } } if (-not $NoProfileUpdate) { $Script:OMPProfile['Theme'] = $Name Export-OMPProfile } Write-Verbose "$($FunctionName): End." } } Function Set-OMPWindowTitle { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Set-OMPWindowTitle.md #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string]$Title ) $Global:Host.UI.RawUI.WindowTitle = $Title } function Show-OMPHelp { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Show-OMPHelp.md #> [CmdletBinding()] param () $Help = @' Current OhMyPsh Profile: {{Profile}} Loaded Plugins: {{Plugins}} OhMyPsh Basics This module is a personal profile management and profile loading wizard for PowerShell 5.0 (and greater) users that uses a simple json configuration file to manage plugins, theming, module autoloading, module upgrading, module cleanup, and other chores so that you can be more productive in the shell. Plugin Power Plugins are dot sourced files that run scripts or import functions/variables/aliases into your session in a seamless manner. These are extremely powerful and versitile with only a nominal amount of effort to create and deploy. Here are a few examples on what you might do with them: EXAMPLE 1 - Keep a dumping ground of your personal 'One-off' script functions. With this module you can quickly load one off functions in your profile every time you start this module. This is common for many users that simply need to use a particular function over and over but don't have a need to turn them into full blown modules. First create your plugin framwork automatically with: New-OMPPlugin -Name 'personalfunctions' New-OMPPluginManifest -Name 'personalfunctions' -Description 'My personal functions' Simply define the function in the global scope like so: function Global:MyFunction { Write-Output 'Test' } Then save the function (or functions) in a file in the plugins\personalfunctions\src directory and run the following: Add-OMPPlugin -Name 'personalfunctions' Doing this will automatically update your profile to include the personalfunctions plugin everytime you load OhMyPsh. If this is not what you want then run the following instead to just load it for this session: Add-OMPPlugin -Name 'personalfunctions' -Force -NoProfileUpdate EXAMPLE 2 - Run some task every 5th time you load OhMyPsh Perhaps you need your ego stroked a bit so you you decide to tell yourself how great you are every five times you load OhMyPsh. Easy stuff, first create your template plugin: New-OMPPlugin -Name 'egoboost' Next update the returned plugin.ps1 file with the following code: $Freq = 5 $TotalRuns = Get-OMPProfileSetting -Name:OMPRunCount if (-not ($TotalRuns % $Freq)) { Write-Verbose "Total OMP run count is a multiple of the egoboost frequency setting ($Freq)" Write-Output "I'm Good Enough, I'm Smart Enough, and Doggone It, People Like Me!" } Test and then add the new plugin to your persistent session: Add-OMPPlugin -Name 'personalfunctions' -Force -NoProfileUpdate Add-OMPPlugin -Name 'personalfunctions' -Force Unload and reload the module a few times to be given your positive affirmation. NOTE: Exported functions from plugins will not be shown with get-command -module OhMyPsh! If you want to get a quick view of the functions that are in your session because of plugins then use the following command: Get-OMPPluginFunction Easy Configuration A fairly sane default configuration is provided out of the box with this module. You can see all current settings with the following function: Get-OMPProfileSetting You can easily modify all of these settings without ever having to open it in an editor. Use the Set-OMPProfileSetting function (which includes tab completion for all settings via the 'Name' Parameter BTW). These settings will instantly save to your persistent profile. EXAMPLE 1 - Enable verbose output when loading your module Set-OMPProfileSetting -Name:OMPDebug -Value:$false EXAMPLE 2 - Disable module auto cleanup (deletion of older version modules) Set-OMPProfileSetting -Name:AutoCleanOldModules -Value:$false Themes Themes are simply customized PSColor hash definitions and a prompt that get imported as a ps1 file. Set your theme with Set-OMPTheme. EXAMPLE 1 - Set the theme to 'norm' Set-OMPTheme norm Further Information The entire module is pure powershell and is hosted on github for your convenience. https://www.github.com/zloeber/OhMyPsh '@ -replace '{{Profile}}', $Script:OMPProfileExportFile -replace '{{Plugins}}', ($Script:OMPState['PluginsLoaded'] -join ', ') Write-Output $Help } function Show-OMPStatus { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Show-OMPStatus.md #> [CmdletBinding()] param () $Status = @' Current OhMyPsh Profile: {{Profile}} Loaded Plugins: {{Plugins}} '@ -replace '{{Profile}}', $Script:OMPProfileExportFile -replace '{{Plugins}}', ($Script:OMPState['PluginsLoaded'] -join ', ') Write-Output $Status } Function Test-OMPConsoleHasANSI { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Test-OMPConsoleHasANSI.md #> # Powershell ISE don't support ANSI, and this test will print ugly chars if($host.PrivateData.ToString() -eq 'Microsoft.PowerShell.Host.ISE.ISEOptions') { return $false } # To test is console supports ANSI, we will print an ANSI code # and check if cursor postion has changed. If it has, ANSI is not # supported $oldPos = $host.UI.RawUI.CursorPosition.X Write-Host -NoNewline "$([char](27))[0m" -ForegroundColor ($host.UI.RawUI.BackgroundColor); $pos = $host.UI.RawUI.CursorPosition.X if($pos -eq $oldPos) { return $true } else { # If ANSI is not supported, let's clean up ugly ANSI escapes Write-Host -NoNewLine ("`b" * 4) return $false } } function Test-OMPInAGitRepo { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Test-OMPInAGitRepo.md #> if ((Test-Path ".git") -eq $TRUE) { return $TRUE } # Test within parent dirs $checkIn = (Get-Item .).parent while ($checkIn -ne $NULL) { $pathToTest = $checkIn.fullname + '/.git' if ((Test-Path $pathToTest) -eq $TRUE) { return $TRUE } else { $checkIn = $checkIn.parent } } return $FALSE } function Test-OMPIsElevated { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Test-OMPIsElevated.md #> [CmdletBinding()] param( ) begin { if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." } process { } end { switch ( Get-OMPOSPlatform -ErrorVariable null ) { 'Linux' { # Add me! } 'OSX' { # Add me! } Default { if (([System.Environment]::OSVersion.Version.Major -gt 5) -and ((New-object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) { return $true } else { return $false } } } Write-Verbose "$($FunctionName): End." } } Function Test-OMPProfileSetting { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Test-OMPProfileSetting.md #> [CmdletBinding()] param ( [Parameter(Position = 0, ValueFromPipeline = $true)] [String]$Name ) Process { if (($Script:OMPProfile).Keys -contains $Name ) { $true } else { $false } } } function Write-OMPGitStatus { <# .EXTERNALHELP OhMyPsh-help.xml .LINK https://github.com/zloeber/OhMyPsh/tree/master/release/0.0.6/docs/Functions/Write-OMPGitStatus.md #> switch ($Script:OMPProfile['OMPGitOutput']) { 'posh-git' { Write-VcsStatus } 'psgit' { Write-VcsStatus } Default { # Script or other method if (Test-OMPInAGitRepo) { $status = Get-OMPGitStatus $currentBranch = Get-OMPGitBranchName Write-Host '[' -nonewline -foregroundcolor Yellow Write-Host $currentBranch -nonewline $gitstatus = ' +' + $status["added"] + ' ~' + $status["modified"] + ' -' + $status["deleted"] + ' !' + $status["untracked"] + ']' Write-Host $gitstatus -foregroundcolor Yellow -NoNewline } } } } ## Post-Load Module code ## # These are core settings which we will not allow to ever get removed $Script:OMPProfileCoreSettings = @( 'AutoLoadModules', 'AutoInstallModules', 'Plugins', 'PersonalFunctions', 'Theme', 'UnloadModulesOnExit', 'OMPRunCount', 'OMPPluginRootPaths', 'OMPDebug', 'OMPGitOutput' ) <# Fill out each of the setting hash entries with some sensible defaults. This is the master template for user profile settings. Once the module runs once these settings are effectively ignored and should be managed via the exported functions instead. #> $Script:OMPProfile = @{ # Load these modules with your OMP profile AutoLoadModules = @() # Download modules if missing? AutoInstallModules = $true # Which plugins would you like to load? Plugins = @() # Personal functions are like plugins but less structured PersonalFunctions = @() # Theme Theme = $null # If this is true we will attempt to unload any modules that weren't already loaded when we started UnloadModulesOnExit = $true # Used to display first time help or just keep a run of how much you love this module OMPRunCount = 0 # Plugins can be located in many locations, this is the list of paths they may reside in OMPPluginRootPaths = @((Join-Path $ModulePath "plugins")) # Use this to see additional output when loading the module OMPDebug = $false # Preferred git status method. Used in prompts, specifically in Write-OMPGitStatus. Can be: # posh-git (module), psgit (module), script/other (no module, use the crappy baked in scripts with this module instead). OMPGitOutput = 'script' } # Load any persistent data (overrides anything in OMPSettings if the hash element exists) if ((Test-Path $OMPProfileExportFile)) { try { Import-OMPProfile -Path $OMPProfileExportFile } catch { throw "Unable to load the OMP profile: $OMPProfileExportFile" } } $VerbosityFlag = @{} if ($Script:OMPProfile['OMPDebug']) { $VerbosityFlag.Verbose = $true $Script:OldVerbosePreference = $VerbosePreference $VerbosePreference = "Continue" } # We need to keep some state information outside of the profile. This is the hash # used for this purpose. This combined with Get-OMPState can speed up some operations. # This is only able to be updated by OMP functions. $OMPState = @{ PluginsLoaded = @() ModulesAlreadyLoaded = @((Get-Module).Name) Platform = Get-OMPOSPlatform } <# Perform profile processing, this is where all the fun begins... #> # 1. Load any specified autoload modules $Script:OMPProfile['AutoLoadModules'] | Import-OMPModule @VerbosityFlag # 2. Now the personal functions $Script:OMPProfile['PersonalFunctions'] | Foreach-Object { try { Invoke-OMPPersonalFunction -Path $_ -Tag 'personalfunction' } catch {} } # 3. Now the plugins Write-Verbose 'Loading Plugins:' Foreach ($Plugin in ($Script:OMPProfile['Plugins'] | Sort-Object)) { Write-Verbose "Attempting to load plugin $Plugin" try { Add-OMPPlugin -Name $Plugin -NoProfileUpdate @VerbosityFlag Write-Verbose "Plugin Loaded: $Plugin" } catch { Write-Warning "Unable to load the following plugin: $($_)" } } # 4. Next the theme try { $Theme = $Script:OMPProfile['Theme'] if (-not [string]::IsNullOrEmpty($Script:OMPProfile['Theme'])) { Set-OMPTheme -Name $Theme -NoProfileUpdate Write-Verbose "Theme Loaded: $($Theme)" } } catch { Write-Warning "Unable to load the following theme: $($Theme)" } # 5. If we made it this far then we can bump up our run count by 1, save, # and continue processing items that rely upon this number $Script:OMPProfile['OMPRunCount'] += 1 Export-OMPProfile -Path $OMPProfileExportFile ######################################################################## # Action to take if the module is removed $ExecutionContext.SessionState.Module.OnRemove = { # Any functions loaded as plugins will get removed from the pssession Write-Output "Removing plugin or other dot sourced functions performed within OhMyPsh.." Get-ChildItem -Path Function:\ -Recurse | Where-Object { $_.ohmypsh -ne $null } | Remove-Item -Force # Run any plugin shutdown code blocks Write-Output "Processing OhMyPsh plugin shutdown scriptblocks" Invoke-OMPPluginShutdown # Remove any newly loaded modules since we started (if enabled) if ($Script:OMPProfile['UnloadModulesOnExit']) { Write-Output "Removing any modules loaded since OhMyPsh started" Get-Module | Where-Object {$OMPState['ModulesAlreadyLoaded'] -notcontains $_.Name} | Foreach-Object { if ($_.Name -ne 'OhMyPsh') { Write-Output " Module being removed from this session: $($_.Name)" Remove-Module -Name $_.Name -Force } } } # Restore prompts, tabcompletion, aliases, and console settings Restore-OMPConsolePrompt Restore-OMPOriginalTabCompletion Restore-OMPOriginalPSDefaultParameter Restore-OMPOriginalAlias Restore-OMPConsoleTitle Restore-OMPConsoleColor } $null = Register-EngineEvent -SourceIdentifier ( [System.Management.Automation.PsEngineEvent]::Exiting ) -Action { # Action to take if the whole pssession is killed # Run any plugin shutdown code blocks at the very least. Invoke-OMPPluginShutdown } if ($Script:OMPProfile['OMPDebug']) { $VerbosityFlag = @{} $VerbosePreference = $Script:OldVerbosePreference } $ThisModuleLoaded = $true |