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"
}
Related
I am writing a script to query what edition of Windows machines are on. So far I have the following code:
$ASSETNUM = Read-Host "Please enter a valid asset tag"
Get-WmiObject Win32_OperatingSystem -ComputerName $ASSETNUM | select PSComputerName, Caption, OSArchitecture, Version, BuildNumber | FL
if (Caption = "Microsoft Windows 10 Enterprise"){
Write-Host "This works"
} else {
Write-Host "This did not work"
}
The first part before the if statement works as intended. However, I wish to query the "Caption" to be able to run a further function afterwards. However, I'm at a loss on how to query this. The Write-Host parts are just for testing until I get this working.
Remove | FL because that is only to display stuff onto the screen.
Instead, capture the output in a variable and use that
$os = Get-WmiObject Win32_OperatingSystem -ComputerName $ASSETNUM | Select-Object PSComputerName, Caption, OSArchitecture, Version, BuildNumber
Next, use the $os variable to get the property you need, in this case you want
if ($os.Caption -eq "Microsoft Windows 10 Enterprise"){
Write-Host "This works"
}
else {
Write-Host "This did not work"
}
P.S. The = is an assignment, in case you want to compare something inside an if(), you need to use PowerShell's comparison operator -eq
I have a csv as below :
Server OS HotFixID
Comp1 Win12 KB452
Comp1 Win12 KB453
svrname3 Win8 KB134
I have written below script for checking OS and if its matched then it should check if the server is having the same HotfixID or not.
$file = Import-Csv .\Desktop\hotfix.csv
if($Win12 = $file | where {$_.os -eq "Win12"} | select Source, HotFixID)
{
Get-HotFix -ComputerName ($Win12.Source) -Id ($Win12.HotFixID)
}
else
{
$Win8 = $file | where {$_.os -eq "Win8"} | select Source, HotFixID
Get-HotFix -ComputerName ($Win8.Source) -Id ($Win8.HotFixID)
}
problem is with output.. I have 2 Win12 server in csv, but I am getting 4 output 2 as duplicate.. I am able to understand that here one nested loop is running but unable to rectify it. Please!! let me know how can we fix this issue.
Assumed I understood your task correct you should iterate over all elements in your CSV file and check each item indivually.
$CSVList = Import-Csv .\Desktop\hotfix.csv
foreach ($CSVItem in $CSVList) {
if ($CSVItem.os -eq 'Win12' -or $CSVItem.os -eq 'Win8') {
if (Test-Connection -ComputerName $CSVItem.Source) {
Get-HotFix -ComputerName $CSVItem.Source -Id $CSVItem.HotFixID
}
}
}
You have multiple entries with Win12 so $Win12 is an array of PSCustomObject. When you use ($Win12.Source) it will output an array of all sources. (Comp1,Comp1). Get-Hotfix accepts this array and tests $Win12.HotFixID (which is an array, too) with each of the sources. Thats the reason you get each Item the Number of times they apear in the CSV. To avoid this, process each line in the CSV on their own. If you want to keep your structure, your code would look like this:
if($Win12 = $file | where {$_.os -eq "Win12"} | select Source, HotFixID)
{
$Win12 | foreach {
Get-HotFix -ComputerName ($_.Source) -Id ($_.HotFixID)
}
}
else
{
$Win8 = $file | where {$_.os -eq "Win8"} | select Source, HotFixID
$Win8 | foreach {
Get-HotFix -ComputerName ($_.Source) -Id ($_.HotFixID)
}
}
However the Code of Olaf is cleaner and does the same.
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 ",""
I'm trying to verify that the file system partitions within each of the servers I'm working on are aligned correctly. I've got the following script that when I've tried running will either claim that all virtual servers are aligned or not aligned based on which if statement I use (one is commented out):
$myArr = #()
$vms = get-vm | where {$_.PowerState -eq "PoweredOn" -and $_.Guest.OSFullName -match "Microsoft Windows*" } | sort name
foreach($vm in $vms){
$wmi = get-wmiobject -class "win32_DiskPartition" -namespace "root\CIMV2" -ComputerName $vm
foreach ($partition in $wmi){
$Details = "" | Select-Object VMName, Partition, Status
#if (($partition.startingoffset % 65536) -isnot [decimal]){
if ($partition.startingoffSet -eq "65536"){
$Details.VMName = $partition.SystemName
$Details.Partition = $partition.Name
$Details.Status = "Partition aligned"
}
else{
$Details.VMName = $partition.SystemName
$Details.Partition = $partition.Name
$Details.Status = "Partition not aligned"
}
$myArr += $Details
}
}
$myArr | Export-CSV -NoTypeInformation "C:\users\a411882\Documents\Scripts\PartitionAlignment.csv"
Would anyone know what is wrong with my code? I'm still learning about partitions so I'm not sure how I need to check the starting off-set number to verify alignment.
You're passing a virtual machine object instead of a string to get-wmiObject -ComputerName. When I do that, get-wmiObject throws an RPC error. You might try -computerName $vm.guest.Hostname instead of -computerName $vm.
In the commented line, your use of % should return a remainder, which will always be a whole number or zero. Maybe you were expecting a quotient instead, and wanted to evaluate if it's an integer?
PS C:\temp> (1 / 2) -isnot [int]
True
PS C:\temp> (2 / 1) -isnot [int]
False
Recent Windows OS align their partitions automatically, so there's that. Here's a good post about alignment generally on VMware, including a link to a more detailed discussion of guest partitions.