Powershell Script working fine in Visual Code but fails running from Terminal

1k Views Asked by At

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

1

There are 1 best solutions below

0
On
  • 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.