Search code examples
stringpowershellnullis-empty

I know you can nest an IfElse statement in a ForEach loop, but is the opposite also possible?


Been using Powershell on and off for years but haven't really gotten into that much automation until now. What I'm trying to accomplish is running a statement based on input for a variable. Each statement will run just fine by itself. The ELSE part of the test will run just fine with input from the variable. However...the issue comes in with trying to run the first statement based on the default input for the variable. This is for verifying proxy settings for users based on machine name. I would like to use the same script to search/output either a single machine or from a list, depending on the input received.

I've tried everything I can think of and everything I can find on the internet. I have a suspicion that I am missing something simple. When I run the whole thing without the ErrorAction, it will run the ELSE statement with no issues if I enter a value into the prompt. However...if I accept the default value (hasn't mattered what I put in there and have tried multiple iterations of values) it just skips directly to the ELSE statement and errors out since there isn't an input (no computer name to search on).

Here is the code as written:

$ErrorActionPreference = "SilentlyContinue"

$pathHKU = 'HKU:\.Default\Environment\'
$pathExists = Test-Path -Path $pathHKU

If(!($pathExists))
{ 
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_Users
}

$defaultValue = ""

$preSID = "Get-ItemPropertyValue 'registry::HKU\"
$postSID = "\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyServer"
$promptOutput = Read-Host "Press enter to search by list or type in the name of a single machine [$($defaultValue)]"
IF($null -eq $promptOutput) {
    $sysName | Add-Content -Path ".\testlist.txt"
ForEach ($sys in $sysName)
    {
        $SID = Invoke-Command -ComputerName $sys -ScriptBlock {Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Username | ForEach-Object { ([System.Security.Principal.NTAccount]$_).Translate([System.Security.Principal.SecurityIdentifier]).Value}}
        $searchProxy = $preSID+$SID+$postSID
        $scriptBlock = [Scriptblock]::Create($searchProxy)
            ForEach ($script in $scriptBlock) {
                $userProxy = Invoke-Command -ComputerName $sys -ScriptBlock $scriptBlock
            }
        $sys+" - "+$userProxy | Out-File -Path ".\TestProxySettings.csv" -Append
    }
}else{
    $nameComp = $promptOutput
    $SID = Invoke-Command -ComputerName $nameComp -ScriptBlock {Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Username | ForEach-Object { ([System.Security.Principal.NTAccount]$_).Translate([System.Security.Principal.SecurityIdentifier]).Value}}
    $searchProxy = $preSID+$SID+$postSID
    $scriptBlock = [Scriptblock]::Create($searchProxy)
        ForEach ($script in $scriptBlock) {
            $userProxy = Invoke-Command -ComputerName $nameComp -ScriptBlock $scriptBlock
$nameComp+" - "+$userProxy
        }
}

Any help will be greatly appreciated. Thank you.


Solution

  • Given that $promptOutput contains the output from a Read-Host call:

    if ($null -eq $promptOutput) { ... }

    is never $true, because Read-Host returns the empty string, not $null, when the user just presses Enter.

    Therefore, use:

    if ('' -eq $promptOutput) { ... }
    

    Or, given that the empty string is implicitly $false in a Boolean context such as an if conditional, you can use:

    • if (-not $promptOutput) { ... }
      If you additionally want to also treat blank (all-whitespace) output the same as empty input:
    • if (-not $promptOutput.Trim()) { ... }

    In cases where the value's type isn't known in advance and may actually be $null or a different type, simply enclose the value in "..." to coerce it to a string first:

    • if (-not "$unknownValue") { ... } to match $null or the empty string (equivalent of [string]::IsNullOrEmpty())
    • if (-not "$unknownValue".Trim()) { ... } to match $null, the empty string, or blank (all-whitespace) strings (equivalent of [string]::IsNullOrWhiteSpace()).

    Note that PowerShell by design in general doesn't store $null in [string]-typed variables: even when explicitly assigning $null it stores '' (the empty string) instead:

    # Despite assigning $null, it is '' (empty string) that is stored.
    [string] $str = $null; $null -eq $str # !! $false 
    

    While there is a workaround for storing actual $null, using the [NullString]::Value singleton, its use is best avoided, except for what it was designed for: passing a true $null to [string]-typed .NET method parameters.