Shared-Functions.ps1
#Write-Debug "Loading ${script:MyInvocation.MyCommand.Name}" <# .SYNOPSIS Simple wrapper ower `Read-Host` intendend to show "[Yes]/[No]" questions .DESCRIPTION Simple wrapper ower `Read-Host` intendend to show "[Yes]/[No]" questions .PARAMETER text Text to be shown in the prompt .EXAMPLE $reply = Show-ConfirmPrompt "Would you like to continue?" if ( -not $reply ) { return } #> function Show-ConfirmPrompt { param ( [Parameter(Position = 0, ParameterSetName = 'Positional', ValueFromPipeline = $True)] [Alias("Question", "Description")] $text ="Would you like to continue?" ) $reply = Read-Host -Prompt "$text` [Y] Yes [N] No [S] Suspend(default is ""Yes""):" if ( $reply -match "[yY]" -and $null -ne $reply ) { return $true } if ( $reply -match "[Ss]" ) { throw "Execution aborted" } return $false } <# .SYNOPSIS Read apiKey(or other information) from input and store it to file .DESCRIPTION Long description .PARAMETER apiKey Reference to the api key value received from the command prompt .PARAMETER fileName Filename to save key .PARAMETER regUrl Help url with description or registration .EXAMPLE Read-ApiKey $ghApiKeyRef gh "https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line" $keyRef=([ref]$apiKey) Read-ApiKey $keyRef nuget "https://www.powershellgallery.com/account/apikeys" Publish-Module -Name ./*.psd1 -NuGetApiKey $keyRef.Value #> function Read-ApiKey { param ( [ref]$apiKey = $null, [string]$fileName, [string]$regUrl ) if(!!(("${apiKey.Value}").Trim())) { return $true } #get api key $apiKeyFile = Join-Path (split-path -parent $profile) ".${fileName}_api_key" if ( !(Test-Path $apiKeyFile)) { $apiKey = Read-Host -Prompt "Please Enter the api key received at $regUrl` And paste it here: " $reply = Show-ConfirmPrompt "Would you like to store it?" if ( $reply ) { $apiKey.Value | Out-File -FilePath $apiKeyFile } } else { Get-Content -Path $apiKeyFile | ForEach-Object { $apiKey.Value = $_ } } return $true } <# .SYNOPSIS Create array from pipeline input .DESCRIPTION Create array from pipeline input Original implementation at https://devblogs.microsoft.com/powershell/converting-to-array/ .EXAMPLE $gateway = $properties.GatewayAddresses | ForEach-Object{ [System.Net.IPAddress]::Parse($_.Address.ToString()) } | ToArray #> function ToArray { begin { $output = @(); } process { $output += $_; } end { return ,$output; } } <# .SYNOPSIS Merge two hashtables into one .DESCRIPTION Add elemtns from $second hastable(or any dictionary based structure) to $first .PARAMETER first Hashtable to add key/value pairs .PARAMETER second Hashtable key/values to be added to $first .EXAMPLE $q = @{a=1;b=4;c=3} [ordered]$w = @{a=2;b=1;c=5;d=6} MergeHashtable $q $w #> function MergeHashtable { param ( [Alias("To")] [Parameter(Position = 0, ValueFromPipelineByPropertyName = $True, Mandatory = $true)] [System.Collections.IDictionary]$first, [Alias("From")] [Parameter(Position = 1, ValueFromPipelineByPropertyName = $True, Mandatory = $true)] [System.Collections.IDictionary]$second ) $second.Keys | ForEach-Object{ $first[$_] = $second[$_]; } } function LoadModules { param ( [bool]$local = $false, [Parameter(Mandatory = $true)] [string]$functionsFolder, [string]$sharedFolder = $PSScriptRoot ) $functions = @( Get-ChildItem -Path $functionsFolder\*.ps1 -ErrorAction SilentlyContinue ) $shared = @( Get-ChildItem -Path $sharedFolder\*.ps1 -ErrorAction SilentlyContinue ) Foreach($import in @($Public + $functions)) { Try { . $import.fullname } Catch { Write-Error -Message "Failed to import function $($import.fullname): $_" } } ## # Add the functions into the runspace GetScriptFunctions $functions | ForEach-Object { $rs.SessionStateProxy.InvokeProvider.Item.Set( 'function:\{0}' -f $_.Name, $_.Body.GetScriptBlock()) } } <# .SYNOPSIS # .DESCRIPTION This function is based on https://stackoverflow.com/a/45929412/959779 .PARAMETER scriptFile Parameter description .EXAMPLE An example .NOTES General notes #> function GetScriptFunctions { param ( [string]$scriptFile ) # Get the AST of the file $tokens = $errors = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile( $scriptFile, [ref]$tokens, [ref]$errors) # Get only function definition ASTs $functionDefinitions = $ast.FindAll({ param([System.Management.Automation.Language.Ast] $Ast) $Ast -is [System.Management.Automation.Language.FunctionDefinitionAst] -and # Class methods have a FunctionDefinitionAst under them as well, but we don't want them. ($PSVersionTable.PSVersion.Major -lt 5 -or $Ast.Parent -isnot [System.Management.Automation.Language.FunctionMemberAst]) }, $true) return $functionDefinitions } <# .SYNOPSIS Check and create folder .DESCRIPTION Check if path and create folder if not exist .PARAMETER Folder Path .EXAMPLE An example .NOTES General notes #> function CreateFolderIfNotExist { param ([string]$Folder) if( Test-Path $Folder -PathType Leaf){ Write-Error "The destanation path ${Folder} is file." } if ( ! (Test-Path $Folder -PathType Container )) { New-Item -Path $Folder -ItemType 'Directory' } } <# .SYNOPSIS Check and create folder .DESCRIPTION Check if path and create folder if not exist .EXAMPLE An example .NOTES General notes #> filter First { $_ Break } filter Last { BEGIN { $current=$null } PROCESS { $current=$_ } END { Write-Host $current } } <# .SYNOPSIS Download executable from internet .DESCRIPTION Check if path and create folder if not exist .EXAMPLE An example .NOTES General notes #> function Receive-File { param ( [string]$name, [string]$file, [string]$url ) $reply = Show-ConfirmPrompt if ( -not $reply ) { Write-Error "Execution aborted" return -1; } Write-Output "Starting download '$name'" Write-Debug "Downoad url:${url}" (New-Object System.Net.WebClient).DownloadFile($url, $file) Write-Debug "File downloaded to ${file}." } function Extract-ZipFile { param ( [ValidateScript( { Test-Path $_ -pathType leaf })] [Parameter(Mandatory = $true)] [string]$FileName, [ValidateScript( { Test-Path $_ -pathType Container })] [Parameter(Mandatory = $true)] [string]$Path ) Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($FileName, $Path) } function Get-TempFileName() { return [System.IO.Path]::GetTempFileName() } function Test-Empty { param ( [Parameter(Position = 0)] [string]$string ) return [string]::IsNullOrWhitespace($string) } function Combine-Path { param ( [string]$baseDir, [string]$path ) $allArgs = $PsBoundParameters.Values + $args [IO.Path]::Combine([string[]]$allArgs) } function Get-ProfileDataFile { param ( [string]$file, [string]$moduleName = $null ) return Join-Path (Get-ProfileDir $moduleName) $file } function Get-ProfileDir { param ( [string]$moduleName = $null ) $profileDir = $ENV:AppData if( Test-Empty $moduleName ){ if ( $script:MyInvocation.MyCommand.Name.EndsWith('.psm1') ){ $moduleName = $script:MyInvocation.MyCommand.Name } if ( $script:MyInvocation.MyCommand.Name.EndsWith('.ps1') ){ $modulePath = Split-Path -Path $script:MyInvocation.MyCommand.Path $moduleName = Split-Path -Path $modulePath -Leaf } } if( Test-Empty $moduleName ){ throw "Unable to read module name." } $scriptProfile = Combine-Path $profileDir '.ps1' 'ScriptData' $moduleName if ( ! (Test-Path $scriptProfile -PathType Container )) { New-Item -Path $scriptProfile -ItemType 'Directory' } return $scriptProfile } function CheckPsGalleryUpdate { param ( [string] $moduleName, [string] $currentVersion ) Try { Write-Output "Update check..." $feed = Invoke-WebRequest -Uri "https://www.powershellgallery.com/api/v2/FindPackagesById()?id=%27$moduleName%27" $last=([xml]$feed.Content).feed.entry |Sort-Object -Property updated | Last $version= $last.properties.Version if ($version -gt $currentVersion) { Write-Output "Found a new module version {$version}." $notes=$last.properties.ReleaseNotes.'#text' Write-Output "Release notes: {$notes}." Write-Output "Recomendent to update module with command: Update-Module -Name $moduleName -Force" } } Catch { } } |