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 has been even more interesting. I’ve tried a lot of things. The below worked very well just now on Server 2019. There may be one extra module install in it, will test when it comes up again.
#Begin winget installation
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
Set-PSRepository -InstallationPolicy Trusted -Name PSGallery
PrepareModule("NuGet")
Install-Script -Name winget-install
#End winget installation
If you can get to an administrative or system shell:
Reset-ComputerMachinePassword -Server DC.domain.local -Credential (Get-Credential)
Try this:
@("MsOnline","ExchangeOnlineManagement","AzureAD","AzureRM","Az","Microsoft.Graph","MicrosoftTeams","Microsoft.Online.SharePoint.PowerShell","Microsoft.PowerApps.Administration.PowerShell","Microsoft.PowerApps.PowerShell","WhiteboardAdmin","O365CentralizedAddInDeployment","PnP.PowerShell","MicrosoftPowerBIMgmt")|%{if(!(get-module -listavailable -name $_)){install-module -name $_ -skippublishercheck -allowclobber -force}elseif((get-module -listavailable -name $_).version -lt (find-module $_).version){update-module -name $_ -force;Get-InstalledModule -name $_ -allversions| where {$_.version -lt (get-installedmodule -name $_.name).version} | Uninstall-Module -force}}
From www.tbone.se/2023/02/27/update-your-windows-11-with-some-powerful-one-liners/”
To get the link speed of all NICs in Powershell:
Get-NetAdapter | select interfaceDescription, name, status, linkSpeed.
It also removes old versions.
Get-InstalledModule |%{if((get-module -listavailable -name $_.name).version -lt (find-module $_.name).version){update-module -name $_.name -force;Get-InstalledModule -name $_.name -allversions| where {$_.version -lt (get-installedmodule -name $_.name).version} | Uninstall-Module -force}}
From www.tbone.se/2023/02/27/update-your-windows-11-with-some-powerful-one-liners/
This method uses Powershell module PsWindowsUpdate.
- Run this in administrative Powershell:
[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 check the list of available updates:
Get-WindowsUpdate
- The next step is to actually do the 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
.
Reset-WUComponents
- To get a full list of functions:
Get-Command -Module PSWindowsUpdate
Get-Help
works for all of them.
- Open up an administrative Powershell. Run
IPCONFIG /ALL
. That will get you a list of active NICs. DNS in use, is set for each NIC if you have more than one.
- The name of each NIC has a prefix that has to be omitted. There are a number of prefixes which are common. For a simple wired NIC, it’s usually “Ethernet Adapter”; on many HPE servers, IPCONFIG /ALL will therefore show the second NIC as
Ethernet adapter Embedded LOM 1 Port 2
.
- So let’s say you have a LAN with three active DNS servers (10.11.12.13, 10.11.12.14, and 10.11.12.15), and you want your HPE server of the above description, with the first two NICs active, to use all of them. Here’s the Powershell commands:
Set-DnsClientServerAddress "Embedded LOM 1 Port 1" -ServerAddresses ("10.11.12.13","10.11.12.14","10.11.12.15")
Set-DnsClientServerAddress "Embedded LOM 1 Port 2" -ServerAddresses ("10.11.12.13","10.11.12.14","10.11.12.15")
- For a second example, let’s say we’re on a common workstation, and we want to change DNS from a static setting, to whatever DHCP will pass out:
Set-DnsClientServerAddress "Ethernet" -ResetServerAddresses
Longstanding, works well unless BITS is corrupt:
Start-BitsTransfer -Source $URL -Destination $Path
On 1809 and up:
curl.exe -O $URL
A pure Powershell method:
(New-Object System.Net.WebClient).DownloadFile($URL,$Path)
This removes all local admins from a machine’s Administrators group, except the built-in Administrator and “Domain Admins” if it’s on a domain.
$LocalDomain = $env:USERDOMAIN
$DomainAdmins = "$LocalDomain\Domain Admins"
$ComputerName = $env:COMPUTERNAME
$OEMAdministrator = "$ComputerName\Administrator"
Get-LocalGroupMember Administrators | ForEach-Object {
$UserName = $_.Name
"Found: $UserName"
If (($UserName -ne $DomainAdmins) -and ($UserName -ne $OEMAdministrator)) {
"Removing $UserName from local Administrators group."
Remove-LocalGroupMember -Group Administrators -Member $UserName
}
""
}
If you see GPO policies get implemented and re-implemented even though the settings have been removed, or if it just doesn’t happen, try the following in administrative Powershell. These clear the GPO cache on the machine you’re looking at.
Remove-Item "$env:windir\system32\GroupPolicy" -Force -Recurse
Remove-Item "HKLM:\Software\Policies\Microsoft" -Force -Recurse
Remove-Item "HKCU:\Software\Policies\Microsoft" -Force -Recurse
Remove-Item "HKCU:\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects" -Force -Recurse
Remove-Item "HKCU:\\Software\Microsoft\Windows\CurrentVersion\Policies" -Force -Recurse