Detection script for windows hotfixes - windows

So we have recently had issues with the KB971033 update within our network and i have managed to get a working script for removing it and reactivating windows, however when trying to get a detection script working to assure it only runs on effected computers i cant get it to correctly output true or false when testing against installed KBs.
So far this is what im running. No matter what i do it will output false. Anything obvious i am missing?
if ((get-hotfix).hotfixid -eq "KB971033") {$true} else {$false}

(get-hotfix).hotfixid returns an array, so you should not compare that with -eq.
This ought to do it:
((Get-HotFix | Select-Object -ExpandProperty HotFixID) -contains 'KB971033')
or for short:
(((Get-HotFix).HotFixID) -contains 'KB971033')

It's IMO quite inefficient to sieve through all Hotfixes when testing a distinct one.
if (Get-Hotfix -ID KB971033 -EA 0) {$true} else {$false}
-EA 0 is an abbreviation for -ErrorAction SilentlyContinue

Maybe Try
if ($(get-hotfix).hotfixid -eq "KB971033") {$true} else {$false}
The "$" is going to make "Get-Hotfix" result into an object with member ".hotfixID".

In my Windows Server 2016 Environment your Code works fine...maybe the Hotfix is not installed or not listed with 'get-hotfix'
Otherwise you can try this:
$HotfixID= "KB971033"
IF((get-hotfix).hotfixid | ?{ $_ -eq $HotfixID}){$true} else {$false}
It works also on Remote Computer:
(get-hotfix).hotfixid -ComputerName "***SomeDNSName / FQDN***"

Related

Is there any method for getting details of all installed apps in a Windows device using shell commands

I need to get all installed applications and its details in a Windows device using shell commands. I tried using
Get-appxpackage
Get-WmiObject
wmic
Apps that were installed manually seems to be missing in the list. Please help by providing a better method.
An alternative can be to query the registry like this for example:
# HKLM - Local Machine
$InstalledSoftware = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
foreach($obj in $InstalledSoftware){write-host $obj.GetValue('DisplayName') -NoNewline; write-host " - " -NoNewline; write-host $obj.GetValue('DisplayVersion')}
# HKCU - Current User
InstalledSoftware = Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
foreach($obj in $InstalledSoftware){write-host $obj.GetValue('DisplayName') -NoNewline; write-host " - " -NoNewline; write-host $obj.GetValue('DisplayVersion')}
Check this page out for more:
https://www.codetwo.com/admins-blog/how-to-check-installed-software-version/
Tip! Browse these locations in the registry manually before you dig in as it will help you see the structure and understand what properties are available. If the information you're seeking is not there, you might just ditch this suggestion.
For Windows 64-bit and 32-bit apps use
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table > C:\ws\apps.txt
the C:\ws\apps.txt need to be adjusted by you, to your output path.
I found the idea here, Social MS

WMIMethodException with .InstallProductKey

First off, this is my first post, so if I incorrectly posted this in the wrong location, please let me know.
So, what we're trying to accomplish is building a powershell script that we can throw on our workstation image so that once our Windows 10 boxes are done imaging, that we can click on a powershell script, have it pull the key from the BIOS, and automagically activate it. That being said, here is the script that we've put together from various sources.
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey | out-file c:\license.txt
$computer = gc env:computername
$key = get-content c:\license.txt
$service = get-wmiObject -query “select * from SoftwareLicensingService” -computername $computer
$service.InstallProductKey($key) <--------THIS IS WHERE IT FAILS
$service.RefreshLicenseStatus()
We start running into the issues on the line $service.InstallProductKey($key). It seems, that no matter how we try to invoke that, it will consistently fail with the error "Exception calling "InstallProductKey"". I've even replaced the variable ($key) with the specific activation key, and it STILL fails with the same error.
The reason we have it outputting to a license txt file part way through is so that we can verify that the command is indeed pulling the product key (which it is).
At this point, I'm not sure where to go. It seems that people have tried to do this before, however, nobody has really wrapped up their posting with what worked and/or what didn't. I can't imagine that this is impossible, but I'm also not fond of wasting anymore time than needed, so anybody that has any insight into this issue, I'd be very grateful.
We've gotten it to work on two machines that were previously activated, and later deactivated, but on new machines that have been freshly imaged, and have yet to be activated, it will fail every time.
Two things as per my observation:
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey | out-file c:\license.txt
I don't think that it is returning any value to your license.txt.
If yes, then I would like you to see if there is any space before and after the license key. You can use trim during getting the content from the file.
Second thing, when you are getting the content from the file make sure it is not separating into multiple lines. In that case, you have to cast it as string like [String]$key or you can call toString() method for this.
One more important thing is to refresh after the installation.
$service.RefreshLicenseStatus()
Note: Make sure you are running the shell in elevated mode.
Alternative: Try Hardcoding the values and see the result
$key = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" # hardcode the key
$computer= "Computer01" # Hardcode the computer
$service = get-wmiObject -query "select * from SoftwareLicensingService" -computername $computer
$service.InstallProductKey($key)
$service.RefreshLicenseStatus()
For further thing ,please post the exact error.
Hope it helps...!!!
Found out that the key from Get-WmiObject has whitespace on the end. The original command will work if a .Trim() is added. Also not running as administrator will result in the same error.
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey | out-file c:\license.txt
$computer = gc env:computername
$key = (get-content c:\license.txt).Trim() #trim here
$service = get-wmiObject -query “select * from SoftwareLicensingService” -computername $computer
$service.InstallProductKey($key)
$service.RefreshLicenseStatus()

Output needs to be in text(not object)

I print outputs like this in my code, but I was told that my outputs needs to be in text(not object). Can somebody explain to me what it means and whats wrong in my code? Thanks.
Write-Output "ALL INSTALLED WINDOWS FEATURES:"
Write-Verbose -Message "Searching installed features..." -Verbose
$obj=Get-WindowsFeature | Where-Object {$_.Installed} | Select-Object Name, InstallState | Format-Table -AutoSize
Write-Output $obj
Write-Output "OPERATING SYSTEM INFO:"
Write-Verbose -Message "Searching operating system info..." -Verbose
$opInfo=Get-CimInstance Win32_OperatingSystem | Select-Object Version, Caption, InstallDate, LastBootUpTime, TotalVirtualMemorySize , SystemDirectory | FL
Write-Output $opInfo
There's nothing technically wrong with your code but personally I would change Write-Output "OPERATING SYSTEM INFO:" to a Write-Verbose, having that header in the output will make working with the results of your function in other parts of the code. However returning the object opInfo rather than a collection of strings is absolutely correct and the only reason someone would be telling you not to is if the code they intend what you are creating to interact with is either written incorrectly or written in an older scripting language like VBS, or if they are just not aware the preference for objects in Powershell development.

Exchange Server - Get CASMailbox - Parameters

When Running a Get CASMailbox command in the Exchange Management Shell, is there a parameter that will return a list of acttive and disabled mailboxes?
This might serve your purpose if you haven't already found the answer:
Get-CASMailbox -Filter {HasActiveSyncDevicePartnership -eq $True -and DisplayName -notlike "CAS_{*"}

Is there a way to check AD group membership for a computer?

I am trying to check computer group membership through Powershell. I want to be able to specify a certain computer name and find which groups that computer is in but from a Powershell script. I am planning on running the script on a computer, grabbing the hostname, and then printing out what AD groups that computer is in. Is there an easy way to do this?
EDIT:
So the plan here is to have a computer check to see what groups it is in, then assign a printer based on which group it is in. We have many printers that only 3 to 4 people use but due to the spread out nature of the users cannot downsize the amount of printers. I was looking at group policy but did not want to create 20 different GPOs. I wanted to do this with a logon/startup script. I'm not sure if this is doable or feasible.
Edit #2:
This edit it really late to the party but I figured if anyone found this it could help. We ended up using item level targeting on User>Preferences>Control Panel>Printers objects. We made an account in AD for each group of users needing access to the printers. This worked although it did create a long logon process for the first logon of the computer. We also enabled Point-to-Print restrictions so the drivers were loaded from the servers quietly.
This will give you the group membership (group names) of the local computer (requires powershell 2.0):
([adsisearcher]"(&(objectCategory=computer)(cn=$env:COMPUTERNAME))").FindOne().Properties.memberof -replace '^CN=([^,]+).+$','$1'
Apologies if I'm a bit late to the party on this but I needed to find a computer's group membership as well. After a lot of trial and error, this worked for me.
Get-ADComputer "mycomp" -Properties MemberOf | %{if ($_.MemberOf -like "*group name*") {Write-Host "found"} }
I noticed that if the string comparison is on a separate line, I needed to do the following
$g=Get-ADGroupMember -Identity "CN=myADgroup,OU=myOU,DC=corp,DC=com" -server corp.com
foreach($mbr in $g) {if($name.MemberOf -like "*mycomp*" -eq $true) {Write-Host "found"}}
Not sure but I imagine that testing the computer might be faster and easier than testing the group depending on the number of members.
the gpresult method seems to be the only way I can find that is accurate. Querying AD is not accurate since the computer may have been added to groups but not rebooted. I am sure someone could condense this but it worked well enough for what I needed to see.
# Get all active domain servers
$staledate = (Get-Date).AddDays(-90)
$computers = Get-ADComputer -Filter {(OperatingSystem -Like "*Server*") -and (Enabled -eq $True) -and (LastLogonDate -ge $staledate) -and (Modified -ge $staledate) -and (PasswordLastSet -ge $staledate) -and (whenChanged -ge $staledate) -and (Name -notlike "PHXVSSA101A")} | Select name -expandproperty name
$computers = $computers | Where {(Resolve-DNSName $_.name -ea 0) -and (Test-Connection -ComputerName $_.Name -Count 1 -ea 0)} | Sort
# Loop through all active domain servers
Foreach ($computer in $computers)
{
# Pull the gpresult for the current server
$Lines = gpresult /s $computer /v /SCOPE COMPUTER
# Initialize arrays
$cgroups = #()
$dgroups = #()
# Out equals false by default
$Out = $False
# Define start and end lines for the section we want
$start = "The computer is a part of the following security groups"
$end = "Resultant Set Of Policies for Computer"
# Loop through the gpresult output looking for the computer security group section
ForEach ($Line In $Lines)
{
If ($Line -match $start) {$Out = $True}
If ($Out -eq $True) {$cgroups += $Line}
If ($Line -match $end) {Break}
}
# Loop through all the gathered groups and check for Active Directory groups
ForEach ($group in $cgroups)
{
Try {
$check = Get-ADgroup $group -ErrorAction Stop
If ($check) {
$dgroups += $group
}
}
Catch {}
}
# Output server name and any Active Directory groups it is in
$computer
$dgroups
# End of computers loop
}
try running gpresult /V and check under "security GROUPS"
You can also try gpresult /scope computer /v under a command prompt (elevated to admin) for more specific results
Heres an LDAP query to find if a computer is in a group recursively:
(((objectClass=computer)(sAMAccountName=COMPUTERNAME$))(memberof:1.2.840.113556.1.4.1941:=DistinguishedNameOfGroup))
More info: http://justanotheritblog.co.uk/2016/01/27/recursively-check-if-a-usercomputer-is-a-member-of-an-ad-group-with-powershell-2-0/
To check the computer's own view of group membership, you can run:
(New-Object System.Security.Principal.WindowsPrincipal("$env:computername$")).IsInRole('Example Group')
True
Taking the computer out of Example Group doesn't affect the output of the above until the computer is rebooted.
Try this DOS Command, this will return all the local groups this computer belong to :
net localgroup

Resources