简体   繁体   English

如何检查是否安装了 PowerShell 模块?

[英]How do I check if a PowerShell module is installed?

To check if a module exists I have tried the following:要检查模块是否存在,我尝试了以下操作:

try {
    Import-Module SomeModule
    Write-Host "Module exists"
} 
catch {
    Write-Host "Module does not exist"
}

The output is: output 是:

Import-Module : The specified module 'SomeModule' was not loaded because no valid module file was found in any module directory.
At D:\keytalk\Software\Client\TestProjects\Export\test.ps1:2 char:5
+     Import-Module SomeModule
+     ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (SomeModule:String) [Import-Module], FileNotFoundException
    + FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand

Module exists

I do get an error, but no exception is thrown, so we see Module exists in the end, although SomeModule does not exist.我确实得到了一个错误,但没有抛出异常,所以我们看到Module exists ,尽管SomeModule不存在。

Is there a good way (preferably without generating an error) to detect if a PowerShell module is installed on the system?有没有一种好方法(最好不会产生错误)来检测系统上是否安装了 PowerShell 模块?

You can use the ListAvailable option of Get-Module :您可以使用Get-ModuleListAvailable选项:

 if (Get-Module -ListAvailable -Name SomeModule) { Write-Host "Module exists" } else { Write-Host "Module does not exist" }

A module could be in the following states:一个模块可能处于以下状态:

  • imported进口的
  • available on disk (or local network)在磁盘(或本地网络)上可用
  • available in an online gallery可在在线画廊中找到

If you just want to have the darn thing available in a PowerShell session for use, here is a function that will do that or exit out if it cannot get it done:如果您只想在 PowerShell session 中使用该死的东西,这里有一个 function 可以做到这一点,如果它不能完成它就退出:

 function Load-Module ($m) { # If module is imported say that and do nothing if (Get-Module | Where-Object {$_.Name -eq $m}) { write-host "Module $m is already imported." } else { # If module is not imported, but available on disk then import if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { Import-Module $m -Verbose } else { # If module is not imported, not available on disk, but is in online gallery then install and import if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { Install-Module -Name $m -Force -Verbose -Scope CurrentUser Import-Module $m -Verbose } else { # If the module is not imported, not available and not in the online gallery then abort write-host "Module $m not imported, not available and not in an online gallery, exiting." EXIT 1 } } } } Load-Module "ModuleName" # Use "PoshRSJob" to test it out

The ListAvailable option doesn't work for me. ListAvailable 选项对我不起作用。 Instead this does:相反,这样做:

 if (-not (Get-Module -Name "<moduleNameHere>")) { # module is not loaded }

Or, to be more succinct:或者,更简洁地说:

 if ( (Get-Module "<moduleNameHere>")) { # module is not loaded }

The current version of Powershell has a Get-InstalledModule function that suits this purpose well (or at least it did in my case).当前版本的 Powershell 有一个Get-InstalledModule function 非常适合这个目的(或者至少在我的情况下是这样)。

Get-InstalledModule

Description描述

The Get-InstalledModule cmdlet gets PowerShell modules that are installed on a computer. Get-InstalledModule cmdlet 获取安装在计算机上的 PowerShell 模块。

The only issue with it is that it throws an exception if the module that is being requested doesn't exist, so we need to set ErrorAction appropriately to suppress that case.唯一的问题是,如果被请求的模块不存在,它会抛出异常,所以我们需要适当地设置ErrorAction来抑制这种情况。

 if ((Get-InstalledModule ` -Name "AzureRm.Profile" ` -MinimumVersion 5.0 ` # Optionally specify minimum version to have -ErrorAction SilentlyContinue) -eq $null) { # Install it... }

You can use the Get-InstalledModule您可以使用Get-InstalledModule

 If (-not(Get-InstalledModule SomeModule -ErrorAction silentlycontinue)) { Write-Host "Module does not exist" } Else { Write-Host "Module exists" }

Just revisiting this as it's something I just faced and there is some incorrect stuff in the answers (though it's mentioned in the comments).只是重新审视它,因为这是我刚刚遇到的问题,并且答案中有一些不正确的东西(尽管在评论中提到了)。

First thing though.不过第一件事。 The original questions ask how to tell if a PowerShell module is installed.原始问题询问如何判断是否安装了 PowerShell 模块。 We need to talk about the word installed.我们需要谈谈安装这个词。 You don't install PowerShell modules (not in the traditional way you install software anyway)您不安装 PowerShell 模块(不是以传统方式安装软件)

PowerShell modules are either available (ie they are on the PowerShell module path), or they are imported (they are imported into your session and you can call the functions contained). PowerShell 模块要么可用(即它们在 PowerShell 模块路径上),要么它们被导入(它们被导入到您的 session 中,您可以调用包含的函数)。 This is how to check your module path, in case you want to know where to store a module:这是检查模块路径的方法,以防您想知道模块的存储位置:

 $env:psmodulepath

I'd argue that it's becoming common to use C:\Program Files\WindowsPowerShell\Modules;我认为使用C:\Program Files\WindowsPowerShell\Modules;变得越来越普遍。 more often due to it being available to all users, but if you want to lock down your modules to your own session, include them in your profile.更常见的是因为它对所有用户都可用,但如果您想将模块锁定到您自己的 session,请将它们包含在您的配置文件中。 C:\Users%username%\Documents\WindowsPowerShell\Modules; C:\Users%username%\Documents\WindowsPowerShell\Modules;

Alright, back to the two states.好吧,回到两个状态。

Is the module available (using available to mean installed in the original question)?该模块是否可用(在原始问题中使用可用表示已安装)?

 Get-Module -Listavailable -Name <modulename>

This tells you if a module is available for import.这会告诉您模块是否可用于导入。

Is the module imported?模块是否导入? (I'm using this as the answer for the word 'exists' in the original question). (我将其用作原始问题中“存在”一词的答案)。

 Get-module -Name <modulename>

This will either return an empty load of nothing if the module is not imported or a one-line description of the module if it is.如果未导入模块,这将返回一个空负载,或者如果是,则返回该模块的单行描述。 As ever on Stack Overflow, try the commands above on your own modules.与 Stack Overflow 上一样,在您自己的模块上尝试上述命令。

When I use non-default modules in my scripts I call the function below.当我在脚本中使用非默认模块时,我在下面调用 function。 Besides the module name, you can provide a minimum version.除了模块名称,您还可以提供最低版本。

 # See https://www.powershellgallery.com/ for module and version info Function Install-ModuleIfNotInstalled( [string] [Parameter(Mandatory = $true)] $moduleName, [string] $minimalVersion ) { $module = Get-Module -Name $moduleName -ListAvailable |` Where-Object { $null -eq $minimalVersion -or $minimalVersion -lt $_.Version } |` Select-Object -Last 1 if ($null -ne $module) { Write-Verbose ('Module {0} (v{1}) is available.' -f $moduleName, $module.Version) } else { Import-Module -Name 'PowershellGet' $installedModule = Get-InstalledModule -Name $moduleName -ErrorAction SilentlyContinue if ($null -ne $installedModule) { Write-Verbose ('Module [{0}] (v {1}) is installed.' -f $moduleName, $installedModule.Version) } if ($null -eq $installedModule -or ($null -ne $minimalVersion -and $installedModule.Version -lt $minimalVersion)) { Write-Verbose ('Module {0} min.vers {1}: not installed; check if nuget v2.8.5.201 or later is installed.' -f $moduleName, $minimalVersion) #First check if package provider NuGet is installed. Incase an older version is installed the required version is installed explicitly if ((Get-PackageProvider -Name NuGet -Force).Version -lt '2.8.5.201') { Write-Warning ('Module {0} min.vers {1}: Install nuget,' -f $moduleName. $minimalVersion) Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force } $optionalArgs = New-Object -TypeName Hashtable if ($null -ne $minimalVersion) { $optionalArgs['RequiredVersion'] = $minimalVersion } Write-Warning ('Install module {0} (version [{1}]) within scope of the current user,' -f $moduleName $minimalVersion) Install-Module -Name $moduleName @optionalArgs -Scope CurrentUser -Force -Verbose } } }

usage example:用法示例:

 Install-ModuleIfNotInstalled 'CosmosDB' '2.1.3.528'

Please let me known if it's useful (or not)请让我知道它是否有用(或没有)

 try { Import-Module SomeModule Write-Host "Module exists" } catch { Write-Host "Module does not exist" }

It should be pointed out that your cmdlet Import-Module has no terminating error, therefore the exception isn't being caught so no matter what your catch statement will never return the new statement you have written.应该指出的是,您的 cmdlet Import-Module没有终止错误,因此不会捕获异常,因此无论您的 catch 语句是什么,都不会返回您编写的新语句。

( https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-6 ( https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-6

From The Above:从上面:

"A terminating error stops a statement from running. If PowerShell does not handle a terminating error in some way, PowerShell also stops running the function or script using the current pipeline. In other languages, such as C#, terminating errors are referred to as exceptions. For more information about errors, see about_Errors." "A terminating error stops a statement from running. If PowerShell does not handle a terminating error in some way, PowerShell also stops running the function or script using the current pipeline. In other languages, such as C#, terminating errors are referred to as exceptions . 有关错误的更多信息,请参阅 about_Errors。”

It should be written as:它应该写成:

 Try { Import-Module SomeModule -Force -Erroraction stop Write-Host "yep" } Catch { Write-Host "nope" }

Which returns:返回:

 nope

And if you really wanted to be thorough you should add in the other suggested cmdlets Get-Module -ListAvailable -Name and Get-Module -Name to be extra cautious, before running other functions/cmdlets.如果您真的想要彻底,您应该在运行其他功能/cmdlet 之前添加其他建议的 cmdlet Get-Module -ListAvailable -NameGet-Module -Name以格外小心。 And if it's installed from ps gallery or elsewhere you could also run a Find-Module cmdlet to see if there is a new version available.如果它是从 ps 库或其他地方安装的,您还可以运行Find-Module cmdlet 以查看是否有可用的新版本。

You can use the #Requires statement (supports modules from PowerShell 3.0).您可以使用#Requires语句(支持来自 PowerShell 3.0 的模块)。

The #Requires statement prevents a script from running unless the PowerShell version, modules, snap-ins, and module and snap-in version prerequisites are met. #Requires 语句会阻止脚本运行,除非满足 PowerShell 版本、模块、管理单元以及模块和管理单元版本的先决条件。

So At the top of the script, simply add #Requires -Module <ModuleName>所以在脚本的顶部,只需添加#Requires -Module <ModuleName>

If the required modules are not in the current session, PowerShell imports them.如果所需模块不在当前 session 中,则 PowerShell 导入它们。

If the modules cannot be imported, PowerShell throws a terminating error.如果无法导入模块,PowerShell 会抛出终止错误。

IMHO, there is difference between checking if a module is:恕我直言,检查模块是否为:

1) installed, or 2) imported: 1) 已安装,或 2) 导入:

To check if installed:检查是否安装:

Option 1: Using Get-Module with -ListAvailable parameter:选项 1:使用带有-ListAvailable参数Get-Module

 If(Get-Module -ListAvailable -Name "<ModuleName>"){'Module is installed'} Else{'Module is NOT installed'}

Option 2: Using $error object:选项 2:使用$error object:

 $error.clear() Import-Module "<ModuleName>" -ErrorAction SilentlyContinue If($error){Write-Host 'Module is NOT installed'} Else{Write-Host 'Module is installed'}

To check if imported:检查是否导入:

Using Get-Module with -Name parameter (which you can omit as it is default anyway):Get-Module-Name参数一起使用(您可以忽略它,因为它是默认值):

 if ((Get-Module -Name "<ModuleName>")) { Write-Host "Module is already imported (ie its cmdlets are available to be used.)" } else { Write-Warning "Module is NOT imported (must be installed before importing)." }
  • First test if the module is loaded首先测试模块是否加载
  • Then import然后导入

``` ```

 if (Get-Module -ListAvailable -Name <<MODULE_NAME>>) { Write-Verbose -Message "<<MODULE_NAME>> Module does not exist." -Verbose } if ( (Get-Module -Name <<MODULE_NAME>>)) { Get-Module -ListAvailable <<MODULE_NAME>> | Import-Module | Out-Null }

``` ```

Coming from Linux background.来自 Linux 背景。 I would prefer using something similar to grep, therefore I use Select-String.我更喜欢使用类似于 grep 的东西,因此我使用 Select-String。 So even if someone is not sure of the complete module name.因此,即使有人不确定完整的模块名称。 They can provide the initials and determine whether the module exists or not.他们可以提供首字母并确定模块是否存在。

Get-Module -ListAvailable -All | Select-String Module_Name Get-Module -ListAvailable -All | Select-String Module_Name (can be a part of the module name) Get-Module -ListAvailable -All | Select-String Module_Name (可以是模块名称的一部分)

Here is the code to check if AZ module is installed or not:这是检查是否安装了 AZ 模块的代码:

 $checkModule = "AZ" $Installedmodules = Get-InstalledModule if ($Installedmodules.name -contains $checkModule) { "$checkModule is installed " } else { "$checkModule is not installed" }

The absolute simplest one-liner without if-else block using Az module as an example:Az模块为例,没有 if-else 块的绝对最简单的单行代码:

 Get-InstalledModule Az

This is what you want if you're working in the shell console and just want to check if a PowerShell module is installed or not.如果您在 shell 控制台中工作并且只想检查是否安装了 PowerShell 模块,这就是您想要的。

Because this came up in so many answers, I am posting this as a separate answer instead of several comments.因为这出现在很多答案中,所以我将其作为单独的答案而不是几条评论发布。 Please consider this as a public service announcement.请将此视为公共服务公告。

The answers based on using Get-InstalledModule are extremely dangerous if you really want to know if a module is available on a PowerShell installation.如果您真的想知道某个模块在PowerShell安装中是否可用,则基于使用Get-InstalledModule的答案非常危险。 Get-InstalledModule will report the presence of a module only if it has been installed from PowerShellGet.仅当从 PowerShellGet 安装模块时, Get-InstalledModule才会报告模块的存在。

Evidence from PowerShell:来自 PowerShell 的证据:

 PS C:\Users\chris> Get-InstalledModule | Select-Object -Property Name, Version Name Version ---- ------- Choco 1.0.0 NTFSSecurity 4.2.6 PS C:\Users\chris> Get-Module | Select-Object -Property Name, Version Name Version ---- ------- chocolateyProfile 0.0 CimCmdlets 7.0.0.0 Microsoft.PowerShell.Management 7.0.0.0 Microsoft.PowerShell.Security 7.0.0.0 Microsoft.PowerShell.Utility 7.0.0.0 Microsoft.WSMan.Management 7.0.0.0 PackageManagement 1.4.7 PowerShellGet 2.2.5 PSReadLine 2.1.0

There are no parameters for Get-InstalledModule that you can use to tell it to "show the other modules that you just aren't displaying right now." Get-InstalledModule没有参数可用于告诉它“显示您现在不显示的其他模块”。 It can't display any others.它不能显示任何其他内容。 As you can see above, it only shows 2 modules installed when I have 9 imported into my session正如您在上面看到的,当我将 9 个模块导入 session 时,它只显示安装了 2 个模块

Since this is an answer, I will add endorsements here:由于这是一个答案,我将在此处添加背书:

  • @Kiemen Schindler's answer ( https://stackoverflow.com/a/28740512/1236579 ) is a good one. @Kiemen Schindler 的回答( https://stackoverflow.com/a/28740512/1236579 )是一个很好的回答。 As others have noted, the -ListAvailable parameter does not actually list all available modules.正如其他人所指出的, -ListAvailable参数实际上并未列出所有可用模块。 But practically, most of us probably don't care too much because if ListAvailable doesn't return a module, then we can't use it unless we already know how to load it using a non-standard/manual method, in which case we are unlikely to be searching for it to begin with.但实际上,我们大多数人可能不太在意,因为如果ListAvailable不返回模块,那么除非我们已经知道如何使用非标准/手动方法加载它,否则我们将无法使用它,在这种情况下我们不太可能一开始就搜索它。
  • If you need something beyond that, I think that both @TJ Galama and @Rod have supplied nice scripts for you to start with.如果您需要除此之外的东西,我认为@TJ Galama 和@Rod 都为您提供了不错的脚本。

So like I said, my best answer is to read other people's answers, but please do not walk away from this page thinking that Get-InstalledModule is a reliable way to determine if a module is installed (locally importable by name) on your PowerShell installation).所以就像我说的,我最好的答案是阅读其他人的答案,但请不要离开这个页面,认为Get-InstalledModule是一种可靠的方法来确定您的 PowerShell 安装中是否安装了模块(按名称本地导入) )。 That is just not what it's for.那不是它的用途。 It will supply you the names of modules installed by PowerShellGet , but it will not supply you with the names of any other locally installed modules.它将为您提供由PowerShellGet安装的模块的名称,但不会为您提供任何其他本地安装的模块的名称。

Test-Path "C:\Program Files\WindowsPowerShell\Modules\ModuleName"

If you know the module name and common install paths, you could use:如果您知道模块名称和常用安装路径,则可以使用:

$a = New-Object -TypeName 'System.Collections.ArrayList'

$paths = "$env:userprofile\*\ModuleName","C:\Program 
Files\WindowsPowerShell\Modules\ModuleName"

foreach ($path in $paths)
{
   $a.add($(Test-path $path))
}

If ($a -contains $true)
{
    Write-Host "ModuleName is installed" -ForegroundColor Green
}
else
{
    Write-Host "ModuleName is not installed" -foregroundcolor Red
}

Don't get me wrong, Get-module -listAvailable |不要误会我的意思,Get-module -listAvailable | where {$_.name -eq "ModuleName"} works very well, it just takes too long for me if you have a lot of modules installed. {$_.name -eq "ModuleName"} 工作得很好,如果你安装了很多模块,这对我来说太长了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM