The seemingly simple problem
I could not believe what a total pain in the ass this was to resolve. I tried getting the CPU and Memory utilization via CMD but that produced incredibly unreliable results. The biggest problem being that division operations in CMD will only return integers so I was getting very weird results. Yes there is a way around this, but it was more of a hassle so I gave up and looked to PowerShell to save the day when CMD fails. However PowerShell has its own problems, there was a reason I was using CMD and that was because I needed to be able to call a batch file from a program that would only execute CMD commands.
The somewhat simple solution
The solution here, once all is said and done, is pretty simple – but getting to this point was NOT simple. There was a lot of frankensteining, google coding and asking coworkers questions. Anyhow below is the solution for those of you who just need to make things work, I am going to explain each part below the code for those interested in the break down.
Batch file component
You need this to call the PowerShell script from CMD in a single execution.
@echo off REM Get the current directory where this is being executed set ThisScriptsDirectory=%~dp0 REM Get the name of the current batch file and append .ps1 to the name set PowerShellScriptPath=%~dpn0.ps1 REM execute the target powershell file PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File """"%PowerShellScriptPath%"""" ' -Verb RunAs}";
PowerShell component
If you just want to run the PowerShell script, then this is all you need.
$c = $env:computername #Use the current computer $path = "C:\SaveYourReadingHere\Reading.txt" #Manually specify where you are saving your data, I tried getting the current directory but it was more complicated than necessary #I borrowed elements of this elegant solution from here: https://stackoverflow.com/a/18091659/603807 $avg = Get-WmiObject win32_processor -computername $c | Measure-Object -property LoadPercentage -Average | Foreach {$_.Average} $mem = Get-WmiObject win32_operatingsystem -ComputerName $c | Foreach {"{0:N2}" -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize)} #In my case I needed the data to be a CSV $a = ($avg.ToString() + "," + $mem.ToString()) #Write data to a file, the encoding part here is very important otherwise your file may not be readable by some programs Out-File -FilePath $path -InputObject $a -Encoding ASCII
How does this work?
The idea here is that you are going to call the batch file which is going to call the PowerShell script, but there is only one caveat with the way I have things configured. You have to name your batch file the same thing as your PowerShell script to make this seamless. This honestly just makes life easier. Do you have to do it this way? No, but again it’s just easier.
Example:
- Create a batch file named “GetCpuAndMemoryReadings.bat”
- Create a PowerShell script named “GetCpuAndMemoryReadings.ps1”
- Make sure to explicitly specify where you are saving your readings file. I used a flat file to save the results because propagating the output back to CMD was a total paint in the ass. Again not worth the time to figure it out (like a lot of things in PowerShell I find is the theme).
- When you run the batch file from CMD your reading will be outputted to the flat file.
- If you have another process that needs to consume the data, read the flat file you just produced
Credit where credit is due
- The PowerShell script is largely adapted from this SO answer: https://stackoverflow.com/a/18091659/603807
- My coworker gave me the batch file solution, I had no idea you could do that – it is very useful for calling PowerShell scripts