3

I'm working on writing a script which will run from AzDo Pipeline to disable F5 WebServers. Below script works fine in Visual Code and does disable the server as expected . But when running from the terminal or PS window fails with the below error . Can someone please help.

$ServerInput = 'server1.abc.com'
$BIGIPBaseURL = "https://ser-f5-1.prod.abc.com"
$usr = "nilesh"
$SecurePassword='P@assword'
Write-Host "Starting the Script..." 
# Initialize variables
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$BIGIPToken = $null
Write-Host -ForegroundColor Green " done!"
$DisableWebServers = $true
# Initialize functions
Write-Host "Initializing functions..." -NoNewline
$PSVersionTable

function Disable-BIGIPNode([string]$NodeName) {
    # servers should use the Disable-BIGIPTelcoNode() function
    Write-Host "In the Disable function"
    if ($NodeName -match "(?i).*telco.*") {
        Write-Host -ForegroundColor Yellow "WARNING: `"$($NodeName.ToUpper().Split('.')[0])`" is in the wrong list.  telcoo hosts should be added to the TelcoServers list in your input file."
        BREAK
    }
    else {
        if ($BIGIPToken -eq $null) {
            Write-Host "Now will enter the Open-Session"
            Open-BIGIPSession
        }

        Write-Host "Disabling node `"$($NodeName.ToUpper().Split('.')[0])`" in BIG-IP..." -NoNewline
        $WebRequestInput = @{
            body = @{
                "session" = "user-disabled"
            } | ConvertTo-Json
            uri = $($BIGIPBaseURL) + "/mgmt/tm/ltm/node/~Common~" + $NodeName.ToLower()
            headers = @{
                "Content-Type" = "application/json"
                "X-F5-Auth-Token" = "$BIGIPToken"
            } 
            method = "PATCH"
        } 
        Write-Host $WebRequestInput
        Write-Host $WebRequestInput.body

        try {
            Write-Host "In the final try block"
            $Request = Invoke-WebRequest @WebRequestInput -UseBasicParsing -SkipCertificateCheck 
        }
        catch {
            Write-Host -ForegroundColor Red " failed!"
            Write-Host -ForegroundColor Red ($_.ErrorDetails | ConvertFrom-Json).Message
        }
        Write-Host -ForegroundColor Green " done!"
        $global:ZabbixRequestID++
    }
}

function Open-BIGIPSession() {
    Write-Host "Authenticating with BIG-IP API..." -NoNewline
    $WebRequestInput = @{
        body = @{
            username = "$usr"
            password = "$SecurePassword"
            loginProviderName = "tmos"
        } | ConvertTo-Json
        uri = $ScriptInput.BIGIPBaseURL + "/mgmt/shared/authn/login"
        headers = @{
            "Content-Type" = "application/json"
        }
        method = "POST"
    }
    try {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Request = Invoke-WebRequest @WebRequestInput -UseBasicParsing -SkipCertificateCheck
    }
    catch {
        Write-Host -ForegroundColor Red " failed!"
        Write-Host -ForegroundColor Red ($_.ErrorDetails | ConvertFrom-Json).Message
        EXIT 1
    }
    Write-Host -ForegroundColor Green " done!"
    $global:BIGIPToken = ($Request.Content | ConvertFrom-Json).token.token 
}

if ($DisableWebServers) {
    Write-Host "Starting the main Methord "
    foreach ($Server in $($ServerInput)) {
        Disable-BIGIPNode -NodeName $Server
    }
}

The PowerShell version is PSVersion 7.2.2

Disabling node "SAC-DEV-WEB2" in BIG-IP...System.Collections.DictionaryEntry System.Collections.DictionaryEntry System.Collections.DictionaryEntry System.Collections.DictionaryEntry
{
  "session": "user-disabled"
}
In the final try block
 failed!
ConvertFrom-Json: C:\Temp\Testing.ps1:49:64
Line |
  49 |  … Host -ForegroundColor Red ($_.ErrorDetails | ConvertFrom-Json).Messag …
     |                                                 ~~~~~~~~~~~~~~~~
     | Conversion from JSON failed with error: Additional text encountered after finished reading JSON content: U. Path '', line
     | 3, position 4.

Its working fine when running from VsCode but fails if called with the file name from the same terminal

like .\Testing.ps1

Please help

3
  • As an aside: the break statement inside your Disable-BIGIPNode function breaks out of your foreach ($Server in $($ServerInput)) loop, i.e. if there are servers remaining, they won't be processed - is that the intent? Commented Apr 21, 2022 at 13:52
  • 1
    @mklement0 if ($NodeName -match "(?i).*telco.*") is just to get out of the loop if the server name contains telco name in it , the issue thats happening here is it fails while creating the token Commented Apr 21, 2022 at 16:13
  • 1
    I see (my suggestion would be to move the break logic into the foreach loop, as that is conceptually clearer). As for the error: The true error is being obscured by the follow-up error stemming from .ErrorDetails not containing valid JSON, so I'd start with printing the true error with Write-Host -ForegroundColor Red $_ Commented Apr 21, 2022 at 16:19

1 Answer 1

5
  • Your incidental problem is that the true error message is being obscured by a follow-up error that results from attempting to parse the error record's .ErrorDetails property as JSON, which it isn't. (You report that examining the true error reveals a 401 authentication error).

  • I have no specific explanation for the difference in behavior you're seeing between running in Visual Studio Code vs. in a regular PowerShell console, but I have a guess:

    • Your Visual Studio Code session in the so-called PowerShell Integrated Console may have lingering state from earlier debugging runs, which may mask a bug in your script.

    • Restarting Visual Studio Code should clarify whether that is the case, but there's also a way to configure the PowerShell extension so that the problem doesn't arise to begin with - see below.


  • By default, code you run (debug) via the Visual Code PowerShell extension executes in the same PowerShell session, directly in the global scope.

    • That is, running a script being edited, say, foo.ps1, in the debugger is effectively the same as invoking it with . .\foo.ps1, i.e. it is in effect dot-sourced.

    • Therefore, a given debugging run can be affected by earlier runs, because the state of earlier runs lingers.

      • This can result in bugs going undetected, such as in the following example:

        • Say your script defines variable $foo and uses it throughout the script. If you debug your script at least one, $foo is now defined in the PowerShell session in the PowerShell Integrated Console.

        • Say you then change the name to $bar, but you forget to also replace (all) references to $foo with $bar.

        • Your script is now effectively broken, but you won't notice in the same session, because $foo is still around from earlier debugging runs.

          • However, running the script from a regular PowerShell console would surface the problem.
    • The obsolescent Windows PowerShell ISE exhibits the same unfortunate behavior, invariably so, but fortunately there is a solution for the PowerShell extension - see next point.

  • You can avoid this problem by activating the Create Temporary Integrated Console setting (via File > Preferences > Settings or Ctrl+,), which ensures that every debugging run creates a new, temporary session to run in, which starts with a clean slate:

    • Whenever a new temporary session is started, any previous one is automatically discarded.

    • A temporary session has prefix [TEMP] in the list of running shells in the integrated terminal.

    • You pay a performance penalty, because a new PowerShell session must be created for every run, and you lose the previous session's display output - but I suspect avoiding the pitfalls of lingering state is worth the price.

    • Note that, in a given temporary session, the dot-sourced invocation described above still applies, but with the lingering-state problem out of the picture, it can now be considered an advantage: After the script finishes, and before the temporary session is replaced with a new one, the variables and functions defined in the script's top-level scope are then available for inspection.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.