I am using PS V3.0 to check Google chrome version:
get-content -Path C:\Support\assets.txt | ForEach-Object ({get-wmiobject win32_product -ComputerName $_ | where-Object {$_.name -eq "google chrome"} |FT version})
{write-host "$_"}
Inside the txt file are the IP addresses of remote devices.
The command is working fine and gives me Chrome version, but I cannot include IP address inside the loop.
It gives me only chrome version without information to which remote device it's from. I would like to get something like this :
IP address - Chrome version
IP address - Chrome version
As far as I understand this it should be Foreach (action){do something}?
Also is there any chance to remove word "version" from the input?
Ok, you've made some very innocent beginner type mistakes, but that's fairly easily remedied.
Let's start with ft. ft is short for Format-Table. Generally speaking, you only use a Format- command when you are trying to output something. You are trying to use the results of that, not output it, so we need to drop the ft. Instead use the Select-Object cmdlet (or more commonly used is the shorter select).
get-content -Path C:\Support\assets.txt | ForEach-Object ({get-wmiobject win32_product -ComputerName $_ | where-Object {$_.name -eq "google chrome"} |Select version})
Ok, that gets you an array of objects that only have the Version property. Not super useful, especially when you wanted to know what computer each is associated with! So, that's a good lesson in general, but not very practical here. Let's move on with actually making things better!
You are making things harder than need be by piping things to a ForEach loop like that. You are making separate Get-WMIObject calls against each IP address. If we look at get-help get-wmiobject -parameter computername we can see that it accepts an array of strings. So we can make 1 call against multiple targets, which should help speed things up a bit.
$IPList = get-content -Path C:\Support\assets.txt
Get-WMIObject win32_product -ComputerName $IPList | Where{$_.Name -eq 'Google Chrome'}
That should speed up your results a bit, but what will make things a whole lot faster is to use Get-WMIObject's -Filter parameter instead of Where. The reason is that the provider is more efficient at filtering its own objects, and returning just what you want, than PowerShell is as filtering things. Also, this reduces the data sent back from the remote machines, so you are only getting the data you want from them rather than potentially hundreds of results per machine, and then parsing down to just the ones you want. Essentially you have all of the computers' processors working on your problem, instead of just yours. So let's use the -Filter parameter:
$IPList = get-content -Path C:\Support\assets.txt
Get-WMIObject win32_product -ComputerName $IPList -Filter "Name='Google Chrome'"
Ok, things should come back a whole lot faster now. So down to the last item, you want the computer name for what each version was found on. Good news, you already have it! Well, we have the actual name of the computer, not the IP address that you specified. It is not displayed by default, but each one of those results has a PSComputerName property that you can refer to. We can simply pipe to Select and specify the properties that we want:
$IPList = get-content -Path C:\Support\assets.txt
Get-WMIObject win32_product -ComputerName $IPList -Filter "Name='Google Chrome'" | Select PSComputerName,Version
That's probably going to get you results that you're happy with. If not, you can run it through a ForEach loop similarly to how you were, and format it like you specified:
$IPList = get-content -Path C:\Support\assets.txt
ForEach($IP in $IPList){
$Version = Get-WMIObject win32_product -ComputerName $IP -Filter "Name='Google Chrome'" | Select -Expand Version
"$IP - $Version"
}
Related
I'm wanting to improve on my script to be able to accomplish the following:
Scan servers based on get-adcomputer on specific OUs.
Scan each server based on whatever drive letter it has.
Scan each server for log4j.
Export all results to a CSV that identifies the folder path, name of file, and the server that the file was found on.
I have been using the following code to start with:
$Servers = Get-ADComputer -Filter * -SearchBase "OU=..." | Select -ExpandProperty Name
foreach ($server in $Servers){
Invoke-Command -ComputerName $Server -ScriptBlock {
$Drives = (Get-PSDrive -PSProvider FileSystem).Root
foreach ($drive in $Drives){
Get-ChildItem -Path $drive -Force -Filter *log4j* -ErrorAction SilentlyContinue | '
foreach{
$Item = $_
$Type = $_.Extension
$Path = $_.FullName
$Folder = $_.PSIsContainer
$Age = $_.CreationTime
$Path | Select-Object `
#{n="Name";e={$Item}}, `
#{n="Created";e={$Age}},`
#{n="FilePath";e={$Path}},`
#{n="Extension";e={if($Folder){"Folder"}else{$Type}}}`
} | Export-Csv C:\Results.csv -NoType
}
}
I am having the following issues and would like to address them to learn.
How would I be able to get the CSV to appear the way I want, but have it collect the information and store it on my machine instead of having it on each local server?
I have noticed extreme performance issues on the remote hosts when running this. WinRM takes 100% of the processor while it is running. I have tried -Include first, then -Filter, but to no avail. How can this be improved so that at worst, it's solely my workstation that's eating the performance hit?
What exactly do the ` marks do?
I agree with #SantiagoSquarzon - that's going to be a performance hit.
Consider using writing a function to run Get-ChildItem recursively with the -MaxDepth parameter, including a Start-Sleep command to pause occasionally. Also, you may want to note this link
You'd also want to Export-CSV to a shared network drive to collect all the machines' results.
The backticks indicate a continuation of the line, like \ in bash.
Finally, consider using a Scheduled Task or start a powershell sub-process with a lowered process priority, maybe that will help?
With this script, I am able to find a specific application on a list of multiple remote devices and determine the version number of the application on their corresponding host system. This is outputted beautifully in the PS window. However, I am having trouble exporting the results properly into excel, that is, I want each property (Name, Version, PSComputerName) to be in a separate column vs all in one column. So far, I've tried the following
$list = Get-Content -Path C:\Users\bob\AppList.txt
$Servers = Get-Content -Path C:\Users\bob\ServerList.txt
foreach ($Serv in $Servers) {
Get-WmiObject -Namespace ROOT\CIMV2 -Class Win32_Product -ComputerName $Serv |
Select-Object -Property Name, Version, PSComputerName |
Where-Object -FilterScript { $_.Name -like "*$list*" } |
Export-Csv -Path C:\Users\bob\ServerListResults.csv
}
This resulted in simply just one device's information being extracted while every other cell was empty
I added -append at the very end! Thank you anyways!
I am trying to collect a list of the viewers installed on a set of servers. I am trying to loop through that list and run a wmi query and store the results and export a table with with the wmi result and server name next to it.
I am running this on server 2012
$computers = Get-Content C:\computers.txt
$WMIQuery = foreach ($computer in $computers){Get-WmiObject -Class
Win32_Product | where-object {$_.name -match "Microsoft Viewer*"}}
$WMIQuery
$WMIQuery | Out-File c:\Viewers.txt
Desired Results
Server Name Object1 Object2
Server1 Microsoft Excel Viewer Microsoft Visio Viewer
I output the file and get a blank txt file.
foreach ($computer in (Get-Content -Path "C:\computers.txt")) {
Get-WMIObject -ComputerName $computer -Class Win32_Product |
Where-Object {$_.name -match "Microsoft Viewer" } |
Out-File -Append -Path "C:\viewers.txt"
}
Your original code wasn't identifying the computer to perform Get-WMIObject against, so it was looking at only the computer that you were running the script on.
If there are many products on the remote computer, you may want to consider filtering on the remote computer instead of locally, so as to avoid transferring large amounts of data over what may be a slower-than-ideal network:
foreach ($computer in (Get-Content -Path "C:\computers.txt")) {
Get-WMIObject -ComputerName $computer -Class Win32_Product -Filter "Name LIKE '*Microsoft Viewer*'"|
Out-File -Append -Path "C:\viewers.txt"
}
(I think I have the filter syntax correct; I seem to have to hack at it every time I write a new filter...)
I don't have enough rep to add a comment, but Jeff is correct. However, there are still issues with the original poster's query. The following piece of code will yield no results based on the examples provided by the poster:
{$_.name -match "Microsoft Viewer*"}
That needs to either be changed to
{$_.name -like "*Microsoft*Viewer*"}
or
{$_.name -match "Microsoft.*?Viewer"}
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={$_}}
}
I am an InfoSec admin with an okay amount of PowerShell experience. I'll keep it short and sweet:
([WMI] "\\$comp\root\CIMV2:CIM_DataFile.Name='$path'").Version)
I use this for calling file versions instead of using get-item VersionInfo.ProductVersion, since this does not always return an accurate value. It works well. However, when $path is equal to something like this:
C:\Windows\System32\Macromed\Flash\Flash*.ocx
The query doesn't work because the file is not found. I imagine this is due to the single quotes around the variable ignoring the wildcard.
I will admit that I did find a work around to my problem here (the answer posted by JPBlanc):
Powershell get-item VersionInfo.ProductVersion incorrect / different than WMI
However, I want to know if it is possible for me to use a wildcard with my existing script.
You can't pass a wildcard directly, but you can query the filesystem with that wildcard and then loop through the results. In both cases here, I'm assuming that you're doing this remotely.
$FlashFiles = invoke-command -computername $comp {Get-ChildItem C:\Windows\System32\Macromed\Flash\Flash*.ocx;};
foreach ($File in $FlashFiles) {
write-output "$($File.Fullname): $(([WMI] "\\$comp\root\CIMV2:CIM_DataFile.Name='$($File.FullName)'").Version)"
}
Or do it with a single pipeline:
invoke-command -computername $comp {Get-ChildItem C:\Windows\System32\Macromed\Flash\Flash*.ocx||foreach-object {write-output "$($_.Fullname): $(([WMI] "\\$comp\root\CIMV2:CIM_DataFile.Name='$($_.FullName)'").Version)"};
You can make the latter even faster by running the WMI query local to the remote computer (you could do it with the first too, but it's not as pretty)
invoke-command -computername $comp {Get-ChildItem C:\Windows\System32\Macromed\Flash\Flash*.ocx|foreach-object {write-output "$($_.Fullname): $(([WMI] "\\.\root\CIMV2:CIM_DataFile.Name='$($_.FullName)'").Version)"}};
The Name property of a CIM_DataFile can't contain wildcards. I don't believe any of them can.
However, you can specify the Drive, Path, and Extension to get a list:
Get-WmiObject -ComputerName $comp -Class CIM_DataFile -Filter "Drive='C:' AND Path='\\Windows\\System32\\Macromed\\Flash\\' AND Extension='ocx'"
The syntax of Path is a bit flaky. You need the trailing backslashes, for example.
You can also pipe to Where-Object for further filtering:
Get-WmiObject -ComputerName $comp -Class CIM_DataFile -Filter "Drive='C:' AND Path='\\Windows\\System32\\Macromed\\Flash\\' AND Extension='ocx'" |`
Where-Object { $_.FileName -like 'Flash*' } |`
ForEach-Object { $_.Name; $_.Version }