Get Registry Name using powershell - powershell

I wanted to loop through registry entries using powershell and uninstall certain MSIs.
I found the answer in this post very simillar to my requirement. However I have a slight different requirement. (I dont want to use UnInstall String)
I get a list of all registries in 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall' and I want to use the NAME (i.e. the productcode) of the registry itself.
My Question: How to get the name of the registry.

You need to use Get-ChildItem.
For example, this gives the Name of the key under Uninstall key.
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Select PSChildName
Update based on the comment:
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Where-Object {
$_.PSChildName -Eq '{D2B9C003-A3CD-44A0-9DE5-52FE986C03E5}'} | Select PSChildName

You shouldn't really be trolling the registry. The correct way to do this for MSI-based installs is to use MsiEnumProducts to find all the installed MSI products, use the returned product code to get info about their names and versions (MsiGetProductInfo) to see if you want to uninstall them, and then use MsiConfigureProduct and set them to installstate_absent. If you dig around you may find some p/invoke interop code to do this from managed code, that would get you into PowerShell.

Related

Remove Appx if version less than

First off, thanks for taking the time to read my issue and hopefully point me in the right direction.
Second, I hate Appxpackages :)
My understanding of how an Appx works is the following, so please correct me if you think I have got it wrong. When a user signs into a PC various windows applications based on Appxpackages will get installed at the current release. For example the calculator could be;
Microsoft.WindowsCalculator_11.2210.0.0_x64__8wekyb3d8bbwe
The user may never sign into that PC again, 6 months down the line there could be a vulnerability discovered in this application and it gets patched with an update. However, this only applies if the user signs in and the store does its job of updating out of date appxpackages.
The issue with this is, if you are in an enterprise environment and you use something like Qualys to scan your clients it will show this vulnerability. Furthermore you could have a mix of users and each user could have a different version.
I'd like to develop a method with powershell to check for the version of the appxpackage for all users and for any user that does not have the currently patched version it uninstalls, I don't believe it is possible to update for a user not signed in.
My idea is to use something along the lines of this
[version]$version=(get-appxpackage -Name *Microsoft.WindowsCalculator* -Allusers).Version
If ($Version -eq [version]"11.2210.0.0")
{
"Minimum version met"
}
ElseIf ($Version -lt [version]"11.2210.0.0")
{
Remove-AppxPackage -Package $version -Allusers
}
I'm certain it won't work, but I can't think how to deal with it. I know I can't use $version as that just finds all versions, so for the else-if I were to user $version it would just remove all versions for everyone.
In the past I have done something similar for the Teams.exe application within Appdata folders for each user. That was much easier to deal with as I know the installer folder in appdata, I could easily query the version number and cycle through each user profile one at a time, but I don't see a way to do this for appxpackages.
Any guidance on this would be really appreciated.
I'm on mobile, so I can't test this.
Have you tried looking at Get-AppxPackageManifest? I can't see the object it returns from the docs, but I'm sure there would be a current version property' or even in Get-AppxPackage
So maybe try
# check for installed, or something version in the output
Get-AppxPackage -Name *Microsoft.WindowsCalculator* | Get-Member
# If there wasn't a property, see if the manifest has one
Get-AppxPackage -Name *Microsoft.WindowsCalculator* | Get-AppxPackageManifest | Get-Member
If there's a property that works the commands would be something like this.
$version = (Get-AppxPackage -Name *Microsoft.WindowsCalculator* | Get-AppxPackageManifest). # fill in property
# you could use a switch statement for this purpose
Switch ($value -Lt 11.2210.0.0)
'true' { Get-AppxPackage -Name *Microsoft.WindowsCalculator* | Remove-AppxPackage -whatif # keep here for testing, and remove -whatif when satisfied}
'false' { Write-Output ' The installed version is $($version), and is not vulnerable}
Try just one user first, and then try the -alluser tag
Hopefully this can help.
Get-Command *appx*

Powershell: Two questions about Get-AppxPackage and the -PackageTypeFilter parameter

I am making a list of app packages installed on my system. In this specific case the ZuneMusic packages. I use the following command:
Get-AppxPackage -AllUsers -PackageTypeFilter Main, Bundle, Resource, Framework |
Where-Object {$_.Name -like "*ZuneMusic*"}
This will get me a list/result with 4 packages. I can see some have IsResourcePackage : True and one has IsBundle : True etc.
It seems this has to do with the -PackageTypeFilter cause if I only use Main is get only one result. I Looked up the parameter -PackageTypeFilter description:
Specifies one or more comma-separated types of packages that the cmdlet gets from the package repository. Valid values are:
Bundle
Framework
Main
Resource
None
Can someone elaborate/explain a bit more what this -PackageTypeFilter parameter does please?
If I want to delete packages of apps that I do not use or want. Do I use all options of this parameter and delete all the results or is one specific option enough?
why dont you just do get-appxpackage -name *zunemusic* -allusers | remove-appxpackage?
dont use -packagetypefilter
the pipeline will get all the returned apps named *zunemusic* and remove them - however, if it floats your boat, specify each package individually
if you remove each package individually, possible future name changes could affect the script and will require manual update if so - probably unlikely though

How do I get a VM Image from Azure in Powershell?

Previously in Powershell I was using the Get-AzureVMImage cmd-let to retrieve a VM Image I had generated. I would store the image an as object to build a VM with New-AzureQuickVM. Below is a code snippet:
$image = Get-AzureVMImage | where { $_.Imagename -like $basicImageNames[$n] } | Sort-Object -Descending -Property PublishedDate | Select-Object -First 1 -OutVariable image
Now with the new AzureRM Powershell Module, the majority of the cmd-lets for Powershell management have been renamed or deprecated. Get-AzureVMImage.
I've attempted to use Get-AzureRmImage, but it doesn't list any of my VM Images.
I've also attempted to use Get-AzureRmVMImage, but this appears to be valid only for official published images, and not my user generated ones.
Does anyone know of an equivalent cmd-let to the deprecated Get-AzureVMImage?
According to your describe, I think you have created a Classic Image ,right?
As I known, Classic image can only be used to create classic VM. Also, you cannot using Azure RM powershell to get a Classic Image and to create a classic VM.
So, I suggest you can go to Azure portal > VM images(classic)> find your generated Image>Create VM . Or you can also use Azure SM powershell to login your Azure Classic Account and then use Get-Azure VM image.
See more details about Get-AzureVMImage in this document.
See more details about Get-AzureRmImage in this document.

Determining Installed Visual Studio Path for 2017

I have a powershell script that looks at a list of VS installations, and determines the highest version installed. It then uses the InstallDir for that version, and uses it to access various commands.
It still uses the lower versions, however.
As of VS2017, it appears that the Registry keys are no longer saved in the same way. I need to update the script to be able to figure out the 2017 settings.
#Add New Versions to this list when new versions of VS are released
$VsVersionsToDisable = "10.0", "11.0", "12.0", "14.0"
[System.Collections.ArrayList]$VsVersions = $VsVersionsToDisable
#Find the Highest installed VS Version, and use it for the TFS.exe Command.
foreach ($version in $VsVersions | Sort-Object -Descending)
{
$keyPath = "HKCU:\Software\Microsoft\VisualStudio\$version`_Config"
If (Test-Path $keyPath)
{
$aliasPath = Get-ItemProperty -Path $keyPath | Select-Object `
-ExpandProperty InstallDir
$proxyPath = Join-Path $aliasPath "tf.exe"
set-alias proxyTF $proxyPath
}
}
To avoid an XY question: We use this script to configure the TFS Proxy settings for a user. It determines the highest installed version, uses it to find the proxy, then iterates through the lower versions configuring their proxy settings with the same value.
What is the best way to determine the installation directory (and also the tf.exe location) for VS2017?
From what I can see, use the SxS\VS7 option:
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7
It should give you the root paths to Visual Studio:
That should get you going.
The tf.exe location is then stored using a symlink under:
.\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe
Since you're using PowerShell, check out https://github.com/microsoft/vssetup.powershell, which is a PS module for detecting installations of VS2017+.
Otherwise, you could need to rely on the Nuget package which is the supported means of detecting VS.
See also this answer on a related question, which predates the PS module I listed above but contains some unsupported methods for finding VS.
I did use this as a reference and came to a solution in another way.
I'm not sure how resilient it is with regards to other versions, but it did the trick for me. It get's the directory of devenv and then I add the extra on the end for TFS. Obviously if the structure is different, then we are screwed.
Hope it helps.
$regKey = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\devenv.exe"
$visualStudioDir = Get-ItemPropertyValue -Path $regKey -Name "(Default)"
$visualStudioDir = ($visualStudioDir.Replace("devenv.exe","")).replace("`"","")
$tfsPath = 'CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe'
Set-Alias tf $visualStudioDir$tfsPath
tf workspaces

How to change extended windows file attributes via Powershell without using attrib.exe?

This seems to be a quite simple question, yet googling gave me nothing.
Here is the error (PS 5.1, win 10.0.14393 x64):
Set-ItemProperty $myFileInfo -Name Attributes -Value ([System.IO.FileAttributes]::Temporary)
The attribute cannot be set because attributes are not supported. Only the following attributes can be set: Archive, Hidden, Normal, ReadOnly, or System.
attrib.exe seems to support most of System.IO.FileAttributes. Unfortunately is does not seem to work with files referenced using FileSystem PSDrives. That is what I am using extensively.
Making wrapper for SetFileAttributes kernel API call would be the last resort.
Am I missing any other [more simple] ways setting these extended file attributes?
PS. Apart from [System.IO.FileAttributes]::Temporary I am interested in setting [System.IO.FileAttributes]::NotContentIndexed.
You can edit the Attributes property of a [FileInfo] object directly. For example, if you wanted to exclude all files in the C:\Temp folder from being content indexed, you could do this:
Get-ChildItem C:\Temp | ForEach{
$_.Attributes = $_.Attributes + [System.IO.FileAttributes]::NotContentIndexed
}
That would get each file, and then add the [System.IO.FileAttributes]::NotContentIndexed attribute to the existing attributes. You could probably filter the files to make sure that the attribute doesn't already exist before trying to add it, since that may throw errors (I don't know, I didn't try).
Edit: As noted by #grunge this does not work in Windows Server 2012 R2. Instead what you have to do is reference the value__ property, which is the bitwise flag value, and add the bitwise flag for NotContentIndexed. This should work for you on any Windows OS:
Get-ChildItem C:\Temp | ForEach{
$_.Attributes = [System.IO.FileAttributes]($_.Attributes.value__ + 8192)
}