WMI BatteryStatus from Windows Server 2012 using Powershell - powershell

I'm writing a Powershell script to do some server management when we have a power outage. Presently the script is using the WMI Win32)Battery class to see if BatteryStatus is a 1 (discharging) or a 2 (unknown (on A/C)) but I am not sure this is the best method. There are several statuses that could be true at the same time.
For example, the battery could be Discharging (1) and Partially Charged (11) or On AC (2) but Critical (5) or charging (6) or Partially Charged (11). This doesn't make sense to me. Is BatteryStatus reliable for my intended purpose? How does Windows determine which status is returned? In my testing I've not seen anything other than statuses of 1 or 2.
The documentation for Win32_Battery indicates Availability might also be an indicator that we are on battery. Is that a better way to go, maybe a combination of BatteryStatus and Availability?
In my search for answers I came across what looks like the perfect answer, using "PowerOnline" from the undocumented BatteryStatus class in the root\wmi namespace. This works great from my laptop but I get the following error when trying to access it from our Windows 2012 server:
PS C:\Windows\system32> gwmi -Class batterystatus -Namespace root\wmi
gwmi : Invalid class "batterystatus"
At line:1 char:1
+ gwmi -Class batterystatus -Namespace root\wmi
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Is this class not available on servers?
So using WMI, what is the most reliable way to know if I am on UPS battery or AC Power?

Related

How do I attach a debugger to a process using Invoke-WmiMethod?

I have a process already running on a remote computer and I'd like to attach a debugger to it. I would like to use Invoke-WMIMethod so that when I disconnect from that remote session, the debugger will remain attached to the process in the background.
So far I have:
$Qry = "Select * from Win32_Process where ProcessID like $ID"
$CimIO = Get-WMIObject -Query $Qry
Invoke-WMIMethod -InputObject $CimIO -Class Win32_Process -Name AttachDebugger -AsJob
And I'm getting the following error:
Invoke-WmiMethod : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ Invoke-WmiMethod -InputObject $CimIO -Class Win32_process -Name Attac ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-WmiMethod], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeWmiMethod
Am I on the right track? When I try other Methods from Win32_Process (like GetOwner), I get the same error message. What's going on here?
EDIT:
Perhaps I am going about this all wrong: My understanding was that the query would return a pointer to the running process which could then be used as an input object to Invoke-WmiMethod.
Debug-Process requires that a separate debugger already be downloaded and installed on the machine whereas "AttachDebugger" as a method is installed by default (at least I'm assuming since it was on a fresh copy of Windows 10). The reason why I want to use built-in methods only is because I would like this script to be usable in a production environment where I will not have control over what's installed on the computers.
I found the method by running the script found here which found the method residing in Win32_Process. I went with Invoke-WmiMethod because when -AsJob is invoked, it creates a job locally on the remote computer where the process I'm sending to a debugger resides.
Thank you for the help and I'm sorry for the confusion: this is part of my first powershell script.
The use case is follows:
In a SIEM environment the user sees a program on the network acting suspicious. The user then remotely logs into the victim computer and freezes the suspicious thread by sending it to a debugger. The user then logs out and will get back to analyzing the thread later. The thread will remain frozen until that time.
I've personally never tried or had a reason to try this use case.
However, AsJob is used for long running tasks. You are only querying to get a listing of a single Process ID and once that listing is provided, the job is done / stopped / completed.
There is nothing to attach to. Lastly, where are you getting this method --- AttachDebugger -- from?
There is no such method using the Get-WmiObject or Invoke-WmiMethod cmdlet parameters. That is what the error is about
Why are you not just using the built-in cmdlet for this effort.
# get function / cmdlet details
(Get-Command -Name Debug-Process).Parameters
Get-help -Name Debug-Process -Examples
Get-help -Name Debug-Process -Full
Get-help -Name Debug-Process -Online

Tigger installation in software center using SCCM 2012 & Powershell

I would need some directions where to look for an solution.
I need to trigger install on a few programs in SCCM 2012 software center on Windows 10 clients through Powershell. I guess some of those are User Based Packages(not sure about this at all) but when i run the following.
$Application = Get-CimInstance -Namespace "root\ccm\clientSDK" -ClassName CCM_application
$Application
I get some of the programs, but many of them is missing.
If I open software center and click install on any programs manually it will then appear when I use the command above.
I've been reading about CCM-Application I found something about you only get device based packages.
I cannot access any servers so accessing CMApplicationCatalog is not possible. Like in the links below.
Trigger available application catalog
install-user-based-application-or-packages
In my case using CCM_Application Client WMI Class seems to be hard, I've not found any other solutions then creating New-WebServiceProxy to do this, and I´m not allowed/have permissions to.
I've tried to get the needed parameters for one of the programs that don't appear with the code above from a computer I've installed it on through Software Center.
When I try to run it with the needed parameters on an new installed computer.
$Program = #{"EnforcePreference"=[UInt32]0
"Id" = [String]"ScopeId_MyScopeID, will leave this out for company rules."
"IsMachineTarget" = [Boolean]$false
"IsRebootIfNeeded" = [Boolean]$false
"Priority" = [String]"High"
"Revision" = [String]"7"
}
Invoke-CimMethod -Namespace Root\ccm\clientSDK -ClassName CCM_application -MethodName "Install" -Arguments $Program
I then get error below
Invoke-CimMethod : Not found At line:1 char:1
+ Invoke-CimMethod -Namespace Root\ccm\clientSDK -ClassName CCM_applica ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Root\ccm\clientSDK:CCM_application:String) [Invoke-CimMethod],
CimException
+ FullyQualifiedErrorId : HRESULT 0x80041002,Microsoft.Management.Infrastructure.CimCmdlets.InvokeCimMethodCommand
Maybe I am doing something wrong or what I am trying to do is not possible.
I've also tried uiresource.uiresourcemgr but It returns empty.
I used this much in SCCM 2007 and it worked great. But now it's not giving me anything.
$RunAdvProg = New-Object -ComObject uiresource.uiresourcemgr
$RunAdvProg.GetAvailableApplications();
With this said, Is there anyway way around this or does it exist another function/Method from another class or DLL?

BizTalk 2016 wmi query failing

In our Powershell deployment scripts we terminate inflight instances identified by the following query:
get-wmiobject -namespace Root\MicrosoftBizTalkServer -query "SELECT * FROM MSBTS_ServiceInstance WHERE (ServiceClass = 1 OR ServiceClass = 64) AND AssemblyName LIKE 'Our.AssemblyName'"
For some reason this has stopped working on a Windows 2016 server, failing with this message:
get-wmiobject : An internal failure occurred for unknown reasons.
At line:1 char:1
+ get-wmiobject -namespace Root\MicrosoftBizTalkServer -query "SELECT * ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Some searching has pointed to recent OS security patches. We uninstalled the KB mentioned from all nodes.
The above query runs without failure on 2 nodes in one environment and 1 node in another. This one box still gives the above error. Not sure what caused the original problem but maybe the uninstall did not clean up properly.
Any ideas where to start looking to fix the problem? I was thinking maybe installing the patch again and uninstalling it to make sure it cleans up properly. It takes about 4 hours for the VM to boot after the uninstall so testing such theories take a long time.
Turns out we have auto patching that kept re-applying the patch. What added to the confusion was the patch number being different for each OS and then there is the 4 hour thing that made it really difficult to poke the issue.
On 2016 it is KB4345418 that is causing the problem.

Win32Shutdown Generic Failure

I am putting together a script which will log off VDI sessions which have been in a disconnected state for over 10 hours. I have managed to get everything together except for the last hurdle - actually forcing a logoff.
ForEach ($Desktop in $VDIlist)
{
$win32OS = Get-wmiobject win32_operatingsystem -ComputerName $desktop.'DNS Name' -EnableAllPrivileges
write-host "Shutting down host $Desktop."DNS Name""
$win32OS.Win32Shutdown(4)
}
This results in the error below.
Exception calling "Win32Shutdown" : "Generic failure "
At line:1 char:1
+ $win32OS.win32shutdown(4)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WMIMethodException
This does not appear to happen when no argument is used
($win32os.win32shutdown()), but this also does not force the log off like I require.
As far as I have read the -EnableAllPrivileges parameter should allow for the remote log off and it does work if I have a live PCoIP session to the VDI I am attempting to shutdown but not when in a disconnected state.
Could anyone point me in the right direction?
Still not entirely sure why the first script is giving an error but I have instead switched to using VMWare View's built in PowerCLI snapin to produce the same result - just faster and more efficiently.
get-remotesession -state "Disconnected" | Where-Object {($_.duration -match 'Day' -or $_.duration -match '\d\d hours')} | Send-SessionLogoff
This will query the Horizon view server for any sessions with the "Disconnected state", it will then filter out any objects that have had a lifetime of less than 10 hours and log off anything that is left.
This requires VMware View PowerCLI PSSnippets to be loaded and connected to your view connection broken.

Delete a SCCM collection from the command-line

When using the UI (SCCM 2012), to be able to delete a collection (let's say CollA), you need first to ensure it is not linked by any rule to another (let's say CollB, etc..) such as :
CollB includes CollA
CollC excludes CollA
When dealing with a lot of collections, deleting a collection can be time-consuming. For that reason, I have created a script,
usable remotely to avoid the need to connect through RDP
which checks that CollA has no rule left (even if that is not a problem if we want to delete CollA)
which checks if CollA is "linked" to other collections (include or exclude rules)
which deletes any rule found (between CollB and CollA, between CollC and CollA)
I'm stuck now for I can not find a way to delete CollA.
For authentication matters and for remote purpose, I use a lot Powershell and WMI.
$CollA=Get-WmiObject -computername servername -namespace root\sms\site_111 -credential $cred -query "select * from SMS_Collection where Name='Tartempion'"
$CollA.get()
At that point, I found a method Delete(), which when I try to use it, it gives me :
Exception calling "Delete" with "0" argument(s): "Generic failure "
At line:1 char:1
+ $coll.delete()
+ ~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
If that is the method that I should use, what are the arguments to be passed ?
EDIT 1
As pointed by theMadTechnician, the SCCM collection, once retrieved in $CollA, a System.Management.ManagementObject.
I should, as described in the MSDN pages, be able to use the following method :
Delete() > produces the error mentioned above
Delete(DeleteOptions) > I can not find the specs for the required options
Delete(ManagementOperationObserver) > I can not find the specs for the required options
To ensure I properly understood the MSDN page regarding *.Delete(), i tried (successfully) the following:
PS C:\> Set-WmiInstance -Class win32_environment -argument #{Name="testvar";VariableValue="testvalue";UserName="<SYSTEM>"}
PS C:\> (gwmi -class win32_environment -filter "Name='testvar'").gettype()
PS C:\> (gwmi -class win32_environment -filter "Name='testvar'").delete()
EDIT 2
The fact is that when deleting a SCCM collection through the console, the collection is not the only thing removed from the inventory : the assignments for instance, are too removed. It reminds of the CASCADE switch when dealing with MySQL or ORACLE. Maybe what I'm trying to do is not possible
without using the console
without using the SCCM cmdlets
If it can not be done that way, I just need to be sure.
EDIT 3
After some maturing, I am starting to wonder if it could be a authorization matter. I mean, the account I am using with the "-credential" switch or when connecting to the server, to open a SCCM console, allows me to create/update/delete collection but, for instance, it does not allow me to delete a device. I would expect the error message to be different but who knows ?
More or less about the same matter (sorry for the digression), trying to remove a device from the commandline, I found this and I have the same error message (see above). If it works for others and not me, could it be authorization related ?
EDIT 4
I requested a service account with more "privileges" than I have with my technical account.
I tested and I have the same error. I am putting aside the authorization hypothesis.
I just tested this in our SCCM 2012 environment by using the following command:
$CollA=Get-WmiObject -computername servername -namespace root\sms\site_111 -query "select * from SMS_Collection where Name='Tartempion'"
Basically, take the -credential out of there. Does it work now?
You could potentially setup a script like so:
#if the delete command fails...
if(!($?))
{
$limitedcollectionName = $colla.LimitedCollectionName
$limitedcollection = Get-WmiObject -computername servername -namespace root\sms\site_111 -query "select * from SMS_Collection where Name=`'$limitedcollectionname`'"
$limitedcollectionname.delete()
}