1

So my question is how do I run a PowerShell script in python, with passable variables from python, then have the python run the PowerShell script, and then from there have specific variables from the PowerShell script pass to the python script.

What I have already is each code working separately. As you can see I am passing in hidden variables from a .ini file and from there I am trying to pass the compList to Powershell.

I am not confident that I am running the command right to call PowerShell and pass the args in my python script

preferences = configparser.ConfigParser()
preferences.read('config.ini')

hostName = preferences.get('Directory', 'hostName')
port = preferences.get('Directory', 'port')
serviceName = preferences.get('Directory', 'serviceName')
usr = preferences.get('Credentials', 'userName')
pswrd = preferences.get('Credentials', 'password')
compList = preferences.get('ComputerList', 'compList')
compList = list(compList.split(","))

p = subprocess.Popen(["powershell.exe", r"C:\Users\pecorgx\TestPS1.ps1", 'arg1 @("compList")'], stdout=sys.stdout)
p.communicate()

My PowerShell Script:

$ArrComputers =  $arg1


Clear-Host
foreach ($Computer in $ArrComputers) 
{
    $computerSystem = get-wmiobject Win32_ComputerSystem -Computer $Computer
    $computerBIOS = get-wmiobject Win32_BIOS -Computer $Computer
    $computerOS = get-wmiobject Win32_OperatingSystem -Computer $Computer
    $computerCPU = get-wmiobject Win32_Processor -Computer $Computer
    $hdds = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter drivetype=3
        write-host "System Information for: " $computerSystem.Name -BackgroundColor DarkCyan
        "-------------------------------------------------------"
        "Manufacturer: " + $computerSystem.Manufacturer
        "Model: " + $computerSystem.Model
        "Serial Number: " + $computerBIOS.SerialNumber
        "CPU: " + $computerCPU.Name
        foreach ($computerhdd in $hdds) { "HDD Drive Letter: " + $computerhdd.DeviceID + "HDD Capacity:" + "{0:N2}" -f ($computerHDD.Size/1GB) + "GB" + " HDD Space: " + "{0:P2}" -f ($computerHDD.FreeSpace/$computerHDD.Size) }
        "RAM: " + "{0:N2}" -f ($computerSystem.TotalPhysicalMemory/1GB) + "GB"
        "Operating System: " + $computerOS.caption + ", Service Pack: " + $computerOS.ServicePackMajorVersion
        "User logged In: " + $computerSystem.UserName
        "Last Reboot: " + $computerOS.ConvertToDateTime($computerOS.LastBootUpTime)
        ""
        "-------------------------------------------------------"
}

I think I am passing this correctly but I want the Powershell to pass back to my python script

$computerSystem.TotalPhysicalMemory/1GB
$computerSystem.Manufacturer
$computerSystem.Model
$computerBIOS.SerialNumber
$computerCPU.Name

and I want this var $computerHDD.Size/1GB to be passed into a list to be also passed to my python script

EDIT: I decided to just use .txt to pass commands. I made $myOBJ = "" | Select "computer" then made $myOBJ.computer = [string](....) with (...) being things I want to pass back out after the script has ran Would love to know a solution to use without having a third party help

  • If you have the powershell script print out json, you should be able to deserialize that in python pretty easily – xdhmoore Apr 13 '21 at 21:25
  • And by "print out" I mean to std out, not a file. – xdhmoore Apr 13 '21 at 21:26
  • This looks relevant: https://stackoverflow.com/questions/4537259/python-how-to-pipe-the-output-using-popen#4537277 – xdhmoore Apr 13 '21 at 21:29
  • Why do you have this random `r` in this command --- `subprocess.Popen(["powershell.exe", r"C:\Users\pecorgx\TestPS1.ps1"` In your ps1, you are not showing what is in `$arg1`, anywhere, so, `$ArrComputers = $arg1`, would be empty. It would be more prudent to set up the info you are after as a hashtable to pscustomobject and return that. Also, why not just use the built-in `Get-ComputerInfo` cmdlet directly to get this info vs all these calls? – postanote Apr 14 '21 at 01:18
  • r for raw string – Glenville Pecor Apr 14 '21 at 16:16

1 Answers1

2

Here is simplified example of your use case:

import subprocess;
process=subprocess.Popen(["powershell","Get-Childitem C:\\Windows\\*.log"],stdout=subprocess.PIPE);
result=process.communicate()[0]
print (result)

Of course the above is just printing out a directory list, but you just replace that command with your .ps1 script path.

Also, as noted in my comment, why not just use the ...

# Get specifics for a module, cmdlet, or function
(Get-Command -Name Get-ComputerInfo).Parameters
(Get-Command -Name Get-ComputerInfo).Parameters.Keys
Get-help -Name Get-ComputerInfo -Examples
Get-Help -Name Get-ComputerInfo -Detailed
Get-help -Name Get-ComputerInfo -Full
Get-help -Name Get-ComputerInfo -Online

Get-ComputerInfo -Property '*'

... cmdlet, to collect this info and select the properties you want? Only running the other collectors for info that Get-ComputerInfo does not provide.

There is also the built-in ...

Get-PhysicalDisk
Get-Volume

... cmdlets to get storage information.

How about constructing your output details this way...

Clear-Host
$env:COMPUTERNAME | 
ForEach-Object{
    $computerSystem = Get-wmiobject Win32_ComputerSystem -ComputerName $PSItem
    $computerBIOS   = Get-wmiobject Win32_BIOS -ComputerName $PSItem
    $computerOS     = Get-wmiobject Win32_OperatingSystem -ComputerName $PSItem
    $computerCPU    = Get-wmiobject Win32_Processor -ComputerName $PSItem


    (
        $ComputerInfo = [PSCustomObject]@{
                            Manufacturer    = $computerSystem.Manufacturer
                            Model           = $computerSystem.Model
                            SerialNumber    = $computerBIOS.SerialNumber
                            CPU             = $computerCPU.Name 
                            RAM             = [math]::Round($($computerSystem.TotalPhysicalMemory/1GB), 3)
                            OperatingSystem = "$($computerOS.caption), Service Pack: $($computerOS.ServicePackMajorVersion)"
                            LoggedOnUser    = $env:USERNAME  
                            LastReboot      = $computerOS.ConvertToDateTime($computerOS.LastBootUpTime) 
                        }
    )

    (
        $StorageInfo = [PSCustomObject]@{
                            DeviceID      = (Get-Volume).DriveLetter
                            Size          = Get-Volume | ForEach {[math]::Round($($PSitem.Size/1GB), 3)}
                            SizeRemaining = Get-Volume | ForEach {[math]::Round($($PSitem.SizeRemaining/1GB), 3)}
                        }
    )
}

... or combine and ouput this way

Clear-Host
$env:COMPUTERNAME | 
ForEach-Object{
    $ComputerSystem  = Get-wmiobject Win32_ComputerSystem -ComputerName $PSItem | 
                       Select-Object -Property Manufacturer, Model, UserName

    $ComputerBIOS    = Get-wmiobject Win32_BIOS -ComputerName $PSItem| 
                       Select-Object -Property SerialNumber

    $ComputerOS      = Get-wmiobject Win32_OperatingSystem -ComputerName $PSItem  | 
                       Select-Object -Property Caption, ServicePackMajorVersion, 
                       @{
                            Name       = 'LastReboot'
                            Expression = {$PSItem.ConvertToDateTime($PSItem.LastBootUpTime)}
                       }

    $ComputerCPU     = Get-wmiobject Win32_Processor -ComputerName $PSItem | 
                       Select-Object -Property Name

    $ComputerStorage = Get-WmiObject Win32_LogicalDisk -ComputerName $PSItem -Filter drivetype=3 | 
                       Select-Object -Property DeviceID, 
                       @{
                           Name        = 'Size'
                           Expression = {[math]::Round($($PSitem.Size/1GB), 3)}
                       }, 
                       @{
                           Name        = 'FreeSpace'
                           Expression = {[math]::Round($($PSitem.FreeSpace/1GB), 3)}
                       }


    $ComputerDetails = New-Object -Type PSObject

    $ComputerSystem, $ComputerBIOS, $ComputerOS, $ComputerCPU, $ComputerStorage | 
    ForEach-Object {
        $CurObj = $PSItem 
        $PSItem | 
        Get-Member | 
        Where-Object {$PSItem.MemberType -match 'NoteProperty'} | 
        ForEach-Object {
            $NewMember = $PSItem.Name
            $ComputerDetails | 
            Add-Member -MemberType NoteProperty -Name $NewMember -Value $CurObj.$NewMember
        }
    }
}
$ComputerDetails
postanote
  • 15,138
  • 2
  • 14
  • 25