Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add posh support. #33

Closed
wants to merge 5 commits into from
Closed

Add posh support. #33

wants to merge 5 commits into from

Conversation

shibayan
Copy link

@shibayan shibayan commented Sep 5, 2015

I added a support to generate a deployment script using PowerShell.

@davidebbo
Copy link
Member

Nice, we have been thinking about supporting PowerShell! Eventually, we might make this the default and give up on .cmd completely.

Would you be able to add basic smoke test coverage to test/smokeTest.js? Thanks!

@shibayan
Copy link
Author

shibayan commented Sep 9, 2015

I added posh scenario to smoke test and passed all. (and added missing node.js)

@davidebbo
Copy link
Member

Great, thanks! It may take us until next week to get to reviewing this as we're in the middle of a release, but it's definitely a change that we want and will look at soon :)

function selectNodeVersion() {
if ($env:KUDU_SELECT_NODE_VERSION_CMD -ne $null) {
# The following are done only on Windows Azure Websites environment
& $env:KUDU_SELECT_NODE_VERSION_CMD "$DEPLOYMENT_SOURCE{SitePath}" "$DEPLOYMENT_TARGET" "$DEPLOYMENT_TEMP"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so after testing this, I found out that & $env:KUDU_SELECT_NODE_VERSION_CMD doesn't work because the value of $env:KUDU_SELECT_NODE_VERSION_CMD is set by Kudu as node "D:\...\Kudu.Services.Web\bin\scripts\selectNodeVersion" and you can't run that with & in powershell. I'm not sure if there is a way to run a variable $var in powershell if

$var = "app.exe `"path to something`""

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invoke-Expression $var

However, it's considered dangerous.

@ahmelsayed
Copy link
Member

I went over the code change and it looks fine to me, thanks for the PR @shibayan 👍
I also changed kudu locally on my machine to use Powershell whenever it's available (BasicSites, DotNetConsole, Node, WAP, and ASP.NET Websites) and all the tests passed except for node.
I added a separate comment about what doesn't work with node.

@shibayan
Copy link
Author

Thank you for feedback @ahmelsayed
I fixed script of node.js, as can be deployed on Kudu. changed the execution method of "selectNodeVersion" and "npm".

@snobu
Copy link

snobu commented Sep 23, 2015

The Invoke-Expression with an $env:xxx as param is a bit unsettling there.

May i suggest building the call along the lines of:

$env:SOME_CMD = 'echo'
$DEPLOYMENT_SOURCE = "C:\deploy source\file.txt"
$DEPLOYMENT_TARGET = "C:\deploy dest\file.txt"

[string]$NodeCmd = $env:SOME_CMD
[array]$arguments = $DEPLOYMENT_SOURCE, $DEPLOYMENT_TARGET

& $NodeCmd $($arguments.ForEach({ $_ -replace '^|$','"' }) -join ' ')

Output:
"C:\deploy source\file.txt" "C:\deploy dest\file.txt"

Maybe even a regex match on $env:SOME_CMD just to be sure it quacks like node before calling it.

@davidebbo
Copy link
Member

@snobu is your concern primarily about attack vectors? On Azure, it's typically not an issue as you need to have full power over the site in order to use any Kudu functionality. i.e. if you have the power to inject an evil environment variable, you can just as easily replace the custom deployment script to do evil directly. But in the end, you can only damage your own site.

@snobu
Copy link

snobu commented Sep 23, 2015

You're right it's not a vulnerability.

If someone other than the site owner can change $envs, using or not using iex is like closing the gates after the horses have left the stables (in the words of Lee Holmes)

Anyhow I guess I liked my quote-on-the-fly .ForEach too much not to offer it as an alternative :)

@ahmelsayed
Copy link
Member

Merged.
Thanks @shibayan for your contribution and thanks @snobu for your help

@ahmelsayed ahmelsayed closed this Sep 25, 2015
@davidebbo
Copy link
Member

I just tried it with a .NET app (https://github.com/KuduApps/Dev14_Net46_Mvc5/blob/powershell/deploy.ps1), and it failed for me when git pushing. The error is a bit puzzling, referring to "Window title cannot be longer than 1023 characters":

Command: powershell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File deploy.ps1
Handling .NET Web Application deployment.
All packages listed in packages.config are already installed.
Window title cannot be longer than 1023 characters.
An error has occurred during web site deployment.
At D:\home\site\repository\deploy.ps1:92 char:3
NuGet restore failed
+   nuget restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln"
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : Argument

Interestingly, when I retried from portal, it worked. But then the next git push failed. I think this may be due to small environmental differences between the git push case (which uses kudu.exe), and the retry/CI case that doesn't.

Thoughts?

@davidebbo
Copy link
Member

I found that changing:

nuget restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln"

to

. nuget restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln"

Fixes the issue. But I'm not good with PowerShell, so I'm not sure if it's the correct thing to do. In fact, I don't understand the failure.

Reopening PR since it seems broken as it is.

@davidebbo davidebbo reopened this Sep 25, 2015
@snobu
Copy link

snobu commented Sep 25, 2015

Dot sourcing.

dot

By dot sourcing a script you still have the vars in your PowerShell session after the script terminates.
Reading the error message it looks like $DEPLOYMENT_SOURCE isn't expanding. I'm looking through the script now to maybe find out why.

@davidebbo
Copy link
Member

Thanks @snobu. I was able to repro by reducing the script to a one-liner with just the nuget command. And the fact that it fails from git push but works in other scenarios is quite puzzling as well.

@snobu
Copy link

snobu commented Sep 25, 2015

Try these two:

& .\nuget.exe restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln"

.\nuget.exe restore $("$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln")
$() should make the var expand first before anything else happens.

@davidebbo
Copy link
Member

@snobu it should be nuget.exe instead of .\nuget.exe in both cases (it's on the path, not the current folder). But beyond that, I confirm that both options work:

& nuget.exe restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln"

nuget.exe restore $("$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln")

So we now have 3 candidate fixes! :)

@snobu
Copy link

snobu commented Sep 25, 2015

Disregard my last comment. The error is ABOVE the line i was reading. It breaks on Window Title too long and calls exitWithMessageOnError($1).

Insert this somewhere before running nuget. Something is making the PowerShell host window go nuts.
host.UI.RawUI.WindowTitle = 'Kudu'

@snobu
Copy link

snobu commented Sep 25, 2015

Ok, so nuget is weird and does things to the Window Title WHEN called "vanilla".
Maybe add the host.UI just in case something else decides to mess around with the title in the future :)

@snobu
Copy link

snobu commented Sep 25, 2015

I'd go with door number two :) Just because it's decisive in telling the parser what to do,
nuget.exe restore $("$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln")

& is "Meh, call this, see what happens, come back with a result, let it be a surprise for both of us"

@davidebbo
Copy link
Member

Darn, bad news. As it turns out, this is not deterministic at all. It seems to fail about half the time in the git push scenario, without making any changes at all to the repo. I've seen it fail and pass with each if the suggested syntaxes, as well as the original one. So I'm not convinced that the different syntaxes we try actually really made any difference.

These types of bugs suck :(

@snobu
Copy link

snobu commented Sep 26, 2015

When it breaks, does it always break on Window title cannot be longer than 1023 characters.?

@shibayan
Copy link
Author

Cause I do not know, but be able to avoid the error if processing the output of nuget using the pipe.
nuget.exe restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln" | write

Maybe there is a problem with the processing of standard output.

@snobu
Copy link

snobu commented Sep 26, 2015

@shibayan How can i test it? I cloned this repo, ran build.cmd.. what do i do next?

@snobu
Copy link

snobu commented Sep 26, 2015

I figured out how to repro..

Yup, getting the same error.

remote: Successfully installed 'WebGrease 1.5.2'.
remote: An error has occurred during web site deployment.
remote: Window title cannot be longer than 1023 characters.
remote: NuGet restore failed
remote: At D:\home\site\repository\deploy.ps1:92 char:3
remote: +   nuget restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln"
remote: +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
remote:     + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
remote:     + FullyQualifiedErrorId : Argument

Let me try a few things here.

@snobu
Copy link

snobu commented Sep 26, 2015

Looks like the problem is that each external binary (like nuget.exe is streaming the output to the Window Title). Don't ask me why, i can not understand this. However, wrapping all binary calls in Start-Process seems to create a new window and the bug doesn't show up anymore. Tested a few times. Please test as well.

C:\tests\Dev14_Net46_Mvc5>git push poshfix master

Username for 'https://poshfix.scm.azurewebsites.net': xxxxx
Password for 'https://[email protected]':
Counting objects: 159, done.
Compressing objects: 100% (123/123), done.
Writing objects: 100% (159/159), 403.52 KiB | 0 bytes/s, done.
Total 159 (delta 52), reused 121 (delta 31)
remote: Updating branch 'master'.
remote: Updating submodules.
remote: Preparing deployment for commit id '57403337e5'.
remote: Running custom deployment command...
remote: Running deployment command...
remote: Handling .NET Web Application deployment.
remote: LALALALALALALALAL==start process  FIX==================================
remote: ...........
remote:   Dev14_Net46_Mvc5.Common -> D:\home\site\repository\Dev14_Net46_Mvc5.Common\bin\Release\Dev14_Net46_Mvc5.Common.dll
remote: ..
remote:   Dev14_Net46_Mvc5 -> D:\home\site\repository\Dev14_Net46_Mvc5\bin\Dev14_Net46_Mvc5.dll
remote:   Transformed Web.config using D:\home\site\repository\Dev14_Net46_Mvc5\Web.Release.config into obj\Release\TransformWebConfig\transformed\Web.config.
remote:   Copying all files to temporary location below for package/publish:
remote:   D:\local\Temp\8d2c65403a2df13.
remote: ...
remote: Finished successfully.
remote: Deployment successful.
To https://poshfix.scm.azurewebsites.net/poshfix.git
 * [new branch]      master -> master

Here's what's changed in deploy.ps1:

Start-Process "nuget.exe" -ArgumentList "restore $DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln" -Wait

...

Start-Process "$KUDU_SYNC_CMD" -ArgumentList "-v 50 -f $DEPLOYMENT_TEMP -t $DEPLOYMENT_TARGET -n $NEXT_MANIFEST_PATH -p $PREVIOUS_MANIFEST_PATH -i .git;.hg;.deployment;deploy.ps1" -Wait
...

Start-Process "$env:POST_DEPLOYMENT_ACTION" -Wait

Try it out.

Also the site is up at http://poshfix.azurewebsites.net

Edit

We got rid of the initial problem but now we have a regression. We can't grab the output of nuget.exe.
We can grab the ErrorExit code though. I'm trying out some more stuff including -WindowStyle Hidden passed to powershell.exe.

PS C:\tmp> $z = start-process "nuget.exe" -ArgumentList "sources" -wait -PassThru

PS C:\tmp> $z.ExitCode
0

PS C:\tmp> $z = start-process "nuget.exe" -ArgumentList "sourcesSSSSSS" -wait -PassThru

PS C:\tmp> $z.ExitCode
1

@snobu
Copy link

snobu commented Sep 26, 2015


~~~command = powershell -WindowStyle Hidden -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File deploy.ps1~~~

~~~That's it. No window No problems. I tested extensively by nuking the site and then redeploy-ing with and without `-WindowStyle Hidden`. I get consistent results, if -WindowStyle Hidden is specified the deployment works every time.~~~

~~~Nothing else needs to be changed. Wrapping things in Start-Process is now unnecessary. 
Please do your own testing and let me know.~~~

#### Later Edit

The `-WindowStyle Hidden` thing i did above isn't quite it. Some sites work every time, some still fail with the same title too long error. Pushing from the same git repo, same North US region, just different websites.

BUT

This DOES seems to work as a workaround. Stealing output into a file and then cat back the content.
But i don't like it one bit.

``` powershell
# Deployment
# ----------

echo "Handling .NET Web Application deployment."

# 1. Restore NuGet packages
if (Test-Path "Dev14_Net46_Mvc5.sln") {
  nuget restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln" | Out-File -Force $env:TEMP\nuget_restore.log
  exitWithMessageOnError "NuGet restore failed"
  cat $env:TEMP\nuget_restore.log
}

# 2. Build to the temporary path
if ($env:IN_PLACE_DEPLOYMENT -ne "1") {
  & $MSBUILD_PATH "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5\Dev14_Net46_Mvc5.csproj" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="$DEPLOYMENT_TEMP"`;AutoParameterizationWebConfigConnectionStrings=false`;Configuration=Release /p:SolutionDir="$DEPLOYMENT_SOURCE\.\\" $env:SCM_BUILD_ARGS | Out-File -Force $env:TEMP\Msbuild14_1.log
  exitWithMessageOnError "MSBuild failed"  
  cat $env:TEMP\Msbuild14_1.log
} else {
  & $MSBUILD_PATH "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5\Dev14_Net46_Mvc5.csproj" /nologo /verbosity:m /t:Build /p:AutoParameterizationWebConfigConnectionStrings=false`;Configuration=Release /p:SolutionDir="$DEPLOYMENT_SOURCE\.\\" $env:SCM_BUILD_ARGS | Out-File -Force $env:TEMP\Msbuild14_2.log
  exitWithMessageOnError "MSBuild failed"
  cat $env:TEMP\Msbuild14_2.log
}


# 3. KuduSync
if ($env:IN_PLACE_DEPLOYMENT -ne "1") {
  & $KUDU_SYNC_CMD -v 50 -f "$DEPLOYMENT_TEMP" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.ps1" | Out-File -Force $env:TEMP\kudusync.log
  exitWithMessageOnError "Kudu Sync failed"
  cat $env:TEMP\kudusync.log
}

#############

# Post deployment stub
if ($env:POST_DEPLOYMENT_ACTION -ne $null) {
  & $env:POST_DEPLOYMENT_ACTION | Out-File -Force $env:TEMP\postdeploy.log
  exitWithMessageOnError "post deployment action failed"
  cat $env:TEMP\postdeploy.log
}
```

### Note

`| Out-Defaut` seems to work as well, exactly as @shibayan predicted.

So maybe try `| Out-Default` first instead of Out-File and the cat.

### After more testing

`| Out-Default` seems to work all the time, no matter what state the local or remote repo is in.
I think we got it. Kudos to @shibayan for hinting about stdout.

``` powershell
# 1. Restore NuGet packages
if (Test-Path "Dev14_Net46_Mvc5.sln") {
  nuget restore "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5.sln" | Out-Default
  exitWithMessageOnError "NuGet restore failed"
}

# 2. Build to the temporary path
if ($env:IN_PLACE_DEPLOYMENT -ne "1") {
  & $MSBUILD_PATH "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5\Dev14_Net46_Mvc5.csproj" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="$DEPLOYMENT_TEMP"`;AutoParameterizationWebConfigConnectionStrings=false`;Configuration=Release /p:SolutionDir="$DEPLOYMENT_SOURCE\.\\" $env:SCM_BUILD_ARGS | Out-Default
} else {
  & $MSBUILD_PATH "$DEPLOYMENT_SOURCE\Dev14_Net46_Mvc5\Dev14_Net46_Mvc5.csproj" /nologo /verbosity:m /t:Build /p:AutoParameterizationWebConfigConnectionStrings=false`;Configuration=Release /p:SolutionDir="$DEPLOYMENT_SOURCE\.\\" $env:SCM_BUILD_ARGS | Out-Default
}

exitWithMessageOnError "MSBuild failed"

# 3. KuduSync
if ($env:IN_PLACE_DEPLOYMENT -ne "1") {
  & $KUDU_SYNC_CMD -v 50 -f "$DEPLOYMENT_TEMP" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.ps1" | Out-Default
  exitWithMessageOnError "Kudu Sync failed"
}

##################################################################################################################################

# Post deployment stub
if ($env:POST_DEPLOYMENT_ACTION -ne $null) {
  & $env:POST_DEPLOYMENT_ACTION | Out-Default
  exitWithMessageOnError "post deployment action failed"
}

echo "Finished successfully."
```

@shibayan
Copy link
Author

@snobu Thank you for testing!
Based on the test results, I add a modified to the posh template.

@snobu
Copy link

snobu commented Sep 28, 2015

I can repro this by doing:

PS C:\Users\Adrian> $host.UI.RawUI.WindowTitle = $('A' * 1023)

PS C:\Users\Adrian> $host.UI.RawUI.WindowTitle = $('A' * 1024)
Exception setting "WindowTitle": "Window title cannot be longer than 1023 characters."
At line:1 char:1
+ $host.UI.RawUI.WindowTitle = $('A' * 1024)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

And i am sure it's powershell.exe host process throwing up, because if i do the same thing with cmd.exe the error message is different:

C:\Users\Adrian>cmd /c title aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Not enough storage is available to process this command.

Maybe it has something to do with the way Kudu invokes powershell.exe as an external process. Unfortunately i don't understand the code well enough to check where this external command gets invoked. Maybe @davidebbo can have a look.

I'm still a bit worried cause we did fix it for now with the stdout redirect but it would still be beneficial to understand WHY it happens if we're going to make PowerShell the default deploy method.

@takekazuomi
Copy link

The following is the result of my examined.

1.Minimum of reproduction script (broken1.ps1)

For($i=1; $i -le 10; $i++){
  where.exe notepad
}

This script runs in the Kudu debug console. It is an error in the start-up of the process as described below. Often an error after a successful several times.

PS D:\home\site\repository> powershell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken1.ps1
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
Window title cannot be longer than 1023 characters.
At D:\home\site\repository\broken1.ps1:2 char:3
+   where.exe notepad
+   ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : Argument

2.Show WindowTitle as follows. (broken2.ps1)

For($i=1; $i -le 10; $i++){
  $Host.UI.RawUI.WindowTitle
  where.exe notepad
}

You want to run this script. Interestingly, at first that contains the command line arguments to WindowTitle. Then the string is changed to random. After errors long string is displayed.

PS D:\home\site\repository> PS D:\home\site\repository> powershell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken2.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken2.ps1
D:\Windows\System32\notepad.exe
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken2.ps1lina.startup.Bootstrap
D:\Windows\System32\notepad.exe
Window title cannot be longer than 1023 characters.
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken2.ps1At D:\home\site\repository\broken2.ps1:3 char:3
+   where.exe notepad
+   ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : Argument


D:\Windows\System32\notepad.exe
Window title cannot be longer than 1023 characters.
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken2.ps1œ?œ?œ?œ?œ?œ?o?œ?œ?œ?œ?R?R?o?o?o?o?o?o?o?o?o?o?o?o?o?o?o?R?o?o?R?R?R?R?Œ?Œ?Œ?Œ?R?Œ?Œ?R?R?R?R?R?R?R?R?R?R?R?R?Œ?Œ?Œ?Œ?œ?œ?œ?œ?œ?œ?œ?œ?œ?œ?œ?œ?R?R?R?r?r?r?r/r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?RTr?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?R?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?r?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S�s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S|s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?sds?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S?S|S?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?s?Š?Š?Š?Š?Š?Š?Š?Š?t?t?t?t?t?t?t?t?T?T?T?T?t?t?t?t?t?t?t?t?t?t?t?t?t?t?t?t?t?t?t?T?u?U?U?U?U?U?U?U?U?U?U?U?
At D:\home\site\repository\broken2.ps1:3 char:3
+   where.exe notepad
+   ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : Argument

... snip ...

3.When the script to put the "| Out-Default" shall not be in error. However, WindowTitle is broken. (broken3.ps1)

For($i=1; $i -le 10; $i++){
  $Host.UI.RawUI.WindowTitle
  where.exe notepad | Out-Default
}
PS D:\home\site\repository> powershell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken3.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken3.ps1
D:\Windows\System32\notepad.exe
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken3.ps1?
D:\Windows\System32\notepad.exe
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken3.ps1pm;D:\Program Files (x86)\nodejs\;d:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;D:\Program Files (x86)\Mercurial\;D:\Program Files (x86)\PHP\v5.4;D:\Python27;
D:\Windows\System32\notepad.exe
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken3.ps1?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????¤???????????????????????????????????????????????????????????????????????????????????????????????????????????8????????????????????????????????????????????????Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????o???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????l???????????????????????????????????????????????????????????????????????<??ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒtƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ?ƒ???????????????????
D:\Windows\System32\notepad.exe
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken3.ps1
D:\Windows\System32\notepad.exe

... snip ...

4.Remove the execution of external process from script. (broken4.ps1)

For($i=1; $i -le 10; $i++){
  $Host.UI.RawUI.WindowTitle
}

PS D:\home\site\repository> powershell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1
"D:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"  -NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken4.ps1

command line argument of powershell.exe have become WindowTitle. But default is a "Windows PowerShell".

In my opinion there is a problem with PowerShell Host implementation of powershell.exe. As a result, not be initialized of WindowTitle.
It seems to behavior such as Dangling pointer.
It is not be reproduced in a local environment.

@snobu
Copy link

snobu commented Sep 28, 2015

Can you retry the first test with start powershell.exe -blahblah instead?

Prepending start should launch a new host window. No idea if that changes anything.

@takekazuomi
Copy link

Now I try simple powershell host implementation. Will be report soon.
https://github.com/takekazuomi/YaPoshHost

@davidebbo
Copy link
Member

Thanks @snobu and @takekazuomi for investigating this! I verified that the 2>&1 | echo change does fix the problem, though it would be great to find a cleaner solution. Concern is that if users write custom deployment scripts and launch new tools, they'll need to use that trick every time, and it makes the scripts a bit quirky.

@takekazuomi
Copy link

Result Of PowerShell Host Implementation
https://github.com/takekazuomi/YaPoshHost

Previous script (broken [1..4] .ps1) ran correctly.

1.broken1.ps1

PS D:\home\site\repository> .\YaPoshHost .\broken1.ps1
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe

2.broken2.ps1

PS D:\home\site\repository> .\YaPoshHost .\broken2.ps1
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe

3.broken3.ps1

PS D:\home\site\repository> .\YaPoshHost .\broken3.ps1
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe
YaPoshHost
D:\Windows\System32\notepad.exe

4.broken4.ps1

also works.

I was confirmed when deploy is successful by modifying the Dev14_Net46_Mvc5. Add YaPoshHost.exe (my powershell host) and modify .deployement
In deploy.ps1, We dont have redirect.

https://github.com/takekazuomi/Dev14_Net46_Mvc5/commit/2eed6b7defe6b533cd2e4da60ddea01d0dad05c9

[config]
command = YaPoshHost deploy.ps1

After replacing a simple powershell host problem does not occur.
I think that there is a problem with the host implementation of powershell.exe.
What to reproduce the problem conditions still do not know exactly.
Perhaps when access to System.Console is limited.

@snobu
Copy link

snobu commented Sep 28, 2015

Quality stuff there!

I've also asked the man himself, Jeffrey Snover about this bug. He's always happy to help if PowerShell is in trouble :) Waiting for his reply.

@snobu snobu closed this Sep 28, 2015
@snobu snobu reopened this Sep 28, 2015
@takekazuomi
Copy link

@snobu

Can you retry the first test with start powershell.exe -blahblah instead?
Prepending start should launch a new host window. No idea if that changes anything.

I tryed. same result.

PS D:\home\site\repository>  Start-Process -FilePath powershell -ArgumentList "-NoProfile -NoLogo -ExecutionPolicy Unrestricted -File broken1.ps1" -Wait -PassThru  -RedirectStandardOutput stdout.txt -RedirectStandardError stderr.txt

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName          
-------  ------    -----      ----- -----   ------     -- -----------          
     24       2      380        300     4     0.00   6052 powershell           

PS D:\home\site\repository> cat .\stdout.txt
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe
D:\Windows\System32\notepad.exe

PS D:\home\site\repository> cat .\stderr.txt
Window title cannot be longer than 1023 characters.
At D:\home\site\repository\broken1.ps1:2 char:3
+   where.exe notepad
+   ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : Argument

Window title cannot be longer than 1023 characters.
At D:\home\site\repository\broken1.ps1:2 char:3
+   where.exe notepad
+   ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : Argument

I tried to reproduce locally. The results we were able to reproduce.It is described here.

I found CreateProces option in Kudu source then try to use same option. But not reproduce.
https://github.com/projectkudu/kudu/blob/master/Kudu.Core/Infrastructure/Executable.cs#L289

https://github.com/takekazuomi/YaPoshHost/blob/master/PoshTest/ProcessTest.cs#L17

UPDATE
In stdout.txt notepad.exe is 10 times. but stderr.txt has "longer than 1023 characters error" 2 times.
Maybe something broken.

@snobu
Copy link

snobu commented Sep 28, 2015

Wonder if this makes any difference:

https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute(v=vs.110).aspx

Edit: Looks like that won't allow us to redirect stdout and stderr so it's a no go.

@shibayan
Copy link
Author

@snobu and @takekazuomi
Thank you for investigation. It might PowerShell.exe problems.

@davidebbo
You're right, this is a tricky way.
I found a way to avoid the problem in the startup script. It is no need to change the custom deployment scripts.

[config]
command = powershell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -Command "& "$pwd\deploy.ps1" 2>&1 | echo"

This might be best as a workaround...

@davidebbo
Copy link
Member

@shibayan I tried that .deployment change and it does seem to work well! While still a bit magic, at least it's out of the way for people focusing on their posh script, so it's way better.

@davidebbo
Copy link
Member

Ok, I pushed that change: 2d19772.

It's Kudu script 1.0.1 on npm: https://www.npmjs.com/package/kuduscript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants