PowerShell 6にプロキシ経由でモジュールインストール

# 概要

PowerShell 6（PowerShell Core）で、プロキシ経由でのモジュールインストールを行うときには`-Proxy`パラメーターを指定します。プロキシが認証を要求するときは、`-ProxyCredential`パラメーターを指定します。

# 詳細

PowerShell 6の[Find-Module](https://docs.microsoft.com/ja-jp/powershell/module/PowershellGet/Find-Module?view=powershell-6)、[Install-Module](https://docs.microsoft.com/ja-jp/powershell/module/PowershellGet/Install-Module?view=powershell-6)、[Save-Module](https://docs.microsoft.com/ja-jp/powershell/module/PowershellGet/Save-Module?view=powershell-6)コマンドレットでは、`-Proxy`および`-ProxyCredential`パラメーターを指定可能です。なお、関連するパッケージ管理用の[Find-PackageProvider](https://docs.microsoft.com/ja-jp/powershell/module/packagemanagement/find-packageprovider?view=powershell-6)、[Install-PackageProvider](https://docs.microsoft.com/ja-jp/powershell/module/packagemanagement/install-packageprovider?view=powershell-6)、[Register-PackageSource](https://docs.microsoft.com/ja-jp/powershell/module/packagemanagement/register-packagesource?view=powershell-6)でもこのパラメーターを利用できます。

これらのコマンドレットでモジュールの検索やインストール、取得を行う際、プロキシを使うときには`-Proxy`パラメータでプロキシサーバのURIを指定します。プロキシが認証を行うときには、認証情報を`-ProxyCredential`パラメーターで`PSCredential`オブジェクトとして指定します。

## プロキシ経由でのモジュールインストール

なんどかパラメーターで指定することになるので、プロキシのURIはあらかじめ変数に格納しておくことにします。`http://proxy.example.com:8080`は使用するプロキシサーバのURIに置き換えてください。

    $ProxyUri = "http://proxy.example.com:8080"

モジュールの検索を、プロキシ経由で行います。以下の例では、`AzureRM`モジュールを検索しています。`-Proxy`パラメータでプロキシのURIを、`-ProxyCredential`でプロキシの認証情報を指定します。

    Find-Module -Name AzureRM -Proxy $ProxyUri
    
    Version  Name     Repository  Description
    -------  ----     ----------  -----------
    6.0.1    AzureRM  PSGallery   Azure Resource Manager Module

モジュールのインストールを、プロキシ経由で行います。同様に`-Proxy`および`-ProxyCredential`パラメーターを指定します。

    Install-Module -Name AzureRM -Proxy $ProxyUri

## 認証プロキシ経由でのモジュールインストール

なんどかパラメーターで指定することになるので、プロキシのURIと認証情報はあらかじめ変数に格納しておくことにします。`http://proxy.example.com:8080`、`MyPassword`、`MyUserName`はそれぞれ使用するプロキシサーバのURIとプロキシ認証時のユーザー名、パスワードに置き換えてください。

    $ProxyUri = "http://proxy.example.com:8080"
    $ProxyPass = ConvertTo-SecureString -AsPlainText -Force "MyPassword"
    $ProxyCred = New-Object System.Management.Automation.PSCredential "MyUserName", $ProxyPass

なお、認証情報は入力ダイアログを表示させて、そこで入力することもできます。その時は、以下のようになります。

    $ProxyUri = "http://proxy.example.com:8080"
    $ProxyCred = Get-Credential

モジュールの検索を、プロキシ経由で行います。以下の例では、`AzureRM`モジュールを検索しています。`-Proxy`パラメータでプロキシのURIを、`-ProxyCredential`でプロキシの認証情報を指定します。

    Find-Module -Name AzureRM -Proxy $ProxyUri -ProxyCredential $ProxyCred
    
    Version  Name     Repository  Description
    -------  ----     ----------  -----------
    6.0.1    AzureRM  PSGallery   Azure Resource Manager Module

モジュールのインストールを、プロキシ経由で行います。同様に`-Proxy`および`-ProxyCredential`パラメーターを指定します。

    Install-Module -Name AzureRM -Proxy $ProxyUri -ProxyCredential $ProxyCred -Scope CurrentUser

## Windows PowerShell 5.0まででのプロキシ経由でのモジュールインストール

`-Proxy`や`-ProxyCredential`パラメーターは「[プロキシの背後での PackageManagement の使用のサポート | WMF 5.1 のパッケージ管理の機能強化 | Microsoft Docs](https://docs.microsoft.com/ja-jp/powershell/wmf/5.1/package-management-improvements#support-for-using-packagemanagement-behind-a-proxy)」で追加されたもののようです。それより前のPowerShell 5.0まででは、以下のような設定を行っておく方法がしばしば紹介されています。

    $ProxyUri = "http://proxy.example.com:8080"
    $ProxyPass = ConvertTo-SecureString -AsPlainText -Force "MyPassword"
    $ProxyCred = New-Object System.Management.Automation.PSCredential "MyUserName", $ProxyPass
    $Proxy = New-Object System.Net.WebProxy $ProxyUri
    $Proxy.Credentials = $ProxyCred
    [System.Net.WebRequest]::DefaultWebProxy = $Proxy

これを行った後は、`-Proxy`等のパラメーターなしで、`Find-Module`等のコマンドレットを実行します。

    Find-Module -Name AzureRM
    Install-Module -Name AzureRM -Proxy $ProxyUri

PowerShell 6.0.2ではこの方法ではうまくいきませんでしたが、私のWindows PowerShell 5.1環境ではこの方法が有効でした。`-Proxy`等のパラメーター指定ができないWindows PowerShell 5.0まででは、こちらの方法を試してみるとよさそうです。

## トラブルシューティング

もしエラー等が起きる場合は、まず`-Verbose`パラメータを使い、詳細情報を出力する状態でコマンドレットを実行して、まずWebアクセスの失敗かそれ以外の問題かを切り分けることをお勧めします。私の環境ではPowerShell 6での最初の`Import-Module`が失敗したので、`-Verbose`パラメータを指定して再実行しました。

    Install-Module -Name AzureRM -Proxy $ProxyUri -ProxyCredential $ProxyCred -Verbose

その際の出力は、以下のようになりました。

    VERBOSE: Using the provider 'PowerShellGet' for searching packages.
    VERBOSE: The -Repository parameter was not specified.  PowerShellGet will use all of the registered repositories.
    VERBOSE: Getting the provider object for the PackageManagement Provider 'NuGet'.
    VERBOSE: The specified Location is 'https://www.powershellgallery.com/api/v2/' and PackageManagementProvider is 'NuGet'.
    VERBOSE: Searching repository 'https://www.powershellgallery.com/api/v2/FindPackagesById()?id='AzureRM'' for ''.
    VERBOSE: Total package yield:'1' for the specified package 'AzureRM'.
    VERBOSE: Performing the operation "Install-Module" on target "Version '6.0.1' of module 'AzureRM'".
    VERBOSE: The installation scope is specified to be 'AllUsers'.
    VERBOSE: The specified module will be installed in 'C:\Program Files\PowerShell\Modules'.
    VERBOSE: The specified Location is 'NuGet' and PackageManagementProvider is 'NuGet'.
    VERBOSE: Downloading module 'AzureRM' with version '6.0.1' from the repository 'https://www.powershellgallery.com/api/v2/'.
    VERBOSE: Searching repository 'https://www.powershellgallery.com/api/v2/FindPackagesById()?id='AzureRM'' for ''.
    VERBOSE: Searching repository 'https://www.powershellgallery.com/api/v2/FindPackagesById()?id='AzureRM.Profile'' for ''
    (略)
    VERBOSE: Searching repository 'https://www.powershellgallery.com/api/v2/FindPackagesById()?id='AzureRM.CognitiveServices'' for ''.
    VERBOSE: Searching repository 'https://www.powershellgallery.com/api/v2/FindPackagesById()?id='AzureRM.Compute'' for ''.
    PackageManagement\Install-Package : One or more errors occurred. (One or more errors occurred. (An error occurred while parsing EntityName. Line 11, position 104.)) (An error occurred while parsing EntityName. Line 11, position 104.)
    At C:\program files\powershell\6.0.2\Modules\PowerShellGet\1.6.0\PSModule.psm1:2057 char:21
    + ...          $null = PackageManagement\Install-Package @PSBoundParameters
    +                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: ($aHR0cHM6Ly93d3...XJzaGVsbGdldA==:String) [Install-Package], Exception
    + FullyQualifiedErrorId : One or more errors occurred. (One or more errors occurred. (An error occurred while parsing EntityName. Line 11, position 104.)) (An error occurred while parsing EntityName. Line 11, position 104.),Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackage

内部動作は知らないなりに、エラーが出るまでに何度かWebへのアクセスをしているようなので、プロキシは利用できていそうだと考えました。エラー箇所として表示されている`PackageManagement\Install-Package @PSBoundParameters`にInstallという文字があるので、ファイル配置などをしようとした際のエラーかもしれないと思いました。

モジュールのインストール先として使われる`C:\Program Files\PowerShell\Modules`および`C:\Users\tsukamoto\Documents\PowerShell\Modules`（`tsukamoto`の部分はユーザー名です）がこの時点では存在しないのが気になり、作成してみました。その後`Install-Module`を行うと、モジュールインストールに成功しました。

# 参考

以下を参考にしました。

* [WMF 5.1 のパッケージ管理の機能強化 | Microsoft Docs](https://docs.microsoft.com/ja-jp/powershell/wmf/5.1/package-management-improvements)
* [Find-Module](https://docs.microsoft.com/ja-jp/powershell/module/PowershellGet/Find-Module?view=powershell-6)
* [Install-Module](https://docs.microsoft.com/ja-jp/powershell/module/PowershellGet/Install-Module?view=powershell-6)
* [Save-Module](https://docs.microsoft.com/ja-jp/powershell/module/PowershellGet/Save-Module?view=powershell-6)

Windows PowerShell 5まででの`[System.Net.WebRequest]::DefaultWebProxy`を指定する方法はどこで知ったのかを忘れましたが、以下で再確認しました。

* [認証proxyを使う環境設定（PowerShell） - Qiita](https://qiita.com/kkdd/items/ac6e65f6e2e8fc32e7ca)

----

本ページ内容は筆者が参照の便のためにある時点でまとめた個人的なメモです。内容を保証するものではなく、また筆者の所属組織等とは一切かかわりがありません。