I'm trying out a script to go grab installed software on servers remotely. Problem is I want it to output certain attribs including the computer name but I can't seem to figure out how to get the name inserted.
Here is what I have so far...
$servers = Get-QADComputer -SearchRoot "OU=servers,OU=mydomain:-),DC=COM" | Select Name
...which works fine of course. Then...
$servers | % {Get-WMIObject -Class Win32Reg_AddREmovePrograms} | select Displayname,Version,InstallDate,PSComputerName
... which provides the full list of software installed on all servers in that OU but the PSComputerName becomes MY COMPUTER (the computer I run the query from - not the computername of the system being queried). The goal is to have the servername the software is installed on on each line item of software. I've asked professor Google and don't seem to see anything helpful (or anything that I understand anyway).
Hope this makes sense. semi-amateur PS script writer so hopefully this is easy for you guys. Thanks in advance for your help
Your command:
Get-WMIObject -Class Win32Reg_AddREmovePrograms
Does not specify computer to query, so it just query computer command being executed on. Thus PSComputerName display MY COMPUTER, as MY COMPUTER is computer being queried. You have to specify -ComputerName parameter to Get-WMIObject cmdlet to query specific computer. And -ComputerName parameter accept array of computer names, so you can put array of computer names to it instead of using ForEach-Object cmdlet and query one computer at time.
Since the object returned from the WMI call doesn't contain the computer you made the request on, you need to include it yourself from include your ForEach-Object (%) block. You could use Add-Member to add it yourself, then do your Select-Object outside like you're doing now:
$servers | % {
Get-WMIObject -Class Win32Reg_AddREmovePrograms -ComputerName $_ |
Add-Member -MemberType NoteProperty -Name ComputerName -Value $_ -PassThru
} | select Displayname,Version,InstallDate,ComputerName
Another way is to move the Select-Object to inside the block and do it within there, by creating a new property on the fly with a hashtable:
$servers | % {
Get-WMIObject -Class Win32Reg_AddREmovePrograms -computername $_ |
Select-Object Displayname,Version,InstallDate,#{Name='ComputerName';Expression={$_}}
}
Related
I've tried a variety of iterations of this and gotten a range of errors. I'm trying to get a a list of installed drivers off from a list of computers. None of the ways I've tried in PowerShell have piped the information into a csv. Here's the current iteration of the script.
#Load Active Directory
Import-Module activedirectory
#Load list of computers
$results = #()
$Computer = Get-Content -path 'C:\ScriptResources\computers.txt'
#Check each computer in the list
foreach($ComputerName in $Computer)
{
$results += Get-ADComputer -Filter " Name -Like '*$ComputerName*' " | Get-PrinterDriver; Start-Sleep -milliseconds 500
}
#Export to CSV file
$results | export-csv 'C:\ScriptResults\InstalledPrinters.csv'
I've also used it with just the Get-Printer command and got the following error.
Get-Printer : No MSFT_Printer objects found with property 'Name' equal to 'Redacted'. Verify the value of the
property and retry.
Depending what I've fed the $Computer file I'll get different errors. I've also gotten the RPC server is unavailable and Error Spooler Service Not Running. I have domain wide privileges and I checked the print spooler service and it is running.
The reason I think this is odd is that I have .bat tool that I use that gets printer info from a singular host and I don't run into any issues. The reason I'm trying to put this in PowerShell is because 1) I want to do the whole domain and 2) PowerShell formats its outputs in a more useable fashion.
wmic /node:%ComputerIP% path win32_printer get deviceid, drivername, portname
Additionally, I've also tried the following in the $results function of the script
$results += Get-WmiObject -class Win32_printer -ComputerName name, systemName, shareName
This didn't give errors. What it did instead is that for each computer in the list of computers it checked the computer I was running the script from for its printers and output on each line which printers were installed on my computer.
I'm at a loss and any help would be appreciated. Thanks!
Just so this is closed out. Vivek's answer ended up working.
$results += Get-WmiObject -class Win32_printer -ComputerName $Computer | Select name, systemName, shareName
The RPC issue I was getting was that the list of computers were all turned off for some reason (remote site + different time zone + doing the testing during second shift). Normally, everything remains on though. So that was just an anomaly.
Thanks for the help!
I'm trying to get a list of installed programs off a group of remote servers. I'm able to get the program name but not return the system name. Below is my script.
$computerfile = get-content "D:\Users\Admin\Docs\PrimaryServers.txt"
ForEach ($computer in $computerfile) {
Get-WmiObject Win32_Product -ComputerName $computer |
Select-Object SystemName,Name,Version,PackageName,Installdate,Vendor |
Format-Table -AutoSize
}
Below is my output
First, -ComputerName can take an array of names so by looping you are going to increase the time because the loop will be in serial where utilizing the array for computername will be in parallel.
Second, it's best practice to use the CIM cmdlets in place of the WMI cmdlets. They operate over WSMAN by default and are easier to work with.
Third, Win32_Product forces a consistency check so reading the Uninstall registry keys is usually superior.
Lastly, SystemName isn't a property name that is returned by Get-WMIObject. PSComputerName is the property you are looking for and you can make a Calculated Property from it.
$computerfile = get-content "D:\Users\Admin\Docs\PrimaryServers.txt"
Get-CimInstance Win32_Product -ComputerName $Computerfile |
Select-Object #{n=SystemName;e={$_.PSComputerName}},Name,Version,PackageName,Installdate,Vendor |
Format-Table -AutoSize
Another approach is to use the Invoke-Command where it automatically extends the result with the PSComputerName column
First build up the script blocks to use as query
Block 1 is my approach for both x32 and x64 implementations. Consider this as an alternative because I has some issues with the proposed implementation.
$block1={
# Query x64 bit applications
$queryPath="HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"
Get-ItemProperty $queryPath | Select-Object -Property DisplayName, Publisher, InstallDate, DisplayVersion
# Query x32 bit applications
$queryPath="HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
Get-ItemProperty $queryPath | Select-Object -Property DisplayName, Publisher, InstallDate, DisplayVersion
}
Block 2 is the proposed approach on this question
$block2={
Get-CimInstance Win32_Product | Select-Object Name,Version,PackageName,Installdate,Vendor
}
For either $block1 or $block2 execute remotely on a server list
Invoke-Command -ComputerName $computernames -ScriptBlock $block1
And one record looks like this
DisplayName : Microsoft Visual C++ 2013 x86 Additional Runtime - 12.0.21005
Publisher : Microsoft Corporation
InstallDate : 20161202
DisplayVersion : 12.0.21005
PSComputerName : MECDEVAPP01
RunspaceId : 4b8cc747-da25-4c6e-b108-0ca3138c0335
I have a simple problem that I can't seem to work through. I need to know what servers are still running server 2008/R2.
I know that Win32_OperatingSystem's Name property contains the information that I'm looking for. I would like to be able to run Get-WmiObject against a collection of servers in an OU.
There are two problems that I'm having:
I can't figure out how to redirect the output of Get-ADComputer to something that Get-WmiObject -ComputerName can use. I think Get-ADComputer is outputting objects of type Microsoft.ActiveDirectory.Management.ADComputer, and Get-WmiObject is looking for type System.Management.ManagementObject. Here's what I came up with but it doesn't appear to work.
Get-WmiObject Win32_OperatingSystem -ComputerName (Get-ADComputer -filter * -SearchBase "OU=Member Servers,DC=Company,DC=Com" | select #{L="ComputerName";e={$_."name"}}) -Property name, csname | select csname, name | Format-Table -AutoSize
My temp workaround: I was able to create a CSV that contains the list of server names. I was able to use the CSV to run Get-WmiObject against. However, the OU contains "dead" servers. So when I try to run Get-WmiObject using the CSV-list of servers that came from AD there are connection timeouts and PowerShell waits a period of time to see if the dead server will respond. This really slows down the operation & we are working to clean this up. Until that happens, Is there a way to only pass the server names that pass a Test-Connection to Get-WmiObject?
Get-WmiObject win32_operatingsystem -ComputerName (Get-Content C:\Users\user1\Desktop\Servers.csv) -Property name, csname | select csname, name | Format-Table -AutoSize
Pick the name component first then it will pass it to the next pipeline object (select -object)
Get-WmiObject Win32_OperatingSystem -ComputerName ((Get-ADComputer -filter * -SearchBase "OU=Member Servers,DC=Company,DC=Com").Name)
Note: -ComputerName: accepts a string object so you cannot pass a base type object directly to that.
I'm having a hell of a time with what seems like an utterly bizarre issue. I'm basically trying to inventory a bunch of workstations via WinRM and the Invoke-Command PowerShell cmdlet, but I'm running into grief when I try to execute more than one Get-WMIObject call at a time.
In this case, I'm specifically trying to get the model and serial number of the workstations and pipe them out to a CSV, making it important that the two commands are executed in the same Scriptblock, giving me something very similar to the below, basically.
Invoke-Command -ScriptBlock { Get-WmiObject Win32_ComputerSystem | Select Model ; Get-WmiObject win32_SystemEnclosure | Select serialnumber } -ComputerName (Get-ADComputer -Server [domain I care about] -filter 'name -Like "[types of computers I care about]"' | Select-Object -expand Name)
Even when run locally, Get-WmiObject Win32_ComputerSystem | Select Model ; Get-WmiObject win32_SystemEnclosure | Select serialnumber only returns the first command. I've tried swapping them around and the first command executes, while the second does not. Some of my colleagues report that it works just fine for them, others see the same result as me, and it doesn't seem to be a version issue, as one of the people for whom this works is running the same version of PowerShell as I am. (5.0.10240.16384)
Screenshot below of a few different command combinations. Anyone have any idea what's going on here?
If you change the list in the select-object cmdlets so both include the properties output by each, you will get the result you want (I think).
Invoke-Command -ScriptBlock { Get-WmiObject Win32_ComputerSystem | Select Model,SerialNumber ; Get-WmiObject win32_SystemEnclosure | Select model,serialnumber } -ComputerName localhost
That will get you output to the screen which should include all of the info. If you just want objects you can just capture the output and see that all of the properties are there.
$objects=Invoke-Command -ScriptBlock { Get-WmiObject Win32_ComputerSystem | Select Model ; Get-WmiObject win32_SystemEnclosure | Select serialnumber } -ComputerName (Get-ADComputer -Server [domain I care about] -filter 'name -Like "[types of computers I care about]"' | Select-Object -expand Name)
If you execute $objects | format-list * you will see that you have two objects, one with a Model and one with a SerialNumber.
Outputting different objects to a single CSV is another issue altogether. You get columns in the CSV based on the properties in the first object, so you will lose the SerialNumber property in the CSV.
So I'm trying to return a list of running process' descriptions on a machine which I can do no problem via get-process | select description
However, when I try: get-process -computer remote | select description nothing is returned, only empty strings.
Is there a reason for this?
Thanks
Well, if you take a look at how the description is retrieved, it will all get clearer:
PS> gps | gm | where {$_.name -eq 'description'} | select Definition
TypeName: System.Diagnostics.Process
Definition
----------
System.Object Description {get=$this.Mainmodule.FileVersionInfo.FileDescription;}
This accesses Process.MainModule for which the documentation has to say that it throws a NotSupportedExcetion in the following case:
You are trying to access the MainModule property for a process that is running on a remote computer. This property is available only for processes that are running on the local computer.
So the attempt to retrieve the description fails for remote processes.
Maybe with WMI and the GetVersionInfo method:
$ComputerName = 'server1'
Get-WmiObject Win32_Process -ComputerName $ComputerName |
Select-Object Name, #{n='Description';e={ [System.Diagnostics.FileVersionInfo]::GetVersionInfo( ($_.ExecutablePath -replace '^(.):',"\\$ComputerName\$`1$")).FileDescription }}
After experimenting with get-process I wrote the below script to show what it 'viewable' via a remote session
get-process -computer computer | select * | where {$_.name -match "tskmgr"}