顯示具有 Powershell 標籤的文章。 顯示所有文章
顯示具有 Powershell 標籤的文章。 顯示所有文章

2019年8月4日 星期日

在微軟官方Asp.net Core runtime image裡安裝powershell

在微軟官方Asp.net Core runtime image裡安裝powershell

微軟官方 asp.net core 的image 其實是base 在 nano server上(https://github.com/dotnet/dotnet-docker/blob/master/2.2/runtime/nanoserver-1809/amd64/Dockerfile)

而nano server 為了縮小體積早就己經移除powershell。但是powershell是個好東西,沒有powershell對我們要做一些客製的行為很麻煩,所以才會想怎麼才能加回來。

其實也沒什麼密訣,現在微軟都把官方image的DockerFile 都放在Github上了,找到官方powershell image 的 Github,看一下人家怎麼做照做就是了

https://github.com/PowerShell/PowerShell-Docker/blob/master/release/stable/nanoserver/docker/Dockerfile

原理就是先找一個有powershell的image ,下載powershell core (註)裝起來後再Copy到 nano server 上

以下是我的DockerFile

# escape=`

FROM mcr.microsoft.com/windows/servercore:ltsc2019 AS installer-env

ARG PS_VERSION=6.2.0
ARG PS_PACKAGE_URL=https://github.com/PowerShell/PowerShell/releases/download/v${PS_VERSION}/PowerShell-${PS_VERSION}-win-x64.zip

SHELL ["C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "-command"]

ARG PS_PACKAGE_URL_BASE64

RUN 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  \PowerShell

# 裝到asp.net core 2.2 runtime 的 image上
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2     

# Copy PowerShell Core from the installer container
ENV ProgramFiles="C:\Program Files" `
    # set a fixed location for the Module analysis cache
    LOCALAPPDATA="C:\Users\ContainerAdministrator\AppData\Local" `
    PSModuleAnalysisCachePath="$LOCALAPPDATA\Microsoft\Windows\PowerShell\docker\ModuleAnalysisCache" `
    # Persist %PSCORE% ENV variable for user convenience
    PSCORE="$ProgramFiles\PowerShell\pwsh.exe"

# Copy PowerShell Core from the installer container
COPY --from=installer-env ["\\PowerShell\\", "$ProgramFiles\\PowerShell\\latest"]

# Set the path 這裡要注意一下,setx /M 需要管理者的權限,
# 但原本的身分是ContainerUser,所以需要先切換身分到ContainerAdministrator ,設完再切回來

USER ContainerAdministrator
RUN setx /M PATH "%ProgramFiles%\PowerShell\latest;%PATH%;"
USER ContainerUser

# 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 ; `
          }"

P.S. 新版的powershell ,己經可以跨平台了,並且改名叫 powershell core 了,而且執行檔名稱也改叫 pwsh.exe,不再是 powershell.exe

2019年7月25日 星期四

在Azure Devops Server 2019 的 powershell task 執行外部執行檔

在Azure Devops Server 2019 的 powershell task 執行外部執行檔

原本的需求是在 Pipelines 部署時,判斷如果docker-compose 己經有把container 建起來了,就更新container,否則就用docker-compose建立新的container。

但是在Pipelines的部署工作裡,似乎要做到上面的需求有困難。所以才想要在powershell裡執行docker-compose

底下是我預備要執行的powershell,

Set-Location -Path C:\composefile

$proxy = 'iisproxy'
$site1 = 'site-blue'
$site2 = 'site-green'

$cID = $(docker ps -qf "name=$proxy")

if(-NOT $cID){
 Write-Host "create new container"
 docker pull myhub.local/iisproxy
 docker pull myhub.local/app
        docker-compose up -d 
    }
    else {
        Write-Host "update container"
 docker pull myhub.local/app
        docker-compose stop $site1 
        docker-compose up -d --force-recreate --no-deps $site1  
 Start-Sleep -s 5
        docker-compose stop $site2
        docker-compose up -d --force-recreate --no-deps $site2        
    }

但是卻發現只要是執行到 docker-compose 就會出現 NativeCommandError 的錯誤

2019-07-24T08:00:10.7991464Z ##[error]位於 C:\azagent\A1\_work\_temp\46980d80-fab6-4a21-8fd7-1a6e7130d9a8.ps1:20 字元:9

+ docker-compose stop $site1  

2019-07-24T08:00:10.8097416Z ##[error]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~  

2019-07-24T08:00:10.8204529Z ##[error] + CategoryInfo : NotSpecified: (Stopping site-blue ... :String) [], RemoteException  

2019-07-24T08:00:10.8301628Z ##[error] + FullyQualifiedErrorId : NativeCommandError  

2019-07-24T08:00:10.8403452Z ##[error]  

2019-07-24T08:00:10.8516019Z ##[error]PowerShell 已結束,代碼為 '1'。

但是直接開啟command視窗執行是正常的。 後來又發現在Powershell ISE 裡執行指令就會有一樣的錯誤。 原來兇手是 powershell 自己,害我錯怪 docker-compose 好幾天。

自此,才有比較明確的追查方向。
找到在stackoverflow上一樣症頭的討論

https://stackoverflow.com/questions/2095088/error-when-calling-3rd-party-executable-from-powershell-when-using-an-ide/20950421#20950421

原來是因為 powershell 在處理 STDERR (standard error) 有不同的行為才造成這樣的錯

照文章內的好幾個做法,要在 Pipelines裡可以正常執行要改成這樣
用 2>&1 來吃掉多出來的錯誤

&cmd /c "docker-compose up -d 2>&1"

下面是完整的script

Set-Location -Path C:\composefile

$proxy = 'iisproxy'
$site1 = 'site-blue'
$site2 = 'site-green'

$cID = $(docker ps -qf "name=$proxy")

if(-NOT $cID){
 Write-Host "create new container"
 docker pull myhub.local/iisproxy
 docker pull myhub.local/app
        &cmd /c "docker-compose up -d 2>&1"
    }
    else {
        Write-Host "update container"
 docker pull myhub.local/app
        &cmd /c "docker-compose stop $site1 2>&1"
        &cmd /c "docker-compose up -d --force-recreate --no-deps $site1 2>&1"
 Start-Sleep -s 5
        &cmd /c "docker-compose stop $site2 2>&1"
        &cmd /c "docker-compose up -d --force-recreate --no-deps $site2 2>&1"
    }

2019年5月15日 星期三

使用Powershell在IIS上安裝SSL憑証

使用Powershell在IIS上安裝SSL憑証

使用Powershell在IIS上安裝SSL憑証

$securePfxPass = "你的密碼" | ConvertTo-SecureString -AsPlainText -Force
Import-PfxCertificate -Password $securePfxPass -CertStoreLocation Cert:\LocalMachine\My -FilePath c:\test.local.pfx   

#取得憑証指紋
$pfxThumbprint = (Get-PfxData -FilePath \test.local.pfx -Password $securePfxPass).EndEntityCertificates.Thumbprint

#新增 https 的繫結在 Default Web Site上
$binding = New-WebBinding -Name "Default Web Site" -Protocol https -IPAddress * -Port 443;
$binding = Get-WebBinding -Name "Default Web Site" -Protocol https;
# 綁定憑証 , 注意這裡的 "my" 是指憑証存放的Sotre , 不要亂改 , 指的是 Cert:\LocalMachine\My <-這個my
$binding.AddSslCertificate($pfxThumbprint, "my");