Select-Object with output from 2 cmdlets - powershell

Suppose I have the following PowerShell script:
Get-WmiObject -Class Win32_Service |
Select DisplayName,#{Name="PID";Expression={$_.ProcessID}} |
Get-Process |
Select Name,CPU
This will:
Line 1: Get all services on the local machine
Line 2: Create a new object with the DisplayName and PID.
Line 3: Call Get-Process for information about each of the services.
Line 4: Create a new object with the Process Name and CPU usage.
However, in Line 4 I want to also have the DisplayName that I obtained in Line 2 - is this possible?

One way to do this is to output a custom object after collecting the properties you want. Example:
Get-WmiObject -Class Win32_Service | foreach-object {
$displayName = $_.DisplayName
$processID = $_.ProcessID
$process = Get-Process -Id $processID
new-object PSObject -property #{
"DisplayName" = $displayName
"Name" = $process.Name
"CPU" = $process.CPU
}
}

A couple of other ways to achieve this:
Add a note property to the object returned by Get-Process:
Get-WmiObject -Class Win32_Service |
Select DisplayName,#{Name="PID";Expression={$_.ProcessID}} |
% {
$displayName = $_.DisplayName;
$gp = Get-Process;
$gp | Add-Member -type NoteProperty -name DisplayName -value $displayName;
Write-Output $gp
} |
Select DisplayName, Name,CPU
Set a script scoped variable at one point in the pipeline, and use it at a later point in the pipeline:
Get-WmiObject -Class Win32_Service |
Select #{n='DisplayName';e={($script:displayName = $_.DisplayName)}},
#{Name="PID";Expression={$_.ProcessID}} |
Get-Process |
Select #{n='DisplayName';e={$script:displayName}}, Name,CPU

Using a pipelinevariable:
Get-CimInstance -ClassName Win32_Service -PipelineVariable service |
Select #{Name="PID";Expression={$_.ProcessID}} |
Get-Process |
Select Name,CPU,#{Name='DisplayName';Expression={$service.DisplayName}}

Related

How to change an output formed by hashstables Powershell

I am storing the following query value in a variable:
$unquotedPaths = Get-WmiObject -Class Win32_Service | Select-Object -Property Name,DisplayName,PathName,StartMode | Select-String "auto"
The problem starts when i print that variable becouse the variable takes from the query an object which is formed by hashtables like in this output:
PS C:\Users\pc> Get-WmiObject -Class Win32_Service | Select-Object -Property Name,DisplayName,PathName,StartMode | Select-String "auto"
#{Name=AGMService; DisplayName=Adobe Genuine Monitor Service; PathName="C:\Program Files (x86)\Common Files\Adobe\AdobeGCClient\AGMService.exe"; StartMode=Auto}
#{Name=AGSService; DisplayName=Adobe Genuine Software Integrity Service; PathName="C:\Program Files (x86)\Common Files\Adobe\AdobeGCClient\AGSService.exe"; StartMode=Auto}
#{Name=asComSvc; DisplayName=ASUS Com Service; PathName=C:\Program Files (x86)\ASUS\AXSP\1.01.02\atkexComSvc.exe; StartMode=Auto}
#{Name=AudioEndpointBuilder; DisplayName=Compilador de extremo de audio de Windows; PathName=C:\WINDOWS\System32\svchost.exe -k LocalSystemNetworkRestricted -p; StartMode=Auto}
How i can get and output like this:
Name DisplayName PathName Startmode
---------- ------------- ------------ ------------
ExampleName ExampleDisplayName C:\Example Auto
Select-String is meant to search and match patterns among strings and files, If you need to filter an object you can use Where-Object:
$unquotedPaths = Get-WmiObject -Class Win32_Service |
Where-Object StartMode -EQ Auto |
Select-Object -Property Name,DisplayName,PathName,StartMode
If the filtering required more complex logic you would need to change from Comparison Statement to Script Block, for example:
$unquotedPaths = Get-WmiObject -Class Win32_Service | Where-Object {
$_.StartMode -eq 'Auto' -and $_.State -eq 'Running'
} | Select-Object -Property Name,DisplayName,PathName,StartMode

powershell wait for command to finish before proceeding

In powershell I am trying to do the following:
$name = "computername"
#get installed programs
Write-Host "****APPLICATIONS"
gwmi win32_Product -ComputerName $name | select name
#gets services
write-host "****SERVICES"
Get-Service -ComputerName $name | ft
the expected output would be
****APPLICATIONS
name
of
app
****SERVICES
running services here
more services here
the actual result is
****APPLICATIONS
****SERVICES
name
of
app
running services here
more services here
I have attempted to do start-job then wait-job , but running gwmi as a job seems to output nothing to the console and sending the output to a separate file defeats the purpose of other parts of the script
I also attempted to use start-sleep and it still finishes both write-host commands before proceeding
Try this:
$name = "computername"
Write-Host "`n****APPLICATIONS`n"
gwmi win32_Product -ComputerName $name | % {$_.name}
write-host "`n****SERVICES"
Get-Service -ComputerName $name | ft
If you want the results alphabetical:
$name = "computername"
Write-Host "`n****APPLICATIONS`n"
$apps = gwmi win32_Product -ComputerName $name | % {$_.name}
$apps | sort
write-host "`n****SERVICES"
Get-Service -ComputerName $name | ft
Param(
$ComputerName = 'AT805061'
)
# Get installed programs
Write-Host "`n****APPLICATIONS`n"
Get-WmiObject win32_Product -ComputerName $ComputerName | Select-Object -ExpandProperty Name | Sort-Object
# Get services
Write-Host "`n****SERVICES`n"
Get-Service -ComputerName $ComputerName | Where-Object -Property Status -eq -Value Running | Select-Object -ExpandProperty Name | Sort-Object

Powershell Script to join two function results based on common key columns

Could someone provide a PowerShell script to join two function results based on common key columns.
Example:
Result1 and Result2 has common field 'Name'. I want to join both the results and fetch the below informations.
$Result1 = get-wmiobject -ComputerName localhost -Class win32_service
$Result2 = get-service
Result
Name : wuauserv
DisplayName : Windows Update
Status : Running
StartMode : Manual
ProcessId : 400
Use below PowerShell script to join both the results based on common key column (Name).
$Result1=get-wmiobject -ComputerName localhost -Class win32_service
$Result2=get-service
$Result=#()
for($i=0;$i -lt $Result2.count;$i++)
{
$startmode=($Result1 | where{$_.Name -eq $Result2[$i].Name})|Select StartMode,ProcessId
$tempObj=new-object PSObject
$tempObj | Add-member noteproperty Name $Result2[$i].Name
$tempObj | Add-member noteproperty DisplayName $Result2[$i].DisplayName
$tempObj | Add-member noteproperty Status $Result2[$i].Status
$tempObj | Add-member noteproperty StartMode $startmode.StartMode
$tempObj | Add-member noteproperty ProcessId $startmode.ProcessId
$Result += $tempObj
}
$Result
No need to combine the output of the two commands. All of the properties are already out from the Get-WMIObject. (Personally I like using the CIM cmdlets instead of WMI wherever possible too)
Get-CimInstance Win32_Service | select Name, DisplayName, State, StartMode, ProcessId
Edit: The output of State from gcim is the Status property of Get-Service (Here's a calculated property to fix that, if that's an issue)
Get-CimInstance Win32_Service | select Name, DisplayName, #{Name="Status";Expression={$_.State}}, StartMode, ProcessId
try this
$result=get-wmiobject -ComputerName localhost -Class win32_service | %{ New-Object psobject -Property #{ objectwmi=$_; objectgetservice=(get-service | where name -eq $_.Name | select -first 1)} }

Combining output of many objects into a CSV

I'd like to take specific output of four objects and put them into a CSV.
$obj1 = get-wmiobject win32_computersystem | select-object name,manufacturer,model,totalphysicalram
$obj2 = get-wmiobject win32_processor | select-object deviceid,name,maxclockspeed,numberofcores
$obj3 = get-wmiobject win32_bios | select-object serialnumber
$obj4 = get-wmiobject win32_operatingsystem | select-object osarchitecture
I'd like to combine all of those into the same output row in a csv.
How can I do this with powershell? Should I build an array of objects?
I don't fault you for not having a start on this, I wouldn't have had any idea where to go with code a year ago myself. Try this out and see how it strikes you...
$obj1 = get-wmiobject win32_computersystem | select-object name,manufacturer,model,TotalPhysicalMemory
$obj2 = get-wmiobject win32_processor | select-object deviceid,#{l="Proc";e={$_.name}},maxclockspeed,numberofcores
$obj3 = get-wmiobject win32_bios | select-object serialnumber
$obj4 = get-wmiobject win32_operatingsystem | select-object osarchitecture
$Combined = New-Object -Type PSObject
$obj1,$obj2,$obj3,$obj4|%{$CurObj = $_;$_|gm|?{$_.MemberType -match "NoteProperty"}|%{$NewMember = $_.Name;$Combined|Add-Member -MemberType NoteProperty -Name $NewMember -Value $CurObj.$NewMember}}
I fixed TotalPhysicalMemory (not totalphysicalram), and changed the proc query so it renamed the Name property to Proc, that way you don't have 2 properties with the same name. Then I fed all 4 objects into a ForEach loop, and for each object I got it's members and filtered for the NoteProperty members (getting rid of Methods and what not). For each one I took the member's name and created a property in a new PSCustomObject that I had created with that same name, and assigned the value from the original object associated with that property. I hope that makes sense, I found it a little hard to follow and I wrote the thing...
Edit: Dur... I didn't answer the original question, I just got all the prep work done. Here's how you output it:
$Combined|Export-CSV -Path C:\SomeFolder\MachineSpecs.CSV -NoTypeInfo
I tried running TheMadTechnician's answer on PSv3 and it didn't like the Out-CSV cmdlet. So I replaced it with Export-CSV and it worked fine.
$obj1 = get-wmiobject win32_computersystem | select-object name,manufacturer,model,TotalPhysicalMemory
$obj2 = get-wmiobject win32_processor | select-object deviceid,#{l="Proc";e={$_.name}},maxclockspeed,numberofcores
$obj3 = get-wmiobject win32_bios | select-object serialnumber
$obj4 = get-wmiobject win32_operatingsystem | select-object osarchitecture
$Combined = New-Object -Type PSObject
$obj1,$obj2,$obj3,$obj4|%{$CurObj = $_;$_|gm|?{$_.MemberType -match "NoteProperty"}|%{$NewMember = $_.Name;$Combined|Add-Member -MemberType NoteProperty -Name $NewMember -Value $CurObj.$NewMember}}
$Combined | Export-CSV -Path H:\MachineSpecs.CSV -NoTypeInfo
Gives the output of:
"manufacturer","model","name","TotalPhysicalMemory","deviceid","maxclockspeed","numberofcores","Proc","serialnumber","osarchitecture"
"Hewlett-Packard","HP EliteBook 8760w","LAUCA-44A135","8537874432","CPU0","2201","4","Intel(R) Core(TM) i7-2670QM CPU # 2.20GHz","USH244A135","64-bit"
Here's a readable syntax I like for this task, hope this helps. This creates a hashtable of properties and adds it to a PSObject, then adds that to an array. You can do as you wish with the resulting array. I typically run this in a foreach loop against a list of remote computers. You can glom together all kinds of disparate data for reporting very easily this way.
$Results = #()
$obj1 = get-wmiobject win32_computersystem
$obj2 = get-wmiobject win32_processor
$obj3 = get-wmiobject win32_bios
$obj4 = get-wmiobject win32_operatingsystem
$Obj = new-object psobject -property#{
PropertyName = $Obj2.Property
SomeOtherPropertName = $obj1.Property
SerialNumber = $obj3.SerialNumber
DateCollected = (get-date).DateTime
OSArchitecture = $obj4.OsArchitecture
}
$Results+=$obj

PowerShell - Select-Object from Win32_OperatingSystem displays rather oddly

First time poster here, I'm a bit of a beginner and I've been keen to get my PowerShell scripting skills up to scratch and I'm come across something rather confusing...
I've made a script to query a collection of computers and I want to query Win32_OperatingSystem but only extrapolate the Build number so I can populate my PSObject with it. I'm trying to add some If logic so that if the build number is 7601, I can write a message under my OS column.
The problem I'm having is that the BuildNumber values are coming out as #{BuildNumber=7601} instead of 7601 for instance. That, and my If statement is borked.
$Machines = Get-Content .\Computers.txt
Foreach($Machine in $Machines)
{
$sweet = (Get-WmiObject -Class Win32_OperatingSystem -computer $Machine | Select-Object BuildNumber)
$dversion = if ($sweet -eq "#{BuildNumber=7601}") {Yes!} else {"Nooooo!"}
New-Object PSObject -Property #{
ComputerName = $Machine
Sweet = $sweet
OS = $dversion
}
}
The issue is that the Get-WMIObject cmdlet is returning a Hash Table. Then the Select-Object is returning just the BuildNumber section you want, the BuildNumber property and it's value. You need to add the -ExpandProperty parameter to only get the value back, not the name/value pair.
Get-WMIObject -Class Win32_OperatingSystem | Select-Object BuildNumber
Returns
#{BuildNumber=7601}
With ExpandProperty
Get-WMIObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber
Returns
7601
Just another option with a ping test to skip unavailable machines.
Get-Content .\Computers.txt | Where-Object {Test-Connection -ComputerName $_ -Count 1 -Quiet} | Foreach-Object {
$sweet = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $_ | Select-Object -ExpandProperty BuildNumber
New-Object PSObject -Property #{
ComputerName = $_.__SERVER
Sweet = $sweet
OS = if ($sweet -eq 7601) {'Yes!'} else {'Nooooo!'}
}
}