Utilities.psm1
[Cmdletbinding()] param() $scriptName = $MyInvocation.MyCommand.Name Write-Verbose "[$scriptName] Importing subcomponents" #region - Data import Write-Verbose "[$scriptName] - [data] - Processing folder" $dataFolder = (Join-Path $PSScriptRoot 'data') Write-Verbose "[$scriptName] - [data] - [$dataFolder]" Get-ChildItem -Path "$dataFolder" -Recurse -Force -Include '*.psd1' -ErrorAction SilentlyContinue | ForEach-Object { Write-Verbose "[$scriptName] - [data] - [$($_.Name)] - Importing" New-Variable -Name $_.BaseName -Value (Import-PowerShellDataFile -Path $_.FullName) -Force Write-Verbose "[$scriptName] - [data] - [$($_.Name)] - Done" } Write-Verbose "[$scriptName] - [data] - Done" #endregion - Data import #region - From /public Write-Verbose "[$scriptName] - [/public] - Processing folder" #region - From /public/Base64 Write-Verbose "[$scriptName] - [/public/Base64] - Processing folder" #region - From /public/Base64/ConvertFrom-Base64String.ps1 Write-Verbose "[$scriptName] - [/public/Base64/ConvertFrom-Base64String.ps1] - Importing" filter ConvertFrom-Base64String { <# .SYNOPSIS Convert to string from Base64 .DESCRIPTION Convert to string from Base64 .EXAMPLE ConvertFrom-Base64String -String 'SABlAGwAbABvACAAVwBvAHIAbABkAA==' Hello World Converts the string from Base64 to a regular string. #> [CmdletBinding()] param ( # The string to convert from Base64 [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [string] $String ) $ConvertedString = [System.Convert]::FromBase64String($String) $DecodedText = [System.Text.Encoding]::Unicode.GetString($ConvertedString) $DecodedText } Write-Verbose "[$scriptName] - [/public/Base64/ConvertFrom-Base64String.ps1] - Done" #endregion - From /public/Base64/ConvertFrom-Base64String.ps1 #region - From /public/Base64/ConvertTo-Base64String.ps1 Write-Verbose "[$scriptName] - [/public/Base64/ConvertTo-Base64String.ps1] - Importing" filter ConvertTo-Base64String { <# .SYNOPSIS Convert a string to Base64 .DESCRIPTION Convert a string to Base64 .EXAMPLE 'Hello World' | ConvertTo-Base64String SABlAGwAbABvACAAVwBvAHIAbABkAA== Converts the string 'Hello World' to Base64. #> [OutputType([string])] [CmdletBinding()] param( # The string to convert to Base64 [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [string] $String ) $bytes = [System.Text.Encoding]::Unicode.GetBytes($String) $encodedText = [System.Convert]::ToBase64String($bytes) #$ADOToken = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PAT)")) $encodedText } Write-Verbose "[$scriptName] - [/public/Base64/ConvertTo-Base64String.ps1] - Done" #endregion - From /public/Base64/ConvertTo-Base64String.ps1 Write-Verbose "[$scriptName] - [/public/Base64] - Done" #endregion - From /public/Base64 #region - From /public/Boolean Write-Verbose "[$scriptName] - [/public/Boolean] - Processing folder" #region - From /public/Boolean/ConvertTo-Boolean.ps1 Write-Verbose "[$scriptName] - [/public/Boolean/ConvertTo-Boolean.ps1] - Importing" filter ConvertTo-Boolean { <# .SYNOPSIS Convert string to boolean. .DESCRIPTION Convert string to boolean. .EXAMPLE ConvertTo-Boolean -String 'true' True Convert string to boolean. #> [OutputType([bool])] [CmdletBinding()] param( # The string to be converted to boolean. [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [string] $String ) switch -regex ($String.Trim()) { '^(1|true|yes|on|enabled)$' { $true } default { $false } } } Write-Verbose "[$scriptName] - [/public/Boolean/ConvertTo-Boolean.ps1] - Done" #endregion - From /public/Boolean/ConvertTo-Boolean.ps1 Write-Verbose "[$scriptName] - [/public/Boolean] - Done" #endregion - From /public/Boolean #region - From /public/Files Write-Verbose "[$scriptName] - [/public/Files] - Processing folder" #region - From /public/Files/Get-FileInfo.ps1 Write-Verbose "[$scriptName] - [/public/Files/Get-FileInfo.ps1] - Importing" function Get-FileInfo { <# .SYNOPSIS Get file information .DESCRIPTION Get file information .EXAMPLE Get-FileInfo -Path 'C:\temp\test.txt' Gets detailed information about the file. .NOTES Supported OS: Windows #> [OutputType([pscustomobject])] [CmdletBinding()] param ( # The path to the file. [Parameter(Mandatory)] [string] $Path ) if (-not (Test-Path -Path $Path)) { Write-Error 'Path does not exist' -ErrorAction Stop } $Item = Get-Item -Path $Path #If item is directory, fail if ($Item.PSIsContainer) { Write-Error 'Path is a directory' -ErrorAction Stop } $shell = New-Object -ComObject Shell.Application $shellFolder = $shell.Namespace($Item.Directory.FullName) $shellFile = $shellFolder.ParseName($Item.name) $fileDetails = New-Object pscustomobject foreach ($i in 0..1000) { $propertyName = $shellfolder.GetDetailsOf($null, $i) $propertyValue = $shellfolder.GetDetailsOf($shellfile, $i) if (-not [string]::IsNullOrEmpty($propertyValue)) { Write-Verbose "[$propertyName] - [$propertyValue]" $fileDetails | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue } } return $fileDetails } Write-Verbose "[$scriptName] - [/public/Files/Get-FileInfo.ps1] - Done" #endregion - From /public/Files/Get-FileInfo.ps1 #region - From /public/Files/Remove-EmptyFolder.ps1 Write-Verbose "[$scriptName] - [/public/Files/Remove-EmptyFolder.ps1] - Importing" Function Remove-EmptyFolder { <# .SYNOPSIS Removes empty folders under the folder specified .DESCRIPTION Removes empty folders under the folder specified .EXAMPLE Remove-EmptyFolder -Path . -Verbose Removes empty folders under the current path and outputs the results to the console. #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess)] param( # The path to the folder to be cleaned [Parameter(Mandatory)] [string] $Path ) Get-ChildItem -Path $Path -Recurse -Directory | ForEach-Object { if ($null -eq (Get-ChildItem $_.FullName -Force -Recurse)) { Write-Verbose "Removing empty folder: [$($_.FullName)]" if ($PSCmdlet.ShouldProcess("folder [$($_.FullName)]", 'Remove')) { Remove-Item $_.FullName -Force } } } } Write-Verbose "[$scriptName] - [/public/Files/Remove-EmptyFolder.ps1] - Done" #endregion - From /public/Files/Remove-EmptyFolder.ps1 Write-Verbose "[$scriptName] - [/public/Files] - Done" #endregion - From /public/Files #region - From /public/Git Write-Verbose "[$scriptName] - [/public/Git] - Processing folder" #region - From /public/Git/Clear-GitRepo.ps1 Write-Verbose "[$scriptName] - [/public/Git/Clear-GitRepo.ps1] - Importing" function Clear-GitRepo { <# .SYNOPSIS Clear a Git repository of all branches except main .DESCRIPTION Clear a Git repository of all branches except main .EXAMPLE Clear-GitRepo Clear a Git repository of all branches except main #> [OutputType([void])] [CmdletBinding()] param() git fetch --all --prune (git branch).Trim() | Where-Object { $_ -notmatch 'main|\*' } | ForEach-Object { git branch $_ --delete --force } } Write-Verbose "[$scriptName] - [/public/Git/Clear-GitRepo.ps1] - Done" #endregion - From /public/Git/Clear-GitRepo.ps1 #region - From /public/Git/Invoke-GitSquash.ps1 Write-Verbose "[$scriptName] - [/public/Git/Invoke-GitSquash.ps1] - Importing" function Invoke-GitSquash { <# .SYNOPSIS Squash all commits on a branch into a single commit .DESCRIPTION Squash all commits on a branch into a single commit .EXAMPLE Invoke-GitSquash Squash all commits on a branch into a single commit #> [OutputType([void])] [CmdletBinding()] [Alias('Squash-Main')] param( # The commit message to use for the squashed commit [Parameter()] [string] $CommitMessage = 'Squash', # The branch to squash [Parameter()] [string] $BranchName = 'main' ) git fetch --all --prune $gitHightFrom2ndCommit = [int](git rev-list --count --first-parent $BranchName) - 1 git reset HEAD~$gitHightFrom2ndCommit git commit -am "$CommitMessage" git push --force } Write-Verbose "[$scriptName] - [/public/Git/Invoke-GitSquash.ps1] - Done" #endregion - From /public/Git/Invoke-GitSquash.ps1 #region - From /public/Git/Invoke-SquashBranch.ps1 Write-Verbose "[$scriptName] - [/public/Git/Invoke-SquashBranch.ps1] - Importing" function Invoke-SquashBranch { <# .SYNOPSIS Squash a branch to a single commit .DESCRIPTION Squash a branch to a single commit .EXAMPLE Invoke-SquashBranch #> [Alias('Squash-Branch')] [CmdletBinding()] param( # The name of the branch to squash [Parameter()] [string] $BranchName = 'main' ) git reset $(git merge-base $BranchName $(git branch --show-current)) } Write-Verbose "[$scriptName] - [/public/Git/Invoke-SquashBranch.ps1] - Done" #endregion - From /public/Git/Invoke-SquashBranch.ps1 #region - From /public/Git/Reset-GitRepo.ps1 Write-Verbose "[$scriptName] - [/public/Git/Reset-GitRepo.ps1] - Importing" function Reset-GitRepo { <# .SYNOPSIS Reset a Git repository to the upstream branch .DESCRIPTION Reset a Git repository to the upstream branch .EXAMPLE Reset-GitRepo Reset a Git repository to the upstream branch #> [OutputType([void])] [CmdletBinding()] param( # The upstream repository to reset to [Parameter()] [string] $Upstream = 'upstream', # The branch to reset [Parameter()] [string] $Branch = 'main', # Whether to push the reset [Parameter()] [switch] $Push ) git fetch $Upstream git checkout $Branch git reset --hard $Upstream/$Branch if ($Push) { git push origin $Branch --force } } Set-Alias -Name Reset -Value Reset-Repo Write-Verbose "[$scriptName] - [/public/Git/Reset-GitRepo.ps1] - Done" #endregion - From /public/Git/Reset-GitRepo.ps1 #region - From /public/Git/Restore-GitRepo.ps1 Write-Verbose "[$scriptName] - [/public/Git/Restore-GitRepo.ps1] - Importing" function Restore-GitRepo { <# .SYNOPSIS Restore a Git repository with upstream .DESCRIPTION Restore a Git repository with upstream .EXAMPLE Restore-GitRepo #> [OutputType([void])] [CmdletBinding()] param( # The name of the branch to squash [Parameter()] [string] $BranchName = 'main' ) git remote add upstream https://github.com/Azure/ResourceModules.git git fetch upstream git restore --source upstream/$BranchName * ':!*global.variables.*' ':!settings.json*' } Write-Verbose "[$scriptName] - [/public/Git/Restore-GitRepo.ps1] - Done" #endregion - From /public/Git/Restore-GitRepo.ps1 #region - From /public/Git/Sync-GitRepo.ps1 Write-Verbose "[$scriptName] - [/public/Git/Sync-GitRepo.ps1] - Importing" function Sync-GitRepo { <# .SYNOPSIS Sync a Git repository with upstream .DESCRIPTION Sync a Git repository with upstream .EXAMPLE Sync-GitRepo #> [OutputType([void])] [CmdletBinding()] param() git fetch upstream --prune git pull git push } Set-Alias -Name sync -Value Sync-Git Write-Verbose "[$scriptName] - [/public/Git/Sync-GitRepo.ps1] - Done" #endregion - From /public/Git/Sync-GitRepo.ps1 #region - From /public/Git/Sync-Repo.ps1 Write-Verbose "[$scriptName] - [/public/Git/Sync-Repo.ps1] - Importing" function Sync-Repo { <# .SYNOPSIS Sync a Git repository with upstream .DESCRIPTION Sync a Git repository with upstream .EXAMPLE Sync-Repo #> [OutputType([void])] [CmdletBinding()] param() git checkout main git pull git remote update origin --prune git branch -vv | Select-String -Pattern ': gone]' | ForEach-Object { $_.toString().Trim().Split(' ')[0] } | ForEach-Object { git branch -D $_ } } Write-Verbose "[$scriptName] - [/public/Git/Sync-Repo.ps1] - Done" #endregion - From /public/Git/Sync-Repo.ps1 Write-Verbose "[$scriptName] - [/public/Git] - Done" #endregion - From /public/Git #region - From /public/GitHub Write-Verbose "[$scriptName] - [/public/GitHub] - Processing folder" #region - From /public/GitHub/Import-Variables.ps1 Write-Verbose "[$scriptName] - [/public/GitHub/Import-Variables.ps1] - Importing" filter Import-Variables { <# .SYNOPSIS Import variables from a JSON file into the current session .DESCRIPTION Import variables from a JSON file into the current session .EXAMPLE Import-Variables -Path 'C:\path\to\variables.json' #> [OutputType([void])] [CmdletBinding()] param ( # Path to the JSON file containing the variables [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [string] $Path ) Write-Output "$($MyInvocation.MyCommand) - $Path - Processing" if (-not (Test-Path -Path $Path)) { throw "$($MyInvocation.MyCommand) - $Path - File not found" } $Variables = Get-Content -Path $Path -Raw -Force | ConvertFrom-Json $NestedVariablesFilePaths = ($Variables.PSObject.Properties | Where-Object Name -EQ 'VariablesFilePaths').Value foreach ($NestedVariablesFilePath in $NestedVariablesFilePaths) { Write-Output "$($MyInvocation.MyCommand) - $Path - Nested variable files - $NestedVariablesFilePath" $NestedVariablesFilePath | Import-Variables } Write-Output "$($MyInvocation.MyCommand) - $Path - Loading variables" foreach ($Property in $Variables.PSObject.Properties) { if ($Property -match 'VariablesFilePaths') { continue } Set-GitHubEnv -Name $Property.Name -Value $Property.Value -Verbose } Write-Output "$($MyInvocation.MyCommand) - $Path - Done" } Write-Verbose "[$scriptName] - [/public/GitHub/Import-Variables.ps1] - Done" #endregion - From /public/GitHub/Import-Variables.ps1 #region - From /public/GitHub/New-GitHubLogGroup.ps1 Write-Verbose "[$scriptName] - [/public/GitHub/New-GitHubLogGroup.ps1] - Importing" function New-GitHubLogGroup { <# .SYNOPSIS Create a new log group in GitHub Actions .DESCRIPTION Create a new log group in GitHub Actions .EXAMPLE New-GitHubLogGroup -Title 'My log group' #> [OutputType([void])] [CmdletBinding()] param ( # Title of the log group [Parameter()] [string] $Title ) Write-Output "::group::$Title" } Write-Verbose "[$scriptName] - [/public/GitHub/New-GitHubLogGroup.ps1] - Done" #endregion - From /public/GitHub/New-GitHubLogGroup.ps1 #region - From /public/GitHub/Set-GitHubEnv.ps1 Write-Verbose "[$scriptName] - [/public/GitHub/Set-GitHubEnv.ps1] - Importing" function Set-GitHubEnv { <# .SYNOPSIS Set a GitHub environment variable .DESCRIPTION Set a GitHub environment variable .EXAMPLE Set-GitHubEnv -Name 'MyVariable' -Value 'MyValue' #> [OutputType([void])] [CmdletBinding()] param ( # Name of the variable [Parameter(Mandatory)] [string] $Name, # Value of the variable [Parameter(Mandatory)] [string] $Value ) if ($PSBoundParameters.ContainsKey('Verbose')) { @{ "$Name" = $Value } | Format-Table -HideTableHeaders -Wrap } Write-Output "$Name=$Value" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append } Write-Verbose "[$scriptName] - [/public/GitHub/Set-GitHubEnv.ps1] - Done" #endregion - From /public/GitHub/Set-GitHubEnv.ps1 Write-Verbose "[$scriptName] - [/public/GitHub] - Done" #endregion - From /public/GitHub #region - From /public/Hashtable Write-Verbose "[$scriptName] - [/public/Hashtable] - Processing folder" #region - From /public/Hashtable/Merge-Hashtables.ps1 Write-Verbose "[$scriptName] - [/public/Hashtable/Merge-Hashtables.ps1] - Importing" function Merge-Hashtables { <# .SYNOPSIS Merge two hashtables, with the second hashtable overriding the first .DESCRIPTION Merge two hashtables, with the second hashtable overriding the first .EXAMPLE $Main = [ordered]@{ Action = '' ResourceGroupName = 'Main' Subscription = 'Main' ManagementGroupID = '' Location = 'Main' ModuleName = '' ModuleVersion = '' } $Overrides = [ordered]@{ Action = 'overrides' ResourceGroupName = 'overrides' Subscription = 'overrides' ManagementGroupID = '' Location = 'overrides' ModuleName = '' ModuleVersion = '' } Merge-Hashtables -Main $Main -Overrides $Overrides #> [OutputType([Hashtable])] [CmdletBinding()] param ( # Main hashtable [Parameter(Mandatory)] [hashtable] $Main, # Hashtable with overrides [Parameter(Mandatory)] [hashtable] $Overrides ) $Output = $Main.Clone() ForEach ($Key in $Overrides.Keys) { if (($Output.Keys) -notcontains $Key) { $Output.$Key = $Overrides.$Key } if ($Overrides.item($Key) | IsNotNullOrEmpty) { $Output.$Key = $Overrides.$Key } } return $Output } Write-Verbose "[$scriptName] - [/public/Hashtable/Merge-Hashtables.ps1] - Done" #endregion - From /public/Hashtable/Merge-Hashtables.ps1 Write-Verbose "[$scriptName] - [/public/Hashtable] - Done" #endregion - From /public/Hashtable #region - From /public/PowerShell Write-Verbose "[$scriptName] - [/public/PowerShell] - Processing folder" #region - From /public/PowerShell/Module Write-Verbose "[$scriptName] - [/public/PowerShell/Module] - Processing folder" #region - From /public/PowerShell/Module/Invoke-PruneModule.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/Module/Invoke-PruneModule.ps1] - Importing" function Invoke-PruneModule { <# .SYNOPSIS Remove all but the newest version of a module .DESCRIPTION Remove all but the newest version of a module .EXAMPLE Invoke-PruneModule -Name 'Az.*' -Scope CurrentUser #> [OutputType([void])] [CmdletBinding()] [Alias('Prune-Module')] param ( # Name of the module(s) to prune [Parameter()] [string[]] $Name = '*', # Scope of the module(s) to prune [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] [string[]] $Scope = 'CurrentUser' ) if ($Scope -eq 'AllUsers' -and -not (IsAdmin)) { $message = 'Administrator rights are required to uninstall modules for all users. Please run the command again with' + " elevated rights (Run as Administrator) or provide '-Scope CurrentUser' to your command." throw $message } $UpdateableModules = Get-InstalledModule | Where-Object Name -Like "$Name" $UpdateableModuleNames = $UpdateableModules.Name | Sort-Object -Unique foreach ($UpdateableModuleName in $UpdateableModuleNames) { $UpdateableModule = $UpdateableModules | Where-Object Name -EQ $UpdateableModuleName | Sort-Object -Property Version -Descending Write-Verbose "[$($UpdateableModuleName)] - Found [$($UpdateableModule.Count)]" -Verbose $NewestModule = $UpdateableModule | Select-Object -First 1 Write-Verbose "[$($UpdateableModuleName)] - Newest [$($NewestModule.Version -join ', ')]" -Verbose $OutdatedModules = $UpdateableModule | Select-Object -Skip 1 Write-Verbose "[$($UpdateableModuleName)] - Outdated [$($OutdatedModules.Version -join ', ')]" -Verbose foreach ($OutdatedModule in $OutdatedModules) { Write-Verbose "[$($UpdateableModuleName)] - [$($OutdatedModule.Version)] - Removing" -Verbose $OutdatedModule | Remove-Module -Force Write-Verbose "[$($UpdateableModuleName)] - [$($OutdatedModule.Version)] - Uninstalling" -Verbose Uninstall-Module -Name $OutdatedModule.Name -RequiredVersion -Force try { $OutdatedModule.ModuleBase | Remove-Item -Force -Recurse -ErrorAction Stop } catch { Write-Warning "[$($UpdateableModuleName)] - [$($OutdatedModule.Version)] - Failed to remove [$($OutdatedModule.ModuleBase)]" continue } } } } Write-Verbose "[$scriptName] - [/public/PowerShell/Module/Invoke-PruneModule.ps1] - Done" #endregion - From /public/PowerShell/Module/Invoke-PruneModule.ps1 #region - From /public/PowerShell/Module/Invoke-ReinstallModule.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/Module/Invoke-ReinstallModule.ps1] - Importing" function Invoke-ReinstallModule { <# .SYNOPSIS Reinstalls module into a given scope. .DESCRIPTION Reinstalls module into a given scope. This is useful when you want to reinstall or clean up your module versions. With this command you always get the newest available version of the module and all the previous version wiped out. .PARAMETER Name The name of the module to be reinstalled. Wildcards are supported. .PARAMETER Scope The scope of the module to will be reinstalled to. .EXAMPLE Reinstall-Module -Name Pester -Scope CurrentUser Reinstall Pester module for the current user. .EXAMPLE Reinstall-Module -Scope CurrentUser Reinstall all reinstallable modules into the current user. #> [CmdletBinding()] [Alias('Reinstall-Module')] param ( # Name of the module(s) to reinstall [Parameter()] [SupportsWildcards()] [string[]] $Name = '*', # Scope of the module(s) to reinstall [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] [string[]] $Scope = 'CurrentUser' ) if ($Scope -eq 'AllUsers' -and -not (IsAdmin)) { $message = 'Administrator rights are required to uninstall modules for all users. Please run the command again with' + " elevated rights (Run as Administrator) or provide '-Scope CurrentUser' to your command." throw $message } $modules = Get-InstalledModule | Where-Object Name -Like "$Name" Write-Verbose "Found [$($modules.Count)] modules" -Verbose $modules | ForEach-Object { if ($_.name -eq 'Pester') { Uninstall-Pester -All continue } Uninstall-Module -Name $_ -AllVersions -Force -ErrorAction SilentlyContinue } $modules.Name | ForEach-Object { Install-Module -Name $_ -Scope $Scope -Force } } Write-Verbose "[$scriptName] - [/public/PowerShell/Module/Invoke-ReinstallModule.ps1] - Done" #endregion - From /public/PowerShell/Module/Invoke-ReinstallModule.ps1 #region - From /public/PowerShell/Module/Uninstall-Pester.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/Module/Uninstall-Pester.ps1] - Importing" function Uninstall-Pester { <# .SYNOPSIS Uninstall Pester 3 from Program Files and Program Files (x86) .DESCRIPTION Uninstall Pester 3 from Program Files and Program Files (x86). This is useful when you want to install Pester 4 and you have Pester 3 installed. .PARAMETER All .EXAMPLE Uninstall-Pester Uninstall Pester 3 from Program Files and Program Files (x86). .EXAMPLE Uninstall-Pester -All Completely remove all built-in Pester 3 installations. #> [OutputType([String])] [CmdletBinding()] param ( # Completely remove all built-in Pester 3 installations [Parameter()] [switch] $All ) $pesterPaths = foreach ($programFiles in ($env:ProgramFiles, ${env:ProgramFiles(x86)})) { $path = "$programFiles\WindowsPowerShell\Modules\Pester" if ($null -ne $programFiles -and (Test-Path $path)) { if ($All) { Get-Item $path } else { Get-ChildItem "$path\3.*" } } } if (-not $pesterPaths) { "There are no Pester$(if (-not $all) {' 3'}) installations in Program Files and Program Files (x86) doing nothing." return } foreach ($pesterPath in $pesterPaths) { takeown /F $pesterPath /A /R icacls $pesterPath /reset # grant permissions to Administrators group, but use SID to do # it because it is localized on non-us installations of Windows icacls $pesterPath /grant '*S-1-5-32-544:F' /inheritance:d /T Remove-Item -Path $pesterPath -Recurse -Force -Confirm:$false } } Write-Verbose "[$scriptName] - [/public/PowerShell/Module/Uninstall-Pester.ps1] - Done" #endregion - From /public/PowerShell/Module/Uninstall-Pester.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/Module] - Done" #endregion - From /public/PowerShell/Module #region - From /public/PowerShell/Object Write-Verbose "[$scriptName] - [/public/PowerShell/Object] - Processing folder" #region - From /public/PowerShell/Object/Copy-Object.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/Object/Copy-Object.ps1] - Importing" filter Copy-Object { <# .SYNOPSIS Copy an object .DESCRIPTION Copy an object .EXAMPLE $Object | Copy-Object Copy an object #> [OutputType([object])] [CmdletBinding()] param ( # Object to copy [Parameter( Mandatory, ValueFromPipeline )] [Object] $InputObject ) $InputObject | ConvertTo-Json -Depth 100 | ConvertFrom-Json } Write-Verbose "[$scriptName] - [/public/PowerShell/Object/Copy-Object.ps1] - Done" #endregion - From /public/PowerShell/Object/Copy-Object.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/Object] - Done" #endregion - From /public/PowerShell/Object #region - From /public/PowerShell/PSCredential Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential] - Processing folder" #region - From /public/PowerShell/PSCredential/New-PSCredential.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential/New-PSCredential.ps1] - Importing" function New-PSCredential { <# .SYNOPSIS Creates a PSCredential .DESCRIPTION Takes in a UserName and a plain text password and creates a PSCredential .EXAMPLE New-PSCredential -UserName "Admin" -Password "P@ssw0rd!" This creates a PSCredential with username "Admin" and password "P@ssw0rd!" .EXAMPLE New-PSCredential -UserName "Admin" Prompts user for password and creates a PSCredential with username "Admin" and password the user provided. .EXAMPLE $SecretPassword = "P@ssw0rd!" | ConvertTo-SecureString -Force New-PSCredential -UserName "Admin" -Password $SecretPassword #> [OutputType([System.Management.Automation.PSCredential])] [Cmdletbinding()] param( # The username of the PSCredential [Parameter()] [string] $Username = (Read-Host -Prompt 'Enter a username'), # The plain text password of the PSCredential [Parameter()] [SecureString] $Password = (Read-Host -Prompt 'Enter Password' -AsSecureString) ) $credential = New-Object -TypeName System.Management.Automation.PSCredential($Username, $Password) return $credential } Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential/New-PSCredential.ps1] - Done" #endregion - From /public/PowerShell/PSCredential/New-PSCredential.ps1 #region - From /public/PowerShell/PSCredential/Restore-PSCredential.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential/Restore-PSCredential.ps1] - Importing" function Restore-PSCredential { <# .SYNOPSIS Restores a PSCredential from a file. .DESCRIPTION Takes in a UserName and restores a PSCredential from a file. .EXAMPLE Restore-PSCredential -UserName "Admin" This restores the PSCredential from the default location of $env:HOMEPATH\.creds\Admin.cred .EXAMPLE Restore-PSCredential -UserName "Admin" -Path "C:\Temp" This restores the PSCredential from the location of C:\Temp\Admin.cred #> [OutputType([System.Management.Automation.PSCredential])] [CmdletBinding()] param( # The username of the PSCredential [Parameter(Mandatory)] [string] $UserName, # The folder path to restore the PSCredential from. [Parameter()] [string] $Path = "$env:HOMEPATH\.creds" ) $fileName = "$UserName.cred" $credFilePath = Join-Path -Path $Path -ChildPath $fileName $credFilePathExists = Test-Path $credFilePath if ($credFilePathExists) { $secureString = Get-Content $credFilePath | ConvertTo-SecureString $credential = New-Object -TypeName System.Management.Automation.PSCredential($UserName, $secureString) } else { throw "Unable to locate a credential file for $($Username)" } return $credential } Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential/Restore-PSCredential.ps1] - Done" #endregion - From /public/PowerShell/PSCredential/Restore-PSCredential.ps1 #region - From /public/PowerShell/PSCredential/Save-PSCredential.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential/Save-PSCredential.ps1] - Importing" filter Save-PSCredential { <# .SYNOPSIS Saves a PSCredential to a file. .DESCRIPTION Takes in a PSCredential and saves it to a file. .EXAMPLE $Credential = New-PSCredential -UserName "Admin" -Password "P@ssw0rd!" Save-PSCredential -Credential $Credential This saves the PSCredential to the default location of $env:HOMEPATH\.creds\Admin.cred .EXAMPLE $Credential = New-PSCredential -UserName "Admin" -Password "P@ssw0rd!" Save-PSCredential -Credential $Credential -Path "C:\Temp" This saves the PSCredential to the location of C:\Temp\Admin.cred #> [OutputType([void])] [CmdletBinding()] param( # The PSCredential to save. [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [System.Management.Automation.PSCredential] $Credential, # The folder path to save the PSCredential to. [Parameter()] [string] $Path = "$env:HOMEPATH\.creds" ) $fileName = "$($Credential.UserName).cred" $credFilePath = Join-Path -Path $Path -ChildPath $fileName $credFilePathExists = Test-Path $credFilePath if (-not $credFilePathExists) { try { $null = New-Item -ItemType File -Path $credFilePath -ErrorAction Stop -Force } catch { throw $_.Exception.Message } } $Credential.Password | ConvertFrom-SecureString | Out-File $credFilePath -Force } # $SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force # $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword) # $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) # [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential/Save-PSCredential.ps1] - Done" #endregion - From /public/PowerShell/PSCredential/Save-PSCredential.ps1 Write-Verbose "[$scriptName] - [/public/PowerShell/PSCredential] - Done" #endregion - From /public/PowerShell/PSCredential Write-Verbose "[$scriptName] - [/public/PowerShell] - Done" #endregion - From /public/PowerShell #region - From /public/String Write-Verbose "[$scriptName] - [/public/String] - Processing folder" #region - From /public/String/Search-GUID.ps1 Write-Verbose "[$scriptName] - [/public/String/Search-GUID.ps1] - Importing" filter Search-GUID { <# .SYNOPSIS Search a string for a GUID .DESCRIPTION Search a string for a GUID .EXAMPLE '123e4567-e89b-12d3-a456-426655440000' | Search-GUID #> [Cmdletbinding()] [OutputType([guid])] param( # The string to search [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [string] $String ) Write-Verbose "Looking for a GUID in $String" $GUID = $String.ToLower() | Select-String -Pattern '[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}' | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value Write-Verbose "Found GUID: $GUID" $GUID } Write-Verbose "[$scriptName] - [/public/String/Search-GUID.ps1] - Done" #endregion - From /public/String/Search-GUID.ps1 #region - From /public/String/Test-IsGUID.ps1 Write-Verbose "[$scriptName] - [/public/String/Test-IsGUID.ps1] - Importing" filter Test-IsGUID { <# .SYNOPSIS Test if a string is a GUID .DESCRIPTION Test if a string is a GUID .EXAMPLE '123e4567-e89b-12d3-a456-426655440000' | Test-IsGUID True #> [Cmdletbinding()] [Alias('IsGUID')] [OutputType([bool])] param ( # The string to test [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [string] $String ) [regex]$guidRegex = '(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$' # Check GUID against regex $String -match $guidRegex } Write-Verbose "[$scriptName] - [/public/String/Test-IsGUID.ps1] - Done" #endregion - From /public/String/Test-IsGUID.ps1 #region - From /public/String/Test-IsNotNullOrEmpty.ps1 Write-Verbose "[$scriptName] - [/public/String/Test-IsNotNullOrEmpty.ps1] - Importing" filter Test-IsNotNullOrEmpty { <# .SYNOPSIS Test if an object is not null or empty .DESCRIPTION Test if an object is not null or empty .EXAMPLE '' | Test-IsNotNullOrEmpty False #> [Alias('IsNotNullOrEmpty')] [Cmdletbinding()] [OutputType([bool])] param( # Object to test [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [object] $Object ) return -not ($Object | IsNullOrEmpty) } Write-Verbose "[$scriptName] - [/public/String/Test-IsNotNullOrEmpty.ps1] - Done" #endregion - From /public/String/Test-IsNotNullOrEmpty.ps1 #region - From /public/String/Test-IsNullOrEmpty.ps1 Write-Verbose "[$scriptName] - [/public/String/Test-IsNullOrEmpty.ps1] - Importing" filter Test-IsNullOrEmpty { <# .SYNOPSIS Test if an object is null or empty .DESCRIPTION Test if an object is null or empty .EXAMPLE '' | IsNullOrEmpty -Verbose True #> [alias('IsNullOrEmpty')] [OutputType([bool])] [Cmdletbinding()] param( # The object to test [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [object] $Object ) try { if ($null -eq $Object) { Write-Verbose 'Object is null' return $true } if ($Object -eq 0) { Write-Verbose 'Object is 0' return $true } if ($Object.GetType() -eq [string]) { if ([String]::IsNullOrWhiteSpace($Object)) { Write-Verbose 'Object is empty string' return $true } else { return $false } } if ($Object.count -eq 0) { Write-Verbose 'Object count is 0' return $true } if (-not $Object) { Write-Verbose 'Object evaluates to false' return $true } if (($Object.GetType().Name -ne 'pscustomobject') -or $Object.GetType() -ne [pscustomobject]) { Write-Verbose 'Casting object to PSCustomObject' $Object = [pscustomobject]$Object } if (($Object.GetType().Name -eq 'pscustomobject') -or $Object.GetType() -eq [pscustomobject]) { if ($Object -eq (New-Object -TypeName pscustomobject)) { Write-Verbose 'Object is similar to empty PSCustomObject' return $true } if ($Object.psobject.Properties | IsNullOrEmpty) { Write-Verbose 'Object has no properties' return $true } } } catch { Write-Verbose 'Object triggered exception' return $true } return $false } Write-Verbose "[$scriptName] - [/public/String/Test-IsNullOrEmpty.ps1] - Done" #endregion - From /public/String/Test-IsNullOrEmpty.ps1 Write-Verbose "[$scriptName] - [/public/String] - Done" #endregion - From /public/String #region - From /public/TLS Write-Verbose "[$scriptName] - [/public/TLS] - Processing folder" #region - From /public/TLS/Get-TLSConfig.ps1 Write-Verbose "[$scriptName] - [/public/TLS/Get-TLSConfig.ps1] - Importing" function Get-TLSConfig { <# .SYNOPSIS Get the TLS configuration of the current session .DESCRIPTION Get the TLS configuration of the current session .EXAMPLE Get-TLSConfig Gets the TLS configuration of the current session .EXAMPLE Get-TLSConfig -ListAvailable Gets the available TLS configurations #> [OutputType(ParameterSetName = 'Default', [Net.SecurityProtocolType])] [OutputType(ParameterSetName = 'ListAvailable', [Array])] [CmdletBinding(DefaultParameterSetName = 'Default')] param( # List available TLS configurations [Parameter(ParameterSetName = 'ListAvailable')] [switch] $ListAvailable ) if ($ListAvailable) { return [enum]::GetValues([Net.SecurityProtocolType]) } return [Net.ServicePointManager]::SecurityProtocol } Write-Verbose "[$scriptName] - [/public/TLS/Get-TLSConfig.ps1] - Done" #endregion - From /public/TLS/Get-TLSConfig.ps1 #region - From /public/TLS/Set-TLSConfig.ps1 Write-Verbose "[$scriptName] - [/public/TLS/Set-TLSConfig.ps1] - Importing" function Set-TLSConfig { <# .SYNOPSIS Set the TLS configuration for the current PowerShell session .DESCRIPTION Set the TLS configuration for the current PowerShell session .EXAMPLE Set-TLSConfig -Protocol Tls12 Set the TLS configuration for the current PowerShell session to TLS 1.2 #> [OutputType([void])] [CmdletBinding()] param( # The TLS protocol to enable [Parameter()] [Net.SecurityProtocolType[]] $Protocol = [Net.SecurityProtocolType]::Tls12 ) foreach ($protocolItem in $Protocol) { Write-Verbose "Enabling $protocolItem" [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor $protocolItem } } Write-Verbose "[$scriptName] - [/public/TLS/Set-TLSConfig.ps1] - Done" #endregion - From /public/TLS/Set-TLSConfig.ps1 Write-Verbose "[$scriptName] - [/public/TLS] - Done" #endregion - From /public/TLS #region - From /public/URI Write-Verbose "[$scriptName] - [/public/URI] - Processing folder" #region - From /public/URI/Join-Uri.ps1 Write-Verbose "[$scriptName] - [/public/URI/Join-Uri.ps1] - Importing" function Join-Uri { <# .SYNOPSIS Join a base URI with a child paths. .DESCRIPTION Join a base URI with a child paths to create a new URI. The child paths are normalized before joining with the base URI. .EXAMPLE Join-Uri -Path 'https://example.com' -ChildPath 'foo' -AdditionalChildPath 'bar' Joins the base URI 'https://example.com' with the child paths 'foo' and 'bar' to create the URI 'https://example.com/foo/bar'. .EXAMPLE Join-Uri 'https://example.com' '/foo/' '/bar/' '//baz/something/' '/test/' https://example.com/foo/bar/baz/something/test Combines the base URI 'https://example.com' with the child paths '/foo/', '/bar/', '//baz/something/', and '/test/'. #> [OutputType([uri])] [CmdletBinding()] param ( # The base URI to join with the child path. [Parameter(Mandatory)] [uri]$Path, # The child path to join with the base URI. [Parameter(Mandatory)] [string] $ChildPath, # Additional child paths to join with the base URI. [Parameter(ValueFromRemainingArguments)] [string[]] $AdditionalChildPath ) $segments = $ChildPath, $AdditionalChildPath $normalizedSegments = $segments | ForEach-Object { $_.Trim('/') } $uri = $Path.ToString().TrimEnd('/') + '/' + ($normalizedSegments -join '/') $uri } Write-Verbose "[$scriptName] - [/public/URI/Join-Uri.ps1] - Done" #endregion - From /public/URI/Join-Uri.ps1 Write-Verbose "[$scriptName] - [/public/URI] - Done" #endregion - From /public/URI #region - From /public/Windows Write-Verbose "[$scriptName] - [/public/Windows] - Processing folder" #region - From /public/Windows/winget Write-Verbose "[$scriptName] - [/public/Windows/winget] - Processing folder" #region - From /public/Windows/winget/Invoke-CleanWingetApps.ps1 Write-Verbose "[$scriptName] - [/public/Windows/winget/Invoke-CleanWingetApps.ps1] - Importing" function Invoke-CleanWingetApps { <# .SYNOPSIS Remove bloat-ware using winget .DESCRIPTION Remove bloat-ware using winget .EXAMPLE Invoke-CleanWingetApps Remove bloat-ware using winget #> [Alias('Clean-WingetApps')] [OutputType([void])] [CmdletBinding()] param () winget source update winget uninstall --id Microsoft.549981C3F5F10_8wekyb3d8bbwe winget uninstall --id Microsoft.Getstarted_8wekyb3d8bbwe winget uninstall --id Microsoft.BingNews_8wekyb3d8bbwe winget uninstall --id Microsoft.BingWeather_8wekyb3d8bbwe winget uninstall --id Microsoft.GetHelp_8wekyb3d8bbwe winget uninstall --id Microsoft.PowerAutomateDesktop_8wekyb3d8bbwe winget uninstall --id Microsoft.WindowsFeedbackHub_8wekyb3d8bbwe winget uninstall --id Microsoft.ZuneMusic_8wekyb3d8bbwe winget uninstall --id Microsoft.YourPhone_8wekyb3d8bbwe winget uninstall --id Microsoft.People_8wekyb3d8bbwe winget uninstall --id Microsoft.MicrosoftEdge.Stable_8wekyb3d8bbwe winget uninstall --id Microsoft.GamingApp_8wekyb3d8bbwe winget uninstall --id Microsoft.XboxGamingOverlay_8wekyb3d8bbwe winget uninstall --id Microsoft.XboxGameOverlay_8wekyb3d8bbwe winget uninstall --id Microsoft.XboxSpeechToTextOverlay_8wekyb3d8bbwe winget uninstall --id Microsoft.XboxIdentityProvider_8wekyb3d8bbwe winget uninstall --id Microsoft.Xbox.TCUI_8wekyb3d8bbwe winget uninstall --id MicrosoftTeams_8wekyb3d8bbwe winget uninstall --id Clipchamp.Clipchamp_yxz26nhyzhsrt winget uninstall --id microsoft.windowscommunicationsapps_8wekyb3d8bbwe } Write-Verbose "[$scriptName] - [/public/Windows/winget/Invoke-CleanWingetApps.ps1] - Done" #endregion - From /public/Windows/winget/Invoke-CleanWingetApps.ps1 Write-Verbose "[$scriptName] - [/public/Windows/winget] - Done" #endregion - From /public/Windows/winget #region - From /public/Windows/Show-FileExtension.ps1 Write-Verbose "[$scriptName] - [/public/Windows/Show-FileExtension.ps1] - Importing" filter Show-FileExtension { <# .SYNOPSIS Show or hide file extensions in Windows Explorer .DESCRIPTION Show or hide file extensions in Windows Explorer .EXAMPLE Show-FileExtension -On Show file extensions in Windows Explorer .EXAMPLE Show-FileExtension -Off Hide file extensions in Windows Explorer .NOTES Supported OS: Windows #> [CmdletBinding(DefaultParameterSetName = 'On')] Param ( # Show file extensions in Windows Explorer [Parameter( Mandatory, ParameterSetName = 'On' )] [switch] $On, # Hide file extensions in Windows Explorer [Parameter( Mandatory, ParameterSetName = 'Off' )] [switch] $Off ) # Set a variable with the value we want to set on the registry value/subkey. if ($On) { $Value = 0 } if ($Off) { $Value = 1 } # Define the path to the registry key that contains the registry value/subkey $Path = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' # Set the registry value/subkey. Set-ItemProperty -Path $Path -Name HideFileExt -Value $Value # Refresh open Explorer windows. # You will need to refresh the window if you have none currently open. # Create the Shell.Application ComObject $Shell = New-Object -ComObject Shell.Application # For each one of the open windows, refresh it. $Shell.Windows() | ForEach-Object { $_.Refresh() } } Write-Verbose "[$scriptName] - [/public/Windows/Show-FileExtension.ps1] - Done" #endregion - From /public/Windows/Show-FileExtension.ps1 #region - From /public/Windows/Show-HiddenFiles.ps1 Write-Verbose "[$scriptName] - [/public/Windows/Show-HiddenFiles.ps1] - Importing" function Show-HiddenFiles { <# .SYNOPSIS Show or hide hidden files in Windows Explorer .DESCRIPTION Show or hide hidden files in Windows Explorer .EXAMPLE Show-HiddenFiles -On Show hidden files in Windows Explorer .EXAMPLE Show-HiddenFiles -Off Hide hidden files in Windows Explorer #> [CmdletBinding(DefaultParameterSetName = 'On')] Param ( # Show hidden files in Windows Explorer [Parameter( Mandatory, ParameterSetName = 'On' )] [switch] $On, # Dont show hidden files in Windows Explorer [Parameter( Mandatory, ParameterSetName = 'Off' )] [switch] $Off ) Process { # Set a variable with the value we want to set on the registry value/subkey. if ($On) { $Value = 1 } if ($Off) { $Value = 2 } # Define the path to the registry key that contains the registry value/subkey $Path = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' # Set the registry value/subkey. Set-ItemProperty -Path $Path -Name Hidden -Value $Value # Refresh open Explorer windows. # You will need to refresh the window if you have none currently open. # Create the Shell.Application ComObject $Shell = New-Object -ComObject Shell.Application # For each one of the open windows, refresh it. $Shell.Windows() | ForEach-Object { $_.Refresh() } } } Write-Verbose "[$scriptName] - [/public/Windows/Show-HiddenFiles.ps1] - Done" #endregion - From /public/Windows/Show-HiddenFiles.ps1 #region - From /public/Windows/Test-Role.ps1 Write-Verbose "[$scriptName] - [/public/Windows/Test-Role.ps1] - Importing" function Test-Role { <# .SYNOPSIS Test if the current context is running as a specified role. .DESCRIPTION Test if the current context is running as a specified role. .EXAMPLE Test-Role -Role Administrator Test if the current context is running as an Administrator. .EXAMPLE Test-Role -Role User Test if the current context is running as a User. .NOTES Supported OS: Windows #> [OutputType([Boolean])] [CmdletBinding()] [alias('Test-Admin', 'Test-Administrator', 'IsAdmin', 'IsAdministrator')] param( # Role to test [Parameter()] [Security.Principal.WindowsBuiltInRole] $Role = 'Administrator' ) Write-Verbose "Test Role - [$Role]" $user = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal($user) $isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::$Role) Write-Verbose "Test Role - [$Role] - [$isAdmin]" $isAdmin } Write-Verbose "[$scriptName] - [/public/Windows/Test-Role.ps1] - Done" #endregion - From /public/Windows/Test-Role.ps1 Write-Verbose "[$scriptName] - [/public/Windows] - Done" #endregion - From /public/Windows Write-Verbose "[$scriptName] - [/public] - Done" #endregion - From /public Export-ModuleMember -Function 'ConvertFrom-Base64String','ConvertTo-Base64String','ConvertTo-Boolean','Get-FileInfo','Remove-EmptyFolder','Clear-GitRepo','Invoke-GitSquash','Invoke-SquashBranch','Reset-GitRepo','Restore-GitRepo','Sync-GitRepo','Sync-Repo','Import-Variables','New-GitHubLogGroup','Set-GitHubEnv','Merge-Hashtables','Invoke-PruneModule','Invoke-ReinstallModule','Uninstall-Pester','Copy-Object','New-PSCredential','Restore-PSCredential','Save-PSCredential','Search-GUID','Test-IsGUID','Test-IsNotNullOrEmpty','Test-IsNullOrEmpty','Get-TLSConfig','Set-TLSConfig','Join-Uri','Invoke-CleanWingetApps','Show-FileExtension','Show-HiddenFiles','Test-Role' -Cmdlet '' -Variable '' -Alias '' |