winget: new Windows package management
article #1504, updated 22 hours 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.

# 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 is even more interesting. There is a module in PSGallery called winget-install which works well in console, but not scripting. Below is one that works well in scripting, though it cannot be pasted interactively:

<# Winget-Install.ps1

Source for Some Functions: https://github.com/homotechsual/ninjaget/blob/dev/PS/NinjaGet.Functions.Installation.ps1

2023-11-22 - 0.0.2 - assembled and modified by David Szpunar - Initial version

DOWNLOAD: https://discord.com/channels/676451788395642880/1232432179141808228

2024-04-23 - 0.1.0 - Simplified and Modified by GraphicHealer - Initial Version

DESCRIPTION: Installs or updates WinGet.exe to the latest version. Intended to run as SYSTEM.
        Use '-Force' to ignore version check.
-----
LICENSE: The MIT License (MIT)

Original Copyright 2023 Mikey O'Toole, modified by David Szpunar, Simplified and Modified by GraphicHealer.
#>

# Add -Force switch to force install
param(
    [switch]$Force = $false
)

# Start Logging
Start-Transcript -Path ".\winget-install.log" -IncludeInvocationHeader -Append -Force

# Setup Error Codes
$Script:ExitCode = 0

# Function to get OS Information
function Get-OSInfo {
    try {
        # Get registry values
        $registryValues = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
        $releaseIdValue = $registryValues.ReleaseId
        $displayVersionValue = $registryValues.DisplayVersion
        $nameValue = $registryValues.ProductName
        $editionIdValue = $registryValues.EditionId

        # Strip out "Server" from the $editionIdValue if it exists
        $editionIdValue = $editionIdValue -replace 'Server', ''

        # Get OS details using Get-CimInstance because the registry key for Name is not always correct with Windows 11
        $osDetails = Get-CimInstance -ClassName Win32_OperatingSystem
        $nameValue = $osDetails.Caption

        # Get architecture details of the OS (not the processor)
        # Get only the numbers
        $architecture = ($osDetails.OSArchitecture -replace '[^\d]').Trim()

        # If 32-bit or 64-bit replace with x32 and x64
        if ($architecture -eq '32') {
            $architecture = 'x32'
        } elseif ($architecture -eq '64') {
            $architecture = 'x64'
        }

        # Get OS version details (as version object)
        $versionValue = [System.Environment]::OSVersion.Version

        # Determine product type
        # Reference: https://learn.microsoft.com/en-us/dotnet/api/microsoft.powershell.commands.producttype?view=powershellsdk-1.1.0
        if ($osDetails.ProductType -eq 1) {
            $typeValue = 'Workstation'
        } elseif ($osDetails.ProductType -eq 2 -or $osDetails.ProductType -eq 3) {
            $typeValue = 'Server'
        } else {
            $typeValue = 'Unknown'
        }

        # Extract numerical value from Name
        $numericVersion = ($nameValue -replace '[^\d]').Trim()

        # Create and return custom object with the required properties
        $result = [PSCustomObject]@{
            ReleaseId      = $releaseIdValue
            DisplayVersion = $displayVersionValue
            Name           = $nameValue
            Type           = $typeValue
            NumericVersion = $numericVersion
            EditionId      = $editionIdValue
            Version        = $versionValue
            Architecture   = $architecture
        }

        return $result
    } catch {
        Write-Error "Unable to get OS version details.`nError: $_"
        exit 1
    }
}

# Function to Install WinGet (modified)
function Install-WinGet {
    # Install VCPPRedist Requirements
    $Visual2019 = 'Microsoft Visual C++ 2015-2019 Redistributable*'
    $Visual2022 = 'Microsoft Visual C++ 2015-2022 Redistributable*'
    $VCPPInstalled = Get-Item @('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') | Where-Object {
        $_.GetValue('DisplayName') -like $Visual2019 -or $_.GetValue('DisplayName') -like $Visual2022
    }
    if ([System.Environment]::Is64BitOperatingSystem) {
        $OSArch = 'x64'
    } else {
        $OSArch = 'x86'
    }
    if (!($VCPPInstalled)) {
        Write-Output 'VCPPRedist Requirements Not Installed. Installing...'

        $VCPPRedistURL = ('https://aka.ms/vs/17/release/vc_redist.{0}.exe' -f $OSArch)
        $VCPPRedistFileName = [Uri]$VCPPRedistURL | Select-Object -ExpandProperty Segments | Select-Object -Last 1
        $WebClient = New-Object System.Net.WebClient
        $VCPPRedistDownloadPath = "$ENV:SystemRoot\Temp\VCPRedist"
        if (!(Test-Path -Path $VCPPRedistDownloadPath)) {
            $null = New-Item -Path $VCPPRedistDownloadPath -ItemType Directory -Force
        }
        $VCPPRedistDownloadFile = "$VCPPRedistDownloadPath\$VCPPRedistFileName"
        $WebClient.DownloadFile($VCPPRedistURL, $VCPPRedistDownloadFile)
        try {
            Start-Process -FilePath $VCPPRedistDownloadFile -ArgumentList '/quiet', '/norestart' -Wait -ErrorAction Stop | Out-Null
            Write-Output 'VCPPRedist Requirements Installed.'
        } catch {
            Write-Output 'Failed to install VCPPRedist Requirements!'
            $Script:ExitCode = 1
            return
        } finally {
            Remove-Item -Path $VCPPRedistDownloadPath -Recurse -Force -ErrorAction SilentlyContinue
        }
    } else {
        Write-Output 'VCPPRedist Requirements Installed.'
    }

    # Find Latest Download
    $LatestRelease = (Invoke-RestMethod -Uri 'https://api.github.com/repos/microsoft/winget-cli/releases/latest' -Method Get)
    $LatestAsset = ($LatestRelease).assets | Where-Object { $_.name.EndsWith('.msixbundle') }
    [version]$LatestVersion = $LatestRelease.tag_name.TrimStart('v')
    if ((Find-WinGet)) {
        [version]$CurrentVersion = (& (Find-WinGet) '-v').TrimStart('v')
    } else {
        [version]$CurrentVersion = 0
    }

    # Check if WinGet is Updated
    if (!($CurrentVersion -lt $LatestVersion) -and !$Force) {
        # Exit
        Write-Output 'WinGet is up to date. Exiting.'
        return
    }

    # Installing WinGet
    Write-Output 'WinGet not installed or out of date. Installing/updating...'

    # Download WinGet to Temp
    $WebClient = New-Object System.Net.WebClient
    $WinGetDownloadPath = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath $LatestAsset.name
    Write-Output "Downloading WinGet to $WinGetDownloadPath..."
    $WebClient.DownloadFile($LatestAsset.browser_download_url, $WinGetDownloadPath)

    # Download WinGet Source to Temp
    $WinGetSourceDownloadPath = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath 'source.msix'
    Write-Output "Downloading WinGet to $WinGetSourceDownloadPath..."
    Invoke-WebRequest -Uri 'https://cdn.winget.microsoft.com/cache/source.msix' -OutFile $WinGetSourceDownloadPath

    $WinArch = (Get-OSInfo).Architecture

    # Download VCLibs
    $VCLibs_Path = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath "Microsoft.VCLibs.${WinArch}.14.00.Desktop.appx"
    $VCLibs_Url = "https://aka.ms/Microsoft.VCLibs.${WinArch}.14.00.Desktop.appx"
    Write-Output 'Downloading VCLibs...'
    Write-Debug "Downloading VCLibs from $VCLibs_Url to $VCLibs_Path`n`n"
    Invoke-WebRequest -Uri $VCLibs_Url -OutFile $VCLibs_Path

    # Download UI.Xaml
    $UIXaml_Path = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath "Microsoft.UI.Xaml.2.8.${WinArch}.appx"
    $UIXaml_Url = "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.${WinArch}.appx"
    Write-Output 'Downloading UI.Xaml...'
    Write-Debug "Downloading UI.Xaml from $UIXaml_Url to $UIXaml_Path`n"
    Invoke-WebRequest -Uri $UIXaml_Url -OutFile $UIXaml_Path

    # Install Downloaded WinGet
    try {
        Write-Output 'Installing WinGet...'
        Add-AppxProvisionedPackage -Online -PackagePath $WinGetDownloadPath -DependencyPackagePath $UIXaml_Path, $VCLibs_Path -SkipLicense -ErrorAction Stop
        Add-AppxProvisionedPackage -Online -PackagePath $WinGetSourceDownloadPath -SkipLicense -ErrorAction Stop
        Write-Output 'WinGet installed.'
    } catch {
        Write-Output 'Failed to install WinGet!'
        $Script:ExitCode = 1
    } finally {
        Remove-Item -Path $WinGetDownloadPath -Force -ErrorAction SilentlyContinue
    }

    return
}

# Function to Find the WinGet exe (Modified)
function Find-WinGet {
    # 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 Location
    return $WinGet
}

# Test internet connection
$MaxNet = 15
Write-Output 'Checking Internet Connection...'
for ($i = 0; ($i -lt $MaxNet) -and !$net; $i++) {
    $net = Test-Connection 1.1.1.1 -Count 1 -Delay 1 -Quiet
}
if (!$net) {
    Write-Output 'No Internet Detected. Cancelling Installation.'
    Stop-Transcript
    exit 1
}

Write-Output 'Internet Detected, Continuing Installation.'

# Test OS Compatibility
$osVersion = Get-OSInfo

# If it's a workstation, make sure it is Windows 10+
if ($osVersion.Type -eq 'Workstation' -and $osVersion.NumericVersion -lt 10) {
    Write-Error 'winget requires Windows 10 or later on workstations. Your version of Windows is not supported.'
    Stop-Transcript
    exit 0
}

# If it's a workstation with Windows 10, make sure it's version 1809 or greater
if ($osVersion.Type -eq 'Workstation' -and $osVersion.NumericVersion -eq 10 -and $osVersion.ReleaseId -lt 1809) {
    Write-Error 'winget requires Windows 10 version 1809 or later on workstations. Please update Windows to a compatible version.'
    Stop-Transcript
    exit 0
}

# Run the Install/Update
Install-WinGet

& (Find-WinGet) 'list' '--accept-source-agreements'

Stop-Transcript
exit $Script:ExitCode

Categories:      

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

Fix some crashes in Teams and New Outlook with a component reinstall
article #1607, updated 16 days ago

Try this:

winget install microsoft.edgewebview2runtime --force

Categories:      

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

"Optimize", multifaceted cleanup and speedup tool for Windows
article #1590, updated 33 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;

Import-Module BitsTransfer

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

$wco = (New-Object System.Net.WebClient)

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 ".\$ps_script"

	$run_script = ".\$ps_script"

	& $run_script
	Remove-Item ".\$ps_script"
	}

$wco.Dispose()

#end of script

Categories:      

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

SentinelOne agent removal
article #1509, updated 60 days ago

For a long time the standard was, contact your S1 support and receive a removal tool. The sweeper can still be found, but only old versions among rare people that held onto it, and it does not always work. This works sometimes:

SentinelOneInstaller_windows_64bit_v22_2_4_558.exe --clean_only --dont_preserve_config_dir --dont_preserve_agent_uid -t xyzpdqxyzpdq

You’ll want the latest .exe, not the above version. And if this is not an agent from your own console, in the place of xyzpdqxyzpdq, try “1”, or omit the -t … altogether. Sometimes works outside of safe mode, sometimes works inside.

Categories:      

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

Install winget as Local System (for scripting)
article #1606, updated 71 days ago

This works for recent builds of 10 and 11. Server 2019 sometimes has issues.

<# Winget-Install.ps1

Source for Some Functions: https://github.com/homotechsual/ninjaget/blob/dev/PS/NinjaGet.Functions.Installation.ps1

2023-11-22 - 0.0.2 - assembled and modified by David Szpunar - Initial version

DOWNLOAD: https://discord.com/channels/676451788395642880/1232432179141808228

2024-04-23 - 0.1.0 - Simplified and Modified by GraphicHealer - Initial Version

2024-10-11 - 0.1.1 - took out Ninja RMM item - JEB

DESCRIPTION: Installs or updates WinGet.exe to the latest version. Intended to run as SYSTEM.
        Use '-Force' to ignore version check.
-----
LICENSE: The MIT License (MIT)

Original Copyright 2023 Mikey O'Toole, modified by David Szpunar, Simplified and Modified by GraphicHealer.
#>

# Add -Force switch to force install
param(
    [switch]$Force = $false
)

# Start Logging
Start-Transcript -Path ".\winget-install.log" -IncludeInvocationHeader -Append -Force

# Setup Error Codes
$Script:ExitCode = 0

# Function to get OS Information
function Get-OSInfo {
    try {
        # Get registry values
        $registryValues = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
        $releaseIdValue = $registryValues.ReleaseId
        $displayVersionValue = $registryValues.DisplayVersion
        $nameValue = $registryValues.ProductName
        $editionIdValue = $registryValues.EditionId

        # Strip out "Server" from the $editionIdValue if it exists
        $editionIdValue = $editionIdValue -replace 'Server', ''

        # Get OS details using Get-CimInstance because the registry key for Name is not always correct with Windows 11
        $osDetails = Get-CimInstance -ClassName Win32_OperatingSystem
        $nameValue = $osDetails.Caption

        # Get architecture details of the OS (not the processor)
        # Get only the numbers
        $architecture = ($osDetails.OSArchitecture -replace '[^\d]').Trim()

        # If 32-bit or 64-bit replace with x32 and x64
        if ($architecture -eq '32') {
            $architecture = 'x32'
        } elseif ($architecture -eq '64') {
            $architecture = 'x64'
        }

        # Get OS version details (as version object)
        $versionValue = [System.Environment]::OSVersion.Version

        # Determine product type
        # Reference: https://learn.microsoft.com/en-us/dotnet/api/microsoft.powershell.commands.producttype?view=powershellsdk-1.1.0
        if ($osDetails.ProductType -eq 1) {
            $typeValue = 'Workstation'
        } elseif ($osDetails.ProductType -eq 2 -or $osDetails.ProductType -eq 3) {
            $typeValue = 'Server'
        } else {
            $typeValue = 'Unknown'
        }

        # Extract numerical value from Name
        $numericVersion = ($nameValue -replace '[^\d]').Trim()

        # Create and return custom object with the required properties
        $result = [PSCustomObject]@{
            ReleaseId      = $releaseIdValue
            DisplayVersion = $displayVersionValue
            Name           = $nameValue
            Type           = $typeValue
            NumericVersion = $numericVersion
            EditionId      = $editionIdValue
            Version        = $versionValue
            Architecture   = $architecture
        }

        return $result
    } catch {
        Write-Error "Unable to get OS version details.`nError: $_"
        exit 1
    }
}

# Function to Install WinGet (modified)
function Install-WinGet {
    # Install VCPPRedist Requirements
    $Visual2019 = 'Microsoft Visual C++ 2015-2019 Redistributable*'
    $Visual2022 = 'Microsoft Visual C++ 2015-2022 Redistributable*'
    $VCPPInstalled = Get-Item @('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') | Where-Object {
        $_.GetValue('DisplayName') -like $Visual2019 -or $_.GetValue('DisplayName') -like $Visual2022
    }
    if ([System.Environment]::Is64BitOperatingSystem) {
        $OSArch = 'x64'
    } else {
        $OSArch = 'x86'
    }
    if (!($VCPPInstalled)) {
        Write-Output 'VCPPRedist Requirements Not Installed. Installing...'

        $VCPPRedistURL = ('https://aka.ms/vs/17/release/vc_redist.{0}.exe' -f $OSArch)
        $VCPPRedistFileName = [Uri]$VCPPRedistURL | Select-Object -ExpandProperty Segments | Select-Object -Last 1
        $WebClient = New-Object System.Net.WebClient
        $VCPPRedistDownloadPath = "$ENV:SystemRoot\Temp\VCPRedist"
        if (!(Test-Path -Path $VCPPRedistDownloadPath)) {
            $null = New-Item -Path $VCPPRedistDownloadPath -ItemType Directory -Force
        }
        $VCPPRedistDownloadFile = "$VCPPRedistDownloadPath\$VCPPRedistFileName"
        $WebClient.DownloadFile($VCPPRedistURL, $VCPPRedistDownloadFile)
        try {
            Start-Process -FilePath $VCPPRedistDownloadFile -ArgumentList '/quiet', '/norestart' -Wait -ErrorAction Stop | Out-Null
            Write-Output 'VCPPRedist Requirements Installed.'
        } catch {
            Write-Output 'Failed to install VCPPRedist Requirements!'
            $Script:ExitCode = 1
            return
        } finally {
            Remove-Item -Path $VCPPRedistDownloadPath -Recurse -Force -ErrorAction SilentlyContinue
        }
    } else {
        Write-Output 'VCPPRedist Requirements Installed.'
    }

    # Find Latest Download
    $LatestRelease = (Invoke-RestMethod -Uri 'https://api.github.com/repos/microsoft/winget-cli/releases/latest' -Method Get)
    $LatestAsset = ($LatestRelease).assets | Where-Object { $_.name.EndsWith('.msixbundle') }
    [version]$LatestVersion = $LatestRelease.tag_name.TrimStart('v')
    if ((Find-WinGet)) {
        [version]$CurrentVersion = (& (Find-WinGet) '-v').TrimStart('v')
    } else {
        [version]$CurrentVersion = 0
    }

    # Check if WinGet is Updated
    if (!($CurrentVersion -lt $LatestVersion) -and !$Force) {
        # Exit
        Write-Output 'WinGet is up to date. Exiting.'
        return
    }

    # Installing WinGet
    Write-Output 'WinGet not installed or out of date. Installing/updating...'

    # Download WinGet to Temp
    $WebClient = New-Object System.Net.WebClient
    $WinGetDownloadPath = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath $LatestAsset.name
    Write-Output "Downloading WinGet to $WinGetDownloadPath..."
    $WebClient.DownloadFile($LatestAsset.browser_download_url, $WinGetDownloadPath)

    # Download WinGet Source to Temp
    $WinGetSourceDownloadPath = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath 'source.msix'
    Write-Output "Downloading WinGet to $WinGetSourceDownloadPath..."
    Invoke-WebRequest -Uri 'https://cdn.winget.microsoft.com/cache/source.msix' -OutFile $WinGetSourceDownloadPath

    $WinArch = (Get-OSInfo).Architecture

    # Download VCLibs
    $VCLibs_Path = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath "Microsoft.VCLibs.${WinArch}.14.00.Desktop.appx"
    $VCLibs_Url = "https://aka.ms/Microsoft.VCLibs.${WinArch}.14.00.Desktop.appx"
    Write-Output 'Downloading VCLibs...'
    Write-Debug "Downloading VCLibs from $VCLibs_Url to $VCLibs_Path`n`n"
    Invoke-WebRequest -Uri $VCLibs_Url -OutFile $VCLibs_Path

    # Download UI.Xaml
    $UIXaml_Path = Join-Path -Path "$ENV:SystemRoot\Temp" -ChildPath "Microsoft.UI.Xaml.2.8.${WinArch}.appx"
    $UIXaml_Url = "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.${WinArch}.appx"
    Write-Output 'Downloading UI.Xaml...'
    Write-Debug "Downloading UI.Xaml from $UIXaml_Url to $UIXaml_Path`n"
    Invoke-WebRequest -Uri $UIXaml_Url -OutFile $UIXaml_Path

    # Install Downloaded WinGet
    try {
        Write-Output 'Installing WinGet...'
        Add-AppxProvisionedPackage -Online -PackagePath $WinGetDownloadPath -DependencyPackagePath $UIXaml_Path, $VCLibs_Path -SkipLicense -ErrorAction Stop
        Add-AppxProvisionedPackage -Online -PackagePath $WinGetSourceDownloadPath -SkipLicense -ErrorAction Stop
        Write-Output 'WinGet installed.'
    } catch {
        Write-Output 'Failed to install WinGet!'
        $Script:ExitCode = 1
    } finally {
        Remove-Item -Path $WinGetDownloadPath -Force -ErrorAction SilentlyContinue
    }

    return
}

# Function to Find the WinGet exe (Modified)
function Find-WinGet {
    # 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 Location
    return $WinGet
}

# Test internet connection
$MaxNet = 15
Write-Output 'Checking Internet Connection...'
for ($i = 0; ($i -lt $MaxNet) -and !$net; $i++) {
    $net = Test-Connection 1.1.1.1 -Count 1 -Delay 1 -Quiet
}
if (!$net) {
    Write-Output 'No Internet Detected. Cancelling Installation.'
    Stop-Transcript
    exit 1
}

Write-Output 'Internet Detected, Continuing Installation.'

# Test OS Compatibility
$osVersion = Get-OSInfo

# If it's a workstation, make sure it is Windows 10+
if ($osVersion.Type -eq 'Workstation' -and $osVersion.NumericVersion -lt 10) {
    Write-Error 'winget requires Windows 10 or later on workstations. Your version of Windows is not supported.'
    Stop-Transcript
    exit 0
}

# If it's a workstation with Windows 10, make sure it's version 1809 or greater
if ($osVersion.Type -eq 'Workstation' -and $osVersion.NumericVersion -eq 10 -and $osVersion.ReleaseId -lt 1809) {
    Write-Error 'winget requires Windows 10 version 1809 or later on workstations. Please update Windows to a compatible version.'
    Stop-Transcript
    exit 0
}

# Run the Install/Update
Install-WinGet

& (Find-WinGet) 'list' '--accept-source-agreements'

Stop-Transcript
exit $Script:ExitCode

Categories:      

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

Improve New Outlook and Webview performance with winget
article #1605, updated 72 days ago

This seems to be able to help. It does take down New Outlook and New Teams and any other Webview app first.

taskkill /f /im msedgewebview2.exe
$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe"
    if ($ResolveWingetPath){
           $WingetPath = $ResolveWingetPath[-1].Path
    }
$ENV:PATH += ";$WingetPath"
winget install microsoft.edgewebview2runtime --force --accept-package-agreements --accept-source-agreements

Categories:      

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

winget: upgrade all possible
article #1604, updated 85 days ago

This command line will upgrade many things:

winget upgrade --all --include-unknown

Categories:      

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

Give Azure user local admin rights on Azure-joined PC
article #1603, updated 100 days ago

So we have a PC that is Azure-joined, not AD, not standalone. Domain admin is obvious. And we can set PC-local admin using domain admin. But how do we give an Azure user local admin rights? Well, the simplest is in administrative Powershell:

net localgroup Administrators /add "AzureAD\userupn@domain.com"

where userupn@domain.com is the UPN of the user, the user’s login into Azure/365. Note that the text AzureAD is not the domain name, it is literal characters as you see it here. In other words, a breakage of historical syntax!

Categories:      

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

Fixing Windows / Azure / 365 User Connections with dsregcmd
article #1550, updated 101 days ago

Sometimes Windows’ relationship with 365, or a user’s profile, or just a user on a PC or terminal server, will not log into 365. This appears to be the result of corruption of cached credentials.

The most straightforward way is probably to nuke all User/Windows/Azure relationship and recreate. As written, this would probably be very bad on a terminal server, because it will nuke the relationship for all users and all profiles. So far, no per-user commands identified.:

Remove 365 accounts from “Access Work and School”, then run these:

dsregcmd /debug /cleanupaccounts
dsregcmd /debug /leave

from administrative CMD, and also from SYSTEM (paexec or psexec can do this), then reboot, then remove from Access Work and School if still there, then set up user relationship(s) again.

But today we have a report that dsregcmd /status did something, unknown, which fixed one terminal server user. Not sure what. Next time I plan to run many tests with this info:

ss64.com/nt/dsregcmd.html

And if you see error CAA5021, do this:

Search for Manage user certificates in the search bar and open it from Best match. Then navigate to Current User\Personal\Certificates and make sure the MS-Organization-Access and MS-Organization-P2P-Access entries are deleted.

No reboot needed for that last.

Categories:      

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

SAAZ / ITS Removal
article #1602, updated 102 days ago

Run this in administrative Powershell:

wmic product where "name like '%ITSPlatform%'" call uninstall /nointeractive
wmic product where "name like '%ScreenConnect Client%'" call uninstall /nointeractive

Stop-Service -Name "SAAZappr"
Stop-Service -Name "SAAZDPMACTL"
Stop-Service -Name "SAAZRemoteSupport"
Stop-Service -Name "SAAZScheduler"
Stop-Service -Name "SAAZServerPlus"
Stop-Service -Name "SAAZWatchDog"
If (Test-Path "C:\Program Files (x86)\SAAZOD"){
   Remove-Item "C:\Program Files (x86)\SAAZOD" -Force -Recurse
} else {}
If (Test-Path "C:\Program Files (x86)\SAAZODBKP"){
   Remove-Item "C:\Program Files (x86)\SAAZODBKP" -Force -Recurse
} else {}
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest" -Name "ITSPlatformID" -Force
Remove-Item "HKLM:\SOFTWARE\WOW6432Node\SAAZOD" -Force
Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\SAAZappr" -Force
Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\SAAZDPMACTL" -Force
Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\SAAZRemoteSupport" -Force
Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\SAAZScheduler" -Force
Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\SAAZServerPlus" -Force
Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\SAAZWatchDog" -Force

Categories: