Need help on where-object in powershell - powershell

if I execute the below code it is not filtering, it is returning all the results.
$R datatype is below

{} creates a [scriptblock] literal, the value of which will always evaluate to $True when cast to [bool].
Remove the {} around the comparisons inside the filter block:
$filteredRows = $R |Where-Object {$_.db_sync_state -eq 'NOT SYNCHRONIZING' -or -not $_.is_failover_ready}
As Gert Jan Kraaijeveld mentions, you can use () to group the individual comparisons if required:
$filteredRows = $R |Where-Object {($_.db_sync_state -eq 'NOT SYNCHRONIZING') -or (-not $_.is_failover_ready)}

Related

How to check parameter is null in where clause in powershell

I'm trying to write a PowerShell command but stucked on where clause. What i want to achieve is if parameters are not defined, where clause needs to ignore them. I tried this code but couldn't success.
I have parameters;
Param(
[parameter(position=0)]
[String]
$JobName,
[parameter(position=1)]
[String]
$JobID
)
And where clause which i tried and failed,
$Timerjob = Get-SPTimerJob | where { ($_.Id -eq $JobID) -or ($_.Title -eq $JobName) }
If $JobName or $JobID is null (or both of them), where clause should ignore them
how can i achieve this without writing multiple if clause?
Continuing from my comment:
To retrieve all Timer Jobs if both $JobName and $JobID are empty, you will need to add that condition to the Where-Object cmdlet:
$Timerjob = Get-SPTimerJob |Where-Object {
(!$JobName -and !$JobID) -or ($_.Id -eq $JobID) -or ($_.Title -eq $JobName)
}
This means if both $JobName and $JobID are empty, the condition (!$JobName -and !$JobID) is $True. Any condition with the -or comparison operator won't be able to change that (to $false) causing the whole condition to be true in that matter and all Timer Jobs returned.
In case you would like to make a difference between an empty string filter and a parameter that isn't supplied, you would probably want to do something like this:
$Timerjob = Get-SPTimerJob |Where-Object {
($PSBoundParameters.ContainsKey('JobName') -and $PSBoundParameters.ContainsKey('JobID')) -or
($_.Id -eq $JobID) -or ($_.Title -eq $JobName)
}
In this case you would e.g. still be able to retrieve Time Jobs with an empty title (-JobName ''), if even possible.

How to find a specific text is available in .txt file using powershell

I want to write a PowerShell script where I will give two string values as parameters, It should check the .txt file and should tell whether the strings are available or not in the given file. For example, if I have a list of employees details. I will give the emp_id and emp_name as input. If the name and id exist in that .txt file it should print that. If not it should print the else statement.
Function Empdetails {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory=$true)]$empid,
[Parameter(Mandatory=$true)]$empname)
$path = Get-Content C:\empdetails.txt | Where-Object {$_ -like '*name*'}
if ($path -eq $true) {
Write-Host "Found"
}
else {
Write-Host "Not Found"
}
}
I tried the above code, But it is working. Could you please help me to figure it out?
You have two parameters but you are not using them in your function, since it's not clear which parameter should be used for the file path and which for the word you're searching for in the file, I have changed the parameter names for something more explanatory.
Also note, the result of below expression will be either an array of strings, a single string or $null:
$path = ... | Where-Object {$_ -like '*name*'}
Hence, your if condition if ($path -eq $true) can never be met unless $path has assigned the literal string True. If, however, you change the order of the condition to $true -eq $path, then the condition can be met and will be $true as long as $path is not $null / empty string.
$content = 'something'
$content -eq $true # => False
$true -eq $content # => True
$content = 'True'
$content -eq $true # => True
$true -eq $content # => True
From equality operators:
The equality operator can compare objects of different types. It is important to understand that the value is on the right-hand side of the comparison can be converted to the type of the left-hand side value for comparison.
Function Empdetails {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory=$true)]$FilePath,
[Parameter(Mandatory=$true)]$WordToSearch
)
$content = Get-Content $FilePath | Where-Object {$_ -like "*$wordToSearch*"}
if ($content) {
# if `$content` is populated, use return to end the function here
return Write-Host "Found"
}
Write-Host "Not Found"
}
Empdetails -FilePath ./path/to/file.ext -WordToSearch somekeyword

Check if string is in list of strings

Context:
We are making an API to get a list of all VMs and the filter it, using if loops, to return only VMs with name starting only with the values in $MachineList.
The list of servers is split in 2:
set 1: srv-a-1, srv-a-2, srv-b-1, srv-b-2, srv-c-1, srv-c-2, etc.
set 2: tst-a-1, tst-a-2, tst-b-1, tst-b-2, tst-c-1, tst-c-2, etc.
This is the script:
$EnvironmentList = "Environments-4" -or "Environments-5" -or "Environments-41" -or "Environments-61"
$MachineList = "srv-a*" -or "srv-b*" -or "srv-c*" -or "srv-d*" -or "srv-e*" -or "srv-f*" -or "srv-g*" -or "srv-h*" -or" srv-i*" -or "srv-j*" -or "srv-k*" -or "srv-l*"
function CheckService {
$MachinesRequest = (Invoke-WebRequest -Method Get -Headers #{"X-system-ApiKey"="Hashed-API-Key-Value"} -URI https://url-to-site.local/api/machines/all).Content | ConvertFrom-Json
foreach ($Machine in $MachinesRequest) {
if ($EnvironmentList -contains $Machine.EnvironmentIds) {
if ($MachineList -contains $Machine.Name) {
$Machine.Name
}
}
}
}
CheckService
We're trying to return just the items which match the values in the machine list however this is returning the full list of machines (both srv* and tst*).
First and foremost, $MachineList = "srv-a*" -or "srv-b*" -or ... won't do what you apparently think it does. It's a boolean expression that evaluates to $true, because PowerShell interprets non-empty strings as $true in a boolean context. If you need to define a list of values, define a list of values:
$MachineList = "srv-a*", "srv-b*", ...
Also, the -contains operator does exact matches (meaning it checks if any of the values in the array is equal to the reference value). For wildcard matches you need a nested Where-Object filter
$MachineList = "srv-a*", "srv-b*", "srv-c*", ...
...
if ($MachineList | Where-Object {$Machine.Name -like $_}) {
...
}
A better approach in this scenario would be a regular expression match, though, e.g.:
$pattern = '^srv-[a-l]'
...
if ($Machine.Name -match $pattern) {
...
}
use -eq for an exact match. use -match or -contains for a partial string match
$my_list='manager','coordinator','engineer', 'project engineer',
$retval=$False
if ($dd_and_pm -eq "engineer")
{
$retval=$True
}

simpler Powershell OR condition syntax

Is there a simpler way to specify an -or condition? For example, if ($returnValue -eq 0 -or $returnValue -eq 5). I would rather write something like if ($returnValue -eq 0 -or 5) to test two possible values of $returnValue. Of course that's doing something else.
Ok, just thought of coercing the value into a character type using a regular expression:
if ($returnValue -match '0|5')
So, now that I've answered my question, any other ideas?
I would use -contains or -in where appropriate:
if ((0,5) -contains $returnValue)
or
if ($returnValue -in (0,5))
-in was added in PowerShell v3.
I highly discourage the regex "solution" because it can have unintended side effects and reduces clarity. For example 51 -match '0|5' is $true.
Consider just formatting your if statement on multiple lines:
if (
$returnValue -eq 0 -or
$returnValue -eq 5
)
Though I still like -contains and -in for what you're trying to achieve.
$validVals = #(
0,
5,
17
)
if ($validVals -contains $returnVal) {
# ...
}
if ($returnVal -in $validVals) {
# ...
}

Powershell: How can you determine which variable in an "if" statement triggered True?

In powershell, I have code that looks like this. The intention is to populate a handful of variables with data if a user doesn't supply any:
if ($1 -eq $null){$1 = "N/A"}
if ($2 -eq $null){$2 = "N/A"}
if ($3 -eq $null){$3 = "N/A"}
Is it possible to condense these down to something like this?
if ($1 -or $2 -or $3 -eq $null){
$FILLER = "N/A"
}
Where $FILLER is the variable(s) that returned True?
Edit: For example, if $2 was null but $1 and $3 were not- then the code would assign N/A to $2.
Note: I don't have a problem with the individual if statements, I'm just aiming to condense repetitive code.
You can use Get-Variable cmdlet. That cmdlet return PSVariable objects, which represent variables, to you. PSVariable objects have Value property, which allows you get and set value of variable. So that, you can filter variables which have particular value ($null), and then assign new value to them.
Get-Variable 1, 2, 3 |
Where-Object { $null -eq $_.Value } |
ForEach-Object { $_.Value = 'N/A' }
You can use ! to define -eq $null or -eq $false:
if (!$1 -or !$2 -or !$3){
$FILLER = "N/A"
}
You could change the order a bit:
$1 = if (!$1) { "N/A" }
But what you're really asking, how to determine which of multiple conditions returned $true in an if statement, is not possible.
If you want to pass an array of values and get back the ones that satisfy a condition, consider Where-Object:
$result = $1,$2,$3 | Where-Object { -not $_ }
If the condition is a string operator like -match or -like it actually works on arrays already and returns an array:
$result = 'apple','apply','ape','zebra' -like 'app*'