Skip to content

Instantly share code, notes, and snippets.

@jimbrig
Created August 7, 2021 04:49
Show Gist options
  • Save jimbrig/014f18d00bea1c63ca5da34fa66a71e0 to your computer and use it in GitHub Desktop.
Save jimbrig/014f18d00bea1c63ca5da34fa66a71e0 to your computer and use it in GitHub Desktop.
PowerShellScripts
<#
.Synopsis
Allows for easy backup and restore of Microsoft EDGE (Anaheim) Profiles.
EDGE MUST BE CLOSED DURING!
.Description
Will backup all EDGE "User Data" for the current user. This data contains all the "Profiles" within the browser, and the corresponding registry keys will also be saved alongside the backup.
Backups are zipped to allow for easy storage on locations like OneDrive.
Before archiving the backup, all profiles have their Cache emptied.
Restore will replace the current users EDGE data. The command requires that the user chooses how to handle existing data.
.Example
# Backup the current users EDGE Profiles to the _EdgeProfilesBackup folder in the users own OneDrive.
Backup-EDGEProfiles
.Example
# Backup the current users EDGE Profiles to the users own TEMP folder.
Backup-EDGEProfiles -Destination $env:TEMP
.Example
# Restore a previous backup and remove existing user data.
Restore-EDGEProfiles -ZIPSource EDGE-UserData30July2021-MichaelMardahl.zip -REGSource EDGE-ProfilesRegistry30July2021-MichaelMardahl.reg -ExistingDataAction Remove
#>
#Requires -Version 5
function Backup-EDGEProfiles {
<#
.Synopsis
Backup current users Microsoft EDGE (Anaheim) Profiles.
.Description
Will backup all EDGE "User Data" for the current user.
.Parameter Verbose
Enables extended output
.Parameter Destination
(optional)
Location in which to save the backup ZIP and REG files
Defaults to the users OneDrive
.Parameter AddDate
(optional - $true/$false)
Applies a date stamp to the filenames.
Defaults to $true
.Example
# Backup the current users EDGE Profiles to the _EdgeProfilesBackup folder in the users own OneDrive.
Backup-EDGEProfiles
.Example
# Backup the current users EDGE Profiles to the users own TEMP folder.
Backup-EDGEProfiles -Destination $env:TEMP
.NOTES
This function backs up the following for an Edge User Profile:
- Compressed archive backup of folder: %LOCALAPPDATA%\Microsoft\Edge
- Registry backup of path: HKCU\Software\Microsoft\Edge\PreferenceMACs
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $false,
HelpMessage = "Destination of the EDGE profile backup (Defaults to OneDrive Backups folder: ~\OneDrive\Backups\EdgeProfilesBackup)")]
[string]$Destination = (Join-Path -Path $env:OneDrive -ChildPath "\Backups\EdgeProfilesBackup"),
[Parameter(Mandatory = $false,
HelpMessage = "Append the current date to the backup (Defaults to true)")]
[bool]$AddDate = $true
)
#region Execute
#Verify that the entered destination exists
if ((-not (Test-Path $Destination) -and ($Destination -eq (Join-Path -Path $env:OneDrive -ChildPath "\_EdgeProfilesBackup")))) {
#Create default destination
New-Item -ItemType Directory -Path $Destination -Force | Out-Null
}
elseif (-not (Test-Path $Destination)) {
Write-Warning "The entered destination path could not be validated ($Destination)"
break
}
#Verify EDGE is closed
if (Get-Process msedge -ErrorAction SilentlyContinue) {
Write-Error "EDGE is still running, please close any open EDGE Browsers and try again."
break
}
Write-Output "Starting EDGE profiles backup for $($env:USERNAME) to ($Destination) - DON'T OPEN EDGE! and please wait..."
Write-Verbose "Destination root : $Destination"
Write-Verbose "Append date : $AddDate"
#Date name addition check
if ($AddDate) {
$dateName = (get-date -Format ddMMMMyyyy).ToString()
}
else {
$dateName = ""
}
#Setting some important variables
$edgeProfilesPath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath "\Microsoft\Edge")
$edgeProfilesRegistry = "HKCU\Software\Microsoft\Edge\PreferenceMACs"
#Export registry key
$regBackupDestination = (Join-Path -Path $Destination -ChildPath "\EDGE-ProfilesRegistry$($dateName)-$($env:USERNAME).reg")
Write-Verbose "Exporting Registry backup to $regBackupDestination"
#Remove any existing destination file, else the export will stall.
if (($regBackupDestination -ilike "*.reg") -and (Test-Path $regBackupDestination)) {
Remove-Item $regBackupDestination -Force -ErrorAction SilentlyContinue
}
$regCMD = Invoke-Command { reg export "$edgeProfilesRegistry" "$regBackupDestination" }
#Export user data
#Cleaning cache
Write-Verbose "Cleaning up cache before export."
if (Test-Path $edgeProfilesPath) {
$cacheFolders = Get-ChildItem -Path $edgeProfilesPath -r | Where-Object { $_.PsIsContainer -and $_.Name -eq "Cache" }
Foreach ($folder in $cacheFolders) {
$rmPath = Join-Path -Path $folder.fullname -ChildPath "\*"
Write-Verbose "Emptying $rmPath"
Remove-Item $rmPath -Recurse -Force
}
Write-Verbose "Cleanup completed."
}
else {
Write-Error "EDGE user data folder missing - terminating!"
break
}
#Creating ZIP Archive
$zipBackupDestination = (Join-Path -Path $Destination -ChildPath "\EDGE-UserData$($dateName)-$($env:USERNAME).zip")
Write-Verbose "Exporting user data backup to $zipBackupDestination"
#Remove any existing destination file, else the export will fail.
if (($zipBackupDestination -ilike "*.zip") -and (Test-Path $zipBackupDestination)) {
Remove-Item $zipBackupDestination -Force -ErrorAction SilentlyContinue
}
#Compressing data to backup location
try {
Get-ChildItem -Path $edgeProfilesPath | Compress-Archive -DestinationPath $zipBackupDestination -CompressionLevel Fastest
Write-Output "EDGE Profile export completed to: $Destination"
}
catch {
#Error out and cleanup
Write-Error $_
Remove-Item $zipBackupDestination -Force -ErrorAction SilentlyContinue
Remove-Item $regBackupDestination -Force -ErrorAction SilentlyContinue
Write-Error "EDGE Backup failed, did you forget to keep EDGE closed?!"
break
}
#endregion Execute
}
function Restore-EDGEProfiles {
<#
.Synopsis
Restore Microsoft EDGE (Anaheim) Profiles to the current users EDGE Browser.
.Description
Will restore all EDGE "User Data" for the current user from an archive created by the Backup-EDGEProfiles function.
.Parameter Verbose
Enables extended output
.Parameter ZIPSource
(Mandatory - file path)
Location of the User Data backup archive file.
.Parameter REGSource
(Mandatory - file path)
Location of the profile data registry file.
.Parameter ExistingDataAction
(Mandatory - Rename/Remove)
Choose wheather to have the existing User Data removed completely or just renamed. Renaming will add a datestamp to the existing USer Data folder.
.Example
# Restore a previous backup and remove existing user data.
Restore-EDGEProfiles -ZIPSource EDGE-UserData30July2021-MichaelMardahl.zip -REGSource EDGE-ProfilesRegistry30July2021-MichaelMardahl.reg -ExistingDataAction Remove
#>
#Add the -verbose parameter to commandline to get extra output.
[CmdletBinding()]
param (
[Parameter(Mandatory = $true,
HelpMessage = "Source of the EDGE User Data profile backup archive")]
[string]$ZIPSource,
[Parameter(Mandatory = $true,
HelpMessage = "Source of the EDGE Registry profile backup file")]
[string]$REGSource,
[Parameter(Mandatory = $true,
HelpMessage = "How to handle the existing profiles? Options are Backup or Remove")]
[ValidateSet('Rename', 'Remove')]
[string]$ExistingDataAction
)
#region Execute
#Verify that the entered sources exits and have the right fileextention
if (-not ((Test-Path $ZIPSource) -or (-not ($ZIPSource -ilike "*.zip")))) {
Write-Error "The entered source file could not be validated ($ZIPSource)"
break
}
if (-not ((Test-Path $REGSource) -or (-not ($REGSource -ilike "*.reg")))) {
Write-Error "The entered source file could not be validated ($REGSource)"
break
}
#Verify EDGE is closed
if (Get-Process msedge -ErrorAction SilentlyContinue) {
Write-Error "EDGE is still running, please close any open EDGE Browsers and try again."
Break
}
Write-Output "Starting EDGE profiles restore for $($env:USERNAME) - (DON'T OPEN EDGE!) please wait..."
Write-Verbose "Source archive : $ZIPSource"
Write-Verbose "Source registry : $REGSource"
#Define location of EDGE Profile for current user
$edgeProfilesPath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath "\Microsoft\Edge")
#Handle existing User Data
$UserData = (Join-Path -Path $edgeProfilesPath -ChildPath "\User Data")
if (Test-Path $UserData) {
Write-Verbose "Existing User Data folder found in $edgeProfilesPath"
if ($ExistingDataAction -eq "Rename") {
$renameFolder = "$($UserData)-$((get-date -Format ddMMMMyyyy-HHmmss).ToString())"
Write-Verbose "Rename parameter set - Renaming folder to '$renameFolder'"
Rename-Item $UserData $renameFolder
}
else {
Write-Verbose "Remove parameter set - Deleting existing data."
Remove-Item $UserData -Recurse -Force
}
}
#Import registry key
Write-Verbose "Importing Registry backup from $REGSource"
$regCMD = Invoke-Command { reg import "$REGSource" }
#Import user data
#
Write-Verbose "Decompressing '$ZIPSource' to $edgeProfilesPath"
try {
Expand-Archive -Path $ZIPSource -DestinationPath $edgeProfilesPath -Force
Write-Output "EDGE Profile import completed to: $UserData"
}
catch {
#Error out and cleanup
Write-Error $_
Remove-Item $zipBackupDestination -Force -ErrorAction SilentlyContinue
Remove-Item $regBackupDestination -Force -ErrorAction SilentlyContinue
Write-Error "EDGE import failed, did you forget to keep EDGE closed?!"
break
}
#endregion Execute
}
Export-ModuleMember -Function Backup-EDGEProfiles, Restore-EDGEProfiles
Function Install-Choco {
<#
.SYNOPSIS
Installs chocolatey package manager.
.LINK
https://chocolatey.org
.EXAMPLE
Install-Choco
#>
Write-Info "Checking for Chocolatey Installation..."
if (Test-Command choco) {
Write-Success "Chocolatey installation detected; Skipping installation..."
}
else {
Write-Failure "Chocolatey installation not detected; Installing..."
Write-Task "Checking for Administrative Priveledges..."
# Ensure Admin Priveledges
if (!(Test-Admin)) {
Write-Failure "Admin priveledges not detected; Starting new process/shell as admin to install chocolatey..."
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit
}
Write-Host ""
Write-Host "Installing Chocolatey for Windows..." -ForegroundColor Green
Write-Host "------------------------------------" -ForegroundColor Green
Write-Step "1" "Checking/Creating a PowerShell Profile First."
if (!(Test-Path $PROFILE)) {
New-Item -Path $PROFILE -Force
Write-Success "Created new PowerShell Profile at $PROFILE."
}
Write-Step "2" "Installing Chocolatey from URL..."
Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Write-Step "3" "Updating Environment"
Update-Environment
if (Test-Command choco) {
Write-Success "Successfully installed chocolatey to system."
}
else {
Write-Failure "Failed to install chocolatey..."
}
}
}
function Test-ProgramInstalled( $programName ) {
$localmachine_x86_check = ((Get-ChildItem "HKLM:Software\Microsoft\Windows\CurrentVersion\Uninstall") | Where-Object { $_.GetValue('DisplayName') -like "*$programName*" } ).Length -gt 0;
if (Test-Path 'HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall') {
$localmachine_x64_check = ((Get-ChildItem "HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall") | Where-Object { $_.GetValue('DisplayName') -like "*$programName*" } ).Length -gt 0;
}
$user_x86_check = ((Get-ChildItem "HKCU:Software\Microsoft\Windows\CurrentVersion\Uninstall") | Where-Object { $_.GetValue('DisplayName') -like "*$programName*" } ).Length -gt 0;
if (Test-Path 'HKCU:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall') {
# $user_x64_check = ((Get-ChildItem "HKCU:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall") | Where-Object { $_.GetValue('DisplayName') -like "*$programName*" } ).Length -gt 0;
}
$localmachine_check = $localmachine_x86_check -or $localmachine_x64_check;
$user_check = $user_x86_check -or $user__x64_check;
return $localmachine_check -or $user_check;
}
# Install-fromURL
# example: Install-fromURL "<url>" "program-name"
function Install-fromURL($uri, $name) {
$out = "$env:USERPROFILE\Downloads\$name.exe"
Invoke-WebRequest -Uri $uri -OutFile $out
Start-Process $out
}
# Get Github Download URL
# example: Get-GHDownloadURL "user/repo" "*.exe"
function Get-GHDownloadURL($repo, $pattern) {
$releasesUri = "https://api.github.com/repos/$repo/releases/latest"
((Invoke-RestMethod -Method GET -Uri $releasesUri).assets | Where-Object name -like $pattern ).browser_download_url
}
# Download from github
# example: Save-fromGH "user/repo" "*.exe" "program-name"
function Save-fromGH($repo, $pattern, $name) {
$uri = Get-GHDownloadURL $repo $pattern
$extension = $pattern.Replace("*", "")
$out = $name + $extension
Invoke-WebRequest -Uri $uri -OutFile "$env:USERPROFILE\Downloads\$out"
explorer.exe "$env:USERPROFILE\Downloads"
}
# install from github
# example: Install-Github "user/repo" "*.exe" "program-name"
function Install-Github($repo, $pattern, $name) {
Save-fromGH $repo $pattern $name
$extension = $pattern.Replace("*", "")
$installfile = $name + $extension
$installpath = "$env:USERPROFILE\Downloads\" + $installfile
Start-Process $installpath
}
# Install Cascadia Code from Nerd Fonts
function Install-CascadiaCode {
$address = Get-GHDownloadURL "ryanoasis/nerd-fonts" "CascadiaCode.zip"
$archive = "$($Env:TEMP)\CascadiaCode.zip"
$folder = "$($Env:TEMP)\CascadiaCode"
$shell = New-Object -ComObject Shell.Application
$obj = $shell.Namespace(0x14)
$systemFontsPath = $obj.Self.Path
Invoke-RestMethod -Method Get -Uri $address -OutFile $archive
Expand-Archive -Path $archive -DestinationPath $folder -Force
# $shouldReboot = $false
Get-ChildItem -Path $folder | ForEach-Object {
$path = $_.FullName
$fontName = $_.Name
$target = Join-Path -Path $systemFontsPath -ChildPath $fontName
if (test-path $target) {
Write-Host "Ignoring $($path) as it already exists." -ForegroundColor Magenta
}
else {
Write-Host "Installing $($path)..." -ForegroundColor Cyan
$obj.CopyHere($path)
}
}
Remove-Item -Path $folder -Recurse -Force -EA SilentlyContinue
}
# invoke remote script
# example: Invoke-RemoteScript
Function Invoke-RemoteScript {
[CmdletBinding()]
param(
[Parameter(Position = 0)]
[string]$address,
[Parameter(ValueFromRemainingArguments = $true)]
$remainingArgs
)
Invoke-Expression "& { $(Invoke-RestMethod $address) } $remainingArgs"
}
# Download Profile from jimsdots on Github
# Function Download-Profile {
# [CmdletBinding()]
# param(
# [Parameter(Position = 0)]
# [string]$name
# )
# #$template = "Microsoft.PowerShell_%{NAME}%profile.ps1"
# $address = "https://raw.githubusercontent.com/jimbrig/jimsdots/main/powershell/"
# $fileName = Split-Path $profile -Leaf
# $uri = "$($address)$($fileName)"
# $destination = Join-Path -Path (Split-Path $profile) -ChildPath $fileName
# Write-Host "GET $uri HTTP/1.1" -ForegroundColor Magenta
# New-Item `
# -Path (Split-Path $profile) `
# -ItemType Directory `
# -EA SilentlyContinue `
# | Out-Null
# Invoke-RestMethod `
# -Method Get `
# -Uri $uri `
# -OutFile $destination
# Write-Host "$destination updated." -ForegroundColor Cyan
# }
Function Add-DriveMappings {
<#
.SYNOPSIS
This function adds network drive mappings.
.DESCRIPTION
This function in details:
* takes a drives mappings list from a configuration file,
* skips entries marked as disabled,
* maps drive persistently for each entry left,
* supports encrypted secret data.
.PARAMETER CfgFile
Configuration file.
.PARAMETER KeyFile
Encryption key file. If you don't have it, please see New-EncryptionKey.
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/docs/Add-DriveMappings.md
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/docs/New-EncryptionKey.md
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/docs/Protect-Config.md
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/modules/map-drives.psm1
#>
Param(
[Parameter(Mandatory = $true)] [String] $CfgFile,
[Parameter(Mandatory = $true)] [String] $KeyFile )
$pass = ConvertTo-SecureString -AsPlainText -Force "vagrant"
$cred = New-Object pscredential("vagrant", $pass)
$cfg = Get-Content $CfgFile | ConvertFrom-Json
$cfg.drives |
Select-Object -expand secret |
Decrypt $KeyFile
$cfg.drives |
Where-Object { -Not $_.disabled } |
ForEach-Object {
Start-Process powershell -Credential $cred -LoadUserProfile -NoNewWindow -Wait `
-ArgumentList "-NoProfile", `
@"
New-SmbMapping -LocalPath $($_.local) -RemotePath $($_.secret.remote) ``
-Persistent `$True -SaveCredentials
"@
}
}
Function Set-QuickAccessFromCfg {
<#
.SYNOPSIS
This function pins a path to Quick Access in Windows Explorer.
.DESCRIPTION
This function in details:
* takes a path list to pin from a configruation file,
* pins a path to Quick Access in Windows Explorer
.PARAMETER CfgFile
Configuration file.
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/docs/Set-QuickAccessFromCfg.md
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/modules/set-quickaccess.psm1
.LINK
https://gallery.technet.microsoft.com/Set-QuickAccess-117e9a89
#>
Param ( [Parameter(Mandatory = $true)][String] $CfgFile )
$cfg = Get-Content $CfgFile | ConvertFrom-Json
if ( $cfg.quick_access ) {
$cfg.quick_access |
ForEach-Object { Set-QuickAccess -Action Pin -Path ([System.Environment]::ExpandEnvironmentVariables( $_ )) }
}
}
Function Set-QuickAccess {
###################
# Set-QuickAccess #
###################
#Version: 2017-08-10.01
#Author: johan.carlsson@innovatum.se
<#
.SYNOPSIS
Pin or Unpin folders to/from Quick Access in File Explorer.
.DESCRIPTION
Pin or Unpin folders to/from Quick Access in File Explorer.
.EXAMPLE
.\Set-QuickAccess.ps1 -Action Pin -Path "\\server\share\redirected_folders\$env:USERNAME\Links"
Pin the specified UNC server share to Quick Access in File Explorer.
.EXAMPLE
.\Set-QuickAccess.ps1 -Action Unpin -Path "\\server\share\redirected_folders\$env:USERNAME\Links"
Unpin the specified UNC server share from Quick Access in File Explorer.
.NOTES
Thanks to the below sources for inspiration :)
https://blogs.technet.microsoft.com/heyscriptingguy/2013/04/26/use-powershell-to-work-with-windows-explorer/
https://www.reddit.com/r/sysadmin/comments/6g5hz4/removing_pinned_quick_access_pins_via_powershell/
.LINK
https://gallery.technet.microsoft.com/Set-QuickAccess-117e9a89
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory = $true, Position = 1, HelpMessage = "Pin or Unpin folder to/from Quick Access in File Explorer.")]
[ValidateSet("Pin", "Unpin")]
[string]$Action,
[Parameter(Mandatory = $true, Position = 2, HelpMessage = "Path to the folder to Pin or Unpin to/from Quick Access in File Explorer.")]
[string]$Path
)
Write-Host "$Action to/from Quick Access: $Path.. " -NoNewline
#Check if specified path is valid
If ((Test-Path -Path $Path) -ne $true) {
Write-Warning "Path does not exist."
return
}
#Check if specified path is a folder
If ((Test-Path -Path $Path -PathType Container) -ne $true) {
Write-Warning "Path is not a folder."
return
}
#Pin or Unpin
$QuickAccess = New-Object -ComObject shell.application
$TargetObject = $QuickAccess.Namespace("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}").Items() | where { $_.Path -eq "$Path" }
If ($Action -eq "Pin") {
If ($TargetObject -ne $null) {
Write-Warning "Path is already pinned to Quick Access."
return
}
Else {
$QuickAccess.Namespace("$Path").Self.InvokeVerb("pintohome")
}
}
ElseIf ($Action -eq "Unpin") {
If ($TargetObject -eq $null) {
Write-Warning "Path is not pinned to Quick Access."
return
}
Else {
$TargetObject.InvokeVerb("unpinfromhome")
}
}
Write-Host "Done"
}
Function Add-SystemPath {
<#
.SYNOPSIS
This function updates enironment PATH variable.
.DESCRIPTION
This function in details:
* adds specified paths to %PATH% environment variable
.PARAMETER PathToAdd
Array of paths to add.
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/docs/Add-SystemPath.md
.LINK
https://github.com/a4099181/vagrant-provvin/blob/master/modules/extend-PATH-environment-variable.psm1
.NOTES
Author: bryjamus <bryjamus@gmail.com>
#>
Param([array] $PathToAdd)
$VerifiedPathsToAdd = $Null
Foreach ($Path in $PathToAdd) {
$UserPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::User)
if ($UserPath -like "*$Path*") {
Write-Host "Currnet item in path is: $Path"
Write-Host "$Path already exists in Path statement"
}
else {
$VerifiedPathsToAdd += ";$Path"
Write-Host "`$VerifiedPathsToAdd updated to contain: $Path"
}
if ($VerifiedPathsToAdd -ne $null) {
Write-Host "`$VerifiedPathsToAdd contains: $verifiedPathsToAdd"
Write-Host "Adding $Path to Path statement now..."
[Environment]::SetEnvironmentVariable("Path", $UserPath + $VerifiedPathsToAdd, [EnvironmentVariableTarget]::User)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment