I am trying to create a function that goes through the array $packages to uninstall multiple built in applications that come with new PCs. When running this script I am receiving an error "null-valued expression" At line 6 char 3 $app.Uninstall(). Any see where i went wrong?
foreach($package in $packages){
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "$package"
}
$app.Uninstall()
}
Related
I'm new to powershell and am trying to write a program that will get the product key of numerous servers.
I am looping through the server names and trying to do the following code but am getting the error in the title
$LicenseInfo = Get-WmiObject -Class SoftwareLicensingProduct -ComputerName $target -Credential $cred | `
Where-Object { $_.PartialProductKey -and $_.ApplicationID -eq "55c92734-d682-4d71-983e-d6ec3f16059f" } | Select-Object PartialProductKey, Description, ProductKeyChannel, #{ N = "LicenseStatus"; E = { $lstat["$($_.LicenseStatus)"] } }
Any help would be appreciated
That error is very specific. Are you targeting machines that do not have this class available? As per learn.microsoft.com for SoftwareLicensingProduct:
Minimum supported client: Windows 7
Minimum supported server: Windows Server 2008 R2
I'm trying to downgrade TPM on several HP laptops. I'm attempting to create a powershell script that will grab the TPM Manufacturer Version number, and check that number against a list of possible numbers. Once it matches one of those number execute the program to downgrade the TPM version.
I started with throwing the output into a variable, and attempting to check the variable against a static number to start the correct program. The variable is stored, but when I try to check it against "7.61" it doesn't seem to be actually checking the result. The result of 7.61 is not returning "Success"
I realize powershell is different, and my IF ELSE statements are probably just outdated. Any help would be very appreciated!
Assume TPM ManufacturerVersion is 7.61
$variable = get-WmiObject -Namespace root\cimv2\security\microsofttpm -Class Win32_Tpm | Select-Object ManufacturerVersion | Out-String
if($variable -eq "8"){
Write-Host "success"
}else{
Write-Host "Fail"
}
enter image description here
You are comparing strings, rather than 'versions'. If you are only checking for simple equality, then using a direct string comparison will do:
PS C:\> "10.5" -eq "10.5"
True
However, if you want to determine, say, if one version is greater than another, strings won't work. For example:
PS C:\> "100.5" -gt "55.3"
False
In that case, you should cast the version strings to actual Version types, then the comparison will work properly. For example:
$tmp = Get-WmiObject -Namespace "root\cimv2\security\microsofttpm" -Class Win32_TPM
if ([Version]$tmp.ManufacturerVersion -eq [Version]"8.0")
{
"Success"
}
else
{
"Fail"
}
Also, if you need to compare the TPM version against multiple possibilities, then a switch statement makes for neater code:
$tmp = Get-WmiObject -Namespace root\cimv2\security\microsofttpm -Class Win32_TPM
Set-Location "C:\Users\ADministrator\Desktop\TPM Downgrade"
switch([Version]$tmp.ManufacturerVersion)
{
{$_ -eq [Version]"7.62"} { '.\7.62 downgrade.cmd'}
{$_ -eq [Version]"7.61"} { '.\7.61 downgrade.cmd'}
{$_ -eq [Version]"7.60"} { '.\7.60 downgrade.cmd'}
{$_ -eq [Version]"7.41"} { '.\7.41 downgrade.cmd'}
{$_ -eq [Version]"7.40"} { '.\7.40 downgrade.cmd'}
default {"Unable to find downgrade BIN for your firmware version"}
}
Try this one
$variable = get-WmiObject -Namespace root\cimv2\security\microsofttpm -Class Win32_Tpm | Select-Object ManufacturerVersion
if($variable.ManufacturerVersion -eq "8"){
Write-Host "success"
}else{
Write-Host "Fail"
}
Thank you all for your feedback and help. This is the final product and its working great.
$tmp = get-WmiObject -Namespace root\cimv2\security\microsofttpm -Class Win32_TPM
Set-Location "C:\Users\ADministrator\Desktop\TPM Downgrade"
if ([Version]$tmp.ManufacturerVersion -eq [Version]"7.62"){
& '.\7.62 downgrade.cmd'
}elseif ([Version]$tmp.ManufacturerVersion -eq [Version]"7.61"){
& '.\7.61 downgrade.cmd'
}elseif ([Version]$tmp.ManufacturerVersion -eq [Version]"7.60"){
& '.\7.60 downgrade.cmd'
}elseif ([Version]$tmp.ManufacturerVersion -eq [Version]"7.41"){
& '.\7.41 downgrade.cmd'
}elseif ([Version]$tmp.ManufacturerVersion -eq [Version]"7.40"){
& '.\7.40 downgrade.cmd'
}else{
Write-Host "Unable to find downgrade BIN for your firmware version"
}
I have the following script to find the process "dotnet.exe". In my system, I have many dotnet.exe processes running. But I want to kill the "dotnet.exe" which has command line argument "MyService\Web\argument". I'm trying to do it by the following script. But it doesn't find anything, although I see the process in the Task Manager.
$process = Get-WmiObject Win32_Process | select name, commandline
foreach ($p in $process)
{
if ($p.name -contains "dotnet.exe" -and $p.commandline -contains "web")
{
$kp = Get-Process $p;
$kp.CloseMainWindow();
if (!$kp.HasExited)
{
$kp | Stop-Process -Force
}
}
else
{
Write-Host name: $p.name and param: $p.commandline;
}
}
All you need to do is filter the process list directly via Get-WmiObject and then terminate the matching process(es):
$fltr = "name like '%dotnet.exe%' and commandline like '%web%'"
Get-WmiObject Win32_Process -Filter $fltr | ForEach-Object {
$_.Terminate()
}
You could also call Terminate() directly on the output of Get-WmiObject like this:
(Get-WmiObject Win32_Process -Filter $fltr).Terminate()
However, there are situations where this could fail, e.g. if Get-WmiObject doesn't return any results, or if you're using PowerShell v2 or earlier and Get-WmiObject returns more than one result (passing a method call to the members of an array requires member enumeration, which was introduced with PowerShell v3). Using a ForEach-Object loop is both more robust and backwards-compatible.
The Get-WmiObject cmdlet returns quite useful objects, but you have stripped off everything by selecting only the Name and CommandLine parameters:
$process = Get-WmiObject Win32_Process | select name, commandline
If you remove the | select name, commandline part, you can still loop through each process but also make use of methods like Terminate() that will still be available.
You could do it in one shot, as per #ansgar-wiechers comment, or still make use of the loop and add in more logging, etc. if you wanted:
$process = Get-WmiObject Win32_Process
foreach($p in $process){
if($p.Name -eq "*dotnet.exe" -and $p.CommandLine -like "*web*"){
$p.Terminate()
# and so on...
}
}
Note also the comment from #TheIncorrigible1 about the use of comparison operators. I have used -eq for the process name and -like for the command line.
I am querying remote servers for their operating system. I know that I can return the Version, but I want to replace these values with the friendly name. The code I have so far is:
$Computer = (gc c:\servers.txt)
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $Computer -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
If ({$BuildVersion.Version -match "5.2.3790"})
{$Build="2003"}
Elseif ({$BuildVersion.Version -match "6.1.7601"})
{$Build="2008"}
Elseif ({$BuildVersion.Version -like "6.3.9600"})
{$Build="2012"}
But this doesn't seem to work and only returns "2003" regardless. Please help, I'm fairly new to PS and coding.
thanks
The problem is your if statements. Putting the Boolean expression inside squiggly brackets makes it a script block, and that's going to get cast as a string before being cast as a Boolean. Strings cast to Booleans always evaluate to true unless they're empty.
PS C:\> {$BuildVersion.Version -match "5.2.3790"}
$BuildVersion.Version -match "5.2.3790"
PS C:\> ({$BuildVersion.Version -match "5.2.3790"}) -as [bool]
True
PS C:\> $BuildVersion.Version -match "5.2.3790"
False
PS C:\> ($BuildVersion.Version -match "5.2.3790") -as [bool]
False
So what you're running is essentially:
if ([bool]'$BuildVersion.Version -match "5.2.3790"') [...]
And that's always going to be true.
Try:
$Computer = (gc c:\servers.txt)
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $Computer -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
If ($BuildVersion.Version -match "5.2.3790")
{
$Build = "2003"
}
Elseif ($BuildVersion.Version -match "6.1.7601")
{
$Build = "2008"
}
Elseif ($BuildVersion.Version -like "6.3.9600")
{
$Build = "2012"
}
Bottom line is that squiggly brackets are not parentheses and you can't use them like they are.
However, there's also a major logic error here. You're potentially fetching an array for $BuildVersion because you're reading from a file, but then you treat it like a single value. You never loop through $BuildVersion. However, I do not have enough information about what you're actually trying to do with your script (like what you do with $Build) to be able to fix that.
I originally said this, but I've since changed my mind
The reason this is only returning 2003 is that you're only running your If code on a single entry in the list.
Wrong
As TessellatingHeckler says, the reason your if wasn't working is that you had too many curly braces, so PowerShell wasn't actually evaluating your logic.
However, you still need to step through each of the computers to do what you're trying to do. We'll do that by adding in a ForEach loop. I also went ahead and replaced your If {} logic with a Switch statement, which I think is easier to understand for a scenario like this with multiple clauses. If's just get way too verbose.
Finally, I'm assuming you want to output the results too, so I added a custom object here, which is just a way of choosing which properties we want to display.
$Computer = (gc c:\servers.txt)
ForEach ($system in $computer){
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $system -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
switch ($build){
"5.2.3790" {$Build="2003"}
"6.1.7601" {$Build="2008"}
"6.3.9600" {$Build="2012"}
}
#output results
[pscustomobject]#{Server=$system;OSVersion=$build;CSName=$buildVersion.CSname}
}#EndOfForEach
Output
>Server OSVersion CSName
------ --------- ------
dc2012 2012 DC2012
sccm1511 2012 SCCM1511
You can use this:
Get-WmiObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty Caption
Additionally you can see everything this WMI object holds like this:
Get-WmiObject -Class Win32_OperatingSystem | fl *
Edit: if you want to remove some text from the string, you can use -replace:
(Get-WmiObject -Class Win32_OperatingSystem |
Select-Object -ExpandProperty Caption) -replace "Microsoft Windows Server ",""
This is on a Windows XP pro System (yeah I know old OS)
I have been searching for a way to get a list of all devices that do not have drivers installed, or there are problems with the drivers in use.
I have tried
$foo = Get-WmiObject Win32_PNPEntity | Where-Object{$_.ConfigManagerErrorcode -ne 0}
The problem with this, is it does not seem to get all exceptions.
For instance, a HP laptop that has a finger print scanner
shows in device manager as other device - USB Device.
This was not detected using the one liner I listed.
is there a way to get an array of the missing drivers using powershell?
#For formatting:
$result = #{Expression = {$_.Name}; Label = "Device Name"},
#{Expression = {$_.ConfigManagerErrorCode} ; Label = "Status Code" }
#Checks for devices whose ConfigManagerErrorCode value is greater than 0, i.e has a problem device.
Get-WmiObject -Class Win32_PnpEntity -ComputerName localhost -Namespace Root\CIMV2 | Where-Object {$_.ConfigManagerErrorCode -gt 0 } | Format-Table $result -AutoSize
Error Codes in Windows Device Manager :- https://support.microsoft.com/en-us/kb/310123
Win32_PNP Entity Class : https://msdn.microsoft.com/en-us/library/aa394353(v=vs.85).aspx
I did this when i had some devices that where not being picked up by my script , give it a try and see if it detects your devices.
$foo = Get-WmiObject Win32_PNPEntity | Where-Object{$_.Availability -eq 11 -or $_.Availability -eq 12}