4

I have created a script in the Azure PowerShell.

If I use the "echo" command, it displays output to the console.

However, if I use Write-Output and Write-Error, I don't see the output.

I have uploaded the script "change-to-static.ps1" to a storage account. Then I open the "Cloud Shell" with a button at the top bar. Then I type "./change-ip-to-static.ps1" in the PowerShell console.

Therefore, the script does not produce any output unless I replace "Write-Output" and "Write-Error" with "echo" or "print".

Please help me. What should I do to see the output?

The script is below.

There is a similar question at How to output something in PowerShell. I have read it, but there are no concrete examples on how to achieve my goal, i.e. how to modify my script to see the output. And in my case, it does not output even if I redirect to a text file. However, commands like "echo" and "print" in my case work but they are not covered in the above example. See the script below.

$IPs = Get-AzPublicIpAddress; 
$Static = "Static";
foreach ($PublicIP in $IPs) {
    $Method = $PublicIP.PublicIpAllocationMethod;
    $Name = $PublicIP.Name;
    if ($Method -eq $Static) {
        $message = "The method of " + $Name + " is already " + $Static;
        Write-Progress -Activity $message;
    }
    else {
        Write-Progress -Activity "Changing the method of "+$Name+" from "+$Method+" to "+$Static+"...";
        $PublicIP.PublicIpAllocationMethod = $Static;
        Set-AzPublicIpAddress -PublicIpAddress $PublicIP;
        Write-Progress -Activity "Querying the method of "+$Name+"...";
        $ModifiedAddress = Get-AzPublicIpAddress -Name $Name -ResourceGroupName $PublicIP.ResourceGroupName -Location $PublicIP.Location
        $NewMethod = $ModifiedAddress.PublicIpAllocationMethod;
        if ($NewMethod -eq $Static) {
            Write-Output "The method for "+$Name+" has successfully changed to "+$Static;
        }
        else {
            Write-Error -Message "Cannot change the method for "+$Name+" to "+$Static+", it is still "+$NewMethod+"!!!";
        }
    }
}

P.S. I have updated the script (use this URL) according to the suggestions, but there is still no output. Only "echo" or "print" gives the output. P.P.S. The Write-Progress does not even show a temporary message in the status line during Set-AzPublicIpAddress which takes a couple of seconds to complete, or if I add the Start-Sleep cmdlet. It does only set during Get-AzPublicIpAddress.

Maxim Masiutin
  • 3,991
  • 4
  • 55
  • 72
  • 2
    I'm not sure if it has anything to do with your issue, but your "if ($Method = Static)" test should be "if ($Method -eq $Static)". I did a simple test in my Cloud Shell with 3 statements using Write-Output, Write-Error and Write-Host and got text displayed for each of them. – Mike Jun 10 '21 at 13:59
  • Thank you! I have updated the comparison operator. However, my script still does not print anything unless I use "echo". The last version is at https://github.com/maximmasiutin/azure-scripts/blob/main/change-to-static.ps1 – Maxim Masiutin Jun 10 '21 at 15:38
  • 2
    When using the Write-Output & Write-Error statement you should not be using "+" to concatenate strings. It should be more like Write-Output "The method for $Name has successfully changed to $Static" and Write-Error -Message "Cannot change the method for $Name to $Static it is still $NewMethod !!!" This might be contributing to your problem. – Mike Jun 10 '21 at 16:00
  • I have updated the concatenations but it still does not print anything. https://github.com/maximmasiutin/azure-scripts/blob/main/change-to-static.ps1 – Maxim Masiutin Jun 10 '21 at 19:10
  • 2
    I took the code you posted in GitHub and executed the script in Azure Cloud Shell and was able to see the Write-Output statements. If you are not seeing output, my only guess is that the Write-Progess lines might be writing on top of the output, or the output from the Set-AzPublicIpAddress might be causing issues. You might try a couple things: 1) comment out the Write-Progress (for troubleshooting) 2) use $result = Set-AzPublicIpAddress -PublicIpAddress $PublicIP to keep the output from interferring. – Mike Jun 11 '21 at 18:05
  • 1
    Use Write-Verbose – Juanma Feliu Jun 21 '21 at 07:32
  • 1
    Same Script can be executed in powershell the Write-Output Statement work fine. You may try to add Write-Output cmd after the Write-Progress in a if ($Method -eq $Static) method and check whether it may work or not. – Delliganesh Sevanesan Jun 26 '21 at 11:08

2 Answers2

4

After reading your last edit to my answer, I believe you made a bit of confusion in using Write-* commandlets, and in your script logic, so I provided a more detailed answer with context.

echo in the Powershell Azure Cloud Shell is an alias of Write-Output, as executing echo without parameters clearly shows (docs here ).

PS /home/mikelangelo> echo

cmdlet Write-Output at command pipeline position 1
Supply values for the following parameters:
InputObject:

Moreover: the unix echo can also be run in the Powershell Azure Cloud Shell.

PS /home/mikelangelo> which echo
/usr/bin/echo 
PS /home/mikelangelo> /usr/bin/echo ciao mondo
ciao mondo

print, on the other hand, is not a Powershell alias, so the unix counterpart is the one which always get executed when using the print keyword (presently a symlink to run-mailcap - but it's not clear to me how it comes into play into your use case.)

PS /home/mikelangelo> which print
/usr/bin/print

So, basically, echo and Write-Output will both work, because they call the same commandlet, unless you execute /usr/bin/echo directly, mixing up technologies and effectively impairing portability.

Back to the question: Write-Output works as expected. The logic is faulty: You use = as a comparison operator, but you need to use -eq instead.

Write-Progress needs to be used differently, replace it with Write-Host or Write-Output. Refer to the docs for an explanation.

Note that Write-Output sends an object down the pipeline, which can eventually be represented as a console output. Write-Progress and Write-Host, on the other hand, do not generate output - the latter sends an object to the host for displaying, though, so Write-Host is the recommended way to display something in the console. Refer to this question for more details on Write-Host, Write-Output and the Powershell pipeline.

Mike L'Angelo
  • 854
  • 6
  • 16
  • The question is not about "write-progress" but about "Write-Output" and "Write-Error". I've read the link you've mentioned before posting a question. "write-progress" gives intermittent results (in progress only) while "Write-Output" and "Write-Error" are supposed to provide permanent output. And if you read my question, it does not mention a question about "Write-Progress", it only mentions a question about "Write-Output" and "Write-Error". – Maxim Masiutin Jun 10 '21 at 12:50
  • 1
    My answer is in line (I have updated it though for clarity). `write-output` and `-error` are used correctly, it's just they are never executed because the comparison operator is not correct. – Mike L'Angelo Jun 10 '21 at 14:58
  • Thank you very much! I've fixed the comparison operator. – Maxim Masiutin Jun 10 '21 at 15:34
  • Thank you for your reply. I did only need to replace the Write-Progress to Write-Output in the first block (the "if"), while in the other places WriteProgress was OK. – Maxim Masiutin Jun 26 '21 at 13:50
  • 1
    Not really. I understand that now you see in the console what you want to see, but there is a preferred way to produce output to the console, and display progress information. I expanded on my answer to provide more context, and references. – Mike L'Angelo Jun 27 '21 at 16:25
  • Thank you very much for your answer. However, something is wrong with my question, it somehow does not comply to the Stackoverflow policies because it has negative score, and, so I will delete it to comply to the rules. – Maxim Masiutin Jun 27 '21 at 16:32
  • Your note on the comparison operator was irrelevant, because the script had "Write-Progress" in both of the branches of the condition, and Write-Progress did not print regardless of the condition, so even after correcting the comparison operator, Write-Progress did not print anything. It did not print on sleep or Set-AzPublicIpAddress. It did only print for Get-AzPublicIpAddress. – Maxim Masiutin Jun 27 '21 at 16:37
  • 1
    The wrong comparison always resulted in '`$true` so the `if` was always verified. The output produced by `write-progress` is transient, so it disappears as soon as `write-progress` ends. Try executing the code posted as example in the commandlet man page, and remove the `start-sleep -m 150`, or replace it with `-m 1`. The point is that `write-progress` does not display output in the console, just a progress bar with comments _during the commandlet execution_ . You use it to obtain results that the commandlet does _not_ provide, so the usage is conceptually wrong – Mike L'Angelo Jun 27 '21 at 17:05
  • 1
    The downvote can be about the _quality_ of the question, not only to the fact it conforms to SO policies. You can improve it and keep it to save the work people like me and Manuel Batsching put in it. The downvote can be removed, by the way. – Mike L'Angelo Jun 27 '21 at 17:06
2

Like other commenters before me I can also confirm that the code from your gist works just fine in Azure Cloud Shell.

I noticed that there is only an output if you have at least one dynamic public ip that the script can change to static. The reason is, that only in this case you use Write-Output to return a string to the console.

If there is no dynamic public ip left, your script only writes a progress message, but you never get to see it, as the script execution ends too quickly after you write the message and progress messages don't linger.

Put the command Start-Sleep -Seconds 2 under the line with Write-Progress and you will see what I mean:

$IPs = Get-AzPublicIpAddress;
$Static = "Static";
foreach ($PublicIP in $IPs) {
    $Method = $PublicIP.PublicIpAllocationMethod;
    $Name = $PublicIP.Name;
    if ($Method -eq $Static) {
        $message = "The method of $Name is already $Static";
        Write-Progress -Activity $message;
        Start-Sleep -Seconds 2 # This will keep the script running 2 seconds longer and the message visible.
    }
    else {
        Write-Progress -Activity "Changing the method of $Name from $Method to $Static ...";
        $PublicIP.PublicIpAllocationMethod = $Static;
        Set-AzPublicIpAddress -PublicIpAddress $PublicIP;
        Write-Progress -Activity "Querying the method of $Name ...";
        $ModifiedAddress = Get-AzPublicIpAddress -Name $Name -ResourceGroupName $PublicIP.ResourceGroupName
        $NewMethod = $ModifiedAddress.PublicIpAllocationMethod;
        if ($NewMethod -eq $Static) {
            Write-Output "The method for $Name has successfully changed to $Static";
        }
        else {
            Write-Error -Message "Cannot change the method for $Name to $Static, it is still $NewMethod!!!";
        }
    }
}

Write-Progress is probably not the cmdlet that you want to use to write out the progress of your script (despite it's name). As I do not see how you would need to further process the output of your script, you might as well replace it with Write-Host.

Mike L'Angelo
  • 854
  • 6
  • 16
Manuel Batsching
  • 3,406
  • 14
  • 20
  • Manuel, seems to me your answer contains nothing new with respect to the answer I posted 9 days ago, just a workaround to visualize `Write-Progress` output when used in a wrong way. The conclusion is the same: Write-Progress needs to be used differently, replace it with Write-Host or -Output – Mike L'Angelo Jun 19 '21 at 15:21
  • WriteOutput works correctly. It is just Write-Progress that should have been used properly. It does not print anything in my case even for a sleep. But it did produce temporary status in a status line during the Set-AzPublicIpAddress and Get-AzPublicIpAddress. So I had to just replace the first "Write-Progress" (in the "if" block) to the WriteOutput. Anyway, your explanation that the script returned too fast so I didn't see anything of the WriteProgress was essentially correct, thank you! I have modified the script on the github and it now works as I liked. – Maxim Masiutin Jun 26 '21 at 13:48
  • In my case, WriteProgress only displays anything during Get-AzPublicIpAddress. It does not display anything during Set-AzPublicIpAddress or during Start-Sleep, regardless of how long does it take or whether I've added "| Out-null" or not. Anyway, the WriteProgress is not that important, because it only produces temporary ouput. – Maxim Masiutin Jun 26 '21 at 14:14