Faster way to retrieve remote SMS WMI Query in PowerShell - sms

I'm trying to execute an SMS WMI query (now 2012, formerly 2007 with VBS) and it's sometimes taking up to 20 minutes (overseas) and 5-10 minutes (system is downstairs) when using the Get-WMIObject command. I know how to make a faster call in VBS:
lLocator = CreateObject("WbemScripting.SWbemLocator")
gService = lLocator.ConnectServer(Form1.strSQLServer, "root/sms/site_" & Form1.strSiteCode)
'Query for Distribution Points and populate drop down list
colItems = gService.ExecQuery("select PackageID, SourceNALPath from SMS_PackageStatusDistPointsSummarizer where PackageID='" & listBootImage.SelectedItem.ID & "'")
For Each objItems In colItems
ListDistPoint.Items.Add(UCase(Mid(objItems.SourceNALPath, InStr(objItems.SourceNALPath, "\"))))
If InStr(objItems.SourceNALPath, Mid(Form1.strSQLServer, 1, (InStr(Form1.strSQLServer, ".") - 1))) Then
ListDistPoint.SelectedIndex = ListDistPoint.Items.Count - 1
End If
Next
And in PS this is the call I'm making:
invoke-command {Get-WmiObject -namespace root\sms\site_<sitecode> -class SMS_PackageStatusDistPointsSummarizer -computername '<compname>' -property "PackageID","SourceNALPath" | where {$_.PackageID -eq '<pkgname>'} |Select PackageID, SourceNALPath}
or this:
Get-WmiObject -namespace root\sms\site_<sitecode> -class SMS_PackageStatusDistPointsSummarizer -computername '<compname>' -property "PackageID","SourceNALPath" | where {$_.PackageID -eq '<pkgname>'} |Select PackageID, SourceNALPath
and both of those are the same speed. Is there a better, ideal way to do the same thing like in the VB script (remote connect, retrieve info, then come back)? The VB script is noticeably faster. The hardware running the SCCM 2012 server is better, so I don't believe the speed is related to server performance. Also both databases contain the same sites, systems, etc.
Thank you for your help.

Try this:
Get-WmiObject -namespace root\sms\site_$sitecode `
-computername "$compname" `
-query "select PackageID, SourceNALPath from SMS_PackageStatusDistPointsSummarizer where PackageID='$pkgname'"
With your other powershell statements, you're querying for everything and then filtering locally. With the WMI query you're running in the VBS, the querying is done on the server side. There's less data to process, and it's done more efficiently.

Related

How can I uninstall Software Update (Programs and Features\Installed Updates) with Powershell

Is there a simple way of uninstalling Software UPDATES (Service Packs) listed in Programs and Features\Installed Updates with Powershell?
I am not talking about Windows Updates. But a specific software Service Pack that is listed in the same place where the win updates are.
I know how to uninstall Software that is listed in programs and features with PS
But could not figured it out how to remove the Software updates/Service Packs
this command will list all the software
Get-WmiObject -Class Win32_Product | Select-Object -Property Name
or this one
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate,UninstallString | Format-Table –AutoSize
this will remove the software but i need to remove the software Service Pack( UPDATE) only,
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "Software Name"
}
$app.Uninstall()
I have seen that post already:
How can I uninstall an application using PowerShell?
I hope that I am clear enough, thanks
long story short is that I need a command that will list or/and remove selected software UPDATES (service packs etc), thanks
any ideas, thanks
Have you tried to search for any similar topics? I found like 9+
What you're looking for is this:
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "Software Name"
}
$app.Uninstall()
or,
$app = Get-WmiObject -Class Win32_Product -Filter "Name = 'Software Name'"
pulled from: How can I uninstall an application using PowerShell?
Other useful links:
https://redmondmag.com/articles/2019/08/27/powershell-to-uninstall-an-application.aspx
https://www.slashadmin.co.uk/how-to-uninstall-programs-using-powershell/
All with the same conclusions of calling on the method to .uninstall.
for updates:
We can also use DISM for updates:
$SearchUpdates = dism /online /get-packages | findstr "Package_for"
$updates = $SearchUpdates.replace("Package Identity : ", "") | findstr "KBXXXXXX"
#$updates
DISM.exe /Online /Remove-Package /PackageName:$updates /quiet /norestart
Or native powerhsell cmdlets of Get-Package, and uninstall-package.
Made this quick script as a selection for your updates.
$Updates = Get-Package -Name "*Update*" | Select-Object -ExpandProperty Name
for($i=0; $i -lt $Updates.Count; $i++){
write-host "$($i): $($Updates[$i])"
}
$Selection = Read-Host -Prompt "Enter number of updates you would like to uninstall"
$Selection = $Selection -split " "
Foreach($Update in $Updates[$Selection]){
Uninstall-Package -Name $Update -whatif
}
Wusa.exe can also give you similar results if youre familiar with the syntax for it. Run wusa.exe /?. Ex: Wusa /uninstall /KB:KB1234567
Please note, ive only had real success in the past just uninstalling KBs using Wusa. DISM seems to work most of the time, but theres a lot of options available.

PowerShell Script works in Windows 10 but not on Windows Embedded Standard

I have the following script work in windows 10 but not on windows Embdedded Standard:
$LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
$Path1= "TEST\TESTLog_$(get-date -f yyyy-MM-dd).txt"
$AffPBS= Get-Process "LLCService.exe" | Select-Object ProcessorAffinity
$AffLC= Get-Process "LCService.exe" | Select-Object ProcessorAffinity
$AffinityLLCFinal = "LLC " + $AffPBS
$AffinityLCFinal = "LC " + $AffLC
$FinalOutput = $LogTime+" " +$AffinityLLCFinal +" " + $AffinityLCFinal
$FinalOutput | Out-File -Append $Path1
I have run the Powershell_ISE as administrator and also set Set-ExecutionPolicy RemoteSigned.
The results I'm getting on Windows 10:
10-09-2017_03-31-10 LLC #{ProcessorAffinity=63} LC #{ProcessorAffinity=63}
THe results I'm getting on Windows 7:
10-09-2017_11-23-26 LLC LC
It seems like the Get-Process isn't working on Windows Embedded Standard. Is there any other way of doing this.
Win 10 has PS version 5.1.
Win 7 could have 2.0 or 3.0. You can try to upgrade it. If not, in older Versions, you would have to use Select-object -ExpandProperty "ProcessorAffinity" instead of simply using Select-object "ProcessorAffinity".
You could also chose to run it from win 10 and specify the Win7 computer using the -ComputerName parameter of Get-Process. However, you cannot specify credentials if the win 7 requires different creds that what you are logged on with.
In that case you can use Get-WMIObject -Class Win32_Process -ComputerName "Win7Computer" -Credential $PSCredentialObject but that will give you a slightly different results. I Could not find the "Processor Affinity " Property on it.

Why is Get-WMIObject Win32_Process in Powershell so slow and what are the alternatives?

I'm creating a tool that would track the memory and cpu usage or a particular process of choice. To make the tool precise I wanted need to track the resources closely, probing for them every, 50ms let's say.
An assumption was made that anything happening inside a modern computer (excluding network IO, user input) will not take more time than that (if it's not a big computation it should be very fast). I was wrong, and the Get-WMIObject CMD'let takes way more to return results, please compare:
time { Get-WMIObject Win32_Process -Filter "ProcessId='24380'"} -Samples 10 -Silent
# ..........
# Avg: 190.5335ms
# Min: 180.3689ms
# Max: 203.6968ms #>
-
time { get-process -name *chrome* 2> $null } -Samples 10 -Silent
# ..........
# Avg: 5.2ms
# Min: 3.7711ms
# Max: 13.5161ms #>
Questions: why is it so slow and what can I do about it (the main motivation being to use private working set and many other metrics that Get-WMIObject provides inside my tool). Would interacting with Win32_PerfRawData_PerfProc_Process from a C/C++/C# utility be a good alternative to using it in Powershell?
Not to sound pessimistic or anything, but in powershell there's slow and there's slower. Use measure-command to find the time it takes for "stuff" to run.
Usage:
Measure-command { Get-WMIObject Win32_Process -Filter "ProcessId='24380'"}
The "modern" way of interacting with the wmi store is to use CIM instances. See if that's faster for you using the time method you're using or measure-command.
Example:/
Measure-Command {Get-Ciminstance -classname Win32Process -filter "processID='24380'"}

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()

Powershell 3.0 : Alternative to "Get-Volume"

I'm trying to get various properties for each hdd-volume on the computer.
I was using the cmdlet get-volume and then walking through it via foreach, but that cmdlet does not exist in Windows Server 2008. :(
Does anybody know an alternative?
I just need the drive letter, objectId/guid, free space, total space, and the name of each volume.
The WMI class Win32_Volume has the information you are looking for
Get-WMIObject -Class Win32_Volume | Select DriveLetter,FreeSpace,Capacity,DeviceID,Label
Which a little fancy footwork you can make the drive space properties looking a little more appealing.
Get-WmiObject -Class Win32_Volume |
Select DriveLetter,
#{Label="FreeSpace (In GB)";Expression={$_.Freespace/1gb}},
#{Label="Capacity (In GB)";Expression={$_.Capacity/1gb}},
DeviceID,Label |
Format-Table -AutoSize
Get-Volume is only in Powershell 4.
You can do this tho:
Get-WmiObject Win32_LogicalDisk | Select-Object DeviceID, Size, FreeSpace, VolumeName

Resources