Verify driver install through powershell - powershell

I need to install a driver on a bunch of systems. (it should have come from MS but we are using kace for patching so i cant use wsus to push it out) So i found this oneliner RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection DefaultInstall 132 %path to inf%
Next is to put a check into it so it looks if the driver is installed first but I am having trouble finding the driver. I made an assumption that guidid or class from .inf will provide me with the info i need to check.
[Version]
Signature="$Windows NT$"
Class=SmartCard
ClassGuid={990A2BD7-E738-46c7-B26F-1CF8FB9F1391}
Provider=%ProviderName%
CatalogFile=delta.cat
DriverVer=08/11/2015,8.4.9.0"
Get-WmiObject Win32_PnPSignedDriver -Property * | where {$_.ClassGuid -like
"990A2BD7-E738-46c7-B26F-1CF8FB9F1391"}
but I can not find the driver installed. I list all drivers and attempt to scroll through them to find this one and it's not there or it's called something else now.
eventual goal is something like this
if (!(Get-WmiObject Win32_PnPSignedDriver| select devicename, classguid |
where {$_.classguid -like "*990A2BD7-E738-46c7-B26F-1CF8FB9F1391*"})) {echo
do stuff} else { echo dont do stuff}
Any help in being able to identify if the driver is installed or not would be appreciated.

A little googling goes a long way as this has been asked a few times before. Here is a WMIC query against all the installed drivers on the system, then filters out everything except the smartcard class using the classGUID.
Get-WmiObject Win32_PnPSignedDriver| where-object {$_.ClassGUID -eq "{50DD5230-BA8A-11D1-BF5D-0000F805F530}"} |Select *
Here is what got me to my answer if you need additional clarification.
How do I get all the smart card readers on my system via WMI?
https://superuser.com/questions/567927/get-driver-version-via-command-line-windows
https://blogs.technet.microsoft.com/askperf/2012/02/17/useful-wmic-queries/

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 - Unable to look for a registry value

I have McAfee Drive Encryption installed on my Machine and trying to query the application using Powershell, however there is a really strange issue happening.
When i go the Uninstall Key in the registry, i can see McAfee Drive Encryption there, however it does not find it when i run the following command:
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where { $_.DisplayName -match "McAfee Drive" } | select DisplayName, DisplayVersion
now i tried to simply put the code as: Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
and it lists all the applications in there but not the McAfee Value!, i have tried this on another account / Machine and that worked fine, so wondering if anyone had a similar issue at all?
Any Help is appreciated.

Querying Windows Update Errors using PowerShell Get-WinEvent or Get-WMIObject

Trying to create a simple Windows Update error query using Get-WinEvent (although I would prefer querying a WMI Object for use with SCUP):
get-winevent -logname System| Where-Object {$_.ProviderName -eq "Microsoft-Windows-WindowsUpdateClient"}
This seems to work for the most part. However, it only returns informational events and not errors. Are these located somewhere else and, if so, how would I query them? For some background, there is a specific update failure occurring on approximately 10% of Windows 10 machines in my environment (missing assembly file) and I want to target it so that I can deploy a solution.
A solution using Get-WinEvent is fine, though I would prefer using Get-WMIObject if possible.
You can use the Win32_NTLogEvent like this:
Get-WmiObject Win32_NTLogEvent |?{($_.LogFile -eq 'System') -and ($_.SourceName -eq 'Microsoft-Windows-WindowsUpdateClient') }
Note: You can further filter with Type which will tell you about information or error or warning.
Hope it helps.
I cannot find anything that actually states this but it looks like Get-WinEvent by default only returns information messages. If you want to see the other then you need to tell it to return those. One way to do it is with -FilterHashtable.
Get-WinEvent -FilterHashtable #{LogName='System';Level=1,2}
That would return only warnings and error.
1 - Error
2 - Warning
4 - Information
You can look at the enum [System.Diagnostics.EventLogEntryType] to see where I got the numbers from.
Looking at MS you can see what the hashtable filter supports..
LogName=<String[]>
ProviderName=<String[]>
Path=<String[]>
Keywords=<Long[]>
ID=<Int32[]>
Level=<Int32[]>
StartTime=<DateTime>
EndTime=<DataTime>
UserID=<SID>
Data=<String[]>
*=<String[]>
If your WMI queries are having similar issues then you can do something like this
Get-WmiObject -class Win32_NTLogEvent -filter "(logfile='Application') AND (type='error')"
You can find some tangential examples here
Write a WMI query (this overrides weird event type filters):
Get-WmiObject -Query "Select * from Win32_NTLogEvent" |?{(($_.LogFile -eq 'System') -and ($_.Type -in ("Error", "Warning"))) -and ($_.SourceName -eq 'Microsoft-Windows-WindowsUpdateClient') }
Okay, so after doing some additional research, I stumbled upon this website that sheds some light on the issue I'm running into. Essentially, while most, if not all Windows Events are logged in the C:\Windows\System32\Winevt\logs folder, not all Windows Events are replicated in WMI by default.
In PowerShell, Get-WinEvent appears to use the above folder when querying its event data, whereas Get-EventLog uses the Win32_WinNTLogEvent WMI class.
In my original question, I mentioned that I was unable to query Windows Update error events using Get-WinEvent. This is because I was pointing to the System log file, which does not contain the information. The Microsoft-Windows-WindowsUpdateClient/Operational log file (literal path being C:\Windows\System32\Winevt\logs\Microsoft-Windows-UpdateClient%4Operational.evtx) does contain this information, so my query can simply be changed up using something similar to the following:
Get-WinEvent -logname "Microsoft-Windows-WindowsUpdateClient/Operational" | Where-Object {$_.LevelDisplayName -eq "Error"}
In order to query the same data returned by Get-WinEvent using the Win32_NTLogEvent WMI class, the registry must first be modified. Again, the link I posted in this answer describes the process in greater detail, but essentially I performed the following registry mod:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Microsoft-Windows-WindowsUpdateClient/Operational]
"File"="%SystemRoot%\\System32\\Winevt\\Logs\\Microsoft-Windows-WindowsUpdateClient%4Operational.evtx"
"Primary Module"="Microsoft-Windows-WindowsUpdateClient/Operational"
"Microsoft-Windows-WindowsUpdateClient/Operational"=hex(2):25,00,53,00,79,00,73,00,74,\
00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,73,00,79,00,73,00,74,00,\
65,00,6d,00,33,00,32,00,5c,00,77,00,65,00,76,00,74,00,61,00,70,00,69,00,2e,\
00,64,00,6c,00,6c,00,00,00
Note: The "Microsoft-Windows-WindowsUpdateClient/Operational" Expanded String (REG_EXPAND_SZ) at the end there is pointing to %SystemRoot%\system32\wevtapi.dll
Once the registry was modified, I was able to query the error events as follows:
Get-WmiObject -query "SELECT * FROM Win32_NTLogEvent WHERE LogFile='Microsoft-Windows-WindowsUpdateClient/Operational' AND Type='Error'"
Somewhat of a pain considering that Windows Update errors should probably be present in the Win32_NTLogEvent WMI class by default (ah, Microsoft). Still, this essentially resolves my question.
One additional point to mention. The website above states that, upon editing the registry, you'd be able to query the new events immediately. I had to reboot my machine first.

Get-Hotfix throws Get-HotFix : Provider load failure

I have huge list of servers and workstations where I need to review patches for a specific date range. I have my command working, but there is one machine that apparently has a WMI issue, and its throwing an error, effectively aborting the entire operation. I attempted to add some command to ignore the error and keep going but nothing seems to catch and continue, it always aborts and I never see the output.
Get-HotFix -ComputerName (Get-Content .\TARGETS.txt) | Where { $_.InstalledOn -gt '7/29/2017' -AND $_.InstalledOn -lt '8/25/2017' } | sort InstalledOn
I've tried adding $erroractionpreference = 'SilentlyContinue' but that just doesn't throw the error to the screen, the hotfix list still doesn't get displayed.
You may need to trace down the process tree.
Get-Hotfix uses the Win32_QuickFixEngineering WMI class. You can usually find out provider information in PS help files or you can use wbemtest.
Once you know that information, you can check the Windows Event Viewer > View >Show Analytic and Debug logs option. Navigate to Microsoft > Windows > WMI Activity, and right click Operational log then select Enable Log from the pane on the right. Then right click the Trace log, and similarly enable.
The next time you try and run the command (or maybe in a new PS session, not sure) there should be more detailed information to help you determine the root problem.
MS Scripting Guy Ed Wilson details the process with a how-to here as well:
https://blogs.technet.microsoft.com/heyscriptingguy/2012/09/12/use-powershell-to-troubleshoot-provider-load-failure/

Programmatically updating network printer drivers

this is a deployment issue I'm hoping to solve with some simple Powershell:
When doing 32 bit Windows XP to 64 Bit Windows 7 migration, USMT is
migrating all the network printers, which is great. As the drivers
are obviously not correct though, the driver needs to be manually
upgraded (right click printer --> Update Driver).
Is there a WMI function or Powershell cmdlet for this action? I cant seem to find any
documentation on it! As our USMT task sequence is separate from the
deployment and runs under the migrated user's context I'm sure it
would work. If I could just get the right syntax, add a Powershell
script at the end of the TS that would be perfect.
I'm basically looking for the function that would have the same result as right-clicking the printer and clicking 'Update Driver'. I've cross posted here from the MDT forums as I think this would probably be more appropriate!
I've looked at Win32_Printer class but doesn't look like it has what I need.
How I understand it, doing a RC-> Update Driver is not really the correct way to manage print drivers.
Update driver is designed to update a driver from Version X to the next Version Y and not really the correct way to change the driver from a Win XP driver to a Win 7 driver (i.e. if the XP driver is at version 1.0, and the Win 7 driver is at 1.0, then running Update driver will not do anything because the versions will be the same).
The #1 and best option is to use PowerShell remove the printers, and re-add them (which will then also install the Windows 7 drivers). That way you will guarantee that they will work.
The script will be something like this:
#Get list of all the printers on the machine
$printers = gwmi win32_printer
#Save default Printer
$DefaultPrinter = $printers | where{$_.Default} | Select ShareName
#Create a list of all the printers we want to delete (in this case I am deleting all network printers)
$PrintersToDelete = $printers | where{$_.Network -eq $true}
#Create a list of all the printers we want to add (in this case, all network printers I just deleted)
$PrintersToAdd = $printers | where{$_.Network -eq $true} | Select Name
#Delete the printers I want to delete
$PrintersToDelete | foreach{$_.delete()}
#Add back all printers we want to add
$PrintersToAdd | foreach{(New-Object -ComObject WScript.Network).AddWindowsPrinterConnection($_.Name)}
#Get list of all the new printers on the machine
$printers = gwmi win32_printer
#Set the default printer
$NewDefaultPrinter = $printers | where{$_.DeviceID -match $DefaultPrinter}
$NewDefaultPrinter.SetDefaultPrinter()