PSUtil.psm1
$script:ModuleRoot = $PSScriptRoot $script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\PSUtil.psd1").ModuleVersion # Detect whether at some level dotsourcing was enforced $script:doDotSource = Get-PSFConfigValue -FullName PSUtil.Import.DoDotSource -Fallback $false if ($PSUtil_dotsourcemodule) { $script:doDotSource = $true } <# Note on Resolve-Path: All paths are sent through Resolve-Path/Resolve-PSFPath in order to convert them to the correct path separator. This allows ignoring path separators throughout the import sequence, which could otherwise cause trouble depending on OS. Resolve-Path can only be used for paths that already exist, Resolve-PSFPath can accept that the last leaf my not exist. This is important when testing for paths. #> # Detect whether at some level loading individual module files, rather than the compiled module was enforced $importIndividualFiles = Get-PSFConfigValue -FullName PSUtil.Import.IndividualFiles -Fallback $false if ($PSUtil_importIndividualFiles) { $importIndividualFiles = $true } if (Test-Path (Resolve-PSFPath -Path "$($script:ModuleRoot)\..\.git" -SingleItem -NewChild)) { $importIndividualFiles = $true } if ("<was compiled>" -eq '<was not compiled>') { $importIndividualFiles = $true } function Import-ModuleFile { <# .SYNOPSIS Loads files into the module on module import. .DESCRIPTION This helper function is used during module initialization. It should always be dotsourced itself, in order to proper function. This provides a central location to react to files being imported, if later desired .PARAMETER Path The path to the file to load .EXAMPLE PS C:\> . Import-ModuleFile -File $function.FullName Imports the file stored in $function according to import policy #> [CmdletBinding()] Param ( [string] $Path ) $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath if ($doDotSource) { . $resolvedPath } else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) } } #region Load individual files if ($importIndividualFiles) { # Execute Preimport actions . Import-ModuleFile -Path "$ModuleRoot\internal\scripts\preimport.ps1" # Import all internal functions foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Import all public functions foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Execute Postimport actions . Import-ModuleFile -Path "$ModuleRoot\internal\scripts\postimport.ps1" # End it here, do not load compiled code below return } #endregion Load individual files #region Load compiled code <# This file loads the strings documents from the respective language folders. This allows localizing messages and errors. Load psd1 language files for each language you wish to support. Partial translations are acceptable - when missing a current language message, it will fallback to English or another available language. #> Import-PSFLocalizedString -Path "$($script:ModuleRoot)\en-us\*.psd1" -Module 'PSUtil' -Language 'en-US' Register-PSFConfigValidation -Name "PSUBrowseHistoryOptions" -ScriptBlock { param ( $Value ) $result = New-Object PSObject -Property @{ Message = "" Value = $null Success = $false } try { [PSUtil.Configuration.HistoryOption]$option = $Value } catch { $result.Message = "Could not convert $Value into a valid help option. Please specify either of these: Session | Global" return $result } $result.Success = $true $result.Value = $option return $result } Register-PSFConfigValidation -Name "PSUConsoleWidth" -ScriptBlock { param ( $Value ) $result = New-Object PSObject -Property @{ Message = "" Value = $null Success = $false } try { [int]$option = $Value } catch { $result.Message = "Could not convert $Value into a valid integer | $_" return $result } if ($option -le 0) { $result.Message = "Cannot specify a window width of 0 or less" return $result } if ($option -gt $Host.UI.RawUI.MaxWindowSize.Width) { $result.Message = "Cannot specify a window width larger than the maximum width: $option / $($Host.UI.RawUI.MaxWindowSize.Width)" return $result } $result.Success = $true $result.Value = $option return $result } Register-PSFConfigValidation -Name "PSUGetHelpOptions" -ScriptBlock { param ( $Value ) $result = New-Object PSObject -Property @{ Message = "" Value = $null Success = $false } try { [PSUtil.Configuration.HelpOption]$option = $Value } catch { $result.Message = "Could not convert $Value into a valid help option. Please specify either of these: Short | Detailed | Examples | Full | Window | Online" return $result } $result.Success = $true $result.Value = $option return $result } # Configure the current window width Set-PSFConfig -Module PSUtil -Name 'Console.Width' -Value ($Host.UI.RawUI.WindowSize.Width) -Initialize -Validation "PSUConsoleWidth" -Handler { Set-PSUShell -WindowWidth $args[0] } -Description "The width of the current console" # Buffer Length Set-PSFConfig -Module PSUtil -Name 'Console.Buffer' -Value ($Host.UI.RawUI.BufferSize.Height) -Initialize -Validation "integerpositive" -Handler { Set-PSUShell -BufferLength $args[0] } -Description "The length of the console screen history" # Foreground Color Set-PSFConfig -Module PSUtil -Name 'Console.ForegroundColor' -Value ($Host.ui.rawui.ForegroundColor) -Initialize -Validation "consolecolor" -Handler { Set-PSUShell -ForegroundColor $args[0] } -Description "The foreground color used in the PowerShell console" # Background Color Set-PSFConfig -Module PSUtil -Name 'Console.BackgroundColor' -Value ($Host.ui.rawui.BackgroundColor) -Initialize -Validation "consolecolor" -Handler { Set-PSUShell -BackgroundColor $args[0] } -Description "The background color used in the PowerShell console" # Window Title Set-PSFConfig -Module PSUtil -Name 'Console.WindowTitle' -Value ($Host.ui.rawui.Windowtitle) -Initialize -Validation "string" -Handler { Set-PSUShell -WindowTitle $args[0] } -Description "The background color used in the PowerShell console" Set-PSFConfig -Module PSUtil -Name 'Import.Aliases.Grep' -Value $true -Initialize -Validation "bool" -Handler { } -Description "Whether the module will on import create an alias named 'grep' for Select-String" Set-PSFConfig -Module PSUtil -Name 'Import.Keybindings' -Value $true -Initialize -Validation "bool" -Handler { } -Description "Whether the module will on import register keybindings in PSReadline" Set-PSFConfig -Module PSUtil -Name 'Import.Alias.SystemOverride' -Value $false -Initialize -Validation "bool" -Description "Whether the module will on import pverwrite some default aliases with custom versions. Affects 'select' and 'gm'" Set-PSFConfig -Module 'PSUtil' -Name 'Import.DoDotSource' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be dotsourced on import. By default, the files of this module are read as string value and invoked, which is faster but worse on debugging." Set-PSFConfig -Module 'PSUtil' -Name 'Import.IndividualFiles' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be imported individually. During the module build, all module code is compiled into few files, which are imported instead by default. Loading the compiled versions is faster, using the individual files is easier for debugging and testing out adjustments." Set-PSFConfig -Module 'PSUtil' -Name 'Keybinding.GetHelp' -Value "F1" -Initialize -Description "The key chord(s) the open help functionality is bound to. Will provide help for the currently typed command." Set-PSFConfig -Module 'PSUtil' -Name 'Keybinding.ExpandAlias' -Value "Alt+Q" -Initialize -Description "The key chord(s) the alias expansion functionality is bound to. Will expand all aliases in the current input." Set-PSFConfig -Module 'PSUtil' -Name 'Keybinding.CopyAll' -Value "Ctrl+Shift+c" -Initialize -Description "The key chord(s) the copy all functionality is bound to. Will copy all lines of the current input to the clipboard." Set-PSFConfig -Module 'PSUtil' -Name 'Keybinding.BrowseHistory' -Value "F7" -Initialize -Description "The key chord(s) the browse history functionality is bound to. Will open a gridview and allow you to pick from your input history, then insert the chosen line(s) as your current input." Set-PSFConfig -Module 'PSUtil' -Name 'Keybinding.SendToHistory' -Value "Alt+w" -Initialize -Description "The key chord(s) the send to history functionality is bound to. Your current input will be sent to history without actually executing it. Access it by using the Arrow-UP key." Set-PSFConfig -Module 'PSUtil' -Name 'Knowledge.LibraryPath' -Value (Join-Path (Get-PSFPath AppData) 'PSUtil\Knowledge') -Initialize -Validation 'string' -Description "The path where the PSUtil knowledge commands look for knowledge files" Set-PSFConfig -Module 'PSUtil' -Name 'Knowledge.DefaultBook' -Value 'default' -Initialize -Validation 'string' -Description 'The default book of knowledge. Use when creating a new knowledge entry without specifying a book to write to' $defaultHelpPreference = [PSUtil.Configuration.HelpOption]::Window if (-not (Test-PSFPowerShell -OperatingSystem Windows)) { $defaultHelpPreference = [PSUtil.Configuration.HelpOption]::Detailed } Set-PSFConfig -Module PSUtil -Name 'Help.Preference' -Value $defaultHelpPreference -Initialize -Validation "PSUGetHelpOptions" -Handler { } -Description "The way in which help is shown when pressing the 'F1' key. Can be any of the following options: Short | Detailed | Examples | Full | Window | Online" Set-PSFConfig -Module PSUtil -Name 'History.Preference' -Value ([PSUtil.Configuration.HistoryOption]::Session) -Initialize -Validation "PSUBrowseHistoryOptions" -Handler { } -Description "Where the system will retrieve input history when pressing the 'F7' key. Can be any of the following options: Session | Global. Session includes history since the process was started, Global will try to look up the history from PSReadline log-file instead" Set-PSFConfig -Module PSUtil -Name 'History.Limit' -Value (-1) -Initialize -Validation 'integer' -Handler { } -Description "The maximum number of history entries to show when pressing the 'F7' key. Negative numbers disable limit" Set-PSFConfig -Module PSUtil -Name 'Expand.DefaultProperties' -Value "Definition", "Guid", "DisinguishedName", "FullName", "Name", "Length" -Initialize -Validation stringarray -Description "The properties Expand-PSUObject (exp) picks from by default" Set-PSFConfig -Module PSUtil -Name 'Path.Temp' -Value $([System.IO.Path]::GetTempPath()) -Initialize -Validation "string" -Handler { } -Description "The path to move to when calling Invoke-PSUTemp (temp)" Set-PSFConfig -Module PSUtil -Name 'Path.BackupStepsDefault' -Value 1 -Initialize -Validation "integer" -Description "The number of levels you stup up when calling Backup-PSULocation (bu) without parameter" function Import-PSUAlias { <# .SYNOPSIS Internal command to set aliases in a user-controlled fashion. .DESCRIPTION Internal command to set aliases in a user-controlled fashion. - Can be blocked by setting a config "PSUtil.Import.Aliases.$Name" to $false. - Will not overwrite existing aliases .PARAMETER Name Name of the alias to set. .PARAMETER Command Name of the command to alias. .EXAMPLE PS C:\> Import-PSUAlias -Name grep -Command Select-String Sets the alias grep for the command Select-String #> [CmdletBinding()] Param ( $Name, $Command ) if (((-not (Test-Path alias:$name)) -or ($Name -eq "Select") -or ($Name -eq "gm")) -and (Get-PSFConfigValue -FullName PSUtil.Import.Aliases.$name -Fallback $true)) { New-Alias -Name $Name -Value $Command -Force -Scope Global } } function Backup-PSULocation { <# .SYNOPSIS Sets the location n number of levels up. .DESCRIPTION You no longer have to cd ..\..\..\..\ to move back four levels. You can now just type bu 4 .PARAMETER Levels Number of levels to move back. .EXAMPLE PS C:\Users\dlbm3\source\pullrequests\somePR\vsteam> bu 4 PS C:\Users\dlbm3> .NOTES Author: Donovan Brown Source: http://donovanbrown.com/post/Why-cd-when-you-can-just-backup Thank you for sharing and granting permission to use this convenience :) #> [CmdletBinding()] param ( [int] $Levels = (Get-PSFConfigValue -FullName 'PSUtil.Path.BackupStepsDefault' -Fallback 1) ) Set-Location -Path (,".." * $Levels | Join-String -With ([System.IO.Path]::DirectorySeparatorChar)) } Import-PSUAlias -Name "bu" -Command "Backup-PSULocation" function Invoke-PSUDesktop { <# .SYNOPSIS Function that sets the current console path to the user desktop. .DESCRIPTION Function that sets the current console path to the user desktop. Uses the current user's desktop by default, but can be set to the desktop of any locally available profile. .PARAMETER User Alias: u Choose which user's desktop path to move to. Must be available as a local profile for things to work out. .PARAMETER Get Alias: g Returns the path, rather than changing the location .EXAMPLE PS C:\> Desktop Sets the current location to the desktop path of the current user. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseOutputTypeCorrectly", "")] [CmdletBinding()] Param ( [Parameter(Position = 0)] [Alias('u')] [string] $User = $env:USERNAME, [Alias('g')] [switch] $Get ) # Default Path for current user $Path = "$env:SystemDrive\Users\$User\Desktop" if (-not (Test-Path $Path)) { Stop-PSFFunction -Message "Path to Desktop not found: $Path" -Tag fail -Target $User -Category InvalidArgument return } if ($Get) { return $Path } else { Push-Location $Path } } Import-PSUAlias -Name "desktop" -Command "Invoke-PSUDesktop" function Invoke-PSUExplorer { <# .SYNOPSIS Opens the windows explorer at the specified position. .DESCRIPTION Opens the windows explorer at the specified position. .PARAMETER Path Alias: FullName Default: (Get-Location).Path The folder to open in explorer. If a file was passed the containing folder will be opened instead. .PARAMETER Module The module, the base folder of which should be opened. .PARAMETER Duplicates Setting this switch will cause the function to open the same folder multiple times, if it was passed multiple times. By default, the function will not open the same folder multiple times (a dir of a directory with multiple files would otherwise cause multiple open windows). .PARAMETER EnableException This parameters disables user-friendly warnings and enables the throwing of exceptions. This is less user friendly, but allows catching exceptions in calling scripts. .EXAMPLE PS C:\> dir | Explorer Opens each folder in the current directory in a separate explorer Window. #> [CmdletBinding()] Param ( [Parameter(Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('FullName')] [string[]] $Path = (Get-Location).ProviderPath, [System.Management.Automation.PSModuleInfo[]] $Module, [switch] $Duplicates, [switch] $EnableException ) Begin { # Contains previously opened folders $List = @() } Process { foreach ($item in $Path) { try { $resolvedPaths = Resolve-PSFPath -Path $item -Provider FileSystem } catch { Stop-PSFFunction -Message "Path not found: $item" -EnableException $EnableException -ErrorRecord $_ -Continue -Tag input -Target $item } foreach ($resolvedPath in $resolvedPaths) { $object = Get-Item $resolvedPath if ($object.PSIsContainer) { $finalPath = $object.FullName } else { $finalPath = $object.Directory.FullName } # If it was already opened once, skip it unless duplicates are enabled if ((-not $Duplicates) -and ($List -contains $finalPath)) { Write-PSFMessage -Level Verbose -Message "Skipping folder since it already was opened once: $finalPath" -Target $item -Tag skip continue } Write-PSFMessage -Level Verbose -Message "Opening explorer at: $finalPath" explorer.exe $finalPath $List += $finalPath } } foreach ($item in $Module) { if ((-not $Duplicates) -and ($List -contains $item.ModuleBase)) { Write-PSFMessage -Level Verbose -Message "Skipping folder since it already was opened once: $($item.ModuleBase)" -Target $item -Tag skip continue } Write-PSFMessage -Level Verbose -Message "Opening explorer at: $($item.ModuleBase)" explorer.exe $item.ModuleBase $List += $item.ModuleBase } } } Import-PSUAlias -Name "explorer" -Command "Invoke-PSUExplorer" function Invoke-PSUTemp { <# .SYNOPSIS Moves the current location to a temp directory. .DESCRIPTION Moves the current location to a temp directory. The path returned can be set by configuring the 'psutil.path.temp' configuration. E.g.: Set-PSFConfig "psutil.path.temp" "D:\temp\_Dump" If this configuration is not set, it will check the following locations and return the first one found: C:\Temp D:\Temp E:\Temp C:\Service $env:temp .PARAMETER Get Alias: g Rather than move to the directory, return its path. .EXAMPLE PS C:\> Invoke-PSUTemp Moves to the temporary directory. #> [CmdletBinding()] Param ( [Alias('g')] [switch] $Get ) if ($Get) { Get-PSFConfigValue -FullName 'PSUtil.Path.Temp' -Fallback $env:TEMP } else { Push-Location -Path (Get-PSFConfigValue -FullName 'PSUtil.Path.Temp' -Fallback $env:TEMP) } } Import-PSUAlias -Name "temp" -Command "Invoke-PSUTemp" function New-PSUDirectory { <# .SYNOPSIS Creates a folder and moves the current path to it. .DESCRIPTION Creates a folder and moves the current path to it. .PARAMETER Path Name of the folder to create and move to. .EXAMPLE PS C:\> mcd Test creates folder C:\Test, then moves the current location to it. .NOTES Author: Donovan Brown Source: http://donovanbrown.com/post/How-to-create-and-navigate-a-directory-with-a-single-command Thank you for sharing and granting permission to use this convenience :) #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] $Path ) New-Item -Path $Path -ItemType Directory Set-Location -Path $Path } Import-PSUAlias -Name "mcd" -Command "New-PSUDirectory" function Set-PSUDrive { <# .SYNOPSIS Creates a new psdrive, and moves location to it. .DESCRIPTION Will create a PSDrive, by default in the current path. This allows swiftly reducing path length. Then it will immediately change location to the new drive. .PARAMETER Name What to name the new PSDrive? .PARAMETER Root Default: . The root of the new drive. .EXAMPLE PS C:\> set-as pr Sets the current path as drive "pr" and sets it as the current location. .NOTES Author: Donovan Brown Source: http://donovanbrown.com/post/Shorten-your-PowerShell-directory-path Thank you for sharing and granting permission to use this convenience :) #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] $Name, [string] $Root = "." ) $path = Resolve-Path $Root $null = New-PSDrive -PSProvider $path.Provider -Name $Name -Root $Root -Scope Global Set-Location -LiteralPath "$($Name):" } Import-PSUAlias -Name "set-as" -Command "Set-PSUDrive" function Read-PSUKnowledge { <# .SYNOPSIS Searches for knowledge. .DESCRIPTION Searches for knowledge. Generally, knowledge must first be generated using Write-PSUKnowledge. This allows these functions to server as a searchable notes section right within your console. However, there might be some other ways to seek knowledge ... .PARAMETER Name The name of the knowledge entry. .PARAMETER Tags Tags to search by. At least one of the specified tags must be contained. .PARAMETER Pattern Search Name and text of the page by using this regex pattern. .PARAMETER Book The book to search in. By default you only have one and don't need to worry about this. .PARAMETER Online Mysterious parameter. I wonder what it does ... .EXAMPLE PS C:\> Read-PSUKnowledge Lists all knowledge entries. .EXAMPLE PS C:\> Read-PSUKnowledge -Tags DNS Lists all knowledge entries with the tag "DNS" .EXAMPLE PS C:\> read -p ldap Lists all knowledge entries with the string "ldap" in name or text. #> [CmdletBinding()] param ( [parameter(Position = 0)] [Alias('Page')] [string] $Name = '*', [string[]] $Tags, [Alias('p','f','filter')] [string] $Pattern = '.', [string] $Book = '*', [switch] $Online ) begin { $libraryPath = Get-PSFConfigValue -FullName 'PSUtil.Knowledge.LibraryPath' } process { # Gimmick: Search in wikipedia if ($Online) { $url = "https://en.wikipedia.org/wiki/Special:Search/$Name" Start-Process $url return } if (-not (Test-Path -Path $libraryPath)) { return } foreach ($bookFile in (Get-ChildItem -Path $libraryPath -Filter *.json)) { $bookName = [System.Text.Encoding]::UTF8.GetString(([convert]::FromBase64String($bookFile.BaseName))) if ($bookName -notlike $Book) { continue } $data = Get-Content -Path $bookFile.FullName | ConvertFrom-Json foreach ($page in $data) { if ($page.Name -notlike $Name) { continue } if ($Tags -and -not ($Tags | Where-Object { $_ -in $page.Tags })) { continue } if ($Pattern -ne '.') { $matched = $false if ($page.Name -match $Pattern) { $matched = $true } elseif ($page.Text -match $Pattern) { $matched = $true } if (-not $matched) { continue } } $page | Select-PSFObject -KeepInputObject -TypeName 'PSUtil.Knowledge.Page' } } } } Import-PSUAlias -Name 'read' -Command Read-PSUKnowledge Import-PSUAlias -Name 'rdk' -Command Read-PSUKnowledge Import-PSUAlias -Name 'page' -Command Read-PSUKnowledge Import-PSUAlias -Name 'learn' -Command Read-PSUKnowledge function Remove-PSUKnowledge { <# .SYNOPSIS Removes pages from the books of your holy console library of knowledge. .DESCRIPTION Removes pages from the books of your holy console library of knowledge. Contribute new knowledge by using Write-PSUKnowledge or search it by using Read-PSUKnowlege. .PARAMETER Name The name of the page to rip out. .PARAMETER Book The book of knowledge to deface. Defaults to the book specified under the 'PSUtil.Knowledge.DefaultBook' configuration setting. It will look for books in your library path, which can be specified under 'PSUtil.Knowledge.LibraryPath'. .EXAMPLE PS C:\> Remove-PSUKnowledge -Name 'DNS for Dummies' Rips out the page 'DNS for Dummies' from your default book. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('page')] [string[]] $Name, [Parameter(ValueFromPipelineByPropertyName = $true)] [string] $Book = (Get-PSFConfigValue -FullName 'PSUtil.Knowledge.DefaultBook') ) begin { $libraryPath = Get-PSFConfigValue -FullName 'PSUtil.Knowledge.LibraryPath' } process { if (-not (Test-Path -Path $libraryPath)) { return } $bookName = '{0}.json' -f [System.Text.Encoding]::UTF8.GetBytes($Book) $bookPath = Join-Path $libraryPath $bookName if (-not (Test-Path -Path $bookPath)) { return } $pageEntries = Get-Content -Path $bookPath | ConvertFrom-Json $pageEntries = $pageEntries | Where-Object Name -notin $Name $pageEntries | ConvertTo-Json | Set-Content -Path $bookPath } } function Write-PSUKnowledge { <# .SYNOPSIS Writes a piece of knowledge into the designated book. .DESCRIPTION Writes a piece of knowledge into the designated book. This can be later retrieved using Read-PSUKnowledge. "Books" are an arbitrary label grouping one or multiple pieces of text ("pages"). You could separate them by category (e.g. "Active Directory" or "Exchagne Online") or by computer (e.g. "Desktop", "Notebook", ...). .PARAMETER Name The name of the page to write. .PARAMETER Text The page / text to write. .PARAMETER Tags Additional tags to include. Tags help find content later on. .PARAMETER Book The book to write the content to. Defaults to the book specified under the 'PSUtil.Knowledge.DefaultBook' configuration setting. It will look for books in your library path, which can be specified under 'PSUtil.Knowledge.LibraryPath'. .PARAMETER EnableException This parameters disables user-friendly warnings and enables the throwing of exceptions. This is less user friendly, but allows catching exceptions in calling scripts. .EXAMPLE PS C:\> Set-PSUKnowledge -Name 'DNS Queries' -Text $nslookupExplained -Tags dns, network, infrastructure Defines a new page named "DNS Queries" with the text contained in $nslookupExplained. It also adds a few tags to make searching for it later easier. #> [CmdletBinding()] param ( [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Name, [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('Page')] [string] $Text, [parameter(ValueFromPipelineByPropertyName = $true)] [string[]] $Tags, [parameter(ValueFromPipelineByPropertyName = $true)] [string] $Book = (Get-PSFConfigValue -FullName 'PSUtil.Knowledge.DefaultBook'), [switch] $EnableException ) begin { $libraryPath = Get-PSFConfigValue -FullName 'PSUtil.Knowledge.LibraryPath' if (-not (Test-Path -Path $libraryPath)) { try { $null = New-Item -Path $libraryPath -ItemType Directory -Force -ErrorAction Stop } catch { Stop-PSFFunction -String 'Set-PSUKnowledge.Library.Path.CreationFailed' -StringValues $libraryPath -ErrorRecord $_ -EnableException $EnableException return } } } process { if (Test-PSFFunctionInterrupt) { return } # Fake loop to make interrupting easier in pipeline scenarios foreach ($nameItem in $Name) { $bookName = '{0}.json' -f [System.Convert]::ToBase64String(([System.Text.Encoding]::UTF8.GetBytes($Book))) $bookPath = Join-Path $libraryPath $bookName $bookData = @{ } if (Test-Path -Path $bookPath) { try { $pages = Get-Content -Path $bookPath -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop } catch { Stop-PSFFunction -String 'Set-PSUKnowledge.Book.ImportFailed' -StringValues $Book, $bookPath -ErrorRecord $_ -EnableException $EnableException -Continue } foreach ($page in $pages) { $bookdata[$page.Name] = $page } } $bookData[$Name] = [pscustomobject]@{ Name = $Name Text = $Text Tags = $Tags } try { $bookData.Values | ConvertTo-Json -ErrorAction Stop | Set-Content -Path $bookPath -ErrorAction Stop } catch { Stop-PSFFunction -String 'Set-PSUKnowledge.Book.ExportFailed' -StringValues $Name, $Book, $bookPath -ErrorRecord $_ -EnableException $EnableException -Continue } } } } function Convert-PSUObject { <# .SYNOPSIS Converts objects from one data-type/-format to another. .DESCRIPTION Converts objects from one data-type/-format to another. For example can this be used to convert numbers from binary to hex. This function can be dynamically extended by registering conversion paths. Use Register-PSUObjectConversion to set up such a type conversion. .PARAMETER InputObject The object(s) to convert. .PARAMETER From The type/format that is assumed to be the input type. .PARAMETER To The type/format that the input is attempted to convert to. .PARAMETER EnableException Replaces user friendly yellow warnings with bloody red exceptions of doom! Use this if you want the function to throw terminating errors you want to catch. .EXAMPLE PS C:\> 100..110 | convert IntDec IntHex Converts the numbers 100 through 110 from decimal to hexadecimal. #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] $InputObject, [Parameter(Mandatory = $true, Position = 0)] [string] $From, [Parameter(Mandatory = $true, Position = 1)] [string] $To, [switch] $EnableException ) begin { if (-not ([PSUtil.Object.ObjectHost]::Conversions.ContainsKey("$($From):$($To)"))) { Stop-PSFFunction -Message "No conversion path configured for $From --> $To" -EnableException $EnableException -Category NotImplemented -Tag 'fail', 'input', 'convert' return } $scriptBlock = [PSUtil.Object.ObjectHost]::Conversions["$($From):$($To)"].Script } process { if (Test-PSFFunctionInterrupt) { return } foreach ($item in $InputObject) { [PSFramework.Utility.UtilityHost]::ImportScriptBlock($scriptBlock) try { $scriptBlock.Invoke($item) } catch { Stop-PSFFunction -Message "Failed to convert $item from $From to $To" -EnableException $EnableException -ErrorRecord $_ -Target $item -Tag 'fail','convert','item' -Continue } } } } Import-PSUAlias -Name convert -Command Convert-PSUObject function Expand-PSUObject { <# .SYNOPSIS A comfortable replacement for Select-Object -ExpandProperty. .DESCRIPTION A comfortable replacement for Select-Object -ExpandProperty. Allows extracting properties with less typing and more flexibility: Preferred Properties: By defining a list of property-names in $DefaultExpandedProperties the user can determine his own list of preferred properties to expand. This allows using this command without specifying a property at all. It will then check the first object for the property to use (starting from the first element of the list until it finds an exact case-insensitive match). Defined Property: The user can specify the exact property to extract. This is the same behavior as Select-Object -ExpandProperty, with less typing (dir | exp length). Like / Match comparison: Specifying either like or match allows extracting any number of matching properties from each object. Note that this is a somewhat more CPU-expensive operation (which shouldn't matter unless with gargantuan numbers of objects). .PARAMETER Name ParSet: Equals, Like, Match The name of the Property to expand. .PARAMETER Like ParSet: Like Expands all properties that match the -Name parameter using -like comparison. .PARAMETER Match ParSet: Match Expands all properties that match the -Name parameter using -match comparison. .PARAMETER InputObject The objects whose properties are to be expanded. .EXAMPLE PS C:\> dir | exp Expands the property whose name is the first on the defaults list ($DefaultExpandedProperties). By default, FullName would be expanded. .EXAMPLE PS C:\> dir | exp length Expands the length property of all objects returned by dir. Simply ignores those that do not have the property (folders). .EXAMPLE PS C:\> dir | exp name -match Expands all properties from all objects returned by dir that match the string "name" ("PSChildName", "FullName", "Name", "BaseName" for directories) #> [CmdletBinding(DefaultParameterSetName = "Equals")] Param ( [Parameter(Position = 0, ParameterSetName = "Equals")] [Parameter(Position = 0, ParameterSetName = "Like", Mandatory = $true)] [Parameter(Position = 0, ParameterSetName = "Match", Mandatory = $true)] [string] $Name, [Parameter(ParameterSetName = "Like", Mandatory = $true)] [switch] $Like, [Parameter(ParameterSetName = "Match", Mandatory = $true)] [switch] $Match, [Parameter(ValueFromPipeline = $true)] [object] $InputObject ) Begin { Write-PSFMessage -Level Debug -Message "Expanding Objects" -Tag start $ParSet = $PSCmdlet.ParameterSetName Write-PSFMessage -Level InternalComment -Message "Active Parameterset: $ParSet | Bound Parameters: $($PSBoundParameters.Keys -join ", ")" -Tag start # Null the local scoped variable (So later checks for existence don't return super-scoped variables) $n9ZPiBh8CI = $null [bool]$____found = $false # If a property was specified, set it and return it if (Test-PSFParameterBinding -ParameterName "Name") { $n9ZPiBh8CI = $Name $____found = $true } $DefaultExpandedProperties = Get-PSFConfigValue -FullName 'PSutil.Expand.DefaultProperties' } process { :main foreach ($Object in $InputObject) { if ($null -eq $Object) { continue } switch ($ParSet) { #region Equals "Equals" { # If we didn't ask for a property in specific, and we have something prepared for this type: Run it if ((Test-PSFParameterBinding -ParameterName "Name" -Not) -and ([PSUtil.Object.ObjectHost]::ExpandedTypes[$Object.GetType().FullName])) { [PSUtil.Object.ObjectHost]::ExpandedTypes[$Object.GetType()].Invoke($Object) continue main } # If we already have determined the property to use, return it if ($____found) { if ($null -ne $Object.$n9ZPiBh8CI) { $Object.$n9ZPiBh8CI } continue main } # Otherwise, search through defaults and try to match foreach ($Def in $DefaultExpandedProperties) { if (Get-Member -InputObject $Object -MemberType 'Properties' -Name $Def) { $n9ZPiBh8CI = $Def $____found = $true if ($null -ne $Object.$n9ZPiBh8CI) { $Object.$n9ZPiBh8CI } break } } continue main } #endregion Equals #region Like "Like" { # Return all properties whose name are similar foreach ($prop in ($Object.PSObject.Properties | Where-Object Name -like $Name | Select-Object -ExpandProperty Name)) { if ($null -ne $Object.$prop) { $Object.$prop } } continue } #endregion Like #region Match "Match" { # Return all properties whose name match foreach ($prop in ($Object.PSObject.Properties | Where-Object Name -Match $Name | Select-Object -ExpandProperty Name)) { if ($null -ne $Object.$prop) { $Object.$prop } } continue main } #endregion Match } } } End { Write-PSFMessage -Level Debug -Message "Expanding Objects" -Tag end } } Import-PSUAlias -Name "exp" -Command "Expand-PSUObject" function Register-PSUObjectConversion { <# .SYNOPSIS Registers an object conversion for Convert-PSUObject. .DESCRIPTION This command can be used to register an object conversion for Convert-PSUObject, allowing the user to extend the conversion utility as desired. .PARAMETER From The input type. Using a suitable shorthand is recommended ("int" rather than "System.Int32", etc.). .PARAMETER To The conversion target type. Using a suitable shorthand is recommended ("int" rather than "System.Int32", etc.). .PARAMETER ScriptBlock The scriptblock that will be invoked to convert. Receives a single argument: The input object to convert. .EXAMPLE PS C:\> Register-PSUObjectConversion -From 'dec' -To 'oct' -ScriptBlock $ScriptBlock Registers a conversion that is supposed to convert a decimal into an octal number. #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [string] $From, [Parameter(Mandatory = $true)] [string] $To, [Parameter(Mandatory = $true)] [System.Management.Automation.ScriptBlock] $ScriptBlock ) process { $conversion = New-Object PSUtil.Object.ObjectConversionMapping -Property @{ From = $From To = $To Script = $ScriptBlock } [PSUtil.Object.ObjectHost]::Conversions["$($From):$($To)"] = $conversion } } function Register-PSUObjectExpansion { <# .SYNOPSIS Registers a custom scriptblock for a type when processed by Expand-PSUObject. .DESCRIPTION Registers a custom scriptblock for a type when processed by Expand-PSUObject. Expand-PSUObject enables accelerated object expansion, by shortening the "Select-Object -ExpandProperty" call to "exp". It further has a list of default properties to expand, but it also allows implementing custom expansion rules, based on input type. This commands sets up these custom expansion rules. Define a scriptblock, it receives a single parameter - the input object to expand. The scriptblock is then responsible for expanding it and producing the desired output. .PARAMETER TypeName The name of the type to custom-expand. .PARAMETER ScriptBlock The scriptblock performing the expansion. .EXAMPLE PS C:\> Register-PSUObjectExpansion -TypeName 'MyModule.MyClass' -ScriptBlock $ScriptBlock Sets up a custom expansion rule for the 'MyModule.MyClass' class. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [string] $TypeName, [Parameter(Mandatory = $true, Position = 1)] [scriptblock] $ScriptBlock ) process { [PSUtil.Object.ObjectHost]::ExpandedTypes[$TypeName] = $ScriptBlock } } function Select-PSUObjectSample { <# .SYNOPSIS Used to only pick a sample from the objects passed to the function. .DESCRIPTION Used to only pick a sample from the objects passed to the function. .PARAMETER InputObject The objects to pick a sample from. .PARAMETER Skip How many objects to skip. .PARAMETER Number How many objects to pick Use a negative number to pick the last X items instead. .EXAMPLE PS C:\> Get-ChildItem | Select-PSUObjectSample -Skip 1 -Number 3 Scans the current directory, skips the first returned object, then passes through the next three objects and skips the rest. .EXAMPLE PS C:\> dir | s 3 1 Same as the previous example, only this time using aliases and positional binding. Scans the current directory, skips the first returned object, then passes through the next three objects and skips the rest. #> [CmdletBinding()] Param ( [Parameter(ValueFromPipeline = $true, Mandatory = $true)] $InputObject, [Parameter(Position = 1)] [int] $Skip = 0, [Parameter(Position = 0)] [int] $Number = 1 ) Begin { $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Select-Object', [System.Management.Automation.CommandTypes]::Cmdlet) $splat = @{ } if ($Skip -gt 0) { $splat["Skip"] = $Skip } if ($Number -ge 0) { $splat["First"] = $Number + 1 } else { $splat["Last"] = $Number * -1 } $scriptCmd = { & $wrappedCmd @splat } $steppablePipeline = $scriptCmd.GetSteppablePipeline() $steppablePipeline.Begin($true) } Process { foreach ($o in $InputObject) { $steppablePipeline.Process($o) } } End { $steppablePipeline.End() } } Import-PSUAlias -Name "s" -Command "Select-PSUObjectSample" function Set-PSUObjectType { <# .SYNOPSIS Tries to convert an object from one type of another. .DESCRIPTION Tries to convert an object from one type of another. .PARAMETER InputObject The objects to convert. .PARAMETER Type ParSet: Type The type to cast to. .PARAMETER TypeName ParSet: String The type to cast to. .PARAMETER EnableException Replaces user friendly yellow warnings with bloody red exceptions of doom! Use this if you want the function to throw terminating errors you want to catch. .EXAMPLE PS C:\> "01", "02", "03", "42" | Set-PSUObjectType "int" Tries to convert strings with numeric values into pure integers (hint: This will probably succeede). #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding(DefaultParameterSetName = "String")] Param ( [Parameter(ValueFromPipeline = $true)] $InputObject, [Parameter(ParameterSetName = "Type")] [Type] $Type, [Parameter(ParameterSetName = "String", Position = 0)] [String] $TypeName, [switch] $EnableException ) Begin { Write-PSFMessage -Level Debug -Message "Casting Objects to another type" -Tag start $ParSet = $PSCmdlet.ParameterSetName Write-PSFMessage -Level InternalComment -Message "Active Parameterset: $ParSet | Bound Parameters: $($PSBoundParameters.Keys -join ", ")" -Tag start switch ($ParSet) { "Type" { $name = $Type.FullName } "String" { $name = $TypeName } } } Process { foreach ($object in $InputObject) { $temp = $null $temp = $object -as $name if ($temp) { $temp } else { Stop-PSFFunction -Message "Failed to convert '$object' to '$name'" -EnableException $EnableException -Category InvalidData -Tag fail, cast -Target $object -Continue } } } End { Write-PSFMessage -Level Debug -Message "Casting Objects to another type" -Tag end } } Import-PSUAlias -Name "cast" -Command "Set-PSUObjectType" function Out-PSUVariable { <# .SYNOPSIS Writes the input to a variable. .DESCRIPTION Writes the input to a variable. This allows doing variable assignments at the end of a pipeline, rather than just at the beginning. Previous contents will be overwritten. .PARAMETER Name The name of the variable to write to. .PARAMETER InputObject The objects to write. .EXAMPLE PS C:\> Get-ChildItem | Out-PSUVariable -Name 'files' Writes the files & folders in the current path into the variable $files .EXAMPLE PS C:\> dir | ov files Does the same thing as the first example, only this time in a convenient interactive commandline usage #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [string] $Name, [Parameter(ValueFromPipeline = $true)] $InputObject ) begin { $list = New-Object System.Collections.Generic.List[Object] } process { foreach ($object in $InputObject) { $list.Add($object) } } end { # Write to caller scope $PSCmdlet.SessionState.PSVariable.Set($Name, ($list | Write-Output)) } } Import-PSUAlias -Name ov -Command Out-PSUVariable function Select-PSUFunctionCode { <# .SYNOPSIS Function that shows you the definition of a function and allows you to select lines to copy to your clipboard. .DESCRIPTION Function that shows you the definition of a function and allows you to select lines to copy to your clipboard. After running this command you will see a GridView pop up. Select as many lines of code as you would like and select ok to copy them to your clipboard. .PARAMETER Function A description of the Function parameter. .PARAMETER NoWait Shows function code in gridview and returns control without waiting for the window to close .PARAMETER PassThru Presents input command(s) in gridview, selected lines (if any) get returned as output .PARAMETER NoTrim If enabled, the white space will not be trimmed. .PARAMETER EnableException Replaces user friendly yellow warnings with bloody red exceptions of doom! Use this if you want the function to throw terminating errors you want to catch. .EXAMPLE PS C:\> Select-PSUFunctionCode -function 'Start-PSUTimer' This will open up the code for the function Start-PSUTimer in a GridView window. .EXAMPLE PS C:\> Get-Command timer | Select-PSUFunctionCode You can also pipe functions in. .NOTES Author: Andrew Pla #> [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string[]] $Function, [Alias('w')] [Parameter(ParameterSetName = 'NoWait')] [switch] $NoWait, [Alias('p')] [Parameter(ParameterSetName = 'PassThru')] [switch] $PassThru, [Alias('t')] [switch] $NoTrim, [switch] $EnableException ) begin { Write-PSFMessage -Level InternalComment -Message "Bound parameters: $($PSBoundParameters.Keys -join ", ")" -Tag 'debug', 'start', 'param' if (Test-PSFPowerShell -PSMinVersion '6.0' -PSMaxVersion '6.9.9') { Stop-PSFFunction -Message "This command is not supported on PowerShell v6 due to lack of GUI elements!" -Category NotEnabled -Tag fail, ps6 return } $FinalArray = [System.Collections.Arraylist]@() } process { if (Test-PSFFunctionInterrupt) { return } #region Process Items :main foreach ($item in $Function) { #region Resolve Command try { $command = Get-Command $item -ErrorAction Stop } catch { Stop-PSFFunction -Message "Failed to resolve command $item" -Tag fail -ErrorRecord $_ -Target $item -Continue -ContinueLabel main -EnableException $EnableException } switch ($command.CommandType) { 'Alias' { if ($command.ResolvedCommand.CommandType -eq "Function") { $functionText = $command.ResolvedCommand | Expand-PSUObject | Split-String "`n" } else { Stop-PSFFunction -Message "$($command.ResolvedCommand.CommandType) not supported: The alias $item resolves to $($command.ResolvedCommand). Please supply a function or an alias for a function." -Tag fail -Target $item -Continue -ContinueLabel main -EnableException $EnableException } } 'Function' { $functionText = $command | Expand-PSUObject | Split-String "`n" } default { Stop-PSFFunction -Message "$($command.CommandType) not supported: $item. Please supply a function or an alias for a function." -Tag fail -Target $item -Continue -ContinueLabel main -EnableException $EnableException } } #endregion Resolve Command #region Process Definition content $count = 1 foreach ($line in $functionText) { $Object = [PSCustomObject]@{ LineNumber = $Count Text = $line Function = $item } $count++ if ($NoTrim) { $null = $FinalArray.add($Object) } else { if (-not ([string]::IsNullOrWhiteSpace($line))) { $null = $FinalArray.add($Object) } } } #endregion Process Definition content } #endregion Process Items } end { if (Test-PSFFunctionInterrupt) { return } # This is the default behavior with no params if (-not ($NoWait -or $PassThru)) { $data = $FinalArray | Out-GridView -PassThru -Title 'Select-PSUFunctionCode' | Expand-PSUObject text if ($data) { $data | Set-Clipboard } } if ($NoWait) { $FinalArray | Out-GridView -Title 'Select-PSUFunctionCode' } if ($PassThru) { $FinalArray | Out-GridView -PassThru -Title 'Select-PSUFunctionCode' } } } Import-PSUAlias -Name "inspect" -Command "Select-PSUFunctionCode" function Set-PSUPrompt { <# .SYNOPSIS Applies one of the pre-defined prompts. .DESCRIPTION Applies one of the pre-defined prompts. .PARAMETER Prompt The prompt to apply .PARAMETER EnableException This parameters disables user-friendly warnings and enables the throwing of exceptions. This is less user friendly, but allows catching exceptions in calling scripts. .EXAMPLE PS C:\> Set-PSUPrompt -Prompt fred Applies the prompt fred uses. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $Prompt, [switch] $EnableException ) process { if (-not (Test-Path "$script:ModuleRoot\internal\prompts\$Prompt.prompt.ps1")) { Stop-PSFFunction -Message "Failed to find prompt: $Prompt" -Target $Prompt -EnableException $EnableException -Category ObjectNotFound return } & "$script:ModuleRoot\internal\prompts\$Prompt.prompt.ps1" } } function Set-PSUShell { <# .SYNOPSIS Command that sets various console properties .DESCRIPTION Command that sets various console properties. .PARAMETER WindowWidth The width of the console window. Not much of a change on windows 10, more of a chore on older console hosts. .PARAMETER BackgroundColor The background color to use. Is PSReadline aware. .PARAMETER ForegroundColor The foreground color to use. Is PSReadline aware. .PARAMETER BufferLength How lengthy a memory the console screen keeps. The size of the stuff cls clears. .PARAMETER WindowTitle The title the window should have. .PARAMETER EnableException Replaces user friendly yellow warnings with bloody red exceptions of doom! Use this if you want the function to throw terminating errors you want to catch. .EXAMPLE PS C:\> Set-PSUShell -WindowWidth 140 -WindowTitle "The Foo Shell" -ForegroundColor DarkGreen -BackgroundColor Black Sets the current shell to ... - 140 pixel width - have a title of "The Foo Shell" - Use a foreground color of DarkGreen for all output, default prompt color and comment color (PSReadline syntax detection remains unaffected) - Use a background color of Black #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] Param ( [int] $WindowWidth, [System.ConsoleColor] $BackgroundColor, [System.ConsoleColor] $ForegroundColor, [int] $BufferLength, [string] $WindowTitle, [switch] $EnableException ) # Test whether the PSReadline Module is loaded $PSReadline = Get-Module PSReadline #region Utility Functions function Set-ShellWindowWidth { [CmdletBinding()] Param ( $WindowWidth ) $currentWindow = $host.ui.rawui.WindowSize $currentBuffer = $host.ui.rawui.Buffersize if ($currentBuffer.Width -gt $WindowWidth) { # Set Window $currentWindow.Width = $WindowWidth $host.ui.rawui.WindowSize = $currentWindow # Set Buffer $currentBuffer.Width = $WindowWidth $host.ui.rawui.Buffersize = $currentBuffer } else { # Set Buffer $currentBuffer.Width = $WindowWidth $host.ui.rawui.Buffersize = $currentBuffer # Set Window $currentWindow.Width = $WindowWidth $host.ui.rawui.WindowSize = $currentWindow } } #endregion Utility Functions #region Set Buffer if (Test-PSFParameterBinding -ParameterName "BufferLength") { $currentBuffer = $host.ui.rawui.Buffersize $currentBuffer.Height = $BufferLength $host.ui.rawui.Buffersize = $currentBuffer } #endregion Set Buffer #region Set Foreground Color if (Test-PSFParameterBinding -ParameterName "ForegroundColor") { $host.ui.rawui.ForegroundColor = $ForegroundColor if ($PSReadline.Version.Major -eq 1) { Set-PSReadlineOption -ContinuationPromptForegroundColor $ForegroundColor Set-PSReadlineOption -ForegroundColor $ForegroundColor -TokenKind 'Comment' Set-PSReadlineOption -ForegroundColor $ForegroundColor -TokenKind None } elseif ($PSReadline.Version.Major -gt 1) { Set-PSReadLineOption -Colors @{ Default = $ForegroundColor Comment = $ForegroundColor ContinuationPrompt = $ForegroundColor } } } #endregion Set Foreground Color #region Set Background Color if (Test-PSFParameterBinding -ParameterName "BackgroundColor") { $host.ui.rawui.BackgroundColor = $BackgroundColor if ($PSReadline.Version.Major -eq 1) { Set-PSReadlineOption -ContinuationPromptBackgroundColor $BackgroundColor Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'None' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Comment' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Keyword' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'String' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Operator' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Variable' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Command' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Type' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Number' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Member' Set-PSReadlineOption -BackgroundColor $BackgroundColor -TokenKind 'Parameter' Set-PSReadlineOption -EmphasisBackgroundColor $BackgroundColor Set-PSReadlineOption -ErrorBackgroundColor $BackgroundColor } } #endregion Set Background Color #region Set Window Title if (Test-PSFParameterBinding -ParameterName "WindowTitle") { $host.ui.rawui.Windowtitle = $WindowTitle } #endregion Set Window Title #region Set Window Width if (Test-PSFParameterBinding -ParameterName "WindowWidth") { try { Set-ShellWindowWidth -WindowWidth $WindowWidth -ErrorAction Stop } catch { Stop-PSFFunction -Message "Failed to set window width to $WindowWidth" -EnableException $EnableException -ErrorRecord $_ -Tag 'fail', 'width', 'console', 'window' return } } #endregion Set Window Width } function Start-PSUTimer { <# .SYNOPSIS Creates a timer that will alarm the user after it has expired. .DESCRIPTION Creates a timer that will alarm the user after it has expired. Provides both visual and sound warnings. Also provides a progress bar with a time remaining display. .PARAMETER Duration The time to wait. .PARAMETER Message What to wait for. .PARAMETER AlarmCount How often to give warning. .PARAMETER NoProgress Disables progress bar. .PARAMETER AlarmInterval In what time interval to write warnings and send sound. .PARAMETER MinFrequency The minimum frequency of the beeps. Must be at least one lower than MaxFrequency. Increase delta to play random frequency sounds on each beep. .PARAMETER MaxFrequency The maximum frequency of the beeps. Must be at least one higher than MaxFrequency. Increase delta to play random frequency sounds on each beep. .EXAMPLE PS C:\> timer 170 Tea After 170 Duration give warning that the tea is ready. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [Alias('Seconds')] [PSFDateTime] $Duration, [Parameter(Position = 1, Mandatory = $true)] $Message, [Parameter(Position = 2)] [int] $AlarmCount = 25, [switch] $NoProgress, [int] $AlarmInterval = 250, [int] $MinFrequency = 2999, [int] $MaxFrequency = 3000 ) begin { $start = Get-Date $end = $Duration.Value function Get-FriendlyTime { [CmdletBinding()] param ( [int] $Seconds ) $tempSeconds = $Seconds $strings = @() if ($tempSeconds -gt 3599) { [int]$count = [math]::Floor(($tempSeconds / 3600)) $strings += "{0}h" -f $count $tempSeconds = $tempSeconds - ($count * 3600) } if ($tempSeconds -gt 59) { [int]$count = [math]::Floor(($tempSeconds / 60)) $strings += "{0}m" -f $count $tempSeconds = $tempSeconds - ($count * 60) } $strings += "{0}s" -f $tempSeconds $strings -join " " } } process { if (-not $NoProgress) { Write-Progress -Activity "Waiting for $Message" -Status "Starting" -PercentComplete 0 } while ($end -gt (Get-Date)) { Start-Sleep -Milliseconds 500 if (-not $NoProgress) { $friendlyTime = Get-FriendlyTime -Seconds ($end - (Get-Date)).TotalSeconds [int]$percent = ((Get-Date) - $start).TotalSeconds / ($end - $start).TotalSeconds * 100 Write-Progress -Activity "Waiting for $Message" -Status "Time remaining: $($friendlyTime)" -PercentComplete ([System.Math]::Min($percent, 100)) } } if (-not $NoProgress) { Write-Progress -Activity "Waiting for $Message" -Completed } $countAlarm = 0 while ($countAlarm -lt $AlarmCount) { Write-PSFHostColor -String "(<c='sub'>$countAlarm</c>) ### <c='em'>$($Message)</c> ###" [System.Console]::Beep((Get-Random -Minimum $MinFrequency -Maximum $MaxFrequency), $AlarmInterval) Start-Sleep -Milliseconds $AlarmInterval $countAlarm++ } } } Import-PSUAlias -Name "timer" -Command "Start-PSUTimer" function Get-PSUPathAlias { <# .SYNOPSIS Gets the PSUPathAlias configuration values. .DESCRIPTION Gets the PSUPathAlias configuration values from the PSFConfig system. .PARAMETER Alias This is the name of the alias that you want for Set-PSUPath. Wildcards accepted Default Value: * .EXAMPLE PS C:\> Get-PSUPathAlias Returns all aliases #> [CmdletBinding()] param ( [string] $Alias = '*' ) $aliases = Get-PSFConfig -FullName psutil.pathalias.$Alias foreach ($currentAlias in $aliases) { [pscustomobject]@{ Alias = ($currentAlias.fullname -replace '^psutil.pathalias.') Path = $currentAlias.value } } } function Remove-PSUPathAlias { <# .SYNOPSIS Removes a path alias fromm the configuration system. .DESCRIPTION Removes a path alias from the configuration system using Unregister-PSFConfig. Note: This command has no effect on configuration setings currently in memory. .PARAMETER Alias The name of the Alias that you want to remove from the configuration system. .EXAMPLE PS C:\> Remove-PSUPathAlias -Alias work Removes the path alias named work from the configuration system. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(ValuefromPipelineByPropertyName = $true)] $Alias ) process { Get-PSFConfig -FullName psutil.pathalias.$Alias | Unregister-PSFConfig Remove-PSFAlias -Name $Alias } } function Set-PSUPath { <# .SYNOPSIS Detects the alias that called it and sets the location to the corresponding path found in the configuration system. .DESCRIPTION Detects the alias that called it and sets the location to the corresponding path. This function will normally be called using an alias that gets set by using Set-PSUPathAlias. .PARAMETER Alias This is the name of the alias that called the command. Default Value is $MyInvocation.InvocationName and is detected automatically .PARAMETER EnableException Replaces user friendly yellow warnings with bloody red exceptions of doom! Use this if you want the function to throw terminating errors you want to catch. .EXAMPLE PS C:\> Software PS C:\Software> In this example 'Software' is an alias for Set-PSUPath that was created by using Set-PSUPathAlias. Set-PSUPath detected that 'Software' was the alias that called it and then sends it to the path. It receives the path from Get-PSUPathAlias 'software' #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [string] $Alias = $MyInvocation.InvocationName, [switch] $EnableException ) begin { function Resolve-PsuPath { [OutputType([System.String])] [CmdletBinding()] param ( [string] $Path ) $environ = @{} foreach ($item in Get-ChildItem env:) { $environ[$item.Name] = $item.Value } $pattern = '%{0}%' -f ($environ.Keys -join '%|%') $replacement = { param ( [string] $Match ) $environ = @{ } foreach ($item in Get-ChildItem env:) { $environ[$item.Name] = $item.Value } $environ[$Match.Trim('%')] } [regex]::Replace($Path, $pattern, $replacement, 'IgnoreCase') } } process { try { $psfConfigPath = Get-PSFConfigValue -FullName psutil.pathalias.$Alias -NotNull } catch { $paramStopPSFFunction = @{ Message = "Unable to find a path setting for the alias" Category = 'InvalidOperation' Tag = 'fail' ErrorRecord = $_ EnableException = $EnableException } Stop-PSFFunction @paramStopPSFFunction return } try { Set-Location (Resolve-PsuPath -Path $psfConfigPath) -ErrorAction Stop } catch { $psfFuncParams = @{ EnableException = $EnableException Message = "Unable to set location to $psfConfigPath" Category = 'InvalidOperation' Tag = 'fail' ErrorRecord = $_ } Stop-PSFFunction @psfFuncParams return } } } function Set-PSUPathAlias { <# .SYNOPSIS Used to create an an alias that sets your location to the path you specify. .DESCRIPTION A detailed description of the Set-PSUPathAlias function. .PARAMETER Alias Name of the Alias that will be created for Set-PSUPath. Set-PSU Path detects the alias that called it and then finds the corresponding PSFConfig entry for it. .PARAMETER Path This is the path that you want your location to change to when the alias is called. .PARAMETER Register Causes PSUtil to remember the alias across sessions. For more advanced options, see Register-PSFConfig. .PARAMETER EnableException Replaces user friendly yellow warnings with bloody red exceptions of doom! Use this if you want the function to throw terminating errors you want to catch. .EXAMPLE PS C:\> Set-PSUPathAlias -Alias 'work' -Path 'C:\work' Creates an alias to Set-PSUPath that will set the location to 'c:\work' .EXAMPLE PS C:\> Set-PSUPathAlias -Alias 'repos' -Path 'C:\repos' -Register Creates an alias for repos and registers the setting so that it will persist between sessions. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory)] [string] $Alias, [Parameter(Position = 1, Mandatory)] [string] $Path, [switch] $Register, [switch] $EnableException ) try { Set-PSFConfig -FullName psutil.pathalias.$Alias -Value $Path -Description 'Sets an alias for Set-PSUPath that takes you to the path specified in the value.' } catch { $stopParams = @{ Message = 'Error encountered. Alias not set' Category = 'InvalidOperation' Tag = 'Fail' ErroRecord = $_ EnableException = $EnableException } Stop-PSFFunction @stopParams return } if ($Register) { Get-PSFConfig -FullName psutil.pathalias.$Alias | Register-PSFConfig } try { Import-PSUAlias -Name $Alias -Command Set-PSUPath } catch { $stopParams = @{ Message = 'Error. Alias not set' Category = 'InvalidOperation' Tag = 'Fail' ErroRecord = $_ EnableException = $EnableException } Stop-PSFFunction @stopParams return } } Register-PSFTeppScriptblock -Name psutil-convert-object-from -ScriptBlock { [PSUtil.Object.ObjectHost]::Conversions.Values.From | Select-Object -Unique } Register-PSFTeppScriptblock -Name psutil-convert-object-to -ScriptBlock { [PSUtil.Object.ObjectHost]::Conversions.Values | Where-Object From -EQ $fakeBoundParameter.From | Expand-PSUObject -Name To } Register-PSFTeppScriptblock -Name 'PSUtil.Knowledge.Book' -ScriptBlock { $libraryPath = Get-PSFConfigValue -FullName 'PSUtil.Knowledge.LibraryPath' if (-not (Test-Path $libraryPath)) { return } Get-ChildItem -Path $libraryPath -Filter *.json | ForEach-Object { [System.Text.Encoding]::UTF8.GetString(([convert]::FromBase64String($_.BaseName))) } | Sort-Object } Register-PSFTeppScriptblock -Name 'PSUtil.Knowledge.Page' -ScriptBlock { $book = '*' if ($fakeBoundParameter.Book) { $book = $fakeBoundParameter.Book } (Read-PSUKnowledge -Book $book).Name | Select-PSFObject -Unique | Sort-Object } Register-PSFTeppScriptblock -Name 'PSUtil.Knowledge.Tags' -ScriptBlock { $book = '*' if ($fakeBoundParameter.Book) { $book = $fakeBoundParameter.Book } (Read-PSUKnowledge -Book $book).Tags | Select-PSFObject -Unique | Sort-Object } Register-PSFTeppScriptBlock -Name 'PSUtil-Module-Installed' -ScriptBlock { (Get-PSFTaskEngineCache -Module PSUtil -Name Module).InstalledModules } Register-PSFTeppScriptBlock -Name 'PSUtil-Module-Total' -ScriptBlock { (Get-PSFTaskEngineCache -Module PSUtil -Name Module).AvailableModules } Register-PSFTeppScriptblock -Name 'PSUtil-Module-Repository' -ScriptBlock { (Get-PSFTaskEngineCache -Module PSUtil -Name Module).Repositories } Register-PSFTeppScriptblock -Name 'PSUtil-Module-PackageProvider' -ScriptBlock { (Get-PSFTaskEngineCache -Module PSUtil -Name Module).PackageProvider } Register-PSFTeppScriptblock -Name 'psutil.prompt' -ScriptBlock { $module = Get-Module PSUtil & $module { foreach ($item in (Get-ChildItem "$script:ModuleRoot\internal\prompts")) { $item.BaseName -replace '\.prompt$' } } } Register-PSFTeppScriptblock -Name psutil-userprofile -ScriptBlock { Get-ChildItem "$env:SystemDrive\Users" -Force | Where-Object PSIsContainer | Expand-PSUObject Name } Register-PSFTeppArgumentCompleter -Command Invoke-PSUDesktop -Parameter User -Name psutil-userprofile Register-PSFTeppArgumentCompleter -Command Convert-PSUObject -Parameter From -Name psutil-convert-object-from Register-PSFTeppArgumentCompleter -Command Convert-PSUObject -Parameter To -Name psutil-convert-object-to Register-PSFTeppArgumentCompleter -Command Set-PSUPrompt -Parameter Prompt -Name 'psutil.prompt' #region Module Register-PSFTeppArgumentCompleter -Command Update-Module -Parameter Name -Name 'PSUtil-Module-Installed' Register-PSFTeppArgumentCompleter -Command Uninstall-Module -Parameter Name -Name 'PSUtil-Module-Installed' Register-PSFTeppArgumentCompleter -Command Get-InstalledModule -Parameter Name -Name 'PSUtil-Module-Installed' Register-PSFTeppArgumentCompleter -Command Install-Module -Parameter Name -Name 'PSUtil-Module-Total' Register-PSFTeppArgumentCompleter -Command Find-Command -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Find-DscResource -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Find-Module -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Find-RoleCapability -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Find-Script -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Install-Module -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Install-Script -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Publish-Module -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Publish-Script -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Save-Module -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Save-Script -Parameter Repository -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Get-PSRepository -Parameter Name -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Unregister-PSRepository -Parameter Name -Name 'PSUtil-Module-Repository' Register-PSFTeppArgumentCompleter -Command Register-PSRepository -Parameter PackageManagementProvider -Name 'PSUtil-Module-PackageProvider' #endregion Module #region Input Object Property Register-PSFTeppArgumentCompleter -Command Select-Object -Parameter Property -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Select-Object -Parameter ExpandProperty -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Select-Object -Parameter ExcludeProperty -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Expand-PSUObject -Parameter Name -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Get-Member -Parameter Name -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Format-Table -Parameter Property -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Format-List -Parameter Property -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Group-Object -Parameter Property -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Measure-Object -Parameter Property -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Sort-Object -Parameter Property -Name PSFramework-Input-ObjectProperty Register-PSFTeppArgumentCompleter -Command Where-Object -Parameter Property -Name PSFramework-Input-ObjectProperty #endregion Input Object Property Register-PSFTeppArgumentCompleter -Command Read-PSUKnowledge -Parameter Book -Name 'PSUtil.Knowledge.Book' Register-PSFTeppArgumentCompleter -Command Read-PSUKnowledge -Parameter Name -Name 'PSUtil.Knowledge.Page' Register-PSFTeppArgumentCompleter -Command Read-PSUKnowledge -Parameter Tags -Name 'PSUtil.Knowledge.Tags' Register-PSFTeppArgumentCompleter -Command Remove-PSUKnowledge -Parameter Book -Name 'PSUtil.Knowledge.Book' Register-PSFTeppArgumentCompleter -Command Remove-PSUKnowledge -Parameter Name -Name 'PSUtil.Knowledge.Page' Register-PSFTeppArgumentCompleter -Command Write-PSUKnowledge -Parameter Book -Name 'PSUtil.Knowledge.Book' Register-PSFTeppArgumentCompleter -Command Write-PSUKnowledge -Parameter Tags -Name 'PSUtil.Knowledge.Tags' New-PSFLicense -Product 'PSUtil' -Manufacturer 'Friedrich Weinmann' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2018-12-16") -Text @" Copyright (c) 2018 Friedrich Weinmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ <# In this file, all default expansion definitions are stored. Wrap into a region each, with corresponding region label. #> #region Microsoft.PowerShell.Commands.MatchInfo Register-PSUObjectExpansion -TypeName "Microsoft.PowerShell.Commands.MatchInfo" -ScriptBlock { param ( $Object ) foreach ($item in $Object.Matches) { $item.Groups[1 .. ($item.Groups.Count - 1)].Value } } #endregion Microsoft.PowerShell.Commands.MatchInfo #region Microsoft.PowerShell.Commands.MemberDefinition Register-PSUObjectExpansion -TypeName "Microsoft.PowerShell.Commands.MemberDefinition" -ScriptBlock { param ( $Object ) $Object.Definition.Replace("), ", ")þ").Split("þ") } #endregion Microsoft.PowerShell.Commands.MemberDefinition #region System.Management.Automation.FunctionInfo Register-PSUObjectExpansion -TypeName "System.Management.Automation.FunctionInfo" -ScriptBlock { param ( $Object ) @" function $($Object.Name) { $($Object.Definition) } "@ } #endregion System.Management.Automation.FunctionInfo #region System.Management.Automation.AliasInfo Register-PSUObjectExpansion -TypeName "System.Management.Automation.AliasInfo" -ScriptBlock { param ( $Object ) if ($Object.ResolvedCommand.CommandType -eq "Function") { @" function $($Object.ResolvedCommand.Name) { $($Object.ResolvedCommand.Definition) } "@ } else { $Object.ResolvedCommand } } #endregion System.Management.Automation.AliasInfo # The king of aliases Import-PSUAlias -Name "grep" -Command "Select-String" # Strings Import-PSUAlias -Name add -Command Add-String Import-PSUAlias -Name Add-PSUString -Command Add-String Import-PSUAlias -Name wrap -Command Add-String Import-PSUAlias -Name Add-PSUString -Command Add-String Import-PSUAlias -Name format -Command Format-String Import-PSUAlias -Name Format-PSUString -Command Format-String Import-PSUAlias -Name trim -Command Get-SubString Import-PSUAlias -Name Remove-PSUString -Command Get-SubString Import-PSUAlias -Name join -Command Join-String Import-PSUAlias -Name Join-PSUString -Command Join-String Import-PSUAlias -Name replace -Command Set-String Import-PSUAlias -Name Set-PSUString -Command Set-String Import-PSUAlias -Name split -Command Split-String Import-PSUAlias -Name Split-PSUString -Command Split-String # Add simple aliases for everyday cmdlets Import-PSUAlias -Name "a" -Command "Get-Alias" Import-PSUAlias -Name "c" -Command "Get-Command" Import-PSUAlias -Name "m" -Command "Measure-Object" Import-PSUAlias -Name "v" -Command "Get-Variable" # Add aliases for frequent export commands Import-PSUAlias -Name "ix" -Command "Import-PSFClixml" Import-PSUAlias -Name "ex" -Command "Export-PSFClixml" Import-PSUAlias -Name "ic" -Command "Import-Csv" Import-PSUAlias -Name "ec" -Command "Export-Csv" Import-PSUAlias -Name "ctj" -Command "ConvertTo-Json" Import-PSUAlias -Name "cfj" -Command "ConvertFrom-Json" Import-PSUAlias -Name "ctx" -Command "ConvertTo-PSFClixml" Import-PSUAlias -Name "cfx" -Command "ConvertFrom-PSFClixml" # Add alias for easy clipboarding Import-PSUAlias -Name "ocb" -Command "Set-Clipboard" # Add alias for creating object Import-PSUAlias -Name "new" -Command "New-Object" # Add alias for the better select and to avoid breaking on old command Import-PSUAlias -Name "spo" -Command "Select-PSFObject" Import-PSUAlias -Name "Select-PSUObject" -Command "Select-PSFObject" if (Get-PSFConfigValue -FullName 'PSUtil.Import.Alias.SystemOverride') { Remove-PSFAlias -Name select -Force Remove-PSFAlias -Name gm -Force Import-PSUAlias -Name select -Command 'Select-PSFObject' Import-PSUAlias -Name gm -Command 'Get-PSMDMember' } Import-PSUAlias -Name "rmn" -Command "Remove-PSFNull" if ((Get-Module psreadline).Version.Major -ge 2) { Set-PSReadlineKeyHandler -Chord 'Shift+SpaceBar' -BriefDescription Whitespace -Description "Inserts a whitespace" -ScriptBlock { [Microsoft.Powershell.PSConsoleReadLine]::Insert(' ') } } if ((Get-PSFConfigValue -FullName "PSUtil.Import.Keybindings" -Fallback $true) -and (Get-Module PSReadline)) { foreach ($file in (Get-ChildItem -Path (Join-PSFPath $script:ModuleRoot 'internal' 'keybindings'))) { . Import-ModuleFile -Path $file.FullName } } Register-PSUObjectConversion -From dec -To bin -ScriptBlock { Param ( $InputObject ) [System.Convert]::ToString($InputObject, 2) } Register-PSUObjectConversion -From bin -To dec -ScriptBlock { Param ( $InputObject ) [System.Convert]::ToInt32($InputObject, 2) } Register-PSUObjectConversion -From dec -To hex -ScriptBlock { Param ( $InputObject ) [System.Convert]::ToString($InputObject, 16) } Register-PSUObjectConversion -From hex -To dec -ScriptBlock { Param ( $InputObject ) [System.Convert]::ToInt32($InputObject, 16) } Register-PSUObjectConversion -From dec -To oct -ScriptBlock { Param ( $InputObject ) [System.Convert]::ToString($InputObject, 8) } Register-PSUObjectConversion -From oct -To dec -ScriptBlock { Param ( $InputObject ) [System.Convert]::ToInt32($InputObject, 8) } Register-PSUObjectConversion -From hex -To bin -ScriptBlock { Param ( $InputObject ) $temp = [System.Convert]::ToInt32($InputObject, 16) [System.Convert]::ToString($temp, 2) } Register-PSUObjectConversion -From bin -To hex -ScriptBlock { Param ( $InputObject ) $temp = [System.Convert]::ToInt32($InputObject, 2) [System.Convert]::ToString($temp, 16) } Register-PSUObjectConversion -From hex -To oct -ScriptBlock { Param ( $InputObject ) $temp = [System.Convert]::ToInt32($InputObject, 16) [System.Convert]::ToString($temp, 8) } Register-PSUObjectConversion -From oct -To hex -ScriptBlock { Param ( $InputObject ) $temp = [System.Convert]::ToInt32($InputObject, 8) [System.Convert]::ToString($temp, 16) } Register-PSUObjectConversion -From bin -To oct -ScriptBlock { Param ( $InputObject ) $temp = [System.Convert]::ToInt32($InputObject, 2) [System.Convert]::ToString($temp, 8) } Register-PSUObjectConversion -From oct -To bin -ScriptBlock { Param ( $InputObject ) $temp = [System.Convert]::ToInt32($InputObject, 8) [System.Convert]::ToString($temp, 2) } Register-PSUObjectConversion -From script -To encoded -ScriptBlock { Param ( $InputObject ) $bytes = [System.Text.Encoding]::Unicode.GetBytes($InputObject) [Convert]::ToBase64String($bytes) } Register-PSUObjectConversion -From encoded -To script -ScriptBlock { Param ( $InputObject ) $bytes = [System.Convert]::FromBase64String($InputObject) [System.Text.Encoding]::Unicode.GetString($bytes) } Set-PSFTaskEngineCache -Module PSUtil -Name Module -Lifetime 5m -Collector { $paramRegisterPSFTaskEngineTask = @{ Name = 'PSUtil.ModuleCache' Description = 'Refreshes the data on locally available modules and repositories' Once = $true ResetTask = $true ScriptBlock = { $data = @{ InstalledModules = ((Get-InstalledModule).Name | Select-Object -Unique) AvailableModules = ((Get-Module -ListAvailable).Name | Select-Object -Unique) PackageProvider = ((Get-PackageProvider).Name) Repositories = ((Get-PSRepository).Name) } Set-PSFTaskEngineCache -Module PSUtil -Name Module -Value $data } } Register-PSFTaskEngineTask @paramRegisterPSFTaskEngineTask while (-not [PSFramework.TaskEngine.TaskHost]::GetCacheItem('PSUtil', 'Module').Value) { Start-Sleep -Milliseconds 100 } # Deliver expired data right away anyway [PSFramework.TaskEngine.TaskHost]::GetCacheItem('PSUtil', 'Module').Value } #endregion Load compiled code |