plugins/conemu/src/Plugin.ps1
function Global:New-DynamicParameter { [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()] [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) 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 } } } # https://github.com/joonro/ConEmu-Color-Themes/blob/master/Install-ConEmuTheme.ps1 function Global:Install-ConemuTheme { [CmdletBinding()] param ( [Parameter()] [ValidateNotNullOrEmpty()] [ValidateScript( {Test-Path -Path $_})] [string]$ConfigPath = (Join-Path "${env:ConEmuCfgDir}" 'ConEmu.xml'), [Parameter(Mandatory = $true)] [ValidateSet('Add', 'Remove')] [string]$Operation = 'Add' ) dynamicparam { # Create dictionary $DynamicParameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $ConEmuThemesPath = Get-OMPProfileSetting -Name 'ConEmuThemesLocation' if ($Operation -eq 'Add') { $ValidThemes = @(Get-ChildItem -Path $ConEmuThemesPath -File -Filter '*.xml').BaseName $NewParamSettings = @{ Name = 'Theme' Type = 'string' ValidateSet = $ValidThemes HelpMessage = 'The theme to load. Will be applied to conemu config file but conemu will need to be restarted to select and apply the theme.' ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true } } else { if (-not [string]::IsNullOrEmpty($ConfigPath)) { [Xml]$config = Get-Content -Path $ConfigPath } else { [Xml]$config = Get-Content (Join-Path "${env:ConEmuCfgDir}" 'ConEmu.xml') } $installedthemes = @((($config.key.key.key | Where-Object { $_.name -eq ".Vanilla" }).key | Where-Object { $_.name -eq "Colors" }).key | Foreach { $_.Value } | Where-Object {($_.Name -eq 'Name')}).data if ($installedthemes.Count -gt 0) { $NewParamSettings = @{ Name = 'Theme' Type = 'string' ValidateSet = $installedthemes HelpMessage = 'The theme to remove. Will be applied to conemu config file but conemu will need to be restarted.' ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true } } else { $NewParamSettings = @{ Name = 'Theme' Type = 'string' HelpMessage = 'The theme to remove. Will be applied to conemu config file but conemu will need to be restarted.' ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true } } } # Add new dynamic parameter to dictionary New-DynamicParameter @NewParamSettings -Dictionary $DynamicParameters # Return dictionary with dynamic parameters $DynamicParameters } begin { $ConEmuThemesPath = Get-OMPProfileSetting -Name 'ConEmuThemesLocation' } process { if ($null -ne $PSBoundParameters) { # Pull in the dynamic parameters first New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters } } end { try { [Xml]$config = Get-Content -Path $ConfigPath $config.Save([System.IO.Path]::ChangeExtension($ConfigPath, ".backup.xml")) $vanilla = $config.key.key.key | Where-Object { $_.name -eq ".Vanilla" } $colors = $vanilla.key | Where-Object { $_.name -eq 'Colors' } switch ($Operation) { 'Add' { $ThemePath = Join-Path $ConEmuThemesPath "$Theme.xml" [Xml]$themexml = Get-Content -Path $ThemePath if ($colors -eq $null) { [Xml]$emptyColors = "<key name='Colors'><value name='Count' type='long' data='0'/></key>" $vanilla.AppendChild($config.ImportNode($emptyColors.DocumentElement, $true)) | Out-Null $colors = $vanilla.key | Where-Object { $_.name -eq "Colors" } } else { $themeName = ($themexml.key.value | Where-Object { $_.name -eq "Name" }).data $existingTheme = $colors.key | Where-Object { $_.value | Where-Object { $_.name -eq "Name" -and $_.data -eq $themeName } } if ($existingTheme -ne $null) { throw "Theme was already added to config" } } $null = $colors.AppendChild($config.ImportNode($themexml.DocumentElement, $true)) } 'Remove' { if (($null -eq $colors) -or ($null -eq $colors.key)) { throw "No themes in config" } $themexml = $colors.key | Where-Object { $_.value | Where-Object { $_.name -eq 'Name' -and $_.data -eq $Theme } } if ($null -eq $themexml) { throw 'Theme not found in config' } $null = $colors.RemoveChild($themexml) } } if ($colors.key -eq $null) { $colors.value.data = "0" } elseif ($colors.key -is [System.Array]) { $colors.value.data = $colors.key.Count.ToString() for ($i = 0; $i -lt $colors.key.Count; $i++) { $colors.key[$i].name = "Palette$($i + 1)" } } else { $colors.value.data = "1" $colors.key.name = "Palette1" } $config.Save($ConfigPath) } catch { Write-Error -Message $_ } } } |