How to get result of Get-WmiObject into a file - powershell

I have a PowerShell-V2 script I am trying to run. Very simply, I pass it an application, and it outputs the result of the win32_process.
e.g.
$filter = "name like '%"+$_Application+"%'"
$result = Get-WmiObject win32_process -Filter "$filter"
However I need to get this into a file.
But when I run:
write-host $result
I just seem to get the "__RELPATH" result, and not the whole thing.
Trying to get it into a file results in the same thing. Is there a way of doing this, without me having to loop through one by one, listing each one in turn?

You can use the Out-File cmdlet:
$result | Out-File 'your_file_path.txt'
Note: You may want to set the encoding within the Out-File cmdlet. E. g. -Encoding utf8

Related

Problem with declaration of variables in powershell

I have declared 2 PowerShell variables
$prm=Get-WmiObject Win32_Product -Computer . -Filter "vendor = 'Wolters Kluwer Financial Services'" | Select-Object Name, Vendor, Version
$rgteng=Get-WmiObject Win32_Product -Computer . -Filter "vendor = 'WKFS'" | Select-Object Name, Vendor, Version
I want the output of this variable to a text file o/p #{Name=Wolters Kluwer Financial Services Regulatory Reporting FRA Param 11.2.0; Vendor=Wolters Kluwer Financial Services; Version=11.2.0}, I want this o/p to a text file.
I have tried using Write-Output and Write-Host, but none of them gives right o/p
What happens there looks like this (just the big picture):
Get-WmiObject Win32_Product -Computer . -Filter "vendor = 'Wolters Kluwer Financial Services'" creates an WMI object and pipes it to the next command
Select-Object Name, Vendor, Version transforms that object into a new PSCustom type object (more like a table version of your WMI object wtih only the desired information)
Then it gets messy :
if you use write-host or display it on the screen , the output will be formatted according the the powershell's settings (those settings can be changed by altering xml files)
if you use export-csv you basically use a convertto-csv | out-file c:\sometheing.txt + some formatting rules that are applied. (I think the UTF-8 type of the file is changed but I am not sure...)
So if you want to know exactly how your variable / file will look like, without having powershell formatting interfering with your work, use convertto-csv | out-file.

Get current version number of specified program

I started with this, on a recommendation from a friend
Get-WmiObject win32_product | ft name, version
But then I found this, which gives me pause.
A little research led me to this
wmic product where "Name='Revit 2018'" get name,version
Which works as far as the data gathered. And yes, I am looking for a different program in this example. in any case, once I had good info using WMIC I tried to get the data into a variable so I could get just the version number, but the data formatting is something I have never seen before. I was hoping for a simple solution, like
$object = wmic product where "Name='Revit 2018'" get name,version
$object.version
But only the result is an array with 6 items, and only one seems to be the actual data line, and that's a single line, not two properties. And, I really wonder if an old command line utility is the right answer here. If it really is the best way to do this, is there a trick to converting the raw data to something more, PowerShelly? And if it's not the best way to get this info, what is? Is that scary link real, or is Get-WmiObject win32_product actually safe? And if so, is there a way to filter on a specific name, to speed things up? And indeed, Get-WmiObject doesn't work as I was expecting, as
$object = Get-WmiObject win32_product | ft name, version
foreach ($item in $object) {
Write-Host "$($item.version)"
}
Doesn't work as expected at all.
EDIT: This seems to be working as expected, which is progress.
$version = (Get-WmiObject win32_product -filter:"Name = 'Revit 2018'" | Select-Object -property:*).version
Write-Host "$version!"
I guess the question is really, is this a safe and consistent approach, or is there a better one?
Why not use the registry?
Set-Location HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall
$app = Get-ChildItem | Where-Object { $_.GetValue("DisplayName") -match 'YourSoftware' }
$app.GetValue("DisplayVersion")
Or
Set-Location HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall
$apps = Get-ChildItem
foreach ($app in $apps) {
$app.GetValue("DisplayName","DisplayVersion")
}
Note: You'll also need to check the SysWow64 registry location as well
HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
Note: Not all items will have a display version in which case you always have the option of looking in the installation directory for the executable itself, which should have a version on it.

Select-String -Pattern Output when piping into

I try to get PowerShell to spit out a Semantic Versioning Variable but get stuck in it displaying just the command I entered (doing that in the ISE) or either of 2 errors ('missing argument' or 'doesn't accept piped input'), which, if I try to resolve them, end in the command simply being displayed again.
How do I get this:
(Invoke-WebRequest -Uri http://someplace).Links.href | Out-String -Stream |
Select-String -Pattern [regex]$someGoodRegex -OutVariable $NodeVersion_target
assuming the regex and web request point to solid things to simply stick the searched term in the -OutVariable defined?
On a more general note, is there a good way to display the properties of the objects in the pipe? After a great deal of digging, I stumbled upon {$_} but can't get it to display anything but the command again if the command gets a little more complex that just a simple cmdlet.
Remove the [regex]. Select-String already treats the argument to the parameter -Pattern as a regular expression.
Remove the $ from the variable name. You need it to use a variable directly, but the -OutVariable parameter expects the bare variable name without the leading $.
You can also remove the Out-String -Stream.
Something like this should work:
$uri = 'http://www.example.com/'
$re = 'v\d+\.\d+\.\d+/s'
(Invoke-WebRequest -Uri $uri).Links.href |
Select-String -Pattern $re -OutVariable NodeVersion_target
Alternatively you can assign the output of the pipeline to a variable instead of using -OutVariable:
$uri = 'http://www.example.com/'
$re = 'v\d+\.\d+\.\d+/s'
$NodeVersion_target = (Invoke-WebRequest -Uri $uri).Links.href |
Select-String -Pattern $re
The latter is actually more PoSh.
As for inspecting the current object in a pipeline: pipe into Get-Member to get a list of the properties/methods of the pipelined objects, and pipe into Format-List * to get a list of the values of the pipelined objects.

Use of property names in PowerShell pipeline $_ variable

As a C# developer, I'm still learning the basics of PowerShell and often getting confused.
Why does the $_. give me the intellisense list of vaild property names in the first example, but not the second?
Get-Service | Where {$_.name -Match "host" }
Get-Service | Write-Host $_.name
What is the basic difference in these two examples?
When I run the second one, it gives this error on each iteration of Get-Service:
Write-Host : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters
that take pipeline input.
At line:3 char:15
+ Get-Service | Write-Host $_.name
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (wuauserv:PSObject) [Write-Host], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.WriteHostCommand
My coworker and I were first using a foreach loop to iterate a Get-commandlet, and we were stuck getting the property names to appear. We tried to simplify till we go to the core basics above.
Just figured out sometimes it's a typo in the commandlet, below first one fails because the commandlet should be Get-Service instead of Get-Services.
foreach ($item in Get-Services)
{
Write-Host $item.xxx #why no intellisense here?
}
foreach ($item in Get-Service)
{
Write-Host $item.Name
}
First part: you can't use $_ like that, it represents current pipeline object only within script blocks. These script blocks are usually used with any *-Object cmdlet (but there are other use cases too). Not all parameters/ cmdlet support it. Write-Host is one of those that don't.
Second: It looks like you are using own function (GetServices). PowerShell v3 intellisense is depending on command metadata (OutputType). If any cmdlet/ function produces object but is silent about OutputType, intellisense won't work. It's pretty simple to get it, and you can lie and still get proper intellisense for any existing type:
function Get-ServiceEx {
[OutputType('System.ServiceProcess.ServiceController')]
param ()
'This is not really a service!'
}
(Get-ServiceEx).<list of properties of ServiceController object>
You can read more about it on my blog.
Intellisense will work if you put $_ inside a scriptblock.
The following will trigger intellisense:
Get-Service | Foreach-Object {$_.Name} # Intellisense works
Get-Service | Where-Object {$_.Name} # Intellisense works
Get-Service | Write-Host {$_.Name} # Intellisense works
Note that your command need not be a valid command: the third example will not work but intellisense will display auto-complete for $_ anyway because it is inside a scriptblock.
I suspect it is because $_ is only usable inside a scriptblock (e.g. switch, %, ?) but I have no hard-evidence for it.
$_ is the current object in the pipeline. It's the same as $item in a foreach ($item in $array).
Get-Service | Where {$_.name -Match "host" }
Get-Service | Write-Host $_.name
The difference between these two lines is a fundamental part of the PowerShell design. Pipelines are supposed to be easy. You should be able to ex. search for and delete files as simply as:
Get-ChildItem *.txt | Remove-Item
This is clean, simple, and everyone can use it. The cmdlets are built to identify the type of the incoming object, adapt to support the specific type, and process the object.
However, sometimes you need more advanced object manipulation in the pipeline, and that's where Where-Object and Foreach-Object comes in. Both cmdlets lets you write your own processing logic without having to create an function or cmdlet first. To be able to access the object in your code(processing logic), you need an identifier for it, and that is $_. $_ is also supported in some other special cmdlets, but it's not used in most cmdlets(including Write-Host).
Also, Intellisense in foreach ($item in Get-Service) works. You had a typo.

Powershell, paginating output from foreach

Seems like this should be simple, but powershell is winning another battle with me. Simply wanting to output the name of all the services running on a system, and their executable path, and pipe that into something I can use to search through it like Less.
So far I have:
$services = get-WmiObject -query 'select * from win32_service'
foreach($service in $services){$service.Name $service.Pathname} | less
But thats giving me the "An empty pipe element is not allowed." that I seem to have come up alot. Anyone tell me how to fix this, either by outputting to a file and Ill go through it with vim, or pipe to page/less/etc so I can do quick scan (with my eyes not programically quite yet).
Try doing the following
$services | %{ $_.Pathname } | less
EDIT Add multiple to the path
$services | %{ "{0} {1}" -f $_.Pathname,$_.Name } | less
If you are using PowerShell 2.0, you might like this:
gwmi win32_service | select-object Name,PathName | ogv
ogv (Output-GridView) is a new cmdlet in 2.0.
get-wmiobject win32_service | select-object name, pathname | more
This is also powershell 2.0 and is the close to the comment above.
You were just trying to use a foreach when you didn't need to in this case.
Even with the foreach, you were close to getting an output you could work with.
A comma in your foreach would have generated a output like a list and you could have used the more command instead of less.
$services = get-WmiObject -query 'select * from win32_service'
foreach($service in $services){$service.Name $service.Pathname} | more
Here is another way to write this same statement.
get-WmiObject win32_service | foreach{$.Name, $.Pathname} | more
This is still not the same as my first example, but I wanted to show you how close you were.
Looks like a good reason to use foreach-object:
$services = get-WmiObject -query 'select * from win32_service'
$services|ForEach-Object {$_|Select-Object Name,Pathname}|less
Please excuse me while I oneline it:
get-WmiObject -query 'select * from win32_service' |ForEach-Object {$_|Select-Object Name,Pathname}|less
foreach-object will return an object to the pipeline based on the input object.
I'm assuming less is an alias of your own making since I don't seem to have it.