From d34c58db88a823169c42bf618b4be56504c5caa0 Mon Sep 17 00:00:00 2001
From: Matt Seng <mseng3@illinois.edu>
Date: Wed, 31 Jul 2019 11:25:52 -0500
Subject: [PATCH] Moving files over from mseng3's repo

---
 build-software-string.ps1                     |  40 ++
 disable-adobe-updates.ps1                     |  14 +
 enable-adobe-updates.ps1                      |  14 +
 fix-uefi-boot-order.ps1                       |  59 +++
 generate-image-info.ps1                       |  58 +++
 get-lens-info.ps1                             | 264 +++++++++++++
 install-drivers-with-pnputil.ps1              |  22 ++
 ...ll-storage-drivers-before-partitioning.ps1 |  50 +++
 post-to-slack.ps1                             |  60 +++
 post-to-teams.ps1                             |  59 +++
 remove-win10-bloatware-tron.ps1               | 362 ++++++++++++++++++
 set-high-performance-power-plan.ps1           | 127 ++++++
 12 files changed, 1129 insertions(+)
 create mode 100644 build-software-string.ps1
 create mode 100644 disable-adobe-updates.ps1
 create mode 100644 enable-adobe-updates.ps1
 create mode 100644 fix-uefi-boot-order.ps1
 create mode 100644 generate-image-info.ps1
 create mode 100644 get-lens-info.ps1
 create mode 100644 install-drivers-with-pnputil.ps1
 create mode 100644 install-storage-drivers-before-partitioning.ps1
 create mode 100644 post-to-slack.ps1
 create mode 100644 post-to-teams.ps1
 create mode 100644 remove-win10-bloatware-tron.ps1
 create mode 100644 set-high-performance-power-plan.ps1

diff --git a/build-software-string.ps1 b/build-software-string.ps1
new file mode 100644
index 0000000..8a91a46
--- /dev/null
+++ b/build-software-string.ps1
@@ -0,0 +1,40 @@
+# Access to TS variables
+$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
+
+# Array of possible softwares that can be selected
+# Would like to find a way to not have to define this in the script (i.e. pass it from the TS)
+# For now this will work
+$availableArray = @(
+	'BasicApps',
+	'Office',
+	'Matlab',
+	'Origin',
+	'Mathematica',
+	'Autocad'
+)
+
+# Blank array for saving which titles were selected
+$selectedArray = @()
+
+# Add each selected title to the new array
+foreach($software in $availableArray) {
+	if($tsenv.Value("EngrIT_$($software)") -eq "True") {
+		$selectedArray += $software
+	}
+}
+
+# Build the string of selected software
+$softwareString = ""
+foreach($software in $selectedArray) {
+	$softwareString = "$softwareString $($software),"
+}
+# If at least one title was selected, remove trailing comma from $softwareString
+if($softwareString -ne "") {
+	$softwareString = $softwareString.Substring(0, ($softwareString.length - 1))
+}
+# If no titles were selected
+else {
+	$softwareString = "none selected"
+}
+# Save the string to a TS variable
+$tsenv.Value('EngrIT_SelectedSoftware') = $softwareString
\ No newline at end of file
diff --git a/disable-adobe-updates.ps1 b/disable-adobe-updates.ps1
new file mode 100644
index 0000000..fa7b6b5
--- /dev/null
+++ b/disable-adobe-updates.ps1
@@ -0,0 +1,14 @@
+# https://helpx.adobe.com/creative-suite/kb/disable-auto-updates-application-manager.html
+New-Item "${ENV:CommonProgramFiles(x86)}\Adobe\AAMUpdaterInventory\1.0\AdobeUpdaterAdminPrefs.dat" -ItemType File -Force
+$settings = Get-Content "${ENV:CommonProgramFiles(x86)}\Adobe\AAMUpdaterInventory\1.0\AdobeUpdaterAdminPrefs.dat"
+$settings = "<?xml version=`"1.0`" encoding=`"UTF-8`" ?>
+`n
+`n<Preferences>
+`n
+`n<Suppressed>1</Suppressed>
+`n
+`n</Preferences>"
+$settings | Set-Content "${ENV:CommonProgramFiles(x86)}\Adobe\AAMUpdaterInventory\1.0\AdobeUpdaterAdminPrefs.dat"
+
+# http://www.adobe.com/devnet-docs/acrobatetk/tools/PrefRef/Windows/Updater-Win.html?zoom_highlight=updates#Updater(basicsettings)
+reg add "HKLM\SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown" /v "bUpdater" /t "REG_DWORD" /d "0" /f
\ No newline at end of file
diff --git a/enable-adobe-updates.ps1 b/enable-adobe-updates.ps1
new file mode 100644
index 0000000..da66ae8
--- /dev/null
+++ b/enable-adobe-updates.ps1
@@ -0,0 +1,14 @@
+# https://helpx.adobe.com/creative-suite/kb/disable-auto-updates-application-manager.html
+New-Item "${ENV:CommonProgramFiles(x86)}\Adobe\AAMUpdaterInventory\1.0\AdobeUpdaterAdminPrefs.dat" -ItemType File -Force
+$settings = Get-Content "${ENV:CommonProgramFiles(x86)}\Adobe\AAMUpdaterInventory\1.0\AdobeUpdaterAdminPrefs.dat"
+$settings = "<?xml version=`"1.0`" encoding=`"UTF-8`" ?>
+`n
+`n<Preferences>
+`n
+`n<Suppressed>0</Suppressed>
+`n
+`n</Preferences>"
+$settings | Set-Content "${ENV:CommonProgramFiles(x86)}\Adobe\AAMUpdaterInventory\1.0\AdobeUpdaterAdminPrefs.dat"
+
+# http://www.adobe.com/devnet-docs/acrobatetk/tools/PrefRef/Windows/Updater-Win.html?zoom_highlight=updates#Updater(basicsettings)
+reg add "HKLM\SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown" /v "bUpdater" /t "REG_DWORD" /d "1" /f
diff --git a/fix-uefi-boot-order.ps1 b/fix-uefi-boot-order.ps1
new file mode 100644
index 0000000..13e5ee3
--- /dev/null
+++ b/fix-uefi-boot-order.ps1
@@ -0,0 +1,59 @@
+# This script looks for the first non-Windows Boot Manager entry in the UEFI/GPT boot order and moves it to the top
+# For preventing newly installed Windows from hijacking the top boot order spot on my UEFI/GPT image testing VMs
+# by mmseng
+# https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order
+
+# Notes:
+# - There's very little point in using this on regular production machines being deployed. Its main use is for machines being repeatedly imaged, or might be useful for lab machines.
+# - AFAICT bcdedit provideds no way to pull the friendly names of the devices in the overall UEFI boot order list. Therefore, this script only moves the first entry it identifies in the list which is NOT "{bootmgr}" (a.k.a. "Windows Boot Manager"). It's up to the user to make sure the boot order will exist in a state where the desired result is achieved.
+# - In my case, my test UEFI VMs initially have the boot order of 1) "EFI Network", 2) whatever else. When Windows is installed with GPT partitioning, it changes the boot order to 1) "Windows Boot Manager", 2) "EFI Network", 3) whatever else. In that state, this script can be used to change the boot order to 1) "EFI Network", 2) "Windows Boot Manager", 3) whatever else.
+# - This functionality relies on the completely undocumented feature of bcdedit to modify the "{fwbootmgr}" GPT entry, which contains the overall list of UEFI boot devices.
+# - AFAICT bcdedit is really only designed to edit Windows' own "{bootmgr}" entry which represents one of the "boot devices" in the overall UEFI list.
+# - Here are some sources:
+#   - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/
+#   - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi
+#   - https://www.boyans.net/DownloadVisualBCD.html
+#   - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings
+#   - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows
+
+
+# Read current boot order
+echo "Reading current boot order..."
+$bcdOutput = cmd /c bcdedit /enum "{fwbootmgr}"
+echo $bcdOutput
+
+# Kill as many of the stupid characters as possible
+echo "Removing extraneous characters from boot order output..."
+$bcdOutput = $bcdOutput -replace '\s+',''
+$bcdOutput = $bcdOutput -replace '`t',''
+$bcdOutput = $bcdOutput -replace '`n',''
+$bcdOutput = $bcdOutput -replace '`r',''
+$bcdOutput = $bcdOutput.trim()
+$bcdOutput = $bcdOutput.trimEnd()
+$bcdOutput = $bcdOutput.trimStart()
+$bcdOutput = $bcdOutput -replace ' ',''
+echo $bcdOutput
+
+# Define a reliable regex to capture the UUIDs of non-Windows Boot Manager devices in the boot order list
+# This is difficult because apparently Powershell interprets regex is a fairly non-standard way (.NET regex flavor)
+# https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions
+# Even then, .NET regex testers I used didn't match the behavior of what I got out of various Powershell commands that accept regex strings
+# However this seems to work, even though I can't replicate the results in any regex testers
+$regex = [regex]'^{([\-a-z0-9]+)+}'
+echo "Defined regex as: $regex"
+
+# Save matches
+echo "Save strings matching regex..."
+$foundMatches = $bcdOutput -match $regex
+
+# Grab first match
+# If Windows Boot Manager (a.k.a. "{bootmgr}" was the first in the list, this should be the second
+# Which means it was probably the first before Windows hijacked the first spot
+# Which means it was probably my "EFI Network" boot device
+$secondBootEntry = $foundMatches[0]
+echo "First match: $secondBootEntry"
+
+# Move it to the first spot
+echo "Running this command:"
+echo "cmd /c bcdedit $bcdParams /set `"{fwbootmgr}`" displayorder $secondBootEntry /addfirst"
+cmd /c bcdedit $bcdParams /set "{fwbootmgr}" displayorder $secondBootEntry /addfirst
\ No newline at end of file
diff --git a/generate-image-info.ps1 b/generate-image-info.ps1
new file mode 100644
index 0000000..02a6e10
--- /dev/null
+++ b/generate-image-info.ps1
@@ -0,0 +1,58 @@
+$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
+
+Set-Content "c:\engrit\image-info.txt" `
+"=======================
+Image info
+=======================
+The task sequence run was $($tsenv.Value('_SMSTSPackageName')).
+This file was created during imaging on $($tsenv.Value('EngrIT_Timestamp')).
+
+=======================
+TS Variables
+=======================
+EngrIT_isTestTS = $($tsenv.Value('EngrIT_isTestTS'))
+EngrIT_isOSDTS = $($tsenv.Value('EngrIT_isOSDTS'))
+EngrIT_Timestamp = $($tsenv.Value('EngrIT_Timestamp'))
+EngrIT_Model = $($tsenv.Value('EngrIT_Model'))
+EngrIT_LogsGoHere = $($tsenv.Value('EngrIT_LogsGoHere'))
+
+=======================
+TS Variables (UI++)
+=======================
+EngrIT_UIPPRan = $($tsenv.Value('EngrIT_UIPPFailed'))
+EngrIT_UIPPRanFrom = $($tsenv.Value('EngrIT_UIPPRanFrom'))
+EngrIT_OS = $($tsenv.Value('EngrIT_OS'))
+EngrIT_ComputerName = $($tsenv.Value('EngrIT_ComputerName'))
+EngrIT_AdminNetID = $($tsenv.Value('EngrIT_AdminNetID'))
+EngrIT_Office = $($tsenv.Value('EngrIT_Office'))
+EngrIT_Origin = $($tsenv.Value('EngrIT_Origin'))
+EngrIT_Mathematica = $($tsenv.Value('EngrIT_Mathematica'))
+EngrIT_Matlab = $($tsenv.Value('EngrIT_Matlab'))
+EngrIT_Autocad = $($tsenv.Value('EngrIT_Autocad'))
+
+=======================
+TS Variables (Slack)
+=======================
+EngrIT_SelectedSoftware = $($tsenv.Value('EngrIT_Mathematica'))
+EngrIT_SlackMsgStart = $($tsenv.Value('EngrIT_UIPPFailed'))
+EngrIT_SlackMsgMid = $($tsenv.Value('EngrIT_UIPPRanFrom'))
+EngrIT_SlackMsgEnd = $($tsenv.Value('EngrIT_OS'))
+EngrIT_SlackChannel = $($tsenv.Value('EngrIT_ComputerName'))
+EngrIT_SlackName = $($tsenv.Value('EngrIT_AdminNetID'))
+EngrIT_SlackIcon = $($tsenv.Value('EngrIT_Office'))
+EngrIT_SlackWebhook = $($tsenv.Value('EngrIT_Origin'))
+
+=======================
+Collection Variables
+=======================
+isLoaner = $($tsenv.Value('isLoaner'))
+EngrIT_isTestMachine = $($tsenv.Value('EngrIT_isTestMachine'))
+EngrIT_MechSE_JoeMuskin = $($tsenv.Value('EngrIT_MechSE_JoeMuskin'))
+
+=======================
+Built-in Variables
+=======================
+_SMSTSLaunchMode = $($tsenv.Value('_SMSTSLaunchMode'))
+_SMSTSMachineName = $($tsenv.Value('_SMSTSMachineName'))
+OSDComputerName = $($tsenv.Value('OSDComputerName'))
+"
\ No newline at end of file
diff --git a/get-lens-info.ps1 b/get-lens-info.ps1
new file mode 100644
index 0000000..6490d8e
--- /dev/null
+++ b/get-lens-info.ps1
@@ -0,0 +1,264 @@
+param(
+	[switch]$UseServiceAccount,
+	[switch]$CalledFromTS,
+	[switch]$DebugOutput,
+	# Can be "IP" or "MAC"
+	# Passing in anything except "MAC" will cause "IP" to be used
+	# "IP" is safer because it's less likely to return multiple conflicting results
+	[string]$BasedOn="IP",
+	[string]$givenMAC=$false,
+	[string]$givenIP=$false
+)
+
+$log = "x:\engrit\logs\get-lens-info-script.log"
+if($CalledFromTS) {
+	new-item -path $log -itemtype "file" -value "Start of log."
+}
+
+function debug($msg) {
+	if($DebugOutput) {
+		Write-Host $msg
+		if($CalledFromTS) {
+			Write-Output $msg >> $log
+		}
+	}
+}
+
+function debugObject($object) {
+	debug($object)
+	debug("---------------------")
+	debug($object.ip_mac_id)
+	debug($object.ip)
+	debug($object.mac)
+	debug("---")
+	debug($object.most_recent)
+	debug($object.first_seen)
+	debug($object.last_seen)
+	debug("---")
+	debug($object.device_id)
+	debug($object.router_ip)
+	debug($object.router_name)
+	debug("---")
+	debug($object.subnet_id)
+	debug($object.subnet)
+	debug($object.subnet_name)
+	debug("---------------------")
+}
+
+function getLocalIP() {
+	$ip = 'not set'
+	
+	if($GivenIP -ne $false) {
+		$ip = $GivenIP
+	}
+	else {
+		# https://stackoverflow.com/questions/27277701/powershell-get-ipv4-address-into-a-variable
+
+		# Doesn't work without reliable DNS response
+		#$ip = (Test-Connection -ComputerName $env:COMPUTERNAME -Count 1).IPV4Address.IPAddressToString
+
+		# Apparently Get-NetIPConfiguration isn't available in WinPE
+		#$ip = (Get-NetIPConfiguration | Where-Object {$_.IPv4DefaultGateway -ne $null -and $_.NetAdapter.Status -ne "Disconnected"}).IPv4Address.IPAddress
+
+		# Let's try ipconfig then
+		# https://stackoverflow.com/questions/27277701/powershell-get-ipv4-address-into-a-variable
+		$ip = $(ipconfig | where {$_ -match 'IPv4.+\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' } | out-null; $Matches[1])
+	}
+		
+	return $ip
+}
+
+function getLocalMAC() {
+	$mac = 'not set'
+	
+	if($GivenMAC -ne $false) {
+		$mac = $GivenMAC
+	}
+	else {
+		$mac = ipconfig /all | select-string 'Physical.+\s([0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2})' -allmatches | % {$_.matches.groups[1].value}
+	}
+		
+	return $mac
+}
+
+function getLensCreds() {
+	$promptForCreds = $false
+	$lensUser = 'not set'
+	$lensPass = 'not set'
+	
+	# Get creds
+	if($UseServiceAccount) {
+		if($CalledFromTS) {
+			$lensCredsProtected = $tsenv.Value('EngrIT_LensCreds')
+			#debug($lensCredsProtected)
+			$lensCredsSplit = $lensCredsProtected.split(';')
+			#debug($lensCredsSplit)
+			$lensUser = $lensCredsSplit[0]
+			#debug($lensUser)
+			$lensPass = $lensCredsSplit[1]
+			#debug($lensPass)
+		}
+		else {
+			debug("Cannot use service account if not called from TS. Prompting for credentials...")
+			$promptForCreds = $true
+		}
+	}
+	else {
+		$promptForCreds = $true
+	}
+	
+	if($promptForCreds) {
+		$lensCreds = get-credential
+		#debug($lensCreds)
+		$lensUser = $lensCreds.UserName
+		#debug($lensUser)
+		$lensPass = $lensCreds.GetNetworkCredential().Password
+		#debug($lensPass)
+	}
+	
+	return "${lensUser}:${lensPass}"
+}
+
+function getHeaders() {
+	# https://stackoverflow.com/questions/27951561/use-invoke-webrequest-with-a-username-and-password-for-basic-authentication-on-t
+	# https://answers.uillinois.edu/illinois/page.php?id=47895
+	$lensCreds = getLensCreds
+	#debug($lensCreds)
+    $bytes = [System.Text.Encoding]::ASCII.GetBytes($lensCreds)
+	#debug($bytes)
+    $base64 = [System.Convert]::ToBase64String($bytes)
+	#debug($base64)
+    $basicAuthValue = "Basic $base64"
+	#debug($basicAuthValue)
+    $headers = @{ Authorization = $basicAuthValue }
+	#debug($headers)
+
+	return $headers
+}
+
+# "cURL-y" stuff goes here
+function lensCall($local) {
+	$results = 'no result'
+	
+	# "cURL-ing" in PowerShell
+	# https://superuser.com/questions/344927/powershell-equivalent-of-curl
+	# https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Invoke-RestMethod?view=powershell-5.1
+	# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-5.1
+	# https://discoposse.com/2012/06/30/powershell-invoke-restmethod-putting-the-curl-in-your-shell/
+	
+	$BasedOnFinal = "ip"
+	if($BasedOn -eq "MAC") {
+		$BasedOnFinal = "mac"
+	}
+
+	$lensUrl = "https://lens-api.cites.illinois.edu/lens/uiuc-lens/ip_mac?${BasedOnFinal}="
+	$lensContentType = "&content-type=application/json"
+	$requestUrl = $lensUrl + $local.$BasedOnFinal + $lensContentType
+	debug($requestUrl)
+	
+	$headers = getHeaders
+	
+	$results = Invoke-RestMethod -uri $requestUrl -Headers $headers -Method get
+    
+	return $results
+}
+
+function sanitizeIP($ip) {
+	$ip = $ip.replace('[^0-9]', '')
+	return $ip
+}
+
+function sanitizeMAC($mac) {
+	$mac = $mac.ToLower()
+	$mac = $mac.replace('-', '')
+	$mac = $mac.replace('[^a-f0-9]', '')
+	return $mac
+}
+
+function ipsAreEqual($a, $b) {
+	$a = sanitizeIP($a)
+	$b = sanitizeIP($b)
+	if($a -eq $b) {
+		debug("$a -eq $b")
+		return $true
+	}
+	debug("$a -ne $b")
+	return $false
+}
+
+function macsAreEqual($a, $b) {
+	$a = sanitizeMAC($a)
+	$b = sanitizeMAC($b)
+	if($a -eq $b) {
+		debug("$a -eq $b")
+		return $true
+	}
+	debug("$a -ne $b")
+	return $false
+}
+
+if($CalledFromTS) {
+	# Access to TS variables
+	$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
+}
+
+$local = @{
+	ip = 'not set'
+	mac = 'not set'
+}
+
+$local.ip = getLocalIP
+debug($local.ip)
+$local.mac = getLocalMAC
+debug($local.mac)
+
+$return = lensCall($local)
+
+# See this link for the anatomy of a Lens API result object:
+# https://answers.uillinois.edu/illinois/48350
+debug($return)
+
+debug("Status: $($return.status)")
+debug("Error: $($return.error)")
+debug("Message: $($return.message)")
+debug("Result(s): $($return.result)")
+debug("Object(s): $($return.objects)")
+
+$numResults = $return.result.length
+debug("Number of results: $numResults")
+
+$final = @{
+	ip = 'not set'
+	mac = 'not set'
+	subnet = 'not set'
+}
+
+foreach($result in $return.result) {
+	$object = $return.objects.ip_mac.$result
+	debug($object)
+	debug($object.ip)
+	debug($object.mac)
+	debug($object.subnet_name)
+	debug($local.ip)
+	debug($local.mac)
+	
+	# It's possible the Lens call will return multiple results, even multiple conflicting results.
+	# To make sure we're getting the most accurate one, look through the results until we find one that matches the IP and MAC that we know are correct.
+	if(ipsAreEqual $object.ip $local.ip) {
+		if(macsAreEqual $object.mac $local.mac) {
+			$final.ip = sanitizeIP($object.ip)
+			$final.mac = sanitizeMAC($object.mac)
+			$final.subnet = $object.subnet_name
+		}
+	}
+}
+
+debug($final.mac)
+debug($final.ip)
+debug($final.subnet)
+
+if($CalledFromTS) {
+	$tsenv.Value('EngrIT_MAC') = $final.mac
+	$tsenv.Value('EngrIT_IP') = $final.ip
+	$tsenv.Value('EngrIT_Net') = $final.subnet
+}
diff --git a/install-drivers-with-pnputil.ps1 b/install-drivers-with-pnputil.ps1
new file mode 100644
index 0000000..7927bcf
--- /dev/null
+++ b/install-drivers-with-pnputil.ps1
@@ -0,0 +1,22 @@
+param(
+	[string]$Path=""
+)
+
+if($Path -eq "") {
+	$Path = "c:\engrit\drivers\auto"
+}
+
+write-output "Checking recursively for drivers in `"$Path`"" 
+
+$infs = Get-ChildItem -Path $Path -Filter "*.inf" -Recurse -File
+
+foreach($inf in $infs) {
+	# https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/pnputil-command-syntax
+	pnputil /add-driver $inf.Fullname /install
+	
+	# https://gist.github.com/xee5ch/1021553#file-driverimport-bat
+	# Legacy syntax
+	#pnputil -i -a $inf.Fullname
+}
+
+write-output "Done."
\ No newline at end of file
diff --git a/install-storage-drivers-before-partitioning.ps1 b/install-storage-drivers-before-partitioning.ps1
new file mode 100644
index 0000000..c36fad5
--- /dev/null
+++ b/install-storage-drivers-before-partitioning.ps1
@@ -0,0 +1,50 @@
+param(
+	[string]$Source,
+	[string]$Dest,
+	[int]$DiskToWipe=-1
+)
+
+# Copy files from (probably remote) source to (probably local) destination
+write-output "Copying files from `"$Source`" to `"$Dest`"..."
+robocopy /s /e /r:3 /w:5 $Source $Dest
+
+# Get all infs
+write-output "Getting all INF files, recursively, in `"$Dest`"..."
+$infs = Get-ChildItem -Path $Dest -Filter "*.inf" -Recurse -File
+
+# Try to install each inf
+write-output "Installing drivers..."
+foreach($inf in $infs) {
+	write-output "Installing `"$($inf.Fullname)`"..."
+	# https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/pnputil-command-syntax
+	pnputil /add-driver $inf.Fullname /install
+	
+	# https://gist.github.com/xee5ch/1021553#file-driverimport-bat
+	# Legacy syntax
+	#pnputil -i -a $inf.Fullname
+}
+
+# Give time for drive to be recognized?
+Start-Sleep -s 15
+
+# Check to see if drives are recognized
+$diskpartScript = "$Dest\diskpart.txt"
+
+# For whatever reason, you have to explicitly use ascii when writing script files for diskpart's consumption
+# https://social.technet.microsoft.com/Forums/windows/en-US/de65304a-87cc-431c-b3fe-64170d26355d/diskpart-s-scripttxt-not-working-invalid-commands?forum=ITCG
+"list disk" | out-file $diskpartScript -encoding "ascii"
+
+# Wipe drive if requested
+if($DiskToWipe -ne -1) {
+	"select disk $DiskToWipe" | out-file $diskpartScript -encoding "ascii" -append
+	"clean" | out-file $diskpartScript -encoding "ascii" -append
+}
+diskpart /s $diskpartScript 2>&1
+
+# Give more time for drive to be recognized?
+Start-Sleep -s 15
+
+# Check to see if c:\ is recognized
+dir c:\ 2>&1
+
+write-output "Done."
\ No newline at end of file
diff --git a/post-to-slack.ps1 b/post-to-slack.ps1
new file mode 100644
index 0000000..9dcba20
--- /dev/null
+++ b/post-to-slack.ps1
@@ -0,0 +1,60 @@
+# Usage example:
+# powershell.exe -ExecutionPolicy Bypass -file \\engr-wintools\packagedsoftware$\ushar\scripts\PushMessageToSlack.ps1 -channel "slackdevs" -message "%date%: Machine <machine> finished imaging with TS <ts>."
+
+param(
+	[string]$message='No message given',
+	[string]$channel,
+	[string]$name,
+	[string]$icon,
+	[Parameter(Mandatory=$true)][string]$webhook
+)
+
+Write-Output "-----------------"
+Write-Output "PSVersionTable:"
+Write-Output $PSVersionTable
+Write-Output "channel: $channel"
+Write-Output "message: $message"
+Write-Output "name: $name"
+Write-Output "icon: $icon"
+Write-Output "webhook: $webhook"
+
+# Build payload
+$payload = @{}
+$payload['channel'] = $channel
+$payload['text'] = $message
+
+if($name -ne "No name given") {
+	$payload['username'] = $name
+}
+
+if($icon -ne "No icon given") {
+	if($icon.startswith("http")) {
+		$payload['icon_url'] = $icon
+	}
+	else {
+		$payload['icon_emoji'] = $icon
+	}
+}
+
+Write-Output "payload:"
+Write-Output "$payload"
+
+# Send REST call
+# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-5.1
+#Invoke-WebRequest -Body (ConvertTo-Json -Compress -InputObject $payload) -UseBasicParsing -Method Post -Uri $webhook
+Invoke-WebRequest `
+	-Body (ConvertTo-Json -Compress -InputObject $payload) `
+	-UseBasicParsing `
+	-Method Post `
+	-Uri $webhook
+
+Write-Output "-----------------"
+
+<#
+# Testing Saleh's new Teams webhook script
+Write-Output "Testing Saleh's new Teams webhook script..."
+$timestamp = get-date -uformat "%H-%M-%S"
+$teamsLog = "c:\engrit\logs\post-to-teams_$timestamp.log"
+$teamsWebhook = "https://outlook.office.com/webhook/3048eff5-4a13-494f-8ce1-45c377e97e04@44467e6f-462c-4ea2-823f-7800de5434e3/IncomingWebhook/f440555c59dd455692fcf6e99673a8e8/35ba12b7-66ea-41f3-9c97-1c8f812e2d79"
+Powershell -ExecutionPolicy ByPass -file "w:\ushar\scripts\PushMessageToTeams.ps1" -message $message -title $name -webhook $teamsWebhook > $teamsLog 2>&1
+#>
\ No newline at end of file
diff --git a/post-to-teams.ps1 b/post-to-teams.ps1
new file mode 100644
index 0000000..1080382
--- /dev/null
+++ b/post-to-teams.ps1
@@ -0,0 +1,59 @@
+# Usage example:
+# powershell.exe -ExecutionPolicy Bypass -file \\engr-wintools\packagedsoftware$\ushar\scripts\PushMessageToSlack.ps1 -channel "slackdevs" -message "%date%: Machine <machine> finished imaging with TS <ts>."
+
+param(
+	[string]$message='No message given',
+	# [string]$channel,
+	[string]$title='No title given',
+	# [string]$icon,
+	[Parameter(Mandatory=$true)][string]$webhook
+)
+
+Write-Output "-----------------"
+Write-Output "PSVersionTable:"
+Write-Output $PSVersionTable
+# Write-Output "channel: $channel"
+Write-Output "message: $message"
+Write-Output "title: $title"
+# Write-Output "icon: $icon"
+Write-Output "webhook: $webhook"
+
+# Build payload
+
+#Translate emojis from Slack to MSTeams equivalent (Added for testing the script with prod, temporarily)
+if ($message.Contains(":arrow_forward:")){
+	$message = $message.Replace(":arrow_forward: ", "")
+	$title = "&#x25b6; " + $title
+}
+
+if ($message.Contains(":pacman:")){
+	$message = $message.Replace(":pacman: ", "")
+	$title = "&#x1F504; " + $title
+}
+
+if ($message.Contains(":green_checkmark:")){
+	$message = $message.Replace(":green_checkmark: ", "")
+	$title = "&#x2705; " + $title
+}
+
+if ($message.Contains("*")){
+	$message = $message.Replace("*", "**")
+}
+
+$payload = @{}
+$payload['title'] = $title
+$payload['text'] = $message
+
+Write-Output "payload:"
+Write-Output "$payload"
+
+# Send REST call
+# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-5.1
+#Invoke-WebRequest -Body (ConvertTo-Json -Compress -InputObject $payload) -UseBasicParsing -Method Post -Uri $webhook
+Invoke-WebRequest `
+	-Body (ConvertTo-Json -Compress -InputObject $payload) `
+	-UseBasicParsing `
+	-Method Post `
+	-Uri $webhook
+
+Write-Output "-----------------"
diff --git a/remove-win10-bloatware-tron.ps1 b/remove-win10-bloatware-tron.ps1
new file mode 100644
index 0000000..a64d41a
--- /dev/null
+++ b/remove-win10-bloatware-tron.ps1
@@ -0,0 +1,362 @@
+<#
+Purpose:       Script to remove many of the pre-loaded Microsoft Metro "modern app" bloatware. Called by Tron in Stage 2: De-bloat
+               Add any AppX uninstall commands to this list to target them for removal
+Requirements:  1. Administrator access
+               2. Windows 8 and up
+Author:        vocatus on reddit.com/r/TronScript ( vocatus.gate at gmail ) // PGP key: 0x07d1490f82a211a2
+Version:       1.2.9 + Add additional user-submitted entries
+#>
+$ErrorActionPreference = "SilentlyContinue"
+
+
+########
+# PREP #
+########
+$METRO_3RD_PARTY_MODERN_APPS_TO_TARGET_BY_NAME_SCRIPT_VERSION = "1.3.8"
+$METRO_3RD_PARTY_MODERN_APPS_TO_TARGET_BY_NAME_SCRIPT_DATE = "2019-03-09"
+
+# Needed for Removal
+$AppxPackages = Get-AppxProvisionedPackage -online | select-object PackageName,Displayname
+$ProPackageList = Get-AppxPackage -AllUsers | select-object PackageFullName, Name
+$Script:AppxCount3rd = 0
+
+# App Removal function
+Function Remove-App([String]$AppName){
+	If($AppxPackages.DisplayName -match $AppName -or $ProPackageList.Name -match $AppName ) {
+		$PackageFullName = ($ProPackageList | where {$_.Name -like $AppName}).PackageFullName
+		$ProPackageFullName = ($AppxPackages | where {$_.Displayname -like $AppName}).PackageName
+
+		If($PackageFullName -is [array]){
+			For($i=0 ;$i -lt $PackageFullName.Length ;$i++) {
+				$Script:AppxCountMS++
+				$Job = "TronScriptMS$AppxCountMS"
+				$PackageF = $PackageFullName[$i]
+				$ProPackage = $ProPackageFullName[$i]
+				write-output "$AppxCountMS - $PackageF"
+				Start-Job -Name $Job -ScriptBlock {
+					Remove-AppxPackage -Package $using:PackageF | Out-null
+					Remove-AppxProvisionedPackage -Online -PackageName $using:ProPackage | Out-null
+				} | Out-null
+			}
+		} Else {
+			$Script:AppxCountMS++
+			$Job = "TronScriptMS$AppxCountMS"
+			write-output "$AppxCountMS - $PackageFullName"
+			Start-Job -Name $Job -ScriptBlock {
+				Remove-AppxPackage -Package $using:PackageFullName | Out-null
+				Remove-AppxProvisionedPackage -Online -PackageName $using:ProPackageFullName | Out-null
+			} | Out-null
+		}
+	}
+}
+
+###########
+# EXECUTE #
+###########
+# Active identifiers
+#Remove-App "BrowserChoice"                             # "Browser Choice" screen required by the EU antitrust regulation
+#Remove-App "Microsoft.Advertising.JavaScript"          # Advertising framework
+#Remove-App "Microsoft.Advertising.Xaml"                # Advertising framework
+#Remove-App "Microsoft.BingFinance"                     # Money app - Financial news
+#Remove-App "Microsoft.BingFoodAndDrink"                # Food and Drink app
+#Remove-App "Microsoft.BingHealthAndFitness"            # Health and Fitness app
+#Remove-App "Microsoft.BingMaps"
+#Remove-App "Microsoft.BingNews"                        # Generic news app
+#Remove-App "Microsoft.BingSports"                      # Sports app - Sports news
+#Remove-App "Microsoft.BingTranslator"                  # Translator app - Bing Translate
+#Remove-App "Microsoft.BingTravel"                      # Travel app
+#Remove-App "Microsoft.BioEnrollment"
+#Remove-App "Microsoft.ConnectivityStore"
+#Remove-App "Microsoft.DiagnosticDataViewer"
+#Remove-App "Microsoft.FreshPaint"                      # Canvas app
+#Remove-App "Microsoft.GetHelp"                         # Get Help link
+#Remove-App "Microsoft.Getstarted"                      # Get Started link
+#Remove-App "Microsoft.HelpAndTips"
+#Remove-App "Microsoft.Messaging"                       # Messaging app
+#Remove-App "Microsoft.MicrosoftJackpot"                # Jackpot app
+#Remove-App "Microsoft.MicrosoftJigsaw"                 # Jigsaw app
+#Remove-App "Microsoft.MicrosoftMahjong"                # Advertising framework
+#Remove-App "Microsoft.MicrosoftOfficeHub"
+#Remove-App "Microsoft.MicrosoftPowerBIForWindows"      # Power BI app - Business analytics
+#Remove-App "Microsoft.MicrosoftSudoku"
+#Remove-App "Microsoft.MinecraftUWP"
+#Remove-App "Microsoft.MovieMoments"                    # imported from stage_2_de-bloat.bat
+#Remove-App "Microsoft.NetworkSpeedTest"
+#Remove-App "Microsoft.Office.Sway"                     # Sway app
+#Remove-App "Microsoft.OneConnect"                      # OneConnect app
+#Remove-App "Microsoft.People"                          # People app
+#Remove-App "Microsoft.SeaofThieves"
+#Remove-App "Microsoft.SkypeApp"                        # Get Skype link
+#Remove-App "Microsoft.SkypeWiFi"
+#Remove-App "Microsoft.Studios.Wordament"               # imported from stage_2_de-bloat.bat
+#Remove-App "Microsoft.Windows.FeatureOnDemand.InsiderHub"
+#Remove-App "Microsoft.WindowsFeedbackHub"              # Feedback app
+#Remove-App "Microsoft.WindowsReadingList"
+#Remove-App "Microsoft.WorldNationalParks"
+#Remove-App "Windows.CBSPreview"
+#Remove-App "Windows.ContactSupport"
+
+
+# Inactive identifers
+#Remove-App "Microsoft.Appconnector"                   # Not sure about this one
+#Remove-App "Microsoft.BingWeather"                    # Weather app
+#Remove-App "Microsoft.CommsPhone"                     # Phone app
+#Remove-App "Microsoft.MSPaint"                        # MS Paint (Paint 3D)
+#Remove-App "Microsoft.Microsoft3DViewer"              # 3D model viewer
+#Remove-App "Microsoft.MicrosoftSolitaireCollection"   # Solitaire collection
+#Remove-App "Microsoft.MicrosoftStickyNotes"           # Pulled from active list due to user requests
+#Remove-App "Microsoft.Office.OneNote"                 # Onenote app
+#Remove-App "Microsoft.Windows.Photos"                 # Photos app
+#Remove-App "Microsoft.WindowsAlarms"                  # Alarms and Clock app
+#Remove-App "Microsoft.WindowsCalculator"              # Calculator app
+#Remove-App "Microsoft.WindowsCamera"                  # Camera app
+#Remove-App "Microsoft.WindowsMaps"                    # Maps app
+#Remove-App "Microsoft.WindowsSoundRecorder"           # Sound Recorder app
+#Remove-App "Microsoft.WindowsStore"                   # Windows Store
+#Remove-App "Microsoft.Xbox*"
+#Remove-App "Microsoft.Xbox.TCUI"
+#Remove-App "Microsoft.XboxApp"
+#Remove-App "Microsoft.XboxGameCallableUI"
+#Remove-App "Microsoft.XboxGameOverlay"
+#Remove-App "Microsoft.XboxGamingOverlay"
+#Remove-App "Microsoft.XboxIdentityProvider"
+#Remove-App "Microsoft.XboxSpeechToTextOverlay"
+#Remove-App "Microsoft.Zune"                           # Zune collection of apps
+#Remove-App "Microsoft.ZuneMusic"
+#Remove-App "Microsoft.ZuneVideo"
+#Remove-App "Microsoft.windowscommunicationsapps"      # Calendar and Mail app
+
+
+#3rd party identifiers                                 # Not sure if any of this is necessary
+Remove-App "*DragonManiaLegends"
+Remove-App "*HiddenCityMysteryofShadows"
+Remove-App "*MarchofEmpires"
+Remove-App "06DAC6F6.StumbleUpon"
+Remove-App "09B6C2D8.TheTreasuresofMontezuma3"
+Remove-App "10084FinerCode.ChessTactics"
+Remove-App "134D4F5B.Box*"
+Remove-App "1430GreenfieldTechnologie.PuzzleTouch*"
+Remove-App "1867LennardSprong.PortablePuzzleCollection"
+Remove-App "22450.BestVideoConverter"
+Remove-App "25920Bala04.Mideo-VideoPlayer"
+Remove-App "26720RandomSaladGamesLLC.HeartsDeluxe*"
+Remove-App "26720RandomSaladGamesLLC.Hexter"
+Remove-App "26720RandomSaladGamesLLC.SimpleMahjong"
+Remove-App "26720RandomSaladGamesLLC.SimpleSolitaire*"
+Remove-App "26720RandomSaladGamesLLC.Spades"
+Remove-App "2703103D.McAfeeCentral"
+Remove-App "27345RickyWalker.BlackjackMaster3"
+Remove-App "29313JVGoldSoft.5962504421940"
+Remove-App "29534ukaszKurant.Logicos"
+Remove-App "29534ukaszKurant.Logicos2"
+Remove-App "29982CsabaHarmath.UnCompress*"
+Remove-App "2FE3CB00.PicsArt-PhotoStudio*"
+Remove-App "32988BernardoZamora.SolitaireHD"
+Remove-App "34697joal.EasyMovieMaker"
+Remove-App "35229MihaiM.QuizforGeeks"
+Remove-App "35300Kubajzl.MCGuide"
+Remove-App "37442SublimeCo.AlarmClockForYou"
+Remove-App "37457BenoitRenaud.HexWar"
+Remove-App "39674HytoGame.TexasHoldemOnline"
+Remove-App "39806kalinnikol.FreeCellSolitaireHD"
+Remove-App "39806kalinnikol.FreeHeartsHD"
+Remove-App "41879VbfnetApps.FileDownloader"
+Remove-App "46928bounde.EclipseManager*"
+Remove-App "47404LurkingDarknessOfRoy.SimpleStrategyRTS"
+Remove-App "4AE8B7C2.Booking.comPartnerEdition*"
+Remove-App "5269FriedChicken.YouTubeVideosDownloader*"
+Remove-App "56081SweetGamesBox.SlitherSnake.io"
+Remove-App "56491SimulationFarmGames.100BallsOriginal"
+Remove-App "57591LegendsSonicSagaGame.Twenty48Solitaire"
+Remove-App "5A894077.McAfeeSecurity"
+Remove-App "64885BlueEdge.OneCalendar*"
+Remove-App "6Wunderkinder.Wunderlist"
+Remove-App "7475BEDA.BitcoinMiner"
+Remove-App "7906AAC0.TOSHIBACanadaPartners*"
+Remove-App "7906AAC0.ToshibaCanadaWarrantyService*"
+Remove-App "7EE7776C.LinkedInforWindows"
+Remove-App "7digitalLtd.7digitalMusicStore*"
+Remove-App "828B5831.HiddenCityMysteryofShadows"
+Remove-App "89006A2E.AutodeskSketchBook*"
+Remove-App "95FE1D22.VUDUMoviesandTV"
+Remove-App "9E2F88E3.Twitter"
+Remove-App "A278AB0D.DisneyMagicKingdoms"
+Remove-App "A278AB0D.DragonManiaLegends*"
+Remove-App "A278AB0D.MarchofEmpires"
+Remove-App "A34E4AAB.YogaChef*"
+Remove-App "AD2F1837.DiscoverHPTouchpointManager"
+Remove-App "AD2F1837.GettingStartedwithWindows8"
+Remove-App "AD2F1837.HPBusinessSlimKeyboard"
+Remove-App "AD2F1837.HPConnectedMusic"
+Remove-App "AD2F1837.HPConnectedPhotopoweredbySnapfish"
+Remove-App "AD2F1837.HPFileViewer"
+Remove-App "AD2F1837.HPJumpStart"
+Remove-App "AD2F1837.HPPCHardwareDiagnosticsWindows"
+Remove-App "AD2F1837.HPPowerManager"
+Remove-App "AD2F1837.HPRegistration"
+Remove-App "AD2F1837.HPWelcome"
+Remove-App "AD2F1837.SmartfriendbyHPCare"
+Remove-App "ASUSCloudCorporation.MobileFileExplorer*"
+Remove-App "AccuWeather.AccuWeatherforWindows8*"
+Remove-App "AcerIncorporated*"
+Remove-App "AcerIncorporated.AcerExplorer"
+Remove-App "ActiproSoftwareLLC*"
+Remove-App "ActiproSoftwareLLC.562882FEEB491"
+Remove-App "AdobeSystemsIncorporated.AdobePhotoshopExpress*"
+Remove-App "AdobeSystemsIncorporated.AdobeRevel*"
+Remove-App "Amazon.com.Amazon*"
+Remove-App "AppUp.IntelAppUpCatalogueAppWorldwideEdition*"
+Remove-App "B9ECED6F.ASUSGIFTBOX*"
+Remove-App "B9ECED6F.ASUSProductRegistrationProgram"
+Remove-App "B9ECED6F.ASUSWelcome"
+Remove-App "B9ECED6F.MyASUS"
+Remove-App "B9ECED6F.eManual"
+Remove-App "BD9B8345.AlbumbySony*"
+Remove-App "BD9B8345.MusicbySony*"
+Remove-App "BD9B8345.Socialife*"
+Remove-App "BD9B8345.VAIOCare*"
+Remove-App "BD9B8345.VAIOMessageCenter*"
+Remove-App "C27EB4BA.DropboxOEM"
+Remove-App "COMPALELECTRONICSINC.AlienwareOSDKits"
+Remove-App "COMPALELECTRONICSINC.AlienwareTypeCaccessory"
+Remove-App "COMPALELECTRONICSINC.Alienwaredockingaccessory"
+Remove-App "ChaChaSearch.ChaChaPushNotification*"
+Remove-App "ClearChannelRadioDigital.iHeartRadio*"
+Remove-App "CrackleInc.Crackle*"
+Remove-App "CyberLinkCorp.ac.AcerCrystalEye*"
+Remove-App "CyberLinkCorp.ac.SocialJogger*"
+Remove-App "CyberLinkCorp.hs.YouCamforHP*"
+Remove-App "CyberLinkCorp.id.PowerDVDforLenovoIdea*"
+Remove-App "D52A8D61.FarmVille2CountryEscape*"
+Remove-App "D5EA27B7.Duolingo-LearnLanguagesforFree*"
+Remove-App "DB6EA5DB.CyberLinkMediaSuiteEssentials*"
+Remove-App "DailymotionSA.Dailymotion*"
+Remove-App "DellInc.AlienwareCommandCenter"
+Remove-App "DellInc.AlienwareCustomerConnect"
+Remove-App "DellInc.AlienwareProductRegistration"
+Remove-App "DellInc.DellCommandUpdate"
+Remove-App "DellInc.DellCustomerConnect"
+Remove-App "DellInc.DellDigitalDelivery"
+Remove-App "DellInc.DellHelpSupport"
+Remove-App "DellInc.DellPowerManager"
+Remove-App "DellInc.DellProductRegistration"
+Remove-App "DellInc.DellShop"
+Remove-App "DellInc.DellSupportAssistforPCs"
+Remove-App "DeviceDoctor.RAROpener"
+Remove-App "DolbyLaboratories.DolbyAccess*"
+Remove-App "DolbyLaboratories.DolbyAtmosSoundSystem"
+Remove-App "Drawboard.DrawboardPDF*"
+Remove-App "DriverToaster*"
+Remove-App "E046963F.LenovoCompanion*"
+Remove-App "E046963F.LenovoSupport*"
+Remove-App "E0469640.CameraMan*"
+Remove-App "E0469640.DeviceCollaboration*"
+Remove-App "E0469640.LenovoRecommends*"
+Remove-App "E0469640.YogaCameraMan*"
+Remove-App "E0469640.YogaPhoneCompanion*"
+Remove-App "E0469640.YogaPicks*"
+Remove-App "ESPNInc.WatchESPN*"
+Remove-App "EncyclopaediaBritannica.EncyclopaediaBritannica*"
+Remove-App "Evernote.Evernote"
+Remove-App "Evernote.Skitch*"
+Remove-App "EvilGrogGamesGmbH.WorldPeaceGeneral2017"
+Remove-App "F5080380.ASUSPowerDirector*"
+Remove-App "Facebook.317180B0BB486"
+Remove-App "Facebook.Facebook"
+Remove-App "Facebook.InstagramBeta*"
+Remove-App "FilmOnLiveTVFree.FilmOnLiveTVFree*"
+Remove-App "Fingersoft.HillClimbRacing"
+Remove-App "FingertappsInstruments*"
+Remove-App "FingertappsOrganizer*"
+Remove-App "Flipboard.Flipboard*"
+Remove-App "FreshPaint*"
+Remove-App "GAMELOFTSA.Asphalt8Airborne*"
+Remove-App "GAMELOFTSA.SharkDash*"
+Remove-App "GameGeneticsApps.FreeOnlineGamesforLenovo*"
+Remove-App "GettingStartedwithWindows8*"
+Remove-App "GoogleInc.GoogleSearch"
+Remove-App "HPConnectedMusic*"
+Remove-App "HPConnectedPhotopoweredbySnapfish*"
+Remove-App "HPRegistration*"
+Remove-App "HuluLLC.HuluPlus*"
+Remove-App "InsightAssessment.CriticalThinkingInsight"
+Remove-App "JigsWar*"
+Remove-App "K-NFBReadingTechnologiesI.BookPlace*"
+Remove-App "KasperskyLab.KasperskyNow*"
+Remove-App "KeeperSecurityInc.Keeper"
+Remove-App "KindleforWindows8*"
+Remove-App "LenovoCorporation.LenovoID*"
+Remove-App "LenovoCorporation.LenovoSettings*"
+Remove-App "MAGIX.MusicMakerJam*"
+Remove-App "McAfeeInc.01.McAfeeSecurityAdvisorforDell"
+Remove-App "McAfeeInc.05.McAfeeSecurityAdvisorforASUS"
+Remove-App "MobileFileExplorer*"
+Remove-App "MusicMakerJam*"
+Remove-App "NAMCOBANDAIGamesInc.PAC-MANChampionshipEditionDXfo*"
+Remove-App "NAVER.LINEwin8*"
+Remove-App "NBCUniversalMediaLLC.NBCSportsLiveExtra*"
+Remove-App "Nordcurrent.CookingFever"
+Remove-App "Ookla.SpeedtestbyOokla"
+Remove-App "PandoraMediaInc.29680B314EFC2"
+Remove-App "PinballFx2*"
+Remove-App "Playtika.CaesarsSlotsFreeCasino*"
+Remove-App "Priceline"
+Remove-App "PricelinePartnerNetwork.Priceline.comTheBestDealso"
+Remove-App "PublicationsInternational.iCookbookSE*"
+Remove-App "RandomSaladGamesLLC.GinRummyProforHP*"
+Remove-App "RealtekSemiconductorCorp.RealtekAudioControl"
+Remove-App "SAMSUNGELECTRONICSCO.LTD.SamsungPrinterExperience"
+Remove-App "ShazamEntertainmentLtd.Shazam*"
+Remove-App "SolidRhino.SteelTactics"
+Remove-App "SonicWALL.MobileConnect"
+Remove-App "SpotifyAB.SpotifyMusic"
+Remove-App "SymantecCorporation.NortonStudio*"
+Remove-App "TOSHIBATEC.ToshibaPrintExperience"
+Remove-App "TelegraphMediaGroupLtd.TheTelegraphforLenovo*"
+Remove-App "TheNewYorkTimes.NYTCrossword*"
+Remove-App "ThumbmunkeysLtd.PhototasticCollage*"
+Remove-App "ToshibaAmericaInformation.ToshibaCentral*"
+Remove-App "TripAdvisorLLC.TripAdvisorHotelsFlightsRestaurants*"
+Remove-App "TuneIn.TuneInRadio*"
+Remove-App "UniversalMusicMobile.HPLOUNGE"
+Remove-App "UptoElevenDigitalSolution.mysms-Textanywhere*"
+Remove-App "Vimeo.Vimeo*"
+Remove-App "Weather.TheWeatherChannelforHP*"
+Remove-App "Weather.TheWeatherChannelforLenovo*"
+Remove-App "WildTangentGames*"
+Remove-App "WildTangentGames.-GamesApp-"
+Remove-App "WildTangentGames.63435CFB65F55"
+Remove-App "WinZipComputing.WinZipUniversal*"
+Remove-App "XINGAG.XING"
+Remove-App "XeroxCorp.PrintExperience"
+Remove-App "YouSendIt.HighTailForLenovo*"
+Remove-App "ZinioLLC.Zinio*"
+Remove-App "eBayInc.eBay*"
+Remove-App "esobiIncorporated.newsXpressoMetro*"
+Remove-App "fingertappsASUS.FingertappsInstrumentsrecommendedb*"
+Remove-App "fingertappsASUS.JigsWarrecommendedbyASUS*"
+Remove-App "fingertappsasus.FingertappsOrganizerrecommendedbyA*"
+Remove-App "flaregamesGmbH.RoyalRevolt2*"
+Remove-App "king.com*"
+Remove-App "king.com.BubbleWitch3Saga"
+Remove-App "king.com.CandyCrushSaga"
+Remove-App "king.com.CandyCrushSodaSaga"
+Remove-App "king.com.ParadiseBay"
+Remove-App "sMedioforHP.sMedio360*"
+Remove-App "sMedioforToshiba.TOSHIBAMediaPlayerbysMedioTrueLin*"
+Remove-App "toolbar*"
+Remove-App "zuukaInc.iStoryTimeLibrary*"
+
+
+# Inactive identifers
+#Remove-App "Netflix*"
+#Remove-App "4DF9E0F8.Netflix"
+
+##########
+# Finish #
+##########
+# DO NOT REMOVE OR CHANGE (needs to be at end of script)
+# Waits for Apps to be removed before script closes
+Write-Output 'Finishing app removal, please wait...'
+Wait-Job -Name "TronScriptMS*" | Out-Null
+Remove-Job -Name "TronScriptMS*" | Out-Null
\ No newline at end of file
diff --git a/set-high-performance-power-plan.ps1 b/set-high-performance-power-plan.ps1
new file mode 100644
index 0000000..65dbf6e
--- /dev/null
+++ b/set-high-performance-power-plan.ps1
@@ -0,0 +1,127 @@
+# By mseng3
+
+function dumpError($error) {
+	Write-Output " "
+	
+	Write-Output "Error: $error"
+	Write-Output " "
+	
+	$_.PSObject.Properties | ForEach-Object {
+		Write-Output "$($error.Name):"
+		Write-Output "$($error.Value):"
+		Write-Output " "
+	}
+}
+
+# Regex string for pulling out power plan GUID
+$guidRegex = '([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})'
+
+# Get current power plan GUID
+$currPlan = powercfg -getactivescheme
+Write-Output "`$currPlan: `"$currPlan`""
+$currPlanGUID = ($currPlan -split $guidRegex)[1]
+Write-Output "`$currPlanGUID: `"$currPlanGUID`""
+
+# Determine if the high performance power plan exists
+# Necessary because it was removed from laptops around 1709 in favor of some performance slider bullshit
+Write-Output "Checking if high performance plan exists..."
+
+# Get list of power plans
+$plans = powercfg -l
+Write-Output "Performance plans:"
+Write-Output $plans
+Write-Output " "
+
+$highPlanGUID = 'none'
+Write-Output "Looping through performance plans..."
+foreach($plan in $plans) {
+	Write-Output "Checking plan: `"$plan`""
+	if($plan.contains("High performance")) {
+		Write-Output "Plan contains `"High performance`"."
+		$highPlan = $plan
+		Write-Output "`$highPlan: `"$highPlan`""
+		$highPlanGUID = ($highPlan -split $guidRegex)[1]
+		Write-Output "`$highPlanGUID: `"$highPlanGUID`""
+		break
+	}
+	else {
+		Write-Output "Plan does not contain `"High performance`"."
+	}
+}
+
+# If the high performance plan exists, use it
+if($highPlanGUID -ne 'none') {
+	Write-Output "High performance plan exists."
+	
+	Write-Output "Testing if current plan is high performance plan..."
+	if ($currPlanGUID -ne $highPlanGUID) {
+		Write-Output "Current plan is NOT high performance plan."
+		
+		Write-Output "Setting current plan to high performance plan with `"powercfg -setactive $highPlanGUID`"..."
+		Try {
+			powercfg -setactive $highPlanGUID
+			Write-Output "Done."
+		}
+		Catch {
+			Write-Output "Unable to set current plan to high performance plan."
+			dumpError $_
+		}
+	}
+	else {
+		Write-Output "Current plan is already high performance plan."
+	}
+}
+# Otherwise, just change the sleep settings to "Never"
+else {
+	Write-Output "High performance plan does not exist."
+	Write-Output "Setting sleep settings of current plan to `"Never`""
+	# Plugged in
+	Try {
+		powercfg -change -standby-timeout-ac 0
+		Write-Output "Done."
+	}
+	Catch {
+		Write-Output "Unable to change plugged in sleep setting."
+		dumpError $_
+	}
+	# On battery
+	Try {
+		powercfg -change -standby-timeout-dc 0
+		Write-Output "Done."
+	}
+	Catch {
+		Write-Output "Unable to change battery sleep setting."
+		dumpError $_
+	}
+	
+	# Also change the "close lid" action to none
+	# https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/powercfg-command-line-options#option_setacvalueindex
+	# powercfg  /setacvalueindex  scheme_GUID  sub_GUID  setting_GUID  setting_index
+	Write-Output "Setting `"close lid`" actions of current plan to `"None`""
+	
+	# Plugged in
+	Try {
+		powercfg -setacvalueindex SCHEME_CURRENT SUB_BUTTONS LIDACTION 0
+		Write-Output "Done."
+	}
+	Catch {
+		Write-Output "Unable to change plugged in lid close action."
+		dumpError $_
+	}
+	
+	# On battery
+	<#
+	Try {
+		powercfg -setdcvalueindex SCHEME_CURRENT SUB_BUTTONS LIDACTION 0
+		Write-Output "Done."
+	}
+	Catch {
+		Write-Output "Unable to change battery lid close action."
+		dumpError $_
+	}
+	#>
+}
+
+Write-Output "EOF"
+
+
-- 
GitLab