8000 Fixed passing common test modules path to unelevated Powershell by adityapatwardhan · Pull Request #4313 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

Fixed passing common test modules path to unelevated Powershell #4313

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

Merged

Conversation

adityapatwardhan
Copy link
Member
@adityapatwardhan adityapatwardhan commented Jul 20, 2017
  • Fixed the way common test modules are passed to elevated and unelevated powershell. Earlier, only elevated powershell got those through inheritance as a child process. Now we add them to the startup of the process.

  • Fixed error reported by PSScriptAnalyzer about ? / Where-Object

  • Converted all the parameters passed to powershell.exe to be a base64 encoded string to avoid complications with quotes.

  • Removed code which was updated $env:PSModulePath as we do it in startup args for powershell process instead.

  • Added a way to disable -Quiet for Pester.

$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat", "-Quiet")
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat", "-Quiet")
$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat")
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat")
Copy link
Member

Choose a reason for hiding this comment

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

Seems like there's lots of redundancy building the args, would it be better to have $targetArgs and then appending the unique parts of Elevated vs Unelevated closer to execution?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, having a look if this can be simplified.

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed some redundancy by extracting out a function.

Copy link
Member

Choose a reason for hiding this comment

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

If -OutputFormat is the same, why not have it in $targetArgs instead?

$openCoverArgsElevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all","-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"$targetArgStringElevated`""
$openCoverArgsUnelevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all", "-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"$targetArgStringUnelevated`""
$openCoverArgsElevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all","-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"-EncodedCommand $base64targetArgsElevated`""
$openCoverArgsUnelevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all", "-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"-EncodedCommand $base64targetArgsUnelevated`""
Copy link
Member

Choose a reason for hiding this comment

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

Seems like there's lots of redundancy building the args, would it be better to have $targetArgs and then appending the unique parts of Elevated vs Unelevated closer to execution?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, having a look if this can be simplified.

Copy link
Member

Choose a reason for hiding this comment

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

I think the only difference here is $base64targetArgs. You could have $openCoverArgs with all the common args, then on line 513, something like:

& $OpenCoverBin ($openCoverArgsElevated + "-targetargs:`"-EncodedCommand $base64targetArgsElevated`"")

@@ -519,6 +520,9 @@ function Invoke-OpenCover
# poll for process exit every 60 seconds
# timeout of 6 hours
$timeOut = ([datetime]::Now).AddHours(6)
Copy link
Member

Choose a reason for hiding this comment

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

How long does it typically take? Not clear to me if 6 hours is a good value

Copy link
Member Author
@adityapatwardhan adityapatwardhan Jul 20, 2017

Choose a reason for hiding this comment

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

It typically takes around 2.5 - 3 hours total, out of which maybe 2 hours for the unelevated one. '6 hours' was completely pulled out of thin air, to be substantially large enough. And we do not wait for 6 hours, we poll to check completion and end the run if complete.

Copy link
Member

Choose a reason for hiding this comment

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

I think it would be worth putting that data in the comment to give context to 6 hours

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

$updatedEnvPath = "${PowerShellExeDirectory}\Modules;$TestToolsModulesPath"

$startupArgs = "Set-ExecutionPolicy Bypass -Force -Scope Process; `$env:PSModulePath = '${updatedEnvPath}';"
$targetArgs = "${startupArgs}", "Invoke-Pester","${TestDirectory}"
Copy link
Member

Choose a reason for hiding this comment

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

8000

Should we depend on Start-PSPester instead as we've started building more specialization in our test runs in that cmdlet?

Copy link
Member Author

Choose a reason for hiding this comment

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

Start-PSPester launches powershell.exe, we need to launch opencover.console.exe which would launch powershell.exe to collect coverage numbers. Adding this logic to build.psm1 does not seem right and would complicate the implementation on Start-PSPester further.

Copy link
Member

Choose a reason for hiding this comment

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

For example, start-pspester builds some test exes used by some of the tests. Perhaps not in this PR, but eventually we should probably consider having a separate module for test execution (perhaps merge Start-PSPester and OpenCover module?)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I like the idea of have a separate module for test execution. It would have 2 modes, with code coverage and regular.

8000

@adityapatwardhan
Copy link
Member Author

@SteveL-MSFT Updated. Please have a look.

$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat", "-Quiet")
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat", "-Quiet")
$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat")
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat")
Copy link
Member

Choose a reason for hiding this comment

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

If -OutputFormat is the same, why not have it in $targetArgs instead?

$openCoverArgsElevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all","-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"$targetArgStringElevated`""
$openCoverArgsUnelevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all", "-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"$targetArgStringUnelevated`""
$openCoverArgsElevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all","-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"-EncodedCommand $base64targetArgsElevated`""
$openCoverArgsUnelevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all", "-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"-EncodedCommand $base64targetArgsUnelevated`""
Copy link
Member

Choose a reason for hiding this comment

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

I think the only difference here is $base64targetArgs. You could have $openCoverArgs with all the common args, then on line 513, something like:

& $OpenCoverBin ($openCoverArgsElevated + "-targetargs:`"-EncodedCommand $base64targetArgsElevated`"")

@adityapatwardhan
Copy link
Member Author

@SteveL-MSFT Had forgotten to push. Please have a look.

@adityapatwardhan
Copy link
Member Author

@JamesWTruher Can you have a look too?

@adityapatwardhan adityapatwardhan force-pushed the OpenCoverCommonModulesPath branch from 6311b6b to 517d218 Compare July 21, 2017 16:43
Copy link
Collaborator
@JamesWTruher JamesWTruher left a comment

Choose a reason for hiding this comment

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

except for the comment about $SuppressQuiet this is fine

Write-LogPassThru -Message "openCoverPath : $openCoverTargetDirectory\OpenCover"
Write-LogPassThru -Message "psbinpath : $psBinPath"
Write-LogPassThru -Message "elevatedLog : $elevatedLogs"
Write-LogPassThru -Message "unelevatedLog : $unelevatedLogs"
Write-LogPassThru -Message "TestToolsPath : $testToolsPath"

$openCoverParams = @{outputlog = $outputLog;
TestDirectory = $testPath;
TestPath = $testPath;
Copy link
Collaborator

Choose a reason for hiding this comment

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

since these hashtable entries are on separate lines, the ; is not really needed. I don't think it's a big deal, but something to watch in future

OpenCoverPath = "$openCoverTargetDirectory\OpenCover";
PowerShellExeDirectory = "$psBinPath";
PesterLogElevated = $elevatedLogs;
PesterLogUnelevated = $unelevatedLogs;
TestToolsModulesPath = "$testToolsPath\Modules";
}

if($SuppressQuiet)
{
$openCoverParams.Add('$SuppressQuiet', $true)
Copy link
Collaborator

Choose a reason for hiding this comment

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

should $SuppressQuiet be SuppressQuiet?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. Fixed.

F438
$base64targetArgs = [convert]::ToBase64String($bytes)

# the order seems to be important. Always keep -targetargs as the last parameter.
$cmdline = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all","-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"-EncodedCommand $base64targetArgs`""
Copy link
Collaborator

Choose a reason for hiding this comment

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

having these all on one line is a difficult to read, this would work as well:

$cmdline = "-target:$target",
    "-register:user",
    "-output:${outputLog}",
    "-nodefaultfilters",
    "-oldstyle",
    "-hideskipped:all",
    "-mergeoutput",
    "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"",
    "-targetargs:`"-EncodedCommand $base64targetArgs`""

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also converted it to a single string using -join " " before returning


# invoke OpenCover unelevated and poll for completion
"$openCoverBin $openCoverArgsUnelevatedString" | Out-File -FilePath "$env:temp\unelevated.ps1" -Force
"$openCoverBin $cmdlineUnelevated" | Out-File -FilePath "$env:temp\unelevated.ps1" -Force
runas.exe /trustlevel:0x20000 "powershell.exe -file $env:temp\unelevated.ps1"
# wait for process to start
Start-Sleep -Seconds 5
Copy link
Collaborator

Choose a reason for hiding this comment

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

this 5 second sleep is probably not needed since you have the sleep in line 515

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed the wait.

@adityapatwardhan
Copy link
Member Author

@SteveL-MSFT @JamesWTruher I have addressed all feedback, please have a look.

Copy link
Member
@SteveL-MSFT SteveL-MSFT left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -1,7 +1,8 @@
param(
[Parameter(Mandatory = $true, Position = 0)] $coverallsToken,
[Parameter(Mandatory = $true, Position = 1)] $codecovToken,
[Parameter(Position = 2)] $azureLogDrive = "L:\"
[Parameter(Position = 2)] $azureLogDrive = "L:\",
[Parameter] [switch] $SuppressQuiet
Copy link
Member
@daxian-dbw daxian-dbw Jul 24, 2017

Choose a reason for hiding this comment

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

This will make the parameter type of SuppressQuiet be [parameter], for example:

function bar {
param(
  [Parameter] [switch] $SuppressQuiet
)
}

PS> gcm bar -Syntax
bar [[-SuppressQuiet] <Parameter>]

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

Opencover.console.exe gets confused when the base64 encoded parameter is given with '&' invoke.
Writing to a ps1 file and invoking the script works around the issue.
This also makes it similar to how unelevated tests are invoked.
@adityapatwardhan
Copy link
Member Author

@daxian-dbw @SteveL-MSFT please have another look, I have addressed the feedback and added another bug fix.

@daxian-dbw daxian-dbw merged commit 5cd0e85 into PowerShell:master Aug 4, 2017
@adityapatwardhan adityapatwardhan deleted the OpenCoverCommonModulesPath branch August 4, 2017 17:08
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
0