Detecting AC Power connection in WinPE? - c++

I'm trying to determine if a laptop is connected to AC power.
The OS Im running under is WinPE.
My app is written in native C++.
WMI queries using Win32_Battery are not supported and the GetSystemPowerStatus API always returns '1' for ACLineStatus (running on AC power or not).
Any ideas?
Additonal investigation:
Just tried the API 'CallNtPowerInformation' with POWER_INFORMATION_LEVEL::SystemBatteryState. The SYSTEM_BATTERY_STATUS structure element AcOnLine also returns 1 regardless of power supply status. Probably just calls the same system level code but thought I'd add it in here.

I managed to answer my own question and it proved to be very simple in the end.
In WinPE the following noddy script returned null when executed because the battery wasn't being recognised:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Battery",,48)
For Each objItem in colItems
Wscript.Echo objItem.BatteryStatus
Wscript.Echo objItem.Caption
Next
I found a battery device driver in my PE image (\windows\inf\battery.inf) which once installed resulted in the battery being recognised and the above script returning the expected values. i.e. BatteryStatus = 2 (The system has access to AC so no battery is being discharged) or BatteryStatus = 1 (The battery is discharging i.e. AC not connected).
Driver can be installed in the PE image itself or loaded on demand. i.e. drvload

Related

Access Strucuture Sensor via OpenNI 2 from UWP App targeting Windows 10

I'd like to access the Structure Sensor (https://structure.io) via OpenNI 2 (https://github.com/occipital/openni2) from an UWP App running on a Windows 10 Desktop.
The Setup
For this very reason I created a Windows Runtime Component (Universal Windows) in C++ besides my actual UWP App. This component exports several functions basically miming the initialization behavior of one of the samples in above OpenNI Github repo.
I extended the code to also iterate through all available devices:
// Initialize OpenNI
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
logError("Initialize failed + " + std::string(OpenNI::getExtendedError()));
return false;
}
// Get all attached sensors supported by OpenNI
Array<DeviceInfo> deviceList;
OpenNI::enumerateDevices(&deviceList);
for (int i = 0; i < deviceList.getSize(); i++) {
logInfo(deviceList[i].getName());
logInfo(deviceList[i].getUri());
}
// Actual open device
Device device;
rc = device.open(deviceList[0].getUri());
if (rc != STATUS_OK)
{
logError("Error = " + to_string(rc));
logError("Couldn't open device " + std::string(OpenNI::getExtendedError()));
return false;
}
The Problem
Calling above code from my UWP app through the Windows Runtime Component is successful when initializing OpenNI and enumerating over all available devices:
[INFO] PS1080
[INFO] \\?\usb#vid_1d27&pid_0600#13261#{c3b5f022-5a42-1980-1909-ea72095601b1}
Actually Opening the device via device.open is the actual problem (Error 1 = STATUS_ERROR)
[ERROR] Error = 1
[ERROR] Couldn't open device Could not open "\\?\usb#vid_1d27&pid_0600#13261#{c3b5f022-5a42-1980-1909-ea72095601b1}": USB device not found!
I'm also under the impression that above error message is a bit misleading, as the actual message when having no device attached is:
[ERROR] Error = 1
[ERROR] Couldn't open device DeviceOpen using default: no devices found
I already tried to add a USB device capability to the package mainifest without any success.
<DeviceCapability Name="usb">
<Device Id="vidpid:1D27 0600">
<!--<Function Type="classId:ff * *" />-->
<Function Type="name:vendorSpecific"/>
</Device>
</DeviceCapability>
I also verified that above code is working when directly building a classic C++ program without targeting UWP at all.
I would be very happy for any direction/hint you can provide me with
The Solution
Microsoft's UWP policy simply doesn't allow access to USB devices. But you can workaround that by grant the UWP AppContainer Process access to the Structure IO sensor.
Some manual work is required though:
Open the registry editor and go to the USB entry of the Structure IO sensor HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_1D27&PID_0600
Uncollapse this node and right click on the node below this one and copy the whole key in to clipboard. The last digit is very important here and differs from machine to machine (e.g. HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_1D27&PID_0600\13261)
Copy this key into following registry file where the brackets are. The following registry modification basically allows every UWP app access to the structure I/O sensor.
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_1D27&PID_0600\13261]
"Security"=hex:1,0,4,90,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,2,0,60,0,4,0,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,12,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,5,20,0,0,0,20,2,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,B,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,F,2,0,0,0,1,0,0,0
Modify the following batch script to point to the full path(!) of above registry file. This script is needed to modify the registry with the security string. This is only allowed by Window's SYSTEM account. That's why we need to create a task for that.
call schtasks /create /RU SYSTEM /SC ONCE /TN DeviceAC /TR "reg import c:\full\path\to\registry\file.reg" /ST 00:00
call schtasks /run /tn DeviceAC
call schtasks /delete /tn DeviceAC /f
Run the above batch script with Administrator privileges
After successfully executing the script, make sure there's a new entry called "Security" below you node from 2.
If the sensor is already connected to your PC you'll need to reconnect it.
Now the code from my Question above should work :)
You'll find a detailed read on how to solve this problem here:
https://developer.microsoft.com/en-us/windows/iot/Samples/CustomDeviceAccessor

Install correct video driver based on PNP ID

I am very new at scripting and I need some help. I have an unattended windows XP install that I created. We use two different Nvidia cards, about 50 of each, they use different drivers. I would like to be able to install the correct driver, based on the PNP Device ID. The script below outputs the PNP Device ID, next I want to capture the PNP Device ID and install the correct driver. I just need to be able to read the PNP Device ID, then run a silent install for the correct driver and software. I need to have the full Nvidia software installed, not just the driver. Any help would be greatly appreciated.
Paul
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery _
("Select * from Win32_VideoController")
For Each objItem in colItems
For Each strCapability in objItem.AcceleratorCapabilities
Wscript.Echo "Accelerator Capability: " & strCapability
Next
Wscript.Echo "PNP Device ID: " & objItem.PNPDeviceID
Next
Const EVENT_SUCCESS = 0
I would recommend using Windows PowerShell for this, instead of VBscript. If you're new to scripting, then I'd suggest that learning PowerShell would be much more advantageous than learning VBscript. You'll be able to do a lot more, with a lot less code.
Let's move on to some code:
# If a video controller matches the string on the right of the -match operator ...
if ((Get-WmiObject -Class Win32_VideoController) -match 'VEN_10DE&DEV_0DFC') {
# ... then run this program
Start-Process -FilePath setup.exe -ArgumentList '/silent /log:"nvidia.log"';
}

Slow WMI request on Windows 2008R2

Has anyone got any suggestions to speed up this WMI query? I'm updating a client application every 5 seconds to show the CPU stats. It was much quicker on Windows 2003 but takes at least 5 seconds to return an integer for 4 CPU cores:
Private Sub GetProcessorIdleTime(ByVal Server As String)
Dim searcher As New ManagementObjectSearcher("\\" & Server & "\root\CIMV2", "SELECT LoadPercentage FROM Win32_Processor")
Dim collection As ManagementObjectCollection = searcher.[Get]()
For Each row In collection
TextBox1.Text = TextBox1.Text & vbCrLf & Convert.ToInt32(row("LoadPercentage"))
Next
End Sub
Or is there a better way to retrive this information remotely?
To improve the performance, you must re-use the WMI connection to the remote server, establishing a connection is one of the more expensive tasks when you execute a WQL sentence.
In your code you are setting a new WMI remote connection each time. So rewrite your code creating a new method to establish the remote connection and then reuse (share) the ManagementObjectSearcher object in your GetProcessorIdleTime method.

Get VPN IP address via WMI on Vista

How can we enumerate all the network connections in order to extract the IP address of the VPN connection using WMI? On XP, Win32_NetworkAdapterConfiguration works fine but on Vista it only seems to enumerate the physical connections...
If you look at the comments under the documentation for Win32_NetworkAdapterConfiguration you'll see a reference to Win32_NetworkAdapter when dealing with Vista.
'Vista only code???
Set colAdapters = objWMIService.Execquery ("SELECT * FROM Win32_NetworkAdapter WHERE NetEnabled = True")
For Each nic in colAdapters
msg = "nic.DeviceId: " & nic.DeviceId & vbCRLF _
& "nic.Name: " & nic.Name & vbCRLF _
Next
From this you should be able to retreive the InterfaceIndex and lookup the IP address from the Win32_IP4RouteTable class.
It certainly is a roundabout way of getting the information compared to using Win32_NetworkAdapterConfiguration.
Found it in the MSFT classes! Windows Specific implementation of CIM interface object:
gwmi msft_netIPAddress -Namespace 'root/standardcimv2' | format-list -Property InterfaceAlias,IPAddress

How do I listen/identify when a program runs in Windows using C++?

Specifically, I want to listen to when programs are run and record information such as: timestamp, executable, windows name and user.
Alternatively, use the WMI interface to find out what's running and take appropriate action. In the VBScript code below the WMI subsystem is being queried with Select * from Win32_Process so as to change the process priority. Find out what other attributes are available for Win32_Process and you should find stuff that's heading in the direction you want to go.
Const NORMAL_PRIORITY = 32
Const LOW_PRIORITY = 64
Const REALTIME_PRIORITY = 128
Const HIGH_PRIORITY = 256
Const BELOWNORMAL_PRIORITY = 16384
Const ABOVENORMAL_PRIORITY = 32768
Function SetPriority( sProcess, nPriority )
Dim sComputer
Dim oWMIService
Dim cProcesses
Dim oProcess
Dim bDone
bDone = False
sComputer = "."
Set oWMIService = GetObject("winmgmts:\\" & sComputer & "\root\cimv2")
Set cProcesses = oWMIService.ExecQuery ("Select * from Win32_Process Where Name = '" & sProcess & "'")
For Each oProcess in cProcesses
oProcess.SetPriority( nPriority )
bDone = True
Next
SetPriority = bDone
End Function
The most obscene way of doing this is the Google-desktop way
Namely to have your DLL load into every process that is ever started and to log information.
If you're interested more, install google desktop and watch its dll load into your processes. Then look in the registry to see it does it.
Be mindful that this is entering to the realm of virus like behaviour.
I would use the PSAPI function EnumProcesses() to periodically get a list of running processes.
You could set up a WMI permanent event subscription to monitor process creation and log the details. I have some samples here - one of the samples monitors notepad.exe creation and logs the events in a txt file. Permanent event subscription monitors events 'at all times', but if you want to monitor events 'for the duration of your application', you can use WMI COM API with C++ - the WQL event query is the same in both cases. The documentation is here.
Look into using the Perfmon API's (check MSDN for references).