-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
Fixed passing common test modules path to unelevated Powershell #4313
Conversation
test/tools/OpenCover/OpenCover.psm1
Outdated
$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat", "-Quiet") | ||
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat", "-Quiet") | ||
$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat") | ||
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat") |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
test/tools/OpenCover/OpenCover.psm1
Outdated
$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`"" |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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`"")
test/tools/OpenCover/OpenCover.psm1
Outdated
@@ -519,6 +520,9 @@ function Invoke-OpenCover | |||
# poll for process exit every 60 seconds | |||
# timeout of 6 hours | |||
$timeOut = ([datetime]::Now).AddHours(6) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
test/tools/OpenCover/OpenCover.psm1
Outdated
$updatedEnvPath = "${PowerShellExeDirectory}\Modules;$TestToolsModulesPath" | ||
|
||
$startupArgs = "Set-ExecutionPolicy Bypass -Force -Scope Process; `$env:PSModulePath = '${updatedEnvPath}';" | ||
$targetArgs = "${startupArgs}", "Invoke-Pester","${TestDirectory}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we depend on Start-PSPester instead as we've started building more specialization in our test runs in that cmdlet?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?)
There was a problem hiding this comment.
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.
@SteveL-MSFT Updated. Please have a look. |
test/tools/OpenCover/OpenCover.psm1
Outdated
$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat", "-Quiet") | ||
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat", "-Quiet") | ||
$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat") | ||
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat") |
There was a problem hiding this comment.
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?
test/tools/OpenCover/OpenCover.psm1
Outdated
$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`"" |
There was a problem hiding this comment.
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`"")
@SteveL-MSFT Had forgotten to push. Please have a look. |
@JamesWTruher Can you have a look too? |
6311b6b
to
517d218
Compare
There was a problem hiding this 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; |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should $SuppressQuiet
be SuppressQuiet
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Fixed.
test/tools/OpenCover/OpenCover.psm1
Outdated
$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`"" |
There was a problem hiding this comment.
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`""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
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
test/tools/OpenCover/OpenCover.psm1
Outdated
|
||
# 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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the wait.
@SteveL-MSFT @JamesWTruher I have addressed all feedback, please have a look. |
There was a problem hiding this 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 |
There was a problem hiding this comment.
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>]
There was a problem hiding this comment.
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.
@daxian-dbw @SteveL-MSFT please have another look, I have addressed the feedback and added another bug fix. |
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.