Bloatware Cleanup Script
article #1613, updated 27 days ago

This one is set up to remove many different bloatware items found on machines from HP, Dell, and Lenovo. A work in progress. Uses both APPX methods and winget.

#Begin Script

# Set up to run winget if needed...
"Set up to run Winget if needed..."

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Function to find the path to winget.exe
function Find-WinGet-Path {
    # Get the WinGet path (for use when running in SYSTEM context).
    $WinGetPathToResolve = Join-Path -Path $ENV:ProgramFiles -ChildPath 'WindowsApps\Microsoft.DesktopAppInstaller_*_*__8wekyb3d8bbwe'
    $ResolveWinGetPath = Resolve-Path -Path $WinGetPathToResolve | Sort-Object {
        [version]($_.Path -replace '^[^\d]+_((\d+\.)*\d+)_.*', '$1')
    }
    if ($ResolveWinGetPath) {
        # If we have multiple versions - use the latest.
        $WinGetPath = $ResolveWinGetPath[-1].Path
    }

    # Get the User-Context WinGet exe location.
    $WinGetExePath = Get-Command -Name winget.exe -CommandType Application -ErrorAction SilentlyContinue

    # Select the correct WinGet exe
    if (Test-Path -Path (Join-Path $WinGetPath 'winget.exe')) {
        # Running in SYSTEM-Context.
        $WinGet = Join-Path $WinGetPath 'winget.exe'
    } elseif ($WinGetExePath) {
        # Get User-Context if SYSTEM-Context not found.
        $WinGet = $WinGetExePath.Path
    } else {
        Write-Output 'WinGet not Found!'
        Stop-Transcript
        exit 1
    }

    # Return WinGet path
    return ($WinGet -replace '\winget.exe','')
}

Function Add-PathVariable {
    param (
        [string]$addPath
    )
    if (Test-Path $addPath){
        $regexAddPath = [regex]::Escape($addPath)
        $arrPath = $env:Path -split ';' | Where-Object {$_ -notMatch 
"^$regexAddPath\\?"}
        $env:Path = ($arrPath + $addPath) -join ';'
    } else {
        Throw "'$addPath' is not a valid path."
    }
}

Add-PathVariable (Find-Winget-Path)

# Do APPX removals...
"Do APPX removals..."

# First set up item list
$RemovalItems =  @(
"Microsoft.Advertising.Xaml",
"Microsoft.BingWeather",
"Microsoft.BingFinance",
"Microsoft.BingNews",
"Microsoft.BingSports",
"Microsoft.SkypeApp",
"Microsoft.Teams.Classic",
"Microsoft.WindowsCommunicationsApps",
"Microsoft.XboxGameOverlay",
"Microsoft.XboxGamingOverlay",
"Microsoft.XboxGameCallableUI",
"Microsoft.Xbox.TCUI",
"Microsoft.XboxApp",
"Microsoft.XboxSpeechToTextOverlay",
"Microsoft.XboxIdentityProvider",
"Microsoft.YourPhone",
"Microsoft.ZuneVideo",
"Microsoft.ZuneMusic",
"MicrosoftTeams",
".DellDigitalDelivery",
".DellSupportAssistforPCs",
".DellUpdate",
".Power2GoforDell",
".PowerDirectorforDell",
".DellDigitalDelivery",
".DellWatchgdogTimer",
".DelltypeCStatus",
".DiscoverHPTouchpointManager",
".HPDesktopSupportUtilities",
".HPEasyClean",
".HPJumpStart",
".HPPCHardwareDiagnosticsWindows",
".HPPowerManage",
".HPPrivacySettings",
".HPProgrammableKey",
".HPQuickDrop",
".myHP",
".HPSupportAssistant",
".HPSystemInformation",
".HPWorkWell",
".HPAccessoryCenter"
)

$ProvisionedItems = Get-AppxProvisionedPackage -Online
foreach ($ProvItem in $ProvisionedItems) {
	foreach ($RemItem in $RemovalItems) {
		If ($ProvItem.DisplayName -like "*$RemItem*") {
			Write-Host "Deprovisioning:" $ProvItem.DisplayName
			$error.clear()
			try {
				Remove-AppXProvisionedPackage -Online -PackageName $ProvItem.PackageName -ErrorAction SilentlyContinue | Out-Null
			}
			catch { "Failed: Microsoft does not allow, or other error." }
			if (!$error) { "Succeeded!" }
		}
	}
}

$InstalledItems = Get-AppxPackage -AllUsers
foreach ($InstItem in $InstalledItems) {
	foreach ($RemItem in $RemovalItems) {
		if ($InstItem.Name -like "*$RemItem*") {
			Write-Host "User-level removal operation:" $InstItem.Name
			$error.clear()
			try {
				Get-AppxPackage $InstItem.Name -AllUsers | Remove-AppxPackage -Allusers -ErrorAction SilentlyContinue | Out-Null
			}
			catch { "Failed: Microsoft does not allow, or other error." }
			if (!$error) { "Succeeded!" }
		}
	}
}

# And now do winget removals...
"And now do winget removals..."

# HP bloatware
Winget Uninstall "HP Client Security Manager" --accept-source-agreements --silent
Winget Uninstall "HP Connection Optimizer" --accept-source-agreements --silent
Winget Uninstall "HP Desktop Support Utilities" --accept-source-agreements --silent
Winget Uninstall "HP Documentation" --accept-source-agreements --silent
Winget Uninstall "HP Easy Clean" --accept-source-agreements --silent
Winget Uninstall "HP Insights" --accept-source-agreements --silent
Winget Uninstall "HP Insights Analytics" --accept-source-agreements --silent
Winget Uninstall "HP JumpStart Bridge" --accept-source-agreements --silent
Winget Uninstall "HP JumpStart Launch" --accept-source-agreements --silent
Winget Uninstall "HP Notifications" --accept-source-agreements --silent
Winget Uninstall "HP One Agent" --accept-source-agreements --silent
Winget Uninstall "HP PC Hardware Diagnostics Windows" --accept-source-agreements --silent
Winget Uninstall "HP Performance Advisor" --accept-source-agreements --silent
Winget Uninstall "HP PhoneWise Driver" --accept-source-agreements --silent
Winget Uninstall "HP Privacy Settings" --accept-source-agreements --silent
Winget Uninstall "HP Quickdrop" --accept-source-agreements --silent
Winget Uninstall "HP Security Update Service" --accept-source-agreements --silent
Winget Uninstall "HP Sure Recover" --accept-source-agreements --silent
Winget Uninstall "HP Sure Run Module" --accept-source-agreements --silent
Winget Uninstall "HP Wolf Security - Console" --accept-source-agreements --silent
Winget Uninstall "HP System Default Settings" --accept-source-agreements --silent
Winget Uninstall "HP Velocity" --accept-source-agreements --silent
Winget Uninstall "HP WorkWise Service" --accept-source-agreements --silent
Winget Uninstall "myHP" --accept-source-agreements --silent

# Windows Bloatware
Winget Uninstall "MSN Weather" --accept-source-agreements --silent
Winget Uninstall "Get Help" --accept-source-agreements --silent
Winget Uninstall "Microsoft Tips" --accept-source-agreements --silent
Winget Uninstall "Microsoft 365 (office)" --accept-source-agreements --silent
Winget Uninstall "Solitaire & Casual Games" --accept-source-agreements --silent
Winget Uninstall "Mixed Reality Portal" --accept-source-agreements --silent
Winget Uninstall "Microsoft People" --accept-source-agreements --silent
Winget Uninstall "Store Experience Host" --accept-source-agreements --silent
Winget Uninstall "Xbox TCUI" --accept-source-agreements --silent
Winget Uninstall "Xbox Console Companion" --accept-source-agreements --silent
Winget Uninstall "Xbox Game Bar Plugin" --accept-source-agreements --silent
Winget Uninstall "Xbox Game Bar" --accept-source-agreements --silent
Winget Uninstall "Xbox Identity Provider" --accept-source-agreements --silent
Winget Uninstall "Xbox Game Speech Window" --accept-source-agreements --silent
Winget Uninstall "Groove Music" --accept-source-agreements --silent
Winget Uninstall "Movies & TV" --accept-source-agreements --silent
Winget Uninstall Microsoft.Teams.Classic --accept-source-agreements --silent
Winget Uninstall MicrosoftTeams --accept-source-agreements --silent
Winget Uninstall "Microsoft Whiteboard" --accept-source-agreements --silent
Winget Uninstall "Your Phone" --accept-source-agreements --silent
Winget Uninstall "Groove Music" --accept-source-agreements --silent

# Additionals
Winget Uninstall "Partner Promo" --accept-source-agreements --silent
Winget Uninstall "Translator" --accept-source-agreements --silent
Winget Uninstall "Microsoft Solitaire Collection" --accept-source-agreements --silent
Winget Uninstall "Microsoft People" --accept-source-agreements --silent
Winget Uninstall "Skype" --accept-source-agreements --silent
Winget Uninstall "Microsoft Pay" --accept-source-agreements --silent
Winget Uninstall "Xbox" --accept-source-agreements --silent
Winget Uninstall "Microsoft 365 - es-es" --accept-source-agreements --silent
Winget Uninstall "Microsoft 365 - fr-fr" --accept-source-agreements --silent
Winget Uninstall "Waves MaxxAudio Pro For Dell 2022" --accept-source-agreements --silent
Winget Uninstall "Mail and Calendar" --accept-source-agreements --silent
Winget Uninstall "Media Suite Essentials for Dell" --accept-source-agreements --silent
Winget Uninstall "Power2Go for Dell" --accept-source-agreements --silent
Winget Uninstall "PowerDirector for Dell" --accept-source-agreements --silent
Winget Uninstall "Power Media Player For Dell" --accept-source-agreements --silent
Winget Uninstall "Dell Watchdog Timer" --accept-source-agreements --silent
Winget Uninstall "Dell SupportAssist Remediation" --accept-source-agreements --silent
Winget Uninstall "Dell SupportAssist OS Recovery Plugin for Dell Update" --accept-source-agreements --silent
Winget Uninstall "Dell SupportAssist OS Recovery Plugin" --accept-source-agreements --silent
Winget Uninstall "Dell SupportAssist" --accept-source-agreements --silent
Winget Uninstall "Dell Command | Update for Windows 10" --accept-source-agreements --silent
Winget Uninstall "Dell Digital Delivery Services" --accept-source-agreements --silent

# More HP, best last
Winget Uninstall "HP Easy Clean" --accept-source-agreements --silent
Winget Uninstall "myHP" --accept-source-agreements --silent
Winget Uninstall "HP Sure Recover" --accept-source-agreements --silent
Winget Uninstall "HP Sure Run Module" --accept-source-agreements --silent
Winget Uninstall "HP Performance Advisor" --accept-source-agreements --silent
winget Uninstall "HP One Agent" --accept-source-agreements --silent
winget Uninstall "HP Security Update Service" --accept-source-agreements --silent
winget Uninstall "HP Client Security Manager" --accept-source-agreements --silent

# End script

Categories:      

==============

Use All Available CPU Power in Current Windows!
article #1418, updated 57 days ago

Something relatively new. Very interesting changes from some Microsoft documentation, searchable here. Performance improvements have been visible in general behavior of all machines tested for this so far. On some, reported CPU speed does still change over time. BIOS changes are likely to assist as well.

The lines below work in administrative Powershell. It creates a new power scheme called “Maximum Performance”, based on the hidden built-in “Ultimate Performance” if it exists on your system. To revert, just go into Power in the Control Panel and reselect your original power scheme.

# Begin script
powercfg -duplicatescheme e9a42b02-d5df-448d-aa00-03f14749eb61

$oldpower = powercfg -getactivescheme
"Creating power scheme:  Maximum Performance"

$newpower = powercfg -duplicatescheme scheme_current
$newpower = ($newpower[19..54] -join "")
powercfg -changename $newpower "Maximum Performance"
powercfg -setactive $newpower

# Makes maximum CPU speeds available, by default they're not
powercfg -setacvalueindex scheme_current sub_processor PERFBOOSTMODE 2
powercfg -setacvalueindex scheme_current sub_processor PERFBOOSTMODE1 2
powercfg -setacvalueindex scheme_current sub_processor PERFINCTHRESHOLD 0
powercfg -setacvalueindex scheme_current sub_processor PERFINCTHRESHOLD1 0
powercfg -setacvalueindex scheme_current sub_processor PERFINCTIME 0
powercfg -setacvalueindex scheme_current sub_processor PERFINCTIME1 0
powercfg -setacvalueindex scheme_current sub_processor PERFDECTHRESHOLD 100
powercfg -setacvalueindex scheme_current sub_processor PERFDECTHRESHOLD1 100
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTPERF 0
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTPERF1 0
powercfg -setacvalueindex scheme_current sub_processor PERFAUTONOMOUS 0
powercfg -setacvalueindex scheme_current sub_processor PERFDUTYCYCLING 0

# Sets overall throttles to maximum
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMAX 100
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMAX1 100
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMIN 100
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMIN1 100
powercfg -setacvalueindex scheme_current sub_processor HETEROCLASS1INITIALPERF 100
powercfg -setacvalueindex scheme_current sub_processor HETEROCLASS0FLOORPERF 100

# Turns off CPU core controls, tells OS to just use them all.
powercfg -setacvalueindex scheme_current sub_processor CPMAXCORES 100
powercfg -setacvalueindex scheme_current sub_processor CPMINCORES 100
powercfg -setacvalueindex scheme_current sub_processor DISTRIBUTEUTIL 0
powercfg -setacvalueindex scheme_current sub_processor CPDISTRIBUTION 0

# Minimizes CPU spinup time, and maximizes spindown time, just in case
powercfg -setacvalueindex scheme_current sub_processor CPINCREASETIME 0
powercfg -setacvalueindex scheme_current sub_processor CPDECREASETIME 100
powercfg -setacvalueindex scheme_current sub_processor CPHEADROOM 0
powercfg -setacvalueindex scheme_current sub_processor CPCONCURRENCY 0
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTUNPARK 0
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTUNPARK1 0

# Sets energy savings preference to zero
powercfg -setacvalueindex scheme_current sub_processor PERFEPP 0

# Commits all above changes to current power plan
powercfg -setactive scheme_current
# End script

Some detail can be had here and here.

These changes are disrecommended for cooling-poor laptops. And one might want to watch the temperatures of poorly built desktops and even some poorly built servers, too.

A version of the above which alters the original power scheme, and runs in administrative CMD, is below. The below is not very easily reversible. It does not use the “Ultimate Performance” builtin.

# Begin script
REM Makes maximum CPU speeds available, by default they're not
powercfg -setacvalueindex scheme_current sub_processor PERFBOOSTMODE 2
powercfg -setacvalueindex scheme_current sub_processor PERFBOOSTMODE1 2
powercfg -setacvalueindex scheme_current sub_processor PERFINCTHRESHOLD 0
powercfg -setacvalueindex scheme_current sub_processor PERFINCTHRESHOLD1 0
powercfg -setacvalueindex scheme_current sub_processor PERFINCTIME 0
powercfg -setacvalueindex scheme_current sub_processor PERFINCTIME1 0
powercfg -setacvalueindex scheme_current sub_processor PERFDECTHRESHOLD 100
powercfg -setacvalueindex scheme_current sub_processor PERFDECTHRESHOLD1 100
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTPERF 0
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTPERF1 0
powercfg -setacvalueindex scheme_current sub_processor PERFAUTONOMOUS 0
powercfg -setacvalueindex scheme_current sub_processor PERFDUTYCYCLING 0

REM Sets overall throttles to maximum
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMAX 100
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMAX1 100
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMIN 100
powercfg -setacvalueindex scheme_current sub_processor PROCTHROTTLEMIN1 100
powercfg -setacvalueindex scheme_current sub_processor HETEROCLASS1INITIALPERF 100
powercfg -setacvalueindex scheme_current sub_processor HETEROCLASS0FLOORPERF 100

REM Turns off CPU core controls, tells OS to just use them all.
powercfg -setacvalueindex scheme_current sub_processor CPMAXCORES 100
powercfg -setacvalueindex scheme_current sub_processor CPMINCORES 100
powercfg -setacvalueindex scheme_current sub_processor DISTRIBUTEUTIL 0
powercfg -setacvalueindex scheme_current sub_processor CPDISTRIBUTION 0

REM Minimizes CPU spinup time, and maximizes spindown time, just in case
powercfg -setacvalueindex scheme_current sub_processor CPINCREASETIME 0
powercfg -setacvalueindex scheme_current sub_processor CPDECREASETIME 100
powercfg -setacvalueindex scheme_current sub_processor CPHEADROOM 0
powercfg -setacvalueindex scheme_current sub_processor CPCONCURRENCY 0
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTUNPARK 0
powercfg -setacvalueindex scheme_current sub_processor LATENCYHINTUNPARK1 0

REM Sets energy savings preference to zero
powercfg -setacvalueindex scheme_current sub_processor PERFEPP 0

REM Commits all above changes to current power plan
powercfg -setactive scheme_current
# End script

Categories:      

==============

winget: new Windows package management
article #1504, updated 78 days ago

It’s built into most OEM installs of Windows 10 and 11, and can often be installed. On server builds it’s touch and go.

To see if you have it, try winget list from CMD or Powershell.

One good way to test it, is to install Microsoft .NET framework (SDK) 6, thus, from administrative Powershell:

winget install --id Microsoft.DotNet.Runtime.6 --silent --accept-source-agreements

I learned just now that if you add other seemingly valuable options to the one above, e.g., --scope machine, at least while running as SYSTEM, it will fail citing package not found. So you’ll want to test carefully.

Here’s one proven just now for 7zip (there’s a “search” option in winget to get the ID):

winget install --exact --id 7zip.7zip --accept-package-agreements --silent --scope machine

Here’s one for Google Chrome, needs a bit of extra:

winget.exe install --exact --id Google.Chrome --silent --accept-package-agreements --accept-source-agreements --scope machine

And here’s a way to upgrade everything Winget can upgrade. There are some systems to not use this on, e.g., anything with some Autodesk products:

winget upgrade --all --include-unknown

If you do want to use it from the SYSTEM account, in scripting, it gets interesting. You’ll want to first run the below, and then winget will run as expected.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Function to find the path to winget.exe
function Find-WinGet-Path {
    # Get the WinGet path (for use when running in SYSTEM context).
    $WinGetPathToResolve = Join-Path -Path $ENV:ProgramFiles -ChildPath 'WindowsApps\Microsoft.DesktopAppInstaller_*_*__8wekyb3d8bbwe'
    $ResolveWinGetPath = Resolve-Path -Path $WinGetPathToResolve | Sort-Object {
        [version]($_.Path -replace '^[^\d]+_((\d+\.)*\d+)_.*', '$1')
    }
    if ($ResolveWinGetPath) {
        # If we have multiple versions - use the latest.
        $WinGetPath = $ResolveWinGetPath[-1].Path
    }

    # Get the User-Context WinGet exe location.
    $WinGetExePath = Get-Command -Name winget.exe -CommandType Application -ErrorAction SilentlyContinue

    # Select the correct WinGet exe
    if (Test-Path -Path (Join-Path $WinGetPath 'winget.exe')) {
        # Running in SYSTEM-Context.
        $WinGet = Join-Path $WinGetPath 'winget.exe'
    } elseif ($WinGetExePath) {
        # Get User-Context if SYSTEM-Context not found.
        $WinGet = $WinGetExePath.Path
    } else {
        Write-Output 'WinGet not Found!'
        Stop-Transcript
        exit 1
    }

    # Return WinGet path
    return ($WinGet -replace '\winget.exe','')
}

Function Add-PathVariable {
    param (
        [string]$addPath
    )
    if (Test-Path $addPath){
        $regexAddPath = [regex]::Escape($addPath)
        $arrPath = $env:Path -split ';' | Where-Object {$_ -notMatch 
"^$regexAddPath\\?"}
        $env:Path = ($arrPath + $addPath) -join ';'
    } else {
        Throw "'$addPath' is not a valid path."
    }
}

Add-PathVariable (Find-Winget-Path)

Installing has been even more interesting. I’ve tried a lot of things. The below worked very well recently on Server 2019 as well as Server 2022. Sometimes it fails once and has to be re-run. It is a script which installs prerequisites, and installs another script called winget-install. After the installations, it will run winget-install. Once successful, winget runs.

#begin script

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force > $null

Function PrepareModule {
	param( [string]$ModuleName )

	"Preparing Powershell environment: Getting online " + $ModuleName + " info..."
	$OnlineModuleInfo = Find-Module $ModuleName -Repository PSGallery
	"Preparing Powershell environment: Getting local " + $ModuleName + " info (if exists)..."
	$LocalModuleInfo = Get-InstalledModule $ModuleName -ErrorAction SilentlyContinue > $null

	If ($OnlineModuleInfo.Version -ne $LocalModuleInfo.Version) {
		"Preparing Powershell environment: Removing old " + $ModuleName + " (if exists)..."
		Uninstall-Module -Name $ModuleName -ErrorAction SilentlyContinue > $null
		"Preparing Powershell environment: Installing new " + $ModuleName + "..."
		Install-Module -Name $ModuleName -Repository PSGallery
		"Preparing Powershell environment: Importing new " + $ModuleName + "..."
		Import-Module -Name $ModuleName
		}
}

"Setting up to use Powershell Gallery..."
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module PowerShellGet -Force
Set-PSRepository -InstallationPolicy Trusted -Name PSGallery

PrepareModule("NuGet")	

Install-Script -Name winget-install 
winget-install

#End script

Categories:      

==============

"Optimize", multifaceted cleanup and speedup tool for Windows
article #1590, updated 85 days ago

The Powershell below, calls all of the tools listed for it here.

#begin script

if (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
    {
    "Running elevated; good."
    ""
    } else {
    "Not running as elevated.  Starting elevated shell."
    Start-Process powershell -WorkingDirectory $PWD.Path -Verb runAs -ArgumentList "-noprofile -noexit -file $PSCommandPath"
    return "Done. This one will now exit."
    ""
    }

Set-ExecutionPolicy Bypass -Scope Process -Force

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12;

$dfolder = "C:\OptimizeTemp"

$ps_script_list = @(
    'mma-appx-etc.ps1',
    'RunDevNodeClean.ps1',
    'wt_removeGhosts.ps1',
    'TweakDrives.ps1',
	'TweakSMB.ps1',
    'OWTAS.ps1',
    'OVSS.ps1',
    'CATE.ps1',
	'TweakHardware.ps1'
    'TweakMemTCP.ps1'
    )

mkdir $dfolder

"Downloading..."

ForEach ($ps_script in $ps_script_list) {
	$download_url = "https://github.com/jebofponderworthy/windows-tools/raw/master/tools/$ps_script"

	""
	"--- Downloading $ps_script... ---"
	Invoke-WebRequest -Uri $download_url -Outfile "$dfolder\$ps_script"
	}

""
"Running..."

ForEach ($ps_script in $ps_script_list) {
	$run_script = "$dfolder\$ps_script"
	& $run_script

	Remove-Item "$dfolder\$ps_script"
	}	

Remove-Item $dfolder -Recurse -Force

#end of script

Categories:      

==============

Update Windows via Powershell
article #1479, updated 104 days ago

This method uses Powershell module PsWindowsUpdate.

First, a complete script which gets the module in and updates everything available from Microsoft, including patches and drivers and firmware:

#begin script
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-Executionpolicy RemoteSigned -Scope Process -Force
Install-PackageProvider -Name NuGet -Force -ErrorAction 'SilentlyContinue' > $null
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
If (Get-InstalledModule -Name PsWindowsUpdate -ErrorAction 'SilentlyContinue') {
	Update-Module -Name PSWindowsUpdate -Force
} Else {
	Install-Module -Name PSWindowsUpdate -Force
}
Import-Module PSWindowsUpdate
Install-WindowsUpdate -AcceptAll -AutoReboot
# end script

Next, the bits. We do need to install and keep up a module.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-Executionpolicy RemoteSigned -Scope Process -Force
Install-PackageProvider -Name NuGet -Force -ErrorAction 'SilentlyContinue' > $null
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
If (Get-InstalledModule -Name PsWindowsUpdate -ErrorAction 'SilentlyContinue') {
	Update-Module -Name PSWindowsUpdate -Force
} Else {
	Install-Module -Name PSWindowsUpdate -Force
}
Import-Module PSWindowsUpdate

Then we can check the list of available updates:

Get-WindowsUpdate

And then we probably want to actually do updates. There are good reasons and multiple methods to be careful. Alas, thus far, there does not appear to be a way to install updates a given number of days after release, e.g., 30, so as to give Microsoft time to respond to issues. Here is a glancing overview of what we do have:

  • Lots of firmware is being sent by Microsoft now, and some of this is more up-to-date than that available from the vendors. But there is risk in these, don’t forget. You may find that you want to install current Windows patches, but no drivers, firmware, services packs, feature packs, etc. To do this:
Install-WindowsUpdate -NotCategory "Drivers","Service Packs","FeaturePacks" -NotTitle "preview" -AcceptAll 

And to do it while ignoring reboot:

Install-WindowsUpdate -NotCategory "Drivers","Service Packs","FeaturePacks" -NotTitle "preview" -AcceptAll -IgnoreReboot

The -IgnoreReboot ignores all relevant reboot automata. -NotTitle "preview" omits all updates with the word “preview” in their name.

But sometimes, e.g. with a new PC install, we’ll want to install all updates and reboot automatically:

Install-WindowsUpdate -AcceptAll -AutoReboot
  • You may find that you want to omit granularly, e.g., specific build upgrades. If you found one marked KB1234567, you would install all and omit that one thus:
Install-WindowsUpdate -NotKBArticleID KB1234567 -AcceptAll
  • If you wanted to do that, and explicitly not reboot if indicated:
Install-WindowsUpdate -NotKBArticleID KB1234567 -AcceptAll -IgnoreReboot
  • If you had two KBs to omit:
Install-WindowsUpdate -AcceptAll -NotKBArticleID "KB1234567,KB7654321"
  • There are other noteworthy items. Lots of firmware is being sent by Microsoft now, and some of this is more up-to-date than that available from the vendor. But there is risk in firmware updates, don’t forget. Some of the items don’t have KBs, and there are two other command-line arguments to omit those, -NotTitle and -NotUpdateID.
  • And then there’s:
Reset-WUComponents
  • To get a full list of functions:
Get-Command -Module PSWindowsUpdate

Get-Help works for all of them.

Categories:      

==============

USN journal in NTFS: delete and recreate for performance gains
article #1483, updated 298 days ago

The journal can get huge over time, slowing machines down a lot. Here’s how to delete it and recreate it for C:, in CMD. The process can cause interference and conflict with Windows internals and applications, though I have not seen this happen so far. On a machine that has been in use a while, it can help a whole lot.

fsutil usn deletejournal /n C: & fsutil usn createjournal C:

Here are quick pastes for D: and E:.

fsutil usn deletejournal /n D: & fsutil usn createjournal D:
fsutil usn deletejournal /n E: & fsutil usn createjournal E:

In 2012R2/8.1 and before, we must be more specific in the creation:

fsutil usn deletejournal /n C: & fsutil usn createjournal m=1000 a=100 C:
fsutil usn deletejournal /n D: & fsutil usn createjournal m=1000 a=100 D:
fsutil usn deletejournal /n E: & fsutil usn createjournal m=1000 a=100 E:

And here’s Powershell, to do it all for every drive letter in the system:

########################################
# Delete and Recreate NTFS USN Journal #
########################################

# This script iterates through all lettered NTFS drives in Windows, 
# and deletes and recreates the USN Journal of each one.
# Considerable performance gain results if the image has been running
# for a year or more.

# There are slightly different commands between some OS versions.
$OSVer = [System.Environment]::OSVersion.Version
If ($OSVer.Major -gt 10)
{
	"OS > 10. Create uses short command."
	$ShortCommand = $True
} ElseIf ($OSVer.Major -eq 10) {
	If ($OSVer.Build -le 14393)	{
		("OS is 10 build " + $OSVer.Build + ". " + "Create uses long command.")
		$ShortCommand = $False
	}
	Else {
		"OS is 10, build > 14393. Create uses short command."
		$ShortCommand = $True
	}
} ElseIf ($OSVer.Major -lt 10) {
	"OS < 10. Create uses long command."
	$ShortCommand = $False
}	

Get-CimInstance -Query "Select * FROM Win32_LogicalDisk WHERE DriveType=3" | ForEach-Object {
	$DriveID = $_.DeviceID

	If ($DriveID -match "[A-Z]")
	{
		"Deleting USN Journal on " + $DriveID + " ..."
		fsutil usn deletejournal /n $DriveID

		"Recreating USN Journal on " + $DriveID + " ..."
		if ($ShortCommand) {
			fsutil usn createjournal $DriveID
		}
		else {
			fsutil usn createjournal m=1000 a=100 $DriveID
		}
	}
}
# End Script

Reference:

docs.microsoft.com/en-us/windows-server/administration/windows-commands/fsutil-usn

Categories:      

==============

"GetRedists", update/install all Microsoft redistributable libraries
article #1591, updated 349 days ago

The Powershell below, updates/installs all Microsoft redistributable libraries. The general repository is here.

<#PSScriptInfo

.VERSION 4.2

.GUID 03c695c0-bf45-4257-8156-89310e951140

.AUTHOR Jonathan E. Brickman

.COMPANYNAME Ponderworthy Music

.COPYRIGHT (c) 2024 Jonathan E. Brickman

.TAGS

.LICENSEURI https://opensource.org/licenses/BSD-3-Clause

.PROJECTURI https://github.com/jebofponderworthy/windows-tools

.ICONURI

.EXTERNALMODULEDEPENDENCIES 

.REQUIREDSCRIPTS

.EXTERNALSCRIPTDEPENDENCIES

.RELEASENOTES
GetRedists
Retrieve, and install/update, all missing VC++ redistributable libraries
currently being supported by Microsoft, using the excellent
VcRedist module.

.PRIVATEDATA

#> 

<#

.DESCRIPTION 
GetRedists - Get all current Microsoft VC++ redistributables

#>

Param()


#######################################################################
# GetRedists                                                          #
# v5.0                                                                #
#######################################################################

#
# by Jonathan E. Brickman
#
# Retrieves and installs all of the Microsoft redistributable libraries
# currently being supported, using the excellent VcRedist package.
#
# Copyright 2024 Jonathan E. Brickman
# https://notes.ponderworthy.com/
# This script is licensed under the 3-Clause BSD License
# https://opensource.org/licenses/BSD-3-Clause
# and is reprised at the end of this file
#
# GetRedists is entirely dependent upon VcRedist:
# https://docs.stealthpuppy.com/vcredist/function-syntax/get-vclist
# for which profound gratitude is!!!
#
#

""
""
"****************"
"   GetRedists   "
"****************"
""
""

# Items needing work:
# - Command-line option for location of repo folder
# - Error handling; if errors occur at any stage, terminate and print.

# Self-elevate if not already elevated.
if (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
    {
    "Running elevated; good."
    ""
    } else {
    "Not running as elevated.  Starting elevated shell."
    Start-Process powershell -WorkingDirectory $PWD.Path -Verb runAs -ArgumentList "-noprofile -noexit -file $PSCommandPath"
    return "Done. This one will now exit."
    ""
    }

# Sets TLS version.  Necessary for some situations.
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12

$reportStatus = ''
$currentOp = ''
function ShowProgress {
	param( [string]$reportStatus, [string]$currentOp )

	Write-Progress -Activity "Get Microsoft Redistributables" -Status $reportStatus -PercentComplete -1 -CurrentOperation $currentOp
	# Write-Progress is not compatible with some remote shell methods.

}

'Preparing Powershell environment...'

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force > $null

ShowProgress("Preparing Powershell environment...","Setting up to use Powershell Gallery...")

Install-PackageProvider -Name NuGet -Force -ErrorAction 'SilentlyContinue' > $null
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
If (Get-InstalledModule -Name PsWindowsUpdate -ErrorAction 'SilentlyContinue') {
	Update-Module -Name PSWindowsUpdate -Force
} Else {
	Install-Module -Name PSWindowsUpdate -Force
}
Import-Module PSWindowsUpdate

ShowProgress("Preparing Powershell environment...","Checking and preparing module VcRedist...")

# Install or update module VcRedist
If (Get-InstalledModule -Name VcRedist -ErrorAction 'SilentlyContinue') {
	Update-Module -Name VcRedist -Force
} Else {
	Install-Module -Name VcRedist -AllowClobber -Scope CurrentUser -Force
}

# Import VcRedist to this session
Import-Module -Name VcRedist

if ($False -eq (Test-Path C:\VcRedist -PathType Container)) {
	New-Item C:\VcRedist -ItemType Directory | Out-Null 
	}

''

'Getting list of currently installed redistributables...'

ShowProgress("Getting list of currently installed redistributables...","")
$InstalledRedists = Get-InstalledVcRedist

'Getting list of currently available and supported redistributables...'
''

ShowProgress("Getting list of currently available and supported redistributables...","")
$AvailableRedists = Get-VcList

ShowProgress("Checking and installing/upgrading as needed...","")

# Create blank array of redists to install
$RedistsToGet = @()

# Initialize...
$NothingMissing = $True

# Cycle through all available redists
# Using .ProductCode not .Version, .ProductCode will eliminate false downloads
ForEach ($OnlineRedist in $AvailableRedists) {

	'Checking: ' + $OnlineRedist.Name + '...'

	# Cycle through all redists currently installed,
	# checking to see if the available one being checked is there,
	# and if not, add it to the array of those to be installed.

	$IsInstalled = $False

	ForEach ($LocalRedist in $InstalledRedists) {
		If ($OnlineRedist.ProductCode -eq $LocalRedist.ProductCode) {
			'Already installed.'
			""
			$IsInstalled = $True
			break
			}
		}
	If ($IsInstalled -eq $False) {
		'Needed.'
		""
		$RedistsToGet += ,$OnlineRedist
		$NothingMissing = $False
		}
	}

If ($NothingMissing -eq $True)
	{
	"No VC++ redistributables missing."
	""
	Exit
	}

ShowProgress("Retrieving all needed redistributables to repo folder...","")
"Retrieving..."
""
$ListOfDownloads = Get-VcRedist -Verbose -VcList $RedistsToGet -Path C:\VcRedist

ShowProgress("Installing all needed redistributables from repo folder...","")
""
"Installing and reporting current list..."
""
Install-VcRedist -Verbose -VcList $RedistsToGet | ft

# The old brute force get-them-all code
#
# ShowProgress("Retrieving all redistributables to repo folder...","")
# Get-VcList | Get-VcRedist -Verbose -Path C:\VcRedist | Out-Null
# ShowProgress("Installing all redistributables from repo folder...","")
# Get-VcList | Install-VcRedist -Verbose -Path C:\VcRedist | Out-Null

ShowProgress("Removing repo folder...","")
Remove-Item C:\VcRedist -Recurse -Force | Out-Null
ShowProgress("Done!","")

# The 3-Clause BSD License

# SPDX short identifier: BSD-3-Clause

# Note: This license has also been called
# the AYA>A>??sA??.??oNew BSD LicenseAYA>A>??sA??,A? or AYA>A>??sA??.??oModified BSD LicenseAYA>A>??sA??,A?.
# See also the 2-clause BSD License.

# Copyright 2018 Jonathan E. Brickman

# Redistribution and use in source and binary
# forms, with or without modification, are
# permitted provided that the following conditions are met:

# 1. Redistributions of source code must retain the
# above copyright notice, this list of conditions and
# the following disclaimer.

# 2. Redistributions in binary form must reproduce the
# above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or
# other materials provided with the distribution.

# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or
# promote products derived from this software without
# specific prior written permission.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS AYA>A>??sA??.??oAS ISAYA>A>??sA??,A? AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

Categories:      

==============

IP4 subnet calculators
article #79, updated 378 days ago

For CIDR to IP range (IP range extraction):

http://bonomo.info/coyote/cidr-calculator.php

For IP range to CIDR:

http://ip2cidr.com/

IP subnet calculator:

ipcalculator.com

Categories:      

==============

Clear System Volume Information (and Disable Sentinel One)
article #1438, updated 515 days ago

The hidden NTFS “System Volume Information” folders on Windows machines, can build up and up and up in size. I’ve seen instances ranging from 20G to hundreds of gigabytes, and every time this occurs, the overall system slows down, and often slows down a whole lot. SpaceSniffer is my favorite method of identifying this situation, but there are many. The only preventative I have been able to identify so far, is here.

But here we are discussing cleanup. If you have SentinelOne (S1) installed on this machine, you need to know that S1 considers deletion of volume shadows to be very bad actor behavior. This is because it often is a way that cryptolockers and others delete last-known-good checkpoints. S1 will not let you clear SVI, unless you disable it first, and it will complain very loudly if you try. Instructions for disabling S1, are at the end of this article. There may well be other security tools which will behave similarly, and need similar interaction beforehand.

General cleanup steps:

  1. This command usually gets all of them: wmic shadowcopy delete /nointeractive
  2. Very rarely, this will get a few more: vssadmin delete shadows /all
  3. And even more rarely on a server only, the above two don’t get it done, and this is needed:

    diskshadow
    then within diskshadow’s command line: delete shadows all

Any of these can take a while, especially if SVI is big, e.g., more than 20-30 gigabytes. It can get huge occasionally, hundreds of gigabytes. I recently saw 1,022 shadow copies deleted (the first and third methods tell you the count) from one server.

Special case cleanup steps

Special cases do occur. Here are steps which can help a lot.

  • Sometimes the steps above quit in the middle. Start them over again. Often they’ll complete.
  • If the above does not completely solve the situation (if the SVI folder is still huge), do vssadmin resize shadowstorage for the relevant drive(s) (try /? for syntax…), first to 10%, then back to whatever it was. Sometimes Windows will do a lot of steady cleanup for you, sometimes over hours of time. You’ll see it by watching File Explorer.
  • Run CHKDSK /F at reboot. Then start from the beginning :-)

To disable SentinelOne:

  1. First get the Passphrase for the machine, from the S1 console. It’s under Actions, you can choose Show Passphrase. Do be aware that your S1 admin may receive a notice that you have asked for this.
  2. cd "C:\Program Files\SentinelOne\Sentinel*"
  3. Please put the actual passphrase in, and the quotes are necessary:
    .\sentinelctl.exe unload -slam -k "<passphrase>"

Then, and only then, will the cleanup commands above work.

To reenable S1:

  1. .\sentinelctl.exe load -slam

If you should need to reenable S1 and your command prompt is not where you need it, here’s a paste:

cd "C:\Program Files\SentinelOne\Sentinel*"
.\sentinelctl.exe load -slam

Categories:      

==============

Renoberate & Clear Windows Logs
article #1482, updated 886 days ago

Recently it was discovered that a Windows server was running very slow because the Security log’s maximum size was set to 40 gigabytes. Here is a Powershell bit which will look at all event logs, set their max size to 2.5M if set larger, and clear them. Seems to free up a nice healthy dollop of performance in general.

wevtutil el | Foreach-Object {
	$LogObject = Get-WinEvent -ListLog $_
	If ( $LogObject.MaximumSizeInBytes -gt 2500KB ) {
		"$_ has max set to larger than 2.5M.  Setting to 2.5M."
		$LogObject.MaximumSizeInBytes = 2500KB
		$LogObject.SaveChanges()
		}
	wevtutil cl $_
	"$_ cleared."
}

There are times when an operation, a software install or configure perhaps, will error with “Cannot open log for source ———-. You may not have write access.” The below will do the above, and also give read/write to every local admin.

wevtutil el | Foreach-Object {
	wevtutil sl $_ "/ca:O:BAG:SYD:(A;;0x1;;;SY)(A;;0x5;;;BA)(A;;0x1;;;LA)(A;;0x3;;;LA)"
	$LogObject = Get-WinEvent -ListLog $_
	If ( $LogObject.MaximumSizeInBytes -gt 2500KB ) {
		"$_ has max set to larger than 2.5M.  Setting to 2.5M."
		$LogObject.MaximumSizeInBytes = 2500KB
		$LogObject.SaveChanges()
		}
	wevtutil cl $_
	"$_ cleared."
}

The security string is written in something called SDDL. Some more info:

https://itconnect.uw.edu/wares/msinf/other-help/understanding-sddl-syntax/

Categories: