When we run some integration tests in a pipeline inside a docker container, we get timeouts or they are extremely slow. We think it's related to using localhost inside the tests.
This only happens on our build agent.
If we run the integration tests locally in docker we don't get the timeouts. So I have a feeling this is related to the docker engine settings or version. Rather then the container.
If we run the tests outside the docker container they run fast on both machines.
To run our integration tests we use WebApplicationFactory from Microsoft.AspNetCore.Mvc.Testing. Which creates a HttpClient with base address: http://localhost. We already tried with a different base address using: WebApplicationFactoryClientOptions, but no success.
We feel like on every request an additional 15 seconds is added.
Does anyone have an idea where to start searching?
Command to start the container
docker run --name "OurName" -d -t -w c:/workspace/ -v d:/workspace/project/:c:/workspace ****.azurecr.io/win_dotnet:6.0 cmd /c ping -t localhost > NUL
Command we use to run inside container
docker exec -i "OurName" pwsh.exe '-Command' "{replace with commands below}"
Commands we run inside the container
dotnet build --configuration Debug
dotnet test --no-build --filter 'Category=Integration'
Sample Docker image
# escape=`
# Start from servercore:2022
ARG REPO=mcr.microsoft.com/windows/servercore
FROM $REPO:ltsc2022
ARG PS_VERSION=7.2.4
ARG PS_PACKAGE_URL=https://github.com/PowerShell/PowerShell/releases/download/v${PS_VERSION}/PowerShell-${PS_VERSION}-win-x64.zip
ARG DOTNET_SDK_VERSION=6.0.301
ARG AZURE_CLI_VERSION=2.37.0
ENV `
# DOTNET variables
ASPNETCORE_URLS= `
DOTNET_GENERATE_ASPNET_CERTIFICATE=false `
DOTNET_NOLOGO=true `
DOTNET_USE_POLLING_FILE_WATCHER=true `
NUGET_XMLDOC_MODE=skip `
POWERSHELL_DISTRIBUTION_CHANNEL=PSDocker-DotnetSDK-WindowsServerCore-ltsc2022 `
PSCORE="$ProgramFiles\PowerShell\pwsh.exe" `
POWERSHELL_TELEMETRY_OPTOUT="1"`
PSModuleAnalysisCachePath="C:\Users\Public\AppData\Local\Microsoft\Windows\PowerShell\docker\ModuleAnalysisCache"
# Add powershell, dotnet to path
RUN setx /M PATH "%ProgramFiles%\PowerShell\latest;%PATH%;%ProgramFiles%\dotnet;%ProgramFiles(x86)%\Microsoft SDKs\Azure\CLI2\wbin;"
# Install dotnet
RUN powershell -Command " `
$ErrorActionPreference = 'Stop'; `
$ProgressPreference = 'SilentlyContinue'; `
`
# Retrieve .NET SDK
mkdir "$Env:ProgramFiles\dotnet";`
Invoke-WebRequest -OutFile dotnet.zip https://dotnetcli.azureedge.net/dotnet/Sdk/$Env:DOTNET_SDK_VERSION/dotnet-sdk-$Env:DOTNET_SDK_VERSION-win-x64.zip; `
tar -oxzf dotnet.zip -C "$Env:ProgramFiles\dotnet"; `
Remove-Item -Force dotnet.zip; `
`
"
# Install AZ cli
RUN powershell -Command " `
Invoke-WebRequest -Uri https://azcliprod.blob.core.windows.net/msi/azure-cli-$Env:AZURE_CLI_VERSION.msi -OutFile .\AzureCLI.msi; `
Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; `
Remove-Item -Path .\AzureCLI.msi; `
`
az version `
"
# Install powershell core
RUN powershell -Command "`
Write-host "Verifying valid Version..."; `
if (!($env:PS_VERSION -match '^\d+\.\d+\.\d+(-\w+(\.\d+)?)?$' )) { `
throw ('PS_Version ({0}) must match the regex "^\d+\.\d+\.\d+(-\w+(\.\d+)?)?$"' -f $env:PS_VERSION) `
} `
$ProgressPreference = 'SilentlyContinue'; `
if($env:PS_PACKAGE_URL_BASE64){ `
Write-host "decoding: $env:PS_PACKAGE_URL_BASE64" ;`
$url = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($env:PS_PACKAGE_URL_BASE64)) `
} else { `
Write-host "using url: $env:PS_PACKAGE_URL" ;`
$url = $env:PS_PACKAGE_URL `
} `
Write-host "downloading: $url"; `
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12; `
Invoke-WebRequest -Uri $url -outfile /powershell.zip -verbose; `
Expand-Archive powershell.zip -DestinationPath "$Env:ProgramFiles\PowerShell\latest" `
"
# intialize powershell module cache
RUN pwsh `
-NoLogo `
-NoProfile `
-Command " `
$stopTime = (get-date).AddMinutes(15); `
$ErrorActionPreference = 'Stop' ; `
$ProgressPreference = 'SilentlyContinue' ; `
while(!(Test-Path -Path $env:PSModuleAnalysisCachePath)) { `
Write-Host "'Waiting for $env:PSModuleAnalysisCachePath'" ; `
if((get-date) -gt $stopTime) { throw 'timout expired'} `
Start-Sleep -Seconds 6 ; `
}"
# Install AZ iot
RUN az extension add --name azure-iot
General info:
Docker engine version on build server:20.10.9, build 591094d
Docker for windows on dev machine: 20.10.17, build 100c701
Dotnet version:6.0.301
Related
I want to install rust automatically via command line on Windows. It doesn't matter if it's power shell or not but I think power shell is the easiest without having to install other stuff manually.
I found https://www.powershellgallery.com/packages/AppVeyorBYOC/1.0.170/Content/scripts%5CWindows%5Cinstall_rust.ps1 but at
Add-SessionPath "$env:USERPROFILE\.cargo\bin"
it says that Add-SessionPath is a cmdlet that does not exist.
I had the same error. I changed that line to this and the script worked with Powershell 7.
$env:Path = "$env:USERPROFILE\.cargo\bin"
# Make new environment variables available in the current PowerShell session:
function reload {
foreach($level in "Machine","User") {
[Environment]::GetEnvironmentVariables($level).GetEnumerator() | % {
# For Path variables, append the new values, if they're not already in there
if($_.Name -match 'Path$') {
$_.Value = ($((Get-Content "Env:$($_.Name)") + ";$($_.Value)") -split ';' | Select -unique) -join ';'
}
$_
} | Set-Content -Path { "Env:$($_.Name)" }
}
}
Write-Host "Installing Rust..." -ForegroundColor Cyan
$exePath = "$env:TEMP\rustup-init.exe"
Write-Host "Downloading..."
(New-Object Net.WebClient).DownloadFile('https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe', $exePath)
Write-Host "Installing..."
cmd /c start /wait $exePath -y
Remove-Item $exePath
$addPath = "$env:USERPROFILE\.cargo\bin"
[Environment]::SetEnvironmentVariable
($addPath, $env:Path, [System.EnvironmentVariableTarget]::Machine)
reload
cargo --version
rustup --version
rustc --version
HOWTO Discover Postgres Running in Windows Environment
So How do we discover all the Postgres installed in our Windows 2012R2/2016 environment with PowerShell?
I wrote this script but I am told that will not find ALL postgres instances, if the install was not coded to create a service... Ideas?
#List-PostGres-Servers.ps1
Remove-Item -force "drive\path\*-List-PostGres-Servers-log.txt" -ErrorAction
ignore
$today = (Get-Date -Format yyyyMMdd)+"-"+(get-date -uformat %H)
Start-Transcript -Path "drive\path\$today-List-PostGres-Servers-log.txt"
$servers = get-content 'drive\path\input\listofservers.txt'
foreach ($server in $servers){
if ((Test-Connection -Count 1 -ComputerName $server -quiet) -eq $false){continue}
else{
$PostGresSearch = (get-service -ComputerName $server -name *postgres* -ErrorAction Ignore -WarningAction Ignore -InformationAction Continue)
$PostGresServicename = $PostGresSearch.Name
#|out-file -Encoding ascii "drive\path\output\DOMAINNAME-CheckListPostgres.txt" -force -Append
if ($PostGresServicename -eq $null){continue}
else {
$server+","+" "+$PostGresServicename
}
}
}
You could check to see if postgres is currently running with:
Get-Process *postgres*
In the case where neither a service is installed nor is the binary running, then you're not using that postgres install. Alternatively, search $env:ProgramFiles or ${env:ProgramFiles(x86)} for psql.
I'm trying to run a powershell script from rundeck(linux), If I run the script locally[Deletes some files from multiple terminal servers](Windows server) it is working as expected however if I call it from rundeck server(winrm configured) it seems that the script cant access the remote folders I'm trying to access.
I tried running the script using the same user but still shows different result.
Script bellow:
$userAD = "someuser"
$servers = Get-Content C:\TSList.csv
$Folder = "c$\Users\$userAD\"
$TSFolderShare = "\\sharepath"
Write-Output "#####Start of script#####"
Write-output `n
Write-output "Checking if $userAD user profile exist in Terminal servers..."
sleep -seconds 1
foreach ($server in $servers) {
Test-Path "\\$server\$Folder" -PathType Any
Get-ChildItem "\\$server\$Folder"
if (Test-Path "\\$server\$Folder" -PathType Any) {
Write-output "Resetting user profile in $server.."
Get-ChildItem "\\$server\$Folder" -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
sleep -seconds 1
Write-output "Done."
if( (Get-ChildItem "\\$server\$Folder" | Measure-Object).Count -eq 0)
{
Write-output "Done."
}
}
else
{
Write-output "Resetting user profile in $server.."
sleep -seconds 1
Write-output "User profile does not exist in $server."
#Write-output "\\$server\$Folder does not exist in $server!" -ForegroundColor Red
}
}
EDIT: It seems my problem is when running my script from another script with RunAS.
Below I'm trying to access a folder from another server using ps script, but since I want to integrate this to Rundeck I need to call my ps script from my linux server using python. I did a test running the ps script directly and calling the test path script using another script with RunUs using the same user I used to run the script manually
Scenario 1
Running PS script via separate PS script with RunAS(my_account)
$username = "my_account"
$password = "my_password"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
Invoke-Command -FilePath "C:\testpath.ps1" -Credential $cred -Computer localhost
(C:\testpath.ps1) Content below:
Test-Path "\\server\c$\Users\myaccount\"
result:
Access is denied
+ CategoryInfo : PermissionDenied: (\server\c$\Users\myaccount:String) [Test-Path], UnauthorizedAccessException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.TestPathCommand
+ PSComputerName : localhost
False
Scenario 2
Running C:\testpath.ps1 directly as my_account
Test-Path "\\server\c$\Users\myaccount\"
result:
True
I used session configuration in powershell to solve the issue. This way allows you to tie a credential to a PowerShell session configuration and reuse this configuration for all future connections.
https://4sysops.com/archives/solve-the-powershell-multi-hop-problem-without-using-credssp/
Thanks a lot!
You're facing a double-hop issue with Rundeck and Powershell, here the explanation. That's asked before, take a look a this, and here a good workaround. Also this to solve it.
I just set up a few containerized agents and I'm running into build issues with few regression tests which work fine on regular build agents.
Was wondering if anyone had issues with containerized build agents?
Error Log:
Add-Type : (0) : Unable to find messages file 'cscui.dll' (1) : namespace VstsTaskSdk.FS At C:\tfsagent_work_tasks\VSBuild_71a9a2d3-a98a-4caa-96ab-affca411ecda\1.119.0\ps_modules\VstsTaskSdk\LongPathFunctions.ps1:212 char:1 + Add-Type -Debug:$false -TypeDefinition #' + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception + FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
#
Unable to find type [VstsTaskSdk.TerminationException]. Exit code 1
returned from process: file name
'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe', arguments
'-NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted
-Command ". ([scriptblock]::Create('if (!$PSHOME) { $null = Get-Item -LiteralPath ''variable:PSHOME'' } else { Import-Module -Name ([System.IO.Path]::Combine($PSHOME,
''Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1''))
; Import-Module -Name ([System.IO.Path]::Combine($PSHOME,
''Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1''))
}')) 2>&1 | ForEach-Object { Write-Verbose $_.Exception.Message
-Verbose } ; Import-Module -Name 'C:\tfsagent_work_tasks\VSBuild_71a9a2d3-a98a-4caa-96ab-affca411ecda\1.119.0\ps_modules\VstsTaskSdk\VstsTaskSdk.psd1'
-ArgumentList #{ NonInteractive = $true } -ErrorAction Stop ; $VerbosePreference = 'SilentlyContinue' ; $DebugPreference =
'SilentlyContinue' ; Invoke-VstsTaskScript -ScriptBlock
([scriptblock]::Create('.
''C:\tfsagent_work_tasks\VSBuild_71a9a2d3-a98a-4caa-96ab-affca411ecda\1.119.0\VSBuild.ps1'''))"'.
Do anyone know if I can use Invoke-Command in a PowerShell workflow?
Currently I have script that loops through a text file with the list of services but I would like it push to all of the servers at once verses going through one by one. Is this possible?
This is the current script block I am working with:
{
ForEach ($Server in $Servers) {
Write-Host "Copying code to $Server..."
If (!(Test-Path -path \\$Server\c$\Websites\Versions\v$version)) {
New-Item \\$Server\c$\Websites\Versions\v$version -Type Directory | Out-Null
}
Copy-Item .\Packages\v$version\* \\$Server\c$\Websites\Versions\v$version -Force -Recurse
Write-Host "Converting to application on $Server..."
Invoke-Command -ComputerName $Server -ScriptBlock $Script -Argumentlist $Version | Out-Null
}
}
The PowerShell Workflow engine is not capable of directly invoking PowerShell cmdlets. Instead, if a script writer calls a PowerShell cmdlet inside a Workflow definition, the PowerShell Workflow engine will automatically wrap invocations of PowerShell cmdlets inside the InlineScript Workflow Activity.
workflow test
{
ForEach ($Server in $Servers) {
Write-Host "Copying code to $Server..."
If (!(Test-Path -path \\$Server\c$\Websites\Versions\v$version)) {
New-Item \\$Server\c$\Websites\Versions\v$version -Type Directory | Out-Null
}
Copy-Item .\Packages\v$version\* \\$Server\c$\Websites\Versions\v$version -Force -Recurse
Write-Host "Converting to application on $Server..."
InlineScript {
Invoke-Command -ComputerName $Server -ScriptBlock $Script -Argumentlist $Version | Out-Null
}
}
}
As for whether or not it will work, you'll have to try it out, as suggested by Mathias.
#Trevor's response is good as an overall skeleton, but it won't work as it is.
There are several things missing or incorrect:
Passing arguments to workflow
Passing arguments to InlineScript
Passing ScriptBlock as an argument;
Using Out-Null in workflow
The working example:
$serversProd=#"
server1
server2
server3
server4
"#-split'\r\n'
$reportScript = "report.script.ps1"
$generateReport = {
param($reportScript)
cd D:\Automations\ConnectivityCheck
powershell -file $reportScript
}
workflow check-connectivity {
Param ($servers, $actionBlock, $reportScript)
# Prepare the results folder
$resultsFolder = "D:\Automations\ConnectivityCheckResults"
$unused1 = mkdir -Force $resultsFolder
# Run on all servers in parallel
foreach -parallel ($server in $servers) {
# Upload script to the server
$unused2 = mkdir -Force \\$server\D$\Automations\ConnectivityCheck
cp -Force $reportScript \\$server\D$\Automations\ConnectivityCheck\
"Starting on $server..."
# Execute script on the server. It should contain Start-Transcript and Stop-Transcript commands
# For example:
# $hostname = $(Get-Wmiobject -Class Win32_ComputerSystem).Name
# $date = (Get-Date).ToString("yyyyMMdd")
# Start-Transcript -path ".\$date.$hostname.connectivity.report.txt"
# ...Code...
# Stop-Transcript
$results = InlineScript {
$scriptBlock = [scriptblock]::Create($Using:actionBlock)
Invoke-Command -computername $Using:server -ScriptBlock $scriptBlock -ArgumentList $Using:reportScript
}
# Download transcript file from the server
$transcript = [regex]::Match($results,"Transcript started.+?file is \.\\([^\s]+)").groups[1].value
"Completed on $server. Transcript file: $transcript"
cp -Force \\$server\D$\Automations\ConnectivityCheck\$transcript $resultsFolder\
}
}
cls
# Execute workflow
check-connectivity $serversProd $generateReport $reportScript