23 April, 2024

Return an array from PSExec (via Powershell)

 I was 'geekily' excited, when this occurred to me this AM.

Largely because I have been frustratedly  looking for a way to deal with a limitation that PSExec presents, when I am trying to get information from a remote computer.
(More info on PSExec, which is part of the SysInternals suite, here)

When pointing a (PoSh) command at a remote computer via PSExec - Specifically one that returns a result that is an array - Capturing that returned result is not an array - It is a simple string, with multiple lines.

Parsing that returned string is certainly possible - But there are a few steps involve in parsing it.

It would be SO MUCH EASIER if that returned value was still an array... Right?!

Google searching for a way to do this... For YEARS - Has not provided anything on how to keep that array... an array...

This morning... I had a thought...

As it turns out - piping that array to 'ConvertTo-Csv' as part of the command being ran on the remote computer is the key!

Then capturing the returned CSV value and piping it to 'ConvertFrom-Csv' - and Ta-Da! It's an array!

Below is a simple example, and also a more involved sample.

In the more involved sample - I send an actual script to the remote computer and run that script.

There may be a better way to run a multiple line script via PSExec - I am not sure...

But the way I am doing it does make it much easier - If only that I don't have to 'escape' all of the quotes (") and dollar signs ($), with tilde marks (`) all over it (as seen in the simple example).

I certainly am open to suggestions...
(As always - Forgive me for using aliases for commands, that is just how I roll...)

NOTE: I have been in the habit of using this '.split()' for a while, on strings - Just to clean up 'array to string' situations, that invariably end up with leading and trailing spaces:
($Args).Split("`n|`r",[System.StringSplitOptions]::RemoveEmptyEntries) 

$Computer_Name = "<hostname>"

$DiskInfo = (C:\SysInternals\PsExec.exe -s -nobanner \\$Computer_Name /accepteula cmd /c powershell.exe `
"& { get-WmiObject win32_logicaldisk | ? {`$_.DeviceID -eq 'C:'} | Select FreeSpace, Size | ConvertTo-Csv }"`
 2> $null) | ConvertFrom-Csv

######## A more involved example #########

$CMD = 'C:\SysInternals\PsExec.exe -s -nobanner \\$Computer_Name /accepteula cmd /c powershell.exe "& { $C_Line }" 2> $null'

$RAM_Report = @'
$DiskInfo = get-WmiObject win32_logicaldisk | ? {$_.DeviceID -eq 'C:'} | Select FreeSpace, Size 

Get-ComputerInfo | Select `
@{ N = 'Hostname';  E = { $_.CsDNSHostName } },`
@{ N = 'Username';  E = { $_.CsUserName } },`
@{ N = 'Last Boot'; E = { $_.OsLastBootUpTime } },`
@{ N = 'RAM';       E = { "$([math]::round($_.CsPhyicallyInstalledMemory /1MB, 3)) GB" } },`
@{ N = 'Free RAM';  E = { "$([math]::round($_.OsFreePhysicalMemory /1MB, 3)) GB" } },`
@{ N = 'UpTime';    E = { "$($_.OsUptime.Days) Days(s), $($_.OsUptime.Hours) hour(s)" } },`
@{ N = 'DiskSize';  E = { "$([Math]::Round($DiskInfo.Size / 1GB,2)) GB" } },` 
@{ N = 'FreeSpace'; E = { "$([Math]::Round($DiskInfo.FreeSpace / 1GB,2)) GB" } },` 
@{ N = '%Free';     E = { "$(([Math]::Round(($DiskInfo.FreeSpace) / ($DiskInfo.Size),3)) * 100)%" } } | ConvertTo-Csv 
'@
########################################
$OutFilePath = "\\$Computer_Name\c$\Users\Public\Downloads\RAM_Report.txt" 
$RAM_Report | Out-File $OutFilePath -Force

$C_Line = "iex ((New-Object System.Net.WebClient).DownloadString('C:\Users\Public\Downloads\RAM_Report.txt'))"
$Remote_Info = (iex $CMD).Split("`n|`r",[System.StringSplitOptions]::RemoveEmptyEntries) | ConvertFrom-Csv

No comments:

Post a Comment