Why does "Get-Vm | Sls PoweredOff" not grep for VMs that are Powered off? - powershell

I am trying to use PowerCLI to search for a list of PoweredOff VMs.
I want to search the results of the command Get-Vm:
Vm01 PoweredOn 1 16
Vm02 PoweredOff 1 16
etc.
I want to search this list for "PoweredOff", but the PowerShell Sls doesn't seem to work if I type:
Get-Vm | sls PoweredOff
It will not show the PoweredOff virtual machines. Can anyone provide any guidance on outputting this a stream of text to search (rather then a list of Objects to search)?

PowerShell cmdlets return objects, not simple text output. You filter output by the values of specific properties with the Where-Object cmdlet.
Get-Vm | Where-Object { $_.PowerState -eq 'PoweredOff' }
Tabular or list output will normally show you the property names. However, not all of the objects' properties may be displayed by default, and sometimes the default output format of a particular type is made to look differently than the output would normally do (e.g. Get-Process output). You can get a list of all properties (and methods) of an object by using the Get-Member cmdlet. Add the parameter -Force to include intrinsic properties. Add the parameter -Static to show class methods instead of object methods.
For VMware's cmdlets you could also check the PowerCLI documentation, which lists the return types of the cmdlets.

Related

Get serialnumber from asset list

Started in recent weeks in a Junior infrastructure role, and begun playing around with powershell to help save some time here and there.
I am trying to do the following:
1- I'm port a CSV file with a single column names asset
2- Perform a "ForEach" check on each line to find the device's serial number
3- Output results to a CSV with two column "asset" and "serialnumber"
I have dabbled in a few areas, and am currently sitting at something like this:
$file1 = Import-Csv -path "c:\temp\assets.csv" | ForEach-Object {
$asset = $_.asset
}
wmic /node:$asset bios get serialnumber
Export-Csv -Path "c:\temp\assetandserial.csv" -NoTypeInformation
As you may or may not see, I tried to set the column labelled "asset" as the variable, however, not sure if I placed it correctly.
I have tried a few other things, but honestly it's all new to me, so I haven't the foggiest idea where to go from here.
wmic is deprecated, and, for rich type support (OO processing), using PowerShell-native cmdlets is preferable in general.
wmic's immediate PowerShell counterpart is Get-WmiObject, which, however, is equally deprecated, in favor of Get-CimInstance.
Important: The command below uses Get-CimInstance, but note that the CIM cmdlets use a different remoting protocol than the obsolete WMI cmdlets. In short: To use the CIM cmdlets with remote computers, those computers must be set up in the same way that PowerShell remoting requires - see this answer for details.
Get-CimInstance Win32_BIOS -ComputerName (Import-Csv c:\temp\assets.csv).asset |
Select-Object #{ n='Asset'; e='PSComputerName' }, SerialNumber |
Sort-Object Asset |
Export-Csv c:\temp\assetandserial.csv -NoTypeInformation
Note the use of member-access enumeration to extract all .asset values directly from the collection of objects returned from Import-Csv.
All computer (asset) names are passed at once to Get-CimInstance, which queries them in parallel. Since the ordering of the responses from the targeted remote machines isn't guaranteed, Sort-Object is used to sort the results.
A calculated property is used with Select-Object to rename the automatically added .PSComputerName property to Asset.

Powershell how to use Get-command to display specific columns?

I need to use 'Get-Command" to display three specific columns of information. Name, CommandType, and Module. I am new to PowerShell and have been searching for hours to find an answer but have not been able to find any documentation that explains how to do this specifically.
I need to use 'Get-Command" to display three specific columns of information. Name, CommandType, and Module
Since your intent is to display the columns of interest, in tabular format, you can use Format-Table:
Get-Command | Format-Table -Property Name, CommandType, Module
For quick interactive use, you can shorten the command, by using aliases and positional parameter binding:
gcm | ft name, commandtype, module
However, note that Format-* cmdlets are only suited to for-display formatting, not for outputting data suitable for later programmatic processing - see this answer and the Select-Object solution below.
By contrast, if you need to construct new objects that have only a subset of the properties of the input objects (while possibly adding new properties / transforming or renaming existing ones via calculated properties[1]), you can use the Select-Object cmdlet:
Get-Command | Select-Object -Property Name, CommandType, Module
Note: If you print this command's output to the console (host), it will result in the same display output as the Format-Table call above, because PowerShell implicitly uses Format-Table formatting for objects that have 4 or fewer (public) properties.[2]
However, for explicit control of display formatting - such as if you want 5-property objects to be shown in tabular format too - Format-* cmdlets must be used.
[1] You may also use calculated properties with Format-Table, among other cmdlets.
[2] 5 or more properties result in Format-List formatting; Generally, this implicit formatting applies only to .NET types that do not have predefined formatting data associated with them; if they do, that data controls the default view and other aspects - see this answer.
Try piping it to select object
get-command|select-object -expandpoperty Name, CommandType, and Module

Running help <command> and piping output to Where-Object or Select-Object returns empty rows

Running the command help firewall | Select-Object Category. The result is one column blank Category.
The strange thing is that the empty rows number represent the amount of rows that help firewall would result without calling piping it to Select-Object
Or I'm trying to filter the output of help firewall to return only rows with Name that starts with "Get". Running help firewall | Where-Object Name -like "Get" just returns nothing.
Why aren't these pipes on help working? They are working perfectly on other commands.
Powershell Version 5.1 and using default windows console.
To complement Zilog80's helpful answer with background information:
Get-Command help reveals that help is not a mere alias of the Get-Help cmdlet, but a (built-in) function (submit $function:help to see its definition).
As you've noticed yourself:
while Get-Help outputs an object ([pscsustomobject]) with properties that reflect help-topic metadata such as Category, which is then rendered as display text by PowerShell's output-formatting system,
the help function returns strings - a stream of text lines representing the rendered help topic - of necessity.
You can observe the difference in output type by piping to the Get-Member cmdlet (help firewall | Get-Member vs. Get-Help firewall | Get-Member)
The purpose of the help function is to wrap Get-Help with interactive paging, to allow convenient navigation through lengthy help topics that don't fit onto a single console (terminal) screen.
This paging is provided via an external program (by default, more.com on Windows, and less on Unix-like platforms, configurable via $env:PAGER, but only in PowerShell (Core) 7+), and since PowerShell only "speaks text" when communicating with external programs, help must send a stream of strings (lines for display) to them, which it does via
Out-String -Stream.
Note:
When the external paging programs find that their stdout stream isn't connected to a console (terminal), they take no action other than simply passing the input through (in Unix terms, they then behave like cat).
Hypothetically, the help function itself could determine this condition and then (a) not pipe to the paging program and (b) relay the object output by Get-Help as-is.[1] However, determining a command's output target from inside that command, using PowerShell code, may not even be possible.
[1] The function actually already takes this action when a custom pager defined via $env:PAGER is found to be a PowerShell command rather than an external program.
Check the feedback from help help in PowerShell :
You can also type `help` or `man`, which displays one screen of text at a
time. Or, ` -?`, that is identical to `Get-Help`, but only
works for cmdlets.
The helpcommand display "screen of text" which means it is outputting [System.String] objects, not [PSCustomObject] objects.
Only -? will behave identically to Get-help and will provide [PSCustomObject] objects.
To see what's going on, check the different output from :
help firewall | %{ $_.GetType() }
And
Get-help firewall | %{ $_.GetType() }
And, for cmdlet,
Select-Object -? | %{ $_.gettype() }

PowerShell : How can I set a variable from a single column in multi-column output?

I am using Get-PhysicalDisk | Format-Table DeviceID, UniqueID to get a listing of drive number and serial number of all drives on a Windows 2016 Server. I want to search for one serial number and capture only the drive number as a variable. I'm used to awk in UNIX and I'm totally stumped on how to achieve this in PowerShell.
Get-PhysicalDisk | Format-Table DeviceID, UniqueID
DeviceID UniqueID
-------- --------
5 624A937024897B4FF488CBF800027A4B
8 624A937024897B4FF488CBF800028A4D
7 624A937024897B4FF488CBF800027A59
0 {c4d394f5-509e-11e9-a834-806e6f6e6963}
1 {c4d394f6-509e-11e9-a834-806e6f6e6963}
2 {c4d394f7-509e-11e9-a834-806e6f6e6963}
3 {c4d394f8-509e-11e9-a834-806e6f6e6963}
4 {c4d394f9-509e-11e9-a834-806e6f6e6963}
6 624A937024897B4FF488CBF800027A56
I want to expand this command to find SerialNumber 624A937024897B4FF488CBF800027A56 then set a variable called $DriveNumber to the value of 6 as shown in the output.
I then plan to use this variable in Set-Disk to take the drive offline/online as a perform a volume overwrite. I don't want to hard code the drive number because upon reboot, the drive number could change.
NOTE I was using Get-Disk and piping the appropriate output to Set-Disk to perform my drive off/online. But, I have a mysterious issue of the virtual drives not displaying with Get-Disk, therefore I'm trying to find a workaround with Get-PhysicalDisk Thanks!
$driveNumber = (
Get-PhysicalDisk | Where-Object UniqueId -eq '{624A937024897B4FF488CBF800027A56}'
).DeviceId
Note the need to enclose the GUID string in {...}.
As all PowerShell cmdlets do, Get-PhysicalDisk outputs objects whose properties you can query.
Cmdlet Where-Object acts as a filter on the objects it receives from the pipeline and compares the value of property UniqueId to the specified literal GUID (string), which, by definition, matches (at most) one object.
(...).DeviceId returns the value of the target objects' DeviceId property and assigns it to variable $driveNumber.
A note re use of Format-* cmdlets such as Format-Table:
Only ever use Format-* cmdlets for display formatting.
If the intent is further programmatic processing:
either: simply access the input objects' intrinsic properties (whose availability is independent of whether they display by default or via a Format-* cmdlet call)
or: if you need to create simplified or transformed objects with only a subset of the original properties and/or transformed property property values (calculated properties, use Select-Object.

Powershell 5.0 / ISE

I have an example code snippet that suggests using
(Get-Process | Where-Object {$_.WorkingSet64 -gt 20mb}).Count
to return the count of all processess using > 20Mb.
It works, but when typing, neither Intellisense or the "Tab" key shows this property, rather they show the properties of an individual process - which I find misleading.
I understand, that specifying an item property will give me the list of that property only, but is there a way to easily see, in general, what ALL the valid propeties are, including list aggregates etc?
Even assigning to a variable
$processes = Get-Process | Where-Object {$_.WorkingSet64 -gt 20mb}
does not show me "Count" as a valid property of $processes until AFTER the assignment has been actually run and the value assigned - when writing the script it still shows the properties for an individual item.
For me, Intellisense / Tab help that does not cover all the options kind of defeats the purpose ... (not having to remember hundreds objects/functions and their properties / parameters).
Is there any way to improve this situation? Some syntax trick have I missed?
The correct way to find out all of the properties of an object is to pipe the output to Get-Member:
Get-Process | Get-Member
Sometimes there are hidden properties and methods that can only be seen if you add the -force switch:
Get-Process | Get-Member -Force
The count property is an automatic property that is always usable on any collection object but that isn't explicitly listed as a property. Another example of an automatic property is length.
Using #() to force an array type is handy when that is what is wanted.
e.g. $processes = #(Get-Process | Where-Object {$_.WorkingSet64 -gt 20mb}). will show you "Count" and the other array properties.
Other than that, let's say the Intellisense has various limitations / shortcomings that I will just have to learn... sigh.