How are parenthesis around a powershell command different than without? - powershell

I am using Get-NetIPAddress. ALL I want is the actual address without ANY formatting or tables or anything.
If I use
(Get-NetIPAddress).IPAddres
I get a list of addresses for all ports. I want only a single port so I tried to pipe it but gave nothing in return:
(Get-NetIPAddress).IPv4Address | Where-Object InterfaceAlias -eq "MyPortName"
But if I do this:
Get-NetIPAddress.IPv4Address | Where-Object InterfaceAlias -eq "MyPortName"
It says that this is an invalid command.
If I use this:
Get-NetIPAddress | Where-Object InterfaceAlias -eq "MyPortName" | Where-Object AddressFamily -eq IPv4 | Select-Object IPAddress
I get:
IPAddress
---------
10.45.22.100
So what is going on when I put parenthesis around Get-NetIPAddress and how can I get JUST the darn address number for a particular port?

By enclosing a command with () you create an order of precedence, so everything inside of () executes first and after that your other commands are evaluated.
also, there is no such construct as cmdlet.property
as for the second part, after you do (Get-NetIPAddress).IPv4Address you are probably getting another object, just compare output from:
Get-NetIPAddress | Get-Member
and
(Get-NetIPAddress).IPv4Address | Get-Member

Get-NetIpAddress is a cmdlet, PowerShell runs it. It outputs one or more objects, and by that I mean one many names and numbers and features all grouped together into one blob.
Get-NetIpAddress | Select-Object IPv4Address takes the object(s) and turns them into simpler, smaller objects with just one property, the IPv4Address.
That's what this is:
IPAddress
---------
10.45.22.100
it's a rendering of an object with one property.
Get-NetIpAddress | Select-Object -ExpandProperty IPv4Address takes the objects, takes just the IPv4Address, and throws away the grouping and leaves just the IPv4Address as a string.
That would output:
10.45.22.100
10.45.22.101
These have been expanded to strings, there's no column title. They've been unwrapped.
This is something you want to do a lot, but it's a lot of typing. $x = Get-NetIpAddress; $x.IPv4Address is a shortcut way of getting just the Ipv4Address unwrapped from the object and without anything else.
So you want to do
Get-NetIpAddress.IPv4Address but that falls over, because it looks like the name of a different cmdlet and PowerShell tries to run it and cannot. This is just a clash of syntax - it could be a name, it could be a property lookup, and powershell chooses differently. you need something (parens) to make the distinction.
(Get-NetIpAddress).IPv4Address makes it clear to the shell that there is a cmdlet, it runs that, then gets the result into the parentheses, then gets the property from them. That clears up the name clash. But at this point you have thrown away the InterfaceName, so pushing this output to the pipeline can't let you choose based on interface name.
Follow that through and you can see
If you do (Get-NetIPAddress).IPv4Address the output is strings and you have thrown away all the other data that came out of the cmdlet.
If you want to choose one string based on the interface name, you have to do that before you unwrap the IP and throw the interface name away.
So
Get-NetIpAddress |
Where-Object { pick the one I want } |
Select-Object -ExpandProperty 'the thing I want'

Brackets work in the same way as they do in mathematics, they set an order of precedence, so anything within brackets will execute first.
To get just the IP Address value from your final command, do this instead:
(Get-NetIPAddress | Where-Object InterfaceAlias -eq "MyPortName" | Where-Object AddressFamily -eq IPv4).IPAddress
This command:
(Get-NetIPAddress).IPv4Address
Returns the value of the IPv4Address property (probably as a string), which is why this command then doesn't work:
(Get-NetIPAddress).IPv4Address | Where-Object InterfaceAlias -eq "MyPortName"
As you are piping a string object that contains an IP Address into the Where-Object cmdlet and then are looking to filter on the InterfaceAlias property that does not exist in that object.
When you access a property via the . notation you get it's value. When you access a property via the Select-Object cmdlet you return an object (of the same type as the source object) that is filtered down to just containing that single property (unless you use the -ExpandProperty switch, which causes Select-Object to return the value of the defined property instead of an object in the same way as using . notation).
Long story short, do any filtering you need to do first, then access the property/properties you want as a result last.

Using this syntax you provided:
Get-NetIPAddress | Where-Object InterfaceAlias -eq "MyPortName" | Where-Object AddressFamily -eq IPv4 | Select-Object IPAddress
...getting just the IP address (without the object notation), can be done in two ways:
Get-NetIPAddress | Where-Object InterfaceAlias -eq "MyPortName" | Where-Object AddressFamily -eq IPv4 | Select-Object -Expand IPAddress
notice the "ExpandProperty" argument, abbreviated "Expand" on the above line ...or:
(Get-NetIPAddress | Where-Object InterfaceAlias -eq "MyPortName" | Where-Object AddressFamily -eq IPv4 | Select-Object IPAddress).IPAddress
...where we return the object and then reference the IPAddress property on the object.

Related

How to put computers on a network into a variable in PowerShell?

I've been using these lines of code:
$204computernames = Get-ADComputer -searchbase $sb -filter * | ?{$_.name -like "ptfg*-061*"} | select name
$onlineComputers = $204computernames |Where-Object { Test-Connection $_.name -Count 1 -Quiet }
to grab all of my computers on my network and put them into a variable so I can push all of my documents, updates, etc to them so that I dont have to go to each computer individually to get the files I want where I want. When I take the variable and put it into a line of code like this
Test-Connection $onlineComputers
I get errors like this:
Test-Connection : Testing connection to computer '#{name=PTFGW-0613618TN}' failed: A non-recoverable error occurred during a database lookup
At line:1 char:1
+ Test-Connection $onlineComputers
I'm assuming after extensive testing in different codes that there is a problem with the way my variable stores its values. Does anyone know how I can fix this issue?
As #boxdog already pointed out in the comments, with | select name you get objects with the single property Name. Therefore, you don't get a list of computer names, but a list of objects that have the computer name in the Name property. You can work with that and access each computer name like .Name.
But to solve your problem, you can replace | select name (which stands for | Select-Object -Property Name) by | Select-Object -ExpandProperty Name. That way, you filter out only the computer name and expand the result to just this property. After that, you really have just a list of computernames (an array of string objects).

Using Where-Object with an object in PowerShell

I can't seem to get my brain around something and I am hoping someone can help
I have an array of objects called $SnapVMsAll that looks like this:
VMName Name SnapshotType CreationTime ParentSnapshotName
------ ---- ---------- ------------ ------------------
SHARED-server.host.com SHARED-server.host.com - (02/10/2017 - 13:02:44) Standard 02/10/2017 13:05:58
I need to display all the records in this array of objects that have string "Veeam" in the name column, but I think I am having problems isolating a specific attribute of the object to compare.
My attempts have been as follows:
echo $SnapVMsAll | Where-Object (Foreach-Object -MemberName name) -Like "Veeam Replica"
This returned the error:
Where-Object : Cannot validate argument on parameter 'Property'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
I have also tried
echo $SnapVMsAll | Where-Object $SnapVMsAll.name -Like "Veeam Replica"
But again I get the same error.
$SnapVMsAll does not exist inside the pipeline, it is the object you pass to the pipeline. Within a pipeline, objects can be accessed using the automatic variable $_.
Also note that -Like is usually used with wildcards to match a string. If the name is Veeam Replica you should use -eq, if the name contains Veeam Replica, you should change to -Like "*Veeam Replica*"
So changing your code to the following should work:
$SnapVMsAll | Where-Object { $_.name -Like "*Veeam Replica*" }

Getting Calculated Expression to Display Properly in Powershell Exchange Command

So I have a command to look at all the mailboxes in my environment and return the oldest item in any folder that is not the "Contacts" folder of that particular mailbox. The whole thing seems to work except for the calculated expression that I threw in at the end of the command:
#{Name="Address";Expression={Get-Mailbox | ForEach-Object {$_.PrimarySmtpAddress}
The problem is this seems to return every Smtp Address for each line/object instead of one Smtp Address per line/object.
Here's the entire command:
Get-Mailbox | ForEach-Object {Get-MailboxFolderStatistics -IncludeOldestandNewestItems -Identity $_.Alias | Where-Object {($_.OldestItemReceivedDate -ne $null) -and ($_.FolderPath -ne "/Contacts")} | Sort OldestItemReceivedDate | Select First 1 OldestItemReceivedDate, Identity, #{Name="Address";Expression={Get-Mailbox | ForEach-Object {$_.PrimarySmptAddress}}}}
Ideally this would return the date of the oldest item, the folder where it was found, and the primary SMTP Address but it doesn't seem to be pulling only the corresponding SMTP Address. It looks like it's pulling every Primary SMTP Address every iteration. I'm sure it's something with my command but I can't figure out where. Any help would be much appreciated.
The calculated expression has access to the current pipeline object. However you are not using that when creating your expression. You are just calling every mailbox for each user as you have seen. Use the current pipeline object with $_. Get-Mailbox is smart enough to match needed values by property name.
#{Name="Address";Expression={Get-Mailbox $_ | ForEach-Object {$_.PrimarySmtpAddress}}}}
However you might be able to go about this is a different way. You already called all mailboxes at the start of your pipeline. No sense calling it a second time again.
Get-Mailbox | Select-Object Identity, #{Name="Address";Expression={$_.PrimarySmtpAddress}}, #{Name="OldestItemReceivedDate";Expression={
Get-MailboxFolderStatistics -IncludeOldestandNewestItems -Identity $_.Alias | Where-Object {
($_.OldestItemReceivedDate -ne $null) -and ($_.FolderPath -ne "/Contacts")} |
Sort-Object OldestItemReceivedDate |
Select-Object -ExpandProperty OldestItemReceivedDate -Last 1
}}
Now we have 2 calculated properties and we only need to call Get-Mailbox once for each user. You have some spelling mistakes and logic errors that I tried to fix. You will know if it does what you want.

Referencing variables that are not strings

I want to reference properties selected from a cmdlet and then use them later on in my script as $mailboxarray.totalitemsize and $mailboxarray.totalitemsize
This is breaking later on in my script as I assume it doesn't like the type of object it is. How can I make anything I pull into the references a string? At the moment I am getting "No mapping exists from object type System.Management.Automation.PsObject to a known managed provider type". My code at the moment: the first command works fine but I can't use expandproperty when there are multiple entries like line two?
$recipienttype = Get-mailbox -identity $recordset.PrimarySmtpAddress | Select -expandproperty RecipientTypeDetails
$mailboxarray = Get-Mailbox -identity $recordset.PrimarySmtpAddress | Get-MailboxStatistics | Select-object totalitemsize, lastlogontime

Filter the output of a command as if it was text

I have a simple question, but I am also a beginner in PowerShell. I think it has to do with the fact that the output of the Get-Process command (alias ps) is objects and not text.
I want to get a list of the services running that have the name "sql" in them.
This is what I tried so far, but every attempt returns nothing:
Get-Service | where {$_ -match 'sql'}
Get-Service | where {$_ -like 'sql'}
Get-Service | Select-String sql
I am looking for a pattern that lets me treat the output of every command as searchable text.
Just forget it :o)
Outputs are objects. You are right, and you are going to use this.
So mjolinor has the shortest answer, but for your knowledge just test:
Get-Service | Get-Member
So you will understand that
Get-Service | Where-Object {$_.name -match ".*sql.*" }
also works, and there you've got your text as a property of the object.
Most answers here focus on finding the service name with "sql" in the name, not on filtering the entire output as if it was text. Also, the accepted answer uses a non-PowerShell function, "findstr".
So, granted, what follows is not the most elegant solution, but for sake of completeness I would like to provide the 100% PowerShell solution that takes the question of the OP literally:
(get-Service | Out-String) -split "`r`n" | Select-String sql
We need Out-String, because using the solutions provided in other answers doesn't provide us the full text output of the Get-Service command, only the Name parameter.
We need to split on newlines, because Select-String seems to treat the entire text as one long string, and returns it as a whole, if "sql" is found in it.
I use Select-String instead of findstr, because findstr is not a PowerShell function.
This is a purist answer, and in practice, for this specific use-case, I would not recommend it. But for people coming here through Google Search based on the question title, this is a more accurate answer...
Get-Service | Select-String -Pattern "sql"
This works just like grep. And you can even sort:
Get-Service | Select-String -Pattern "sql" | sort
The other answers are right of course about your specific question of starting services that have "sql" in their name, but to answer the generic question:
You can do Get-Service | Out-String, and you will get the output as string, much like how Unix commands work.
Also when the output is piped to non-PowerShell commands, it does get converted to text, so for example: Get-Service | grep sql would work the way you wanted.
But again, like #JPBlanc says, it is good embrace the way PowerShell works, which is that the outputs are objects. It gives you way more control and keeps things simple and readable (the Unix commands with sed, awk and what not operating on text output of other command outputs can get very cryptic!).
You're working way too hard at it:
Get-Service *sql*
If anyone wants more information on logical operations, please see Using the Where-Object Cmdlet:
• -lt -- Less than
• -le -- Less than or equal to
• -gt -- Greater than
• -ge -- Greater than or equal to
• -eq -- Equal to
• -ne -- Not equal to
• -like - Like; uses wildcards for pattern matching
Get-Service | where {$_ -match 'sql'} would be Get-Service | where {$_ -eq "sql"}
Get-Service | where {$_ -like 'sql'} would be Get-Service | where {$_ -like "sql"}
And now an actual example.
PS C:\> Get-Service | where {$_.name -like "net*"}
Status Name DisplayName
------ ---- -----------
Running Net Driver HPZ12 Net Driver HPZ12
Running Netlogon Netlogon
That the text of the name is a property of the object is important to get your head around, and how to use the property values in a filter.
Another aspect of PowerShell you can leverage to solve this is selecting properties out of objects with Select-Object (alias select):
Get-Service | select -expand name
will get you a string array with the names of the servers, and two of your original three filters would work on that. The -like isn't going to work, because there's no wildcards in the test string. The only thing it will ever match is just 'sql'.
I still believe the first solution I posted is best. It's important to know how to do late filtering, but also how to use early filtering when you can.
If you want to list all services with "sql" in the service name, just use:
get-service -name *sql*
You probably want this:
Function Select-ObjectPropertyValues {
param(
[Parameter(Mandatory=$true, Position=0)]
[String]
$Pattern,
[Parameter(ValueFromPipeline)]
$input
)
$input | Where-Object {($_.PSObject.Properties | Where-Object {$_.Value -match $Pattern} | Measure-Object).count -gt 0} | Write-Output
}
Here we are going though each property of an object to see if it matches the given pattern. If the object contains one or more such properties, we write it out. End result: grep by all properties of an object.
Put it in your configuration files and grep to your heart's content.
how about:
Get-Service| Out-String -stream | Select-String sql
where the key point is that -stream option converts the Out-String output in separate lines of text.