brickBOX.psm1
#region "⚡ ScriptProcessing" <# .SYNOPSIS Returns $true, if script runs with administrator privileges #> function Test-Admin { return ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") } Export-ModuleMember -Function Test-Admin <# .SYNOPSIS Executes a PowerShell script or command with elevated rights .EXAMPLE Start-Elevated notepad.exe Runs notepad as administrator #> function Start-Elevated { param( [Parameter(Mandatory)][string]$Command, [switch]$NoExit ) if (!(Test-Admin)) { Write-Host "Script needs elevation: '$Command'" $ArgumentList = [System.Collections.ArrayList]@("-NoProfile", "-ExecutionPolicy Bypass") if ($NoExit) { $ArgumentList.Add("-NoExit")} $ArgumentList.Add("&$Command") Start-Process -Verb RunAs -FilePath powershell.exe -ArgumentList $ArgumentList } } Export-ModuleMember -Function Start-Elevated <# .SYNOPSIS Saves secure strings to hkcu in a secure way. .DESCRIPTION The function becomes handy, if you need eg. passwords or api-key in your script, but you don't want to save them in the script. .EXAMPLE $password = Set-Secret 'myProject' 'SecretName' 'myPassword' Saves the password in the registry as SecureString #> function Set-Secret { param ( [Parameter(Mandatory = $true)][string]$projectName, [Parameter(Mandatory = $true)][string]$Name, [string]$Secret = $null, [switch]$WhatIf = $false ) $regKey = "HKCU:\Software\pageBOX\Secret\$projectName" if (![string]::IsNullOrEmpty($Secret)) { $value = ConvertTo-SecureString $Secret -AsPlainText } else { $value = Read-Host "Please enter '$Name'" -AsSecureString } if (!$WhatIf) { if (!(Test-Path $regKey)) { New-Item -Path $regKey -Force | Out-Null } New-ItemProperty -Path $regKey -Name $Name -Value ($value | ConvertFrom-SecureString) -PropertyType "String" -Force | Out-Null } } Export-ModuleMember -Function Set-Secret <# .SYNOPSIS Reads secure strings from hkcu. .DESCRIPTION The function becomes handy, if you need eg. passwords or api-key in your script, but you don't want to save them in the script. .EXAMPLE $password = Get-Secret 'myProject' 'myPassword' Gets the password earlier saved from the registry and sets $password as SecureString #> function Get-Secret { param ( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$projectName, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Name, [switch]$AsPlainText = $false ) if ((Get-ItemProperty "HKCU:\SOFTWARE\pageBOX\Secret\$projectName\" -ErrorAction SilentlyContinue).PSObject.Properties.Name -contains $Name) { $value = (Get-ItemProperty -Path "HKCU:\Software\pageBOX\Secret\$projectName" -Name $Name -ErrorAction SilentlyContinue).$Name | ConvertTo-SecureString } else { throw "$Name not found in $projectName" } if ($AsPlainText) { return (New-Object System.Management.Automation.PSCredential 0, $value).GetNetworkCredential().Password } return $value } Export-ModuleMember -Function Get-Secret <# .SYNOPSIS Removes secure strings from hkcu. .EXAMPLE Clear-Secret 'myProject' 'myPassword' Removes the 'myPassword' secret form the registry .EXAMPLE Clear-Secret 'myProject' Removes the whole project 'myProject' with all its secret form the registry #> function Clear-Secret { param ( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$projectName, [string]$Name = '' ) if ($Name -eq '') { Remove-Item "HKCU:\SOFTWARE\pageBOX\Secret\$projectName\" -ErrorAction SilentlyContinue } else { Remove-ItemProperty -Path "HKCU:\Software\pageBOX\Secret\$projectName" -Name $Name -ErrorAction SilentlyContinue } } Export-ModuleMember -Function Clear-Secret #endregion #region "⚡ FileSystemObject" <# .SYNOPSIS Add or Update key-value pairs in ini-files .EXAMPLE $payload = Set-IniContent $payload 'color' 'red' sets the color=red in an ini-like content of $payload. #> function Set-IniContent { param ( [Parameter(mandatory=$true)][System.Array]$payload, [Parameter(mandatory=$true)][string]$key, [Parameter(mandatory=$true)][string]$value, [Parameter()][string]$section = "", [switch]$uncomment = $false ) Process{ [String]$ini = "" [String]$cSection = "" # Current Section [bool]$hasSet = $false foreach ($line in $payload.Split("`n")) { $line = $line.Replace("`r","") # remove CR if ($line -eq "") { $ini += "$line`r`n"; continue } # Skip empty line # Section if ($line -match "^\[(?<section>.+)\]") { if (!$hasSet -and ($cSection -eq $section)) { $ini += "$Key=$value`r`n`r`n$line`r`n" } #value has not yet set, but we're going to leave matching section $cSection = $Matches.section $ini += "$line`r`n"; continue } if ($cSection -ne $section) { $ini += "$line`r`n"; continue } # Section doesn't match, skip and continue $isComment = $line -match '^[#;]' if (!$uncomment -and $isComment) { $ini += "$line`r`n"; continue } # Skip comments, if we don't want to uncomment # try to get key-value-pair if ($line -match "(?<key>.*)=(?<value>.*)") { # $line is a key-value pair $cKey = $Matches.key.Trim() if ($isComment) { $cKey = $cKey.Substring(1).TrimStart() } # uncomment sKey if ($key.ToLower() -ne $cKey.ToLower()) { $ini += "$line`r`n"; continue } # key and cKey don't match, skip if ($line -ne "$cKey=$value" ) { # changing value Write-Verbose "🟠 changing: '$line' => '$cKey=$value' in section [$section]" $ini += "$cKey=$value`r`n" } else { # no need to change Write-Verbose "⚪ unchanged: '$line' in section [$section]" $ini += "$line`r`n" } $hasSet = $true } else { $ini += "$line`r`n"; continue } # $line is no key-value-pair } if (!$hasSet) { # value has not yet set. if ($cSection -ne $section) { Write-Verbose "adding: section [$section]"; $ini += "`r`n[$section]`r`n" } # we were even missing the section Write-Verbose "🟢 adding: '$Key=$value' in section [$section]" $ini += "$Key=$value`r`n" } # return (Get-Content $file) -replace $regex, 'https://newurl.com' #| Set-Content $file return $ini.Substring(0,$ini.Length-1) } } Export-ModuleMember -Function Set-IniContent #endregion #region "⚡ API" <# .SYNOPSIS Creates the content of the value for the 'Authorization' Property. .EXAMPLE $PSDefaultParameterValues = @{ "Invoke-RestMethod:Headers"= @{ 'Authorization' = Get-BasicAuthForHeader -username 'username' -password (ConvertTo-SecureString "password" -AsPlainText -Force) } } #> function Get-BasicAuthForHeader { param ( [Parameter(Mandatory=$true)][string]$username, [Parameter(Mandatory=$true)][SecureString]$password ) return "Basic $([Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$username`:$((New-Object System.Management.Automation.PSCredential 0, $password).GetNetworkCredential().Password)")))" } Export-ModuleMember -Function Get-BasicAuthForHeader <# .SYNOPSIS Simplifies Invoke-RestMethod .PARAMETER Method POST Create a record GET Retrieve a record PUT Modify a record. Replace the entire resource with given data (null out fields if they are not provided in the request) DELETE Delete a record PATCH Update a record. Replace only specified fields .PARAMETER Uri complete url of the API, including https .PARAMETER Payload payload, mandatory for post, put and patch .PARAMETER NoOutput Omits any output, but errors .PARAMETER Headers Overwrite the $PSDefaultParameterValues for Invoke-RestMethod:Headers on this call .PARAMETER ContentType Overwrite the $PSDefaultParameterValues for Invoke-RestMethod:ContentType on this call .EXAMPLE Invoke-API get "https://api.ipify.org?format=json" .EXAMPLE Invoke-API post "https://httpbin.org/post" -Payload '{"Id": 12345 }' .EXAMPLE $PSDefaultParameterValues = @{ "Invoke-RestMethod:Headers"= @{ 'Accept' = "application/json" 'Authorization' = "Basic $([Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("username:pa$$word")))" } "Invoke-RestMethod:ContentType"="application/json; charset=utf-8" } Invoke-API post "https://reqres.in/api/users" -Payload @" { "name": "Julius User", "job": "leader" } "@ #> function Invoke-API { param( [ValidateSet('post', 'get', 'put', 'delete', 'patch')][string]$Method = 'get', [string]$Uri, [string]$Payload, [switch]$NoOutput = $false, [Hashtable]$Headers = $(if ($null -ne $Global:PSDefaultParameterValues) {$Global:PSDefaultParameterValues["Invoke-RestMethod:Headers"]} else {@{}}), [string]$ContentType = $(if ($null -ne $Global:PSDefaultParameterValues) {$Global:PSDefaultParameterValues["Invoke-RestMethod:ContentType"]}) # "application/json; charset=utf-8" ) if ($Method -eq 'get') { $response = Invoke-RestMethod -Uri $Uri -Headers $Headers -ContentType $ContentType } else { $response = Invoke-RestMethod -Method $Method -Uri $Uri -Body $Payload -Headers $Headers -ContentType $ContentType } if (!$NoOutput) { if ($response.result) { $response.result } # ServiceNOW else { $response } } } Export-ModuleMember -Function Invoke-API #endregion |