Error in IF statement powershell - powershell

I think there's a problem with this if statement.
Function Get-IsFirewallProfileEnabled([string]$profile)
{
Return [bool](Get-NetFirewallProfile -name "Domain" | Where Enabled -eq "False")
}
# If the firewall for some of the 3 profiles is not enabled
if ( ((Get-IsFirewallProfileEnabled("Domain")) -or (Get-IsFirewallProfileEnabled("Private")) -or (Get-IsFirewallProfileEnabled("Public"))) -eq "False")
{
Write-Output "Enabling..."
# Enable Windows firewall for for all (the 3 profiles)
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
}
Whether I have activated a firewall or not, this script always does nothing. What's happening?
SOLUTION
# Now this function is dynamic
Function Get-IsFirewallProfileEnabled([string]$profile)
{
Return [bool](Get-NetFirewallProfile -name $profile | Where Enabled -eq "True")
}
# If the firewall for some of the 3 profiles is not enabled
if ( -not(Get-IsFirewallProfileEnabled("Domain")) -or -not(Get-IsFirewallProfileEnabled("Private")) -or -not(Get-IsFirewallProfileEnabled("Public")) )
{
Write-Output "Enabling..."
# Enable Windows firewall for for all (the 3 profiles)
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
}

As Robert mentioned, you are using the string False, not the Boolean $false in your if statement.
But the logic in your if statement isn't working as expected:
if(((Boolean) -or (Boolean) -or (Boolean)) -eq $false)
will not produce the desired result in Powershell (it will only execute if all of the values are $false). Since if always executes on $true, you can achieve desired results by simply -not-ing the values from Get-IsFirewallProfileEnabled like so:
if((-not(Get-IsFirewallProfileEnabled("Domain")) -or (-not(Get-IsFirewallProfileEnabled("Private")) -or (-not(Get-IsFirewallProfileEnabled("Public")))
This will execute the if block when any of the values are $false.

You want to use $false not "False".
"False" is a string literal and will never match if the boolean value returned by the condition ((Get-IsFirewallProfileEnabled("Domain")) -or (Get-IsFirewallProfileEnabled("Private")) -or (Get-IsFirewallProfileEnabled("Public"))) is false.
For example:
if ("False") { write-host "true" }
The line above will always write "true" to the host. This is because a non-empty string literal equates to $true.
The line below will never write "true" to the host.
if ($false) { write-host "yes" }

Related

All but one of my elseif loops is running - what is wrong with my syntax?

I am writing a script that checks for a registry key property created by a Bitlocker GPO, checks to see if the device is already protected and if the key is present and the device is not protected then encrypts the device.
I've tested each of these functions individually and they all work, and they all seem to work in the context of the script, outputting the right loop, however when I run the whole script at once, the only loop that DOESN'T work is the loop where the encrypting function runs.
I have the exit codes here because I am using Manage Engine to push out the script to a few remote devices around our estate and I would like to be able to see easily where the script is failing so I can deploy something else.
# FUNCTION - Function created to check existence of Active Directory GPO
Function Test-RegistryValue {
$regPath = 'HKLM:\SOFTWARE\Policies\Microsoft\FVE'
$regPropertyName = 'ActiveDirectoryBackup'
# Value of registry key ported into a script-level variable accessible from outside the function
$regValue = (Get-ItemPropertyValue -Path $regPath -Name $regPropertyName -ErrorAction ignore)
if ($regValue -eq 1)
{
$script:regExit = 0
}
# If the key exists but is not set to write back
elseif ($regValue -eq 0)
{
$script:regExit = 1
}
# If the registry property doesn't exist
else
{
$script:regExit = 5
}
}
# FUNCTION - Function tests if BitLocker protection is already on
function Test-TBBitlockerStatus {$BLinfo = Get-Bitlockervolume
if($blinfo.ProtectionStatus -eq 'On' -and $blinfo.EncryptionPercentage -eq '100')
{
return $true
}
else
{
return $false
}
}
# FUNCTION - This function is the actual encryption script
Function Enable-TBBitlocker {
Add-BitLockerKeyProtector -MountPoint $env:SystemDrive -RecoveryPasswordProtector
$RecoveryKey = (Get-BitLockerVolume -MountPoint $env:SystemDrive).KeyProtector | Where-Object {$_.KeyProtectorType -eq "RecoveryPassword"}
Manage-bde -protectors -adbackup $env:SystemDrive -id $RecoveryKey[0].KeyProtectorId
Enable-BitLocker -MountPoint $env:SystemDrive -UsedSpaceOnly -TpmProtector -SkipHardwareTest
}
# MAIN SCRIPT
# Running the GPO check function
Test-RegistryValue
Test-TBBitlockerStatus
$regExit
if ($regExit -eq 1)
{
Write-Host 'Key present but writeback not enabled.'
exit 51
}
# Exit if GPO not present
elseif ($regExit -eq 5)
{
Write-Host 'GPO not present.'
exit 55
}
# Test for device already being encrypted
elseif ((Test-TBBitlockerStatus -eq True) -and ($regExit -eq 0))
{
Write-Host 'Writeback enabled but device already protected.'
exit 61
}
# Test for device being encrypted and writeback is not enabled.
elseif ((Test-TBBitlockerStatus -eq True) -and ($regExit -ge 1))
{
Write-Host 'Device already protected but AD writeback is not enabled.'
exit 65
}
elseif ((Test-TBBitlockerStatus -eq False) -and ($regExit -eq 0))
{
Enable-TBBitlocker | Write-Output
Write-Host 'Encryption successful.'
exit 10
}
The Write-Host comments are so I can see where it's failing or succeeding. If I manually change the key value to 1 or 0, or encrypt the device and run the script the correct loop runs, however when the device is not encrypted and has the key in the registry, it does absolutely nothing. The exit code doesn't change, there's no output to the host.
I have the output included before the main if scope to see if the values are being set correctly, which they are but that final encryption function loop does not run at all.

PowerShell Variable IF Statement from windows form

I'm trying to so write a PowerShell script that performs a task based on the input from a windows form.
If ($ComboBoxOffice.Text -eq 'Norwich', $CheckBoxNoEquipment.Checked -eq 'False' )
I can get it to work with just the following code:
If ($ComboBoxOffice.Text -eq 'Norwich')
Any ideas on how would go about only actioning the IF statement based on the input from the first code?
Assuming you only want to proceed when BOTH conditions are satisfied, use the -and operator:
if($ComboBoxOffice.Text -eq 'Norwich' -and $CheckBoxNoEquipment.Checked -eq $false){
# ...
}
If you want to proceed when either condition is satisfied, use -or:
if($ComboBoxOffice.Text -eq 'Norwich' -or $CheckBoxNoEquipment.Checked -eq $false){
# ...
}
Notice that I'm using the special boolean variable $false rather than the string 'False', to avoid type confusion bugs

How to check from output of a cmdlet if it contains a specific string and return success in Powershell

I am checking if SMB version 1 is enabled or not on my Windows Server 2008 R2.
Even though SMB1 is enabled and running, when I am doing a if loop comparison if SMB1 is running then it is executing the else condition
Can anyone please tell me where I am going wrong?
Here is my script :
$SMBVersionRunning = sc.exe query mrxsmb10
$SMBVersionState = $SMBVersionRunning | Select-String -Pattern "STATE"
$SMBRunningStatus = $SMBVersionState | Select-String -Pattern "RUNNING"
if( $SMBVersionRunning.Contains($SMBRunningStatus.ToString()) -eq 0)
{
Write-Host "SMB1 is enabled"
}
else
{
Write-Host "SMB1 is not enabled"
}
Using Get-Service allows a simpler and more robust solution:
if ((Get-Service mrxsmb10).Status -eq 'Running') {
"SMB1 is enabled"
}
else {
"SMB1 is not enabled"
}
If there's a chance that the service isn't even installed, add -ErrorAction Ignore (PSv5+) or -ErrorAction SilentlyContinue to the Get-Service call in order to silence error output.
If you do want to stick with the string-parsing approach, you can simplify your attempt to the following:
if ((sc.exe query mrxsmb10) -match 'STATE' -match 'RUNNING') {
"SMB1 is enabled"
}
else {
"SMB1 is not enabled"
}
While probably not necessary in this case, you could make the matching stricter by looking for the search terms only as full words, by enclosing them with \b...\b; i.e., \bSTATE\b and \bRUNNING\b
As for what you tried:
if ($SMBRunningStatus) ... should give you what you want, because it will only be nonempty if both the string STATE and RUNNING were found on the same line, and a nonempty variable is "truthy" in a conditional (in any Boolean context).
$SMBVersionRunning.Contains($SMBRunningStatus.ToString()) doesn't work as intended, because it is not a string operation, but an array containment operation, given that invocation of an external program such as sc.exe query mrxsmb10 returns an array of lines.
That is, the method call would only return $True if $SMBRunningStatus.ToString() matched a line in full.
Aside from that, your logic of comparing to -eq 0 (a) compares the Boolean result from .Contains() to an [int] and (b) has the logic accidentally reversed; to test if a Boolean result is $True, you can use -eq $True, but that isn't necessary: simply use the Boolean result as-is; similarly, to test for $False you can use the -not operator instead of -eq $False.

PowerShell booleans -- How to handle null differently from false?

I'm trying to write a server build script that includes Boolean parameters for various tasks, e.g. whether to install IIS. If the user does not specify this parameter one way or the other, I want the script to prompt for a decision, but for convenience and unattended execution I want the user to be able to explicitly choose to install IIS or NOT install IIS by setting the value to True or False on the command line and therefore avoid being prompted. My issue is that when I create a Boolean parameter, PowerShell automatically sets it to False, rather than leaving it null, if it wasn't specified on the command line. Here is the design that I THOUGHT would've worked:
param(
[bool]$IIS
)
if ($IIS -eq $null) {
$InstallIIS = Read-Host "Do you want to install IIS? (Y/N)"
if ($InstallIIS -eq "Y") {$IIS = $true}
}
if ($IIS) {Do stuff here}
Any suggestions for how to achieve my desired outcome would be most appreciated. Then if this changes anything, what I'd REALLY like to do is leverage PSRemoting to accept these build decision parameters on the user's system host and then pass them to the targets as an ArgumentList, and I'm wondering if that will affect how these Booleans are handled. For example:
param (
[string[]]$Computers
[bool]$IIS
)
$Computers | Foreach-Object {
Invoke-Command -ComputerName $_ -ArgumentList $IIS -ScriptBlock {
param(
[bool]$IIS
)
if ($IIS -eq $null) {
$InstallIIS = Read-Host "Do you want to install IIS? (Y/N)"
if ($InstallIIS -eq "Y") {$IIS = $true}
}
if ($IIS) {Do stuff here}
Ideas?
The way to accomplish this is with Parameter Sets:
[CmdletBinding()]
param (
[Parameter()]
[string[]]$Computers ,
[Parameter(ParameterSetName = 'DoSomethingWithIIS', Mandatory = $true)]
[bool]$IIS
)
$Computers | Foreach-Object {
Invoke-Command -ArgumentList $IIS -ScriptBlock {
param(
[bool]$IIS
)
if ($PSCmdlet.ParameterSetName -ne 'DoSomethingWithIIS') {
$InstallIIS = Read-Host "Do you want to install IIS? (Y/N)"
if ($InstallIIS -eq "Y") {$IIS = $true}
}
if ($IIS) {Do stuff here}
Well of course even though I Googled about this quite a bit before posting here, including discovering the [AllowNull()] parameter and finding that it did NOT help in my use case, I ended up finding the answer in the first Google search AFTER posting. This is what worked:
[nullable[bool]]$IIS
My only gripe with that syntax is that running Get-Help against the script now returns shows this for the IIS parameter:
-IIS <Nullable`1>
instead of:
-IIS <Boolean>
But unless there's a more elegant way to achieve what I need, I think I can live with that by adding a useful description for that parameter as well as Examples.
Even though boolean operators handle $null, $False, '', "", and 0 the same, you can do an equality comparison to see which is which.
If ($Value -eq $Null) {}
ElseIf ($Value -eq $False) {}
..etc..
In your situation, you want to use [Switch]$IIS. This will be $False by default, or $True if entered with the command a la Command -IIS, then you can handle it in your code like:
If ($IIS) {}
Which will only be $True if entered at the command line with -IIS
Instead of using an equality test that's going to try to coerce the value to make the test work:
if ($IIS -eq $Null)
Use -is to check the type directly:
PS C:\> $iis = $null
PS C:\> $iis -is [bool]
False

The PowerShell -and conditional operator

Either I do not understand the documentation on MSDN or the documentation is incorrect.
if($user_sam -ne "" -and $user_case -ne "")
{
Write-Host "Waaay! Both vars have values!"
}
else
{
Write-Host "One or both of the vars are empty!"
}
I hope you understand what I am attempting to output. I want to populate $user_sam and $user_case in order to access the first statement!
You can simplify it to
if ($user_sam -and $user_case) {
...
}
because empty strings coerce to $false (and so does $null, for that matter).
Another option:
if( ![string]::IsNullOrEmpty($user_sam) -and ![string]::IsNullOrEmpty($user_case) )
{
...
}
Try like this:
if($user_sam -ne $NULL -and $user_case -ne $NULL)
Empty variables are $null and then different from "" ([string]::empty).
The code that you have shown will do what you want iff those properties equal "" when they are not filled in. If they equal $null when not filled in for example, then they will not equal "". Here is an example to prove the point that what you have will work for "":
$foo = 1
$bar = 1
$foo -eq 1 -and $bar -eq 1
True
$foo -eq 1 -and $bar -eq 2
False