PowerShell While Loop Multiple Conditions not working - powershell

Want to check multiple conditions in a while loop, but they don't work.
#Debug
if ($DatumArray -notcontains $DatumAktuellerFeiertag) {echo "true"} else {echo "false"}
if ($TagAktuellerFeiertag -ne "Samstag") {echo "true"} else {echo "false"}
if ($TagAktuellerFeiertag -ne "Sonntag") {echo "true"} else {echo "false"}
The above code gives the following result:
true
false
true
Notice, one of the results is "false".
while (($DatumArray -notcontains $DatumAktuellerFeiertag) -and ($TagAktuellerFeiertag -ne "Samstag") -and ($TagAktuellerFeiertag -ne "Sonntag")) {
# some code...
}
The loop is not performed, even though one of the results is "false".
What is the possible way to archive my goal? Why is this while loop not working?
Edit:
This working not as expected, because you not know my condition I think. So I will try to explain:
Got an array with public holidays $DatumArray (01.01.2019, 19.04.2019, 21.04.2019 like this...).
$DatumAktuellerFeiertag is the actual public holiday date.
$TagAktuellerFeiertag is the actual public holiday weekday.
Now I'm trying to figure out the next working day (but if the next working day a public holiday too, it has to consider that).
So my condition will be like: while there is a public holiday OR a Saturday OR a Sunday, increment $DatumAktuellerFeiertag by 1.
while (($DatumArray -notcontains $DatumAktuellerFeiertag) -and (($TagAktuellerFeiertag -ne "Samstag") -or ($TagAktuellerFeiertag -ne "Sonntag"))) {
$DatumAktuellerFeiertag = (Get-Date $DatumAktuellerFeiertag).AddDays(1).ToString("dd/MM/yyy")
$TagAktuellerFeiertag = (Get-Date $DatumAktuellerFeiertag -Format "dddd")
echo $DatumAktuellerFeiertag
}
Edit:
Tried your version, works on "normal" days flawless, but gives me a endless loop at a public holiday.
$ListPublicHoliday = Import-Csv 'datum.csv'
$DateArray = $ListPublicHoliday.Datum
$DateArray = $DateArray | ForEach-Object { (Get-Date $_).Date }
$ActuallyDay = Get-Date 19.04.2019
while (($DateArray -contains $ActuallyDay.Date) -or ('Samstag', 'Sonntag' -contains $ActuallyDay.DayOfWeek)) {
$ActuallyDay.AddDays(1)
}
My CSV:
#TYPE Selected.System.String
"Datum","Feiertag","Wochentag","Value"
"01.01.2019","Neujahrstag","Dienstag","01.01.2019 18:33:01"
"19.04.2019","Karfreitag","Freitag","19.04.2019 18:33:01"
"21.04.2019","Ostersonntag","Sonntag","21.04.2019 18:33:01"
PS: can you explain me this? (Get-Date $_).Date? I didn't find this on Microsoft docs.

The loop is not performed, even though one of the results is "false". [...] Why is this while loop not working?
The loop doesn't work because one of the results is $false. Your condition consists of 3 clauses connected with -and operators, meaning that all of the clauses must evaluate to $true for the loop to operate. However, since your 2nd and 3rd clause are mutually exclusive, that will never happen.
I'm not quite sure what your condition is supposed to look like, but at the very least you need the condition to be A && (B || C) rather than A && B && C.
Change this:
while (($DatumArray -notcontains $DatumAktuellerFeiertag) -and ($TagAktuellerFeiertag -ne "Samstag") -and ($TagAktuellerFeiertag -ne "Sonntag")) {
# some code...
}
into this:
while (($DatumArray -notcontains $DatumAktuellerFeiertag) -and (($TagAktuellerFeiertag -ne "Samstag") -or ($TagAktuellerFeiertag -ne "Sonntag"))) {
# some code...
}
Edit:
After you updated your question, clarifying what you're actually trying to accomplish, your clauses should indeed be connected with -or operators, as Mathias suspected in the comments. However, the operators inside the clauses must not be negated on top of that (you need -contains and -eq instead of -notcontains and -ne). Also, your code would become a lot simpler if $DatumArray contained DateTime objects instead of strings. The two weekday comparisons could be combined in one too.
Something like this should work:
$DatumArray = $DatumArray | ForEach-Object { (Get-Date $_).Date }
$startDate = ...
$cur = Get-Date $startDate
while (($DatumArray -contains $cur.Date) -or ('Samstag', 'Sonntag' -contains $cur.DayOfWeek)) {
$cur = $cur.AddDays(1)
}

Related

elseif not being recognized - Variable not being assigned correct value

I have written a small script that checks the HostName in a URL for a sharepoint Site Collection and then gives a variable a value based on that HostName but the elseif in the script is not working:
$sites = Get-SPSite https://contoso.domain.cs/sites/sc
$Logo = $null
if ($sites.HostName -eq "contoso.domain.cs" -or "contoso1.domain.cs" -or "contoso2.domain.cs")
{
$Logo = "/path/to/logo.jpg"
}
elseif ($sites.HostName -eq "contosoq.domain.cs" -or "contoso1q.domain.cs" -or "contoso2q.domain.cs")
{
$Logo = "/path/to/logo2.jpg"
}
elseif ($sites.HostName -eq "contoso3q.domain.cs")
{
$Logo = "/path/to/logo3.jpg"
}
else {}
The Variable $Logo is always getting the first value "/path/to/logo.jpg" even when the hostname is not equal to "contoso.domain.cs" or "contoso1.domain.cs" or "contoso2.domain.cs"
please help me if you see the error im making. thank you!
You need to alter the way you check the conditions. The entire expression to be evaluated must be repeated after each -or.
For example:
if ($sites.HostName -eq "contoso.domain.cs" -or "contoso1.domain.cs" -or "contoso2.domain.cs")
Could be changed to check each condition explicitly:
if ($sites.HostName -eq "contoso.domain.cs" -or $sites.HostName -eq "contoso1.domain.cs" -or $sites.HostName -eq "contoso2.domain.cs")
Or you could do it by using the -in comparison:
if ($sites.HostName -in ("contoso.domain.cs", "contoso1.domain.cs", "contoso2.domain.cs"))
As mentioned in the comments by iRon the following technique also works:
if ("contoso.domain.cs", "contoso1.domain.cs", "contoso2.domain.cs" -eq $sites.HostName)

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.

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
}

Pipe a string through multiple if-statements with an else for each

Essentially I have an If statement that has two conditions using -and, which a string is then run through. However, what I really want is the string to be run through the first condition, then if that is true, it checks for the second, and if that is true it does one thing, and if it is false do something else.
I currently have:
if(($_ -match "/cls") -and ($env:UserName -eq $Name)){cls}
I know I can do what I want with:
if(($_ -match "/cls") -and ($env:UserName -eq $Name)){cls}
elseif(($_ -match "/cls") -and ($env:UserName -ne $Name)){OTHER COMMAND}
But I would like to know if there was a more simple way.
(The result is already being piped in from somewhere else, hence the $_)
Move the first match to the outer scope.
if($_ -match "/cls")
{
if ($env:UserName -eq $Name))
{
cls
}
else
{
other command
}
}
I would write two if statements to improve readabilty. This way, you also need the pipeline value only once::
if($_ -match "/cls")
{
if ($env:UserName -eq $Name)
{
cls
}
else
{
#OTHER COMMAND
}
}

filtering and though a sharepoint list items with powershell

I have tried below but not getting any result back
Not sure if i'm doing this well.
Can i filter in the foreach or in my if statement
Thanks in advance
[DateTime] $CreatedDate = $item["Created"]
$convertedCreatedDate = $CreatedDate.ToString("yyyy-MM-dd")
$today = (Get-Date).AddDays(-1).ToString("yyyy-MM-dd")
foreach ($item in $list.items | where {$convertedCreatedDate -eq $today}) {
if ($list.items | where {$convertedCreatedDate -eq $today})
{
Write-Host $item["Created"]
}
Write-Host $item["Created"]
}
You can use a complex expression in your foreach as you're doing above. I would wrap it in a #() to make the code a bit more readable and to ensure the result is an array (either length 0, 1 or n) e.g.:
foreach ($item in #($list.items | where {$convertedCreatedDate -eq $today})) {
You can also simplify you're date testing by using the Date property on a DateTime e.g.:
$convertedCreatedDate = ([DateTime]$item["Created"]).Date
$today = (Get-Date).Date
You can also put a complex expression within an if statement condition but PowerShell will only evaluate whether the statement is $true or $false. PowerShell does lots of coercion to try to take something like:
$list.items | where {$convertedCreatedDate -eq $today}
And convert that to a boolean. Essentially if the pipeline evaluates to a non-empty result, the result is $true otherwise it is $false. This is probably not what you intended.
Try this:
$today=(Get-Date).AddDays(-1).ToString("yyyy-MM-dd")
foreach ($item in $list.items) {
[DateTime]$CreatedDate=$item["Created"]
$convertedCreatedDate=$CreatedDate.ToString("yyyy-MM-dd")
if ($convertedCreatedDate -eq $today) {
Write-Host $item["Created"]
}
}