Put each set of conditions in parentheses:
if ( (A -and B) -or (C -and D) ) {
echo do X
}
If either the first or the second set of conditions must be true (but not both of them) use -xor instead of -or:
if ( (A -and B) -xor (C -and D) ) {
echo do X
}
Replace A, B, C, and D with the respective expressions.
Answer from Ansgar Wiechers on Stack Overflow
I have an if statement that I am using to select specific rows from a CSV. Column 1 has a filename in it and then column b has 1 of 4 strings in it comprised of low, medium, high, and critical. I want an if statement that selects the row if column a contains file_1.txt and column b contains either high or critical. I've tried the following:
if(($row.column_a -eq 'file_1.txt') -and ($row.column_b -eq 'high' -or $row.column_b -eq 'critical')) {
$row.column_c
}It does not seem to be working correctly. I should be getting 7 results from column C, but I am only getting 5.
I think there's a better way to express this. Not sure where I am tripping up. Any help would be appreciated! Thanks in advance!
Powershell If statement with multiple conditions - Stack Overflow
Powershell - Multiple if statements
multiple if statement conditions
Multiple Variable Conditions for If Statement in PowerShell - Stack Overflow
Put each set of conditions in parentheses:
if ( (A -and B) -or (C -and D) ) {
echo do X
}
If either the first or the second set of conditions must be true (but not both of them) use -xor instead of -or:
if ( (A -and B) -xor (C -and D) ) {
echo do X
}
Replace A, B, C, and D with the respective expressions.
If you want to make the code in your own answer easier to understand you can remove the duplicate code to make the if statement cleaner.
Assigning the results to variables and using those instead:
$UserName = Get-WmiObject –ComputerName $poste –Class Win32_ComputerSystem | select -ExpandProperty UserName
$WindowsVersion = Get-WmiObject -Computer $poste -Class Win32_OperatingSystem | select -ExpandProperty Version
$LogonuiProcess = Get-Process -name logonui -ComputerName $poste -ErrorAction SilentlyContinue
Then either:
if (($UserName -and $WindowsVersion -like "*10*") -or ($UserName -and -not $LogonuiProcess)) {Write-Output "do X"}
Or
if ($UserName -and $WindowsVersion -like "*10*") {Write-Output "do X"}
elseif ($UserName -and -not $LogonuiProcess) {Write-Output "do Y"}
If this is just for checking and not for keeping a log where you need those specific messages I might go for something simple where we just capture the true and false values for each of the tests.
$path = C:\temp
Get-ChildItem $Path -Directory -Force |
ForEach-Object {
[PSCustomObject]@{
Folder = $_.BaseName
LastWriteTime = $_.LastWriteTime
FolderNameTest = $_.BaseName -match 'test'
DateOKTest = $_.LastWriteTime -lt (Get-Date).AddDays(-30)
}
}
Sample Output
Folder LastWriteTime FolderNameTest DateOKTest
------ ------------- -------------- ----------
.git 06.09.2021 01:06:06 False True
.vscode 25.09.2021 10:06:11 False True
1 22.09.2021 22:30:26 False True
batch_test 02.05.2022 22:29:25 True False
cleanup 20.09.2021 10:02:51 False True
DeviceDatabase 26.09.2021 12:07:26 False True
host 22.09.2021 23:23:38 False True
move_logs 26.04.2022 19:28:59 False False
test_run 01.03.2022 22:14:14 True True
You can then pipe this to Export-Csv if you like
There are various ways to go about this; but this one is clean and easy to understand, so would be my preferred route:
Function Move-FolderConditional { # todo: give this cmdlet a better name for your context
[CmdletBinding()]
Param (
[Parameter(Mandatory, ValueFromPipeline)]
[System.IO.DirectoryInfo[]]$Path
,
[Parameter(Mandatory)]
[System.IO.DirectoryInfo]$Destination
,
# files matching this pattern get moved to the target
[Parameter(Mandatory)]
[string]$ArchivableFolderPattern
,
# Files older than this date get moved to the target
[Parameter()]
[string]$MinKeepDateUtc = (Get-Date).AddDays(-3).ToUniversalTime()
)
Process {
foreach ($directory in $Path) {
if ($directory.BaseName -notmatch $ArchivableFolderPattern) {
Write-Warning "Could not move folder '
directory.FullName)' as the name does not match the required pattern"
continue;
}
if ($directory.LastWriteTimeUtc -ge $MinKeepDateUtc) {
Write-Warning "Could not archive folder '
directory.FullName)' as it was last updated at '
directory.LastWriteTimeUtc.ToString('u'))'"
continue;
}
try {
#Move-Item -Path $directory -Destination $Destination -ErrorAction Stop # Uncommend this if you actually want to move your files
Write-Information "Successfully moved '
directory.FullName)' to '
Destination.FullName)'"
} catch [System.Management.Automation.ItemNotFoundException] { # For this exception we'd probably check in the Begin block instead - but this is just to give the idea that we could add a try/catch if required
Write-Warning "Could not archive folder '
directory.FullName)' the target directory does not exist: '
Destination.FullName)'"
}
}
}
}
# Example usage
Get-ChildItem $path -Directory -Force | Move-FolderConditional -ArchivableFolderPattern '^log' -InformationAction Continue -Destination 'z:\archive\'
But other options are available (I've just included snippets to give the gist of these):
Switch Statement
switch ( $directory )
{
{$_.BaseName -notmatch $ArchivableFolderPattern}
{
Write-Warning "Could not move folder '
_.FullName)' as the name does not match the required pattern"
break
}
{$_.LastWriteTimeUtc -ge $MinKeepDateUtc}
{
Write-Warning "Could not archive folder '
_.FullName)' as it was last updated at '
_.LastWriteTimeUtc.ToString('u'))'"
break
}
default
{
Write-Information "Successfully moved '
_.FullName)' to '
Destination.FullName)'"
}
}
Flags
[bool]$archiveFolder = $true
if ($directory.BaseName -notmatch $ArchivableFolderPattern) {
Write-Warning "Could not move folder '
directory.FullName)' as the name does not match the required pattern"
$archiveFolder = $false
}
if ($directory.LastWriteTimeUtc -ge $MinKeepDateUtc) {
# note: this will process even if archivefolder is already false... you can use `else` or amend the condition to include `$archiveFolder -or ($directory.LastWriteTimeUtc -ge $MinKeepDateUtc)`; though if going that route it's better to use the switch statement.
Write-Warning "Could not archive folder '
directory.FullName)' as it was last updated at '
_.LastWriteTimeUtc.ToString('u'))'"
$archiveFolder = $false
}
if ($archiveFolder) {
Write-Information "Successfully moved '
directory.FullName)' to '
Destination.FullName)'"
}
Other
Or you can do combinations of the above (e.g. use the switch statement to set your flags (in which case you can optionally remove the break so that all issues are displayed).
Hi,
I'm a noob here. I still suck at PowerShell. But I think this should be easy. I cant find an example of what I'm trying to do. It's either just one condition or something so complicated, I can't understand it.
# Define database variables/values
$A_through_F = "A_through_F"
$G_through_K = "G_through_K"
$L_through_P = "L_through_P"
$Q_through_U = "Q_through_U"
$V_through_Z = "V_through_Z"
Write-Host "Enter the user name in the format of first name space last name"
Write-Host "Enclose the users name in quotation marks"
$User = Read-Host "Please enter the user"
Write-host "Fetching $User properties..." -ForegroundColor red -BackgroundColor Black
Write-Host ""
$UserSurname = Get-ADUser -Filter * -Properties * -SearchBase "OU=??? Users,OU=???.com" -Server "MY_AD.MY_DOMAIN" | where-object Name -eq "$User" | select-object -ExpandProperty SN
#Gets Surname
$FirstCharacterSurName = $UserSurname.SubString(0,1)
Write-Host "The first character of the surname of the user you have entered is: $FirstCharacterSurName"
if ( $FirstCharacterSurName -eq "A" -or "B" -or "C" -or "D" -or "E" -or "F" )
{
Write-Host "User belongs in $A_through_F database"
}
elseif ( $FirstCharacterSurName -eq "G" -or "H" -or "I" -or "J" -or "K" )
{
Write-Host "User belongs in $G_through_K database"
}
elseif ( $FirstCharacterSurName -eq "L" -or "M" -or "N" -or "O" -or "P" )
{
Write-Host "User belongs in $L_through_P database"
}
elseif ( $FirstCharacterSurName -eq "Q" -or "R" -or "S" -or "T" -or "U" )
{
Write-Host "User belongs in $Q_through_U database"
}
else
{
Write-Host "User belongs in $V_through_Z database"
}It pulls the first Character of the last name correctly. However, it always choose A_through_F for everything. Can you not have multiple conditions like this?
You can use Compare-Object to compare the value pairs as arrays:
if (Compare-Object $a, $b $c, $d -SyncWindow 0) {
'different'
} else {
'same'
}
Note that this is convenient, but relatively slow, which may matter in a loop with many iterations.
The
Compare-Objectcmdlet compares two arrays and by default returns information about their differences.-SyncWindow 0compares only directly corresponding array elements; in other words:$amust equal$c, and$bmust equal$d; without-SyncWindow, the array elements would be compared in any order so that1, 2would be considered equal to2, 1for instance.Using the
Compare-Objectcall's result as a conditional implicitly coerces the result to a Boolean, and any nonempty result - indicating the presence of at least 1 difference - will evaluate to$True.
As for what you tried:
Use of { ... } in your conditional is not appropriate.
Expressions enclosed in { ... } are script blocks - pieces of code you can execute later, such as with & or .
Even if you used (...) instead to clarify operator precedence (-ne has higher precedence than -and), your conditional wouldn't work as expected, however:
($a -and $b) -ne ($c -and $d)treats all variables as Booleans; in effect, given PowerShell's implicit to-Boolean conversion, you're comparing whether one value pair has at least one empty string to whether the other doesn't.
In addition to the answer from mklement0 and avoiding the rather slow Compare-Object cmdlet:
In what you tried, you will need to compare one specific value with each of the rest of the vales:
($a -eq $b) -and ($a -eq $c) -and ($a -eq $d)
Because the Comparison Operators (-eq) take a higher precedence than the Logical Operators (-and), you can leave the brackets and simplify it to:
$a -eq $b -and $a -eq $c -and $a -eq $d
To make this code DRY and easily expandable for even more values:
if ($a, $b, $c | Where {$_ -ne $d}) {
'different'
} else {
'same'
}