I am creating my first application with VS and PowerShell and need to get the name of a service from my listview. The output of the selection looks like this:
ComputerName Status Name DisplayName
------------ ------ ---- -----------
PC Running Appinfo Application Information
What I want to do is get the value Appinfo from the Name column and assign it to a variable. I've had no luck with regex, but then again I am a beginner so I could be doing something wrong. Is there an easy way to do this?
The output you're currently getting is a formatted (tabular) view on selected properties of an object (namely the properties ComputerName, Status, Name, and DisplayName). You can get the value of a particular property by expanding it via the Select-Object cmdlet:
$name = ... | Select-Object -Expand Name
You could also store the object in a variable and access the property via dot-notation:
$obj = ...
$name = $obj.Name
Beware that if a cmdlet outputs multiple objects the variable will contain an array:
PS C:\> $services = Get-Service
PS C:\> $services.GetType().FullName
System.Object[]
PS C:\> $services.Count
136
You can access properties of a member object by index:
$services[42].Name
or by selecting a specific object via its properties:
$services | Where-Object { $_.DisplayName -eq 'Application Information' } |
Select-Object -Expand Name
Since PowerShell v3 you can also use the dot-property notation to get the value of a particular property of all array members:
$services.Name
Prior to PowerShell v3 this would have thrown an error, because the array object doesn't have a property Name.
Related
Right now I'm running
Get-CimInstance -ComputerName $i.DNSHostName -Class CIM_Processor | Select-Object "Name", "NumberOfCores" | Export-Csv -Path .\test.csv -NoTypeInformation -Append`
This will put the CPU name and core count in a CSV fine but how can I add in the hostname as another column?
This is a good case for using a PsCustomObject, which allows you to dynamically create an object with arbitrary properties/values.
$cimProcessor = Get-CimInstance -ComputerName $hostName -Class CIM_Processor
$row = [PSCustomObject]#{
ComputerName = $hostName
Name = $cimProcessor.Name
NumberOfCores = $cimProcessor.NumberOfCores
}
$row | Export-Csv -Path test.csv -NoTypeInformation -Append
In the case where you want to retrieve information from a remote machine first, then you can skip the calculated property and simply select the PSComputerName property instead:
Note: The ellipses ... indicate the code before or after from your original sample.
... | Select-Object PSComputerName, Name, NumberOfCores | ...
Any cmdlet which connects to remote systems via WinRM should have this property automatically set when data is returned over a remote session.
If you are running this from a local session, you could use Select-Object to create a calculated property, then call the hostname command to populate its value:
... | Select-Object "Name", "NumberOfCores", #{
Name = 'ComputerName';
Expression = { hostname };
} | ...
This solution is often suitable for cross platform scripts since a hostname binary is available out of the box on Windows, MacOS, and most major distributions of Linux.
Explaining Calculated Properties
Calculated properties work by defining a hashtable in a specific format and providing the hashtable as a property to be computed just as you would use a string for a real property on the object:
$property = #{
Name = 'PropertyName';
Expression = { 'ScriptBlock' };
}
# Note that the hashtable can be specified inline as shown above
# or as a variable like shown here
[PSCustomObject]#{ Name = 'Bender'; Loves = 'Bending' } |
Select-Object Name, Loves, $property
Keep in mind that within the Expression ScriptBlock, $PSItem/$_ is set to the current object in the pipeline. Use this to reference static or instance properties from the current object you are selecting information from.
Currently I want to get a list of active user on Windows 10 using Powershell.
After some searching I found this helps:
Get-LocalUser | Where-Object -Property Enabled -eq True
And here is the output:
Name Enabled Description
---- ------- -----------
User_1 True
User_2 True
I just want to concatenate strings to a list of values of Name column from above, which will be like below:
Active user(s): User_1, User_2
Do you have any idea how I can do that? I'm just a non-tech guy trying to learn some useful command so forgive me if this is a basic to you.
You can do the following:
# Retrieve the name values
$Users = Get-LocalUser |
Where-Object Enabled -eq True | Select-Object -Expand Name
# Create the output string
"Active user(s): {0}" -f ($Users -join ', ')
Using -Expand (or -ExpandProperty) from Select-Object, the target property's value is returned rather than the object that contains the property.
-f is the string format operator. It uses substitution for the {position} syntax. The -join operator creates a string from a list with , as the delimiter.
I'm trying to make a table in PowerShell with custom headers, I am able to do this with
"var" | Select #{n="First";e={"1"}}, #{n="Second";e={"2"}},#{n="Third";e={"3"}}
First Second Third
----- ------ -----
1 2 3
However, without the initial object, there is no output
Select #{n="First";e={"1"}}, #{n="Second";e={"2"}},#{n="Third";e={"3"}}
I can't tell the difference between these other than one is after a pipeline while the other isn't. Why won't this work?
Why doesn't this work?
The cmdlet Select-Object (alias Select) has one required parameter which is -inputObject Which also happens to be the object that gets passed through the pipeline.
Select-Object -InputObject "Example" -Property #{n="First";e={"1"}}, #{n="Second";e={"2"}},#{n="Third";e={"3"}}
Will have the output
First Second Third
----- ------ -----
1 2 3
While without -InputObject, it will not have an output because there is no input (Thanks #mklement0).
Select-Object "Example" -Property #{n="First";e={"1"}}, #{n="Second";e={"2"}},#{n="Third";e={"3"}}
# No Output
and with the pipeline, it will
"Example" | Select-Object "Example" -Property #{n="First";e={"1"}}, #{n="Second";e={"2"}},#{n="Third";e={"3"}}
First Second Third
----- ------ -----
1 2 3
The -inputObject Parameter will usually contain the table you would like to select columns from or other things (if you are not using expressions).
Although the answer from #Neko answers the exact question, I think it is important to mention that the Select-Object cmdlet is not mentioned to construct new custom objects:
Quote from the Get-Help Select-Object -Online:
The Select-Object cmdlet selects specified properties of an object
or set of objects.
In other words; the object needs to exist in order to select its properties.
For what you are doing with
"var" | Select #{n="First";e={"1"}}, #{n="Second";e={"2"}},#{n="Third";e={"3"}}`
you're creating a new pscustomobject by removing all the default properties from the "Var" (string) object and adding new properties with a hard-coded (static) expression which is a long-winded syntax and quiet expensive for building a new object.
To construct a new pscustomobject ("table"), you can simply use the constructor syntax:
[pscustomobject]#{First = '1'; Second = '2'; Third = '3'}
For legacy (prior PSv3) POwerShell versions:
New-Object PSObject -Property #{First = '1'; Second = '2'; Third = '3'}
I have a variable stored as a System.Array displayed as;
Site : https://value.sharepoint.com/
Email : value#value.co.uk
DisplayName : value
UniqueId : value
AcceptedAs : value#value.co.uk
WhenCreated : 24/01/2019 06:02:45
InvitedBy : value_value.co.uk#ext##value.onmicrosoft.com
When I try to export this variable as a file it shows in the same format. As this is not in the correct structure for a table (shown below) I am unable to use this data when I try to use it in Power BI.
Site Email ect
---- ---- ----
https://value.sharepoint.com/ value#value.co.uk ect
I need to get my data into the structure shown above. I have tried;
$Test = New-Object -TypeName PSObject -Property $ExternalUsers
However this results in the following error;
New-Object : Cannot convert 'System.Object[]' to the type 'System.Collections.IDictionary' required by parameter 'Property'. Specified method is not supported.
I then tried to loop through all of the items in the array and then create an object for each item, before adding it to a "Master Object";
foreach($var in $ExternalUsers){
$Test = New-Object -TypeName PSObject -Property $ExternalUsers
$Test | Add-Member -MemberType NoteProperty -Name Site -Value $var.Site
$Test | Add-Member -MemberType NoteProperty -Name Email -Value $var.Email
$TestObject += $Test
}
This got each item into the correct structure but when I tried to add all the items back into the one variable I got the error;
Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition'.
Any ideas how I could get around this?
To me it looks like you have an array (System.Object[]) containing PSObjects with the properties Site, Email etc.
A structure like that is ideal for exporting to CSV file, which you can then import in a spreadsheed application like Excel for instance.
For that you use the cmdlet Export-Csv like this:
$ExternalUsers | Export-Csv -Path 'PATH AND FILENAME FOR THE OUTPUT CSV FILE' -NoTypeInformation
If the output you show is complete, it seems there is only one element in the array. You can check this by looking at $ExternalUsers.Count.
I'm not quite sure what you mean by "As this is not in the correct structure for a table", because you can quite easily display it as table using
$ExternalUsers | Format-Table -AutoSize
Output on console window:
Site Email DisplayName UniqueId AcceptedAs WhenCreated InvitedBy
---- ----- ----------- -------- ---------- ----------- ---------
https://value.sharepoint.com/ value#value.co.uk value value value#value.co.uk 24/01/2019 06:02:45 value_value.co.uk#ext##value.onmicrosoft.com
If what you want is less properties, just loop through the array and select the properties you want to keep from the objects in it:
$Shortened = $ExternalUsers | ForEach-Object {
$_ | Select-Object Site, Email
}
$Shortened | Format-Table -AutoSize
Will produce:
Site Email
---- -----
https://value.sharepoint.com/ value#value.co.uk
I'm not into Power BI, but remember that the Format-Table cmdlet is for display purposes on console ONLY.
It does NOT provide anything else but a view on the data.
Hope this helps
use:
$TestObject = #()
and no need to specify (-Property $ExternalUsers)
$Test = New-Object -TypeName PSObject
This command saves list of VM to array.
[string]$arrayVM = Get-VM | select Name
When it refers to the first element of the array: $arrayVM[0]
I get the name of VM, but this value look like: #{name=MACHNINE_1_NAME}
I expected only the same name: MACHNINE_1_NAME
How can I do this?
You need to add the -ExpandProperty parameter to your Select-Object command. What this does is expands the value of the specified property and passes that down the pipeline instead of restricting the properties of the current object to be passed down the pipeline. Right now you are passing a Microsoft.HyperV.PowerShell.VirtualMachine object with only the Name property intact. This will instead pass a string with the value of the Name property.
$arrayVM = Get-VM | select -expand Name
[string]$ArrayVM = (Get-VM | Select-Object -Property Name).Name
[string]$arrayVM = Get-VM | select Name
$arrayVM[0].Name