Comparar módulos de PowerShell
Una de las características atractivas de PowerShell v5 es PowerShellGet. Este módulo incluye comandos que facilitan descubrir e instalar módulos de PowerShell desde Internet o incluso desde su red. Los módulos se almacenan en repositorios en línea. Microsoft mantiene uno llamado PSGallery. Normalmente utilizará comandos de PowerShell para buscar e instalar módulos. Como nota al margen rápida, si bien Microsoft parece realizar cierto grado de revisión utilizando PowerShell Script Analyzer, no hay garantía de que los módulos que encuentre en línea funcionen en su entorno. Es por eso que el repositorio no es de confianza de forma predeterminada. Aún puede descargar e instalar, pero acepta los riesgos potenciales. Pero ese no es el punto aquí. Es bastante fácil descargar nuevos módulos, que incluyen recursos DSC. Sin embargo, se pueden publicar nuevas versiones en el repositorio en línea. Hasta donde yo sé, no existe ningún mecanismo de notificación. Por lo tanto, es posible que tengas que comprobar periódicamente si hay nuevas versiones disponibles. Lo que significa que escribí una herramienta.
Puede verificar fácilmente un módulo comparando su versión local con el repositorio.
Aquí puede ver que instalé el módulo PoshWSUS y todavía está en la versión 2.2.1. Pero la versión en línea ahora es 2.3.1.2. Por cierto, Find-Module utilizará de forma predeterminada la galería de Microsoft para que no tenga que especificar el repositorio. Puedo usar Update-Module para instalar la nueva versión. Pero mi objetivo es poder identificar fácilmente los módulos que se pueden actualizar. Entonces escribí una función de PowerShell llamada Compare-Module.
Compare-Module.ps1:
#requires -version 5.0
# https://gist.github.com/jdhitsolutions/7217ed9293f18e8d454e3f88ecb38b67
Function Compare-Module {
<#
.Synopsis
Compare module versions.
.Description
Use this command to compare module versions between what is installed against an online repository like the PSGallery. Results will be automatically sorted by module name.
.Parameter Name
The name of a module to check. Wildcards are permitted.
.Notes
Version: 1.2
Learn more about PowerShell:
http://jdhitsolutions.com/blog/essential-powershell-resources/
.Example
PS C:\> Compare-Module | Where-objject {$_.UpdateNeeded}
Name : Azure
OnlineVersion : 1.5.1
InstalledVersion : 1.0.4
PublishedDate : 6/27/2016 6:50:11 PM
UpdateNeeded : True
Name : Azure.Storage
OnlineVersion : 1.1.4
InstalledVersion : 1.0.4
PublishedDate : 6/27/2016 6:48:07 PM
UpdateNeeded : True
Name : AzureRM
OnlineVersion : 1.5.1
InstalledVersion : 1.2.0
PublishedDate : 6/27/2016 7:08:50 PM
UpdateNeeded : True
...
.Example
PS C:\> Compare-Module | Where UpdateNeeded | Out-Gridview -title "Select modules to update" -outputMode multiple | Foreach { Update-Module $_.name }
Compare modules and send results to Out-Gridview. Use Out-Gridview as an object picker to decide what modules to update.
.Example
PS C:\> compare-module -name xWindows* | format-table
Name OnlineVersion InstalledVersion PublishedDate UpdateNeeded
---- ------------- ---------------- ------------- ------------
xWindowsEventForwarding 1.0.0.0 1.0.0.0 6/17/2015 9:46:32 PM False
xWindowsRestore 1.0.0 1.0.0 12/18/2014 4:22:42 AM False
xWindowsUpdate 2.5.0.0 2.3.0.0 5/18/2016 11:02:47 PM True
Compare all modules that start with xWindows and display results in a table format.
.Example
PS C:\> get-dscresource cAD* | Select moduleName -Unique | compare-module
Name : cActiveDirectory
OnlineVersion : 1.1.1
InstalledVersion : 1.0.1
PublishedDate : 6/23/2015 9:24:55 PM
UpdateNeeded : True
Get all DSC Resources that start with cAD and select the corresponding module name. Since the module name will be listed for every resource, get a unique list and pipe that to Compare-Module.
.Link
Find-Module
.Link
Get-Module
.Link
Update-Module
.Inputs
[string]
.Outputs
[PSCustomObject]
#>
[cmdletbinding()]
[alias("cmo")]
Param
(
[Parameter(
Position = 0,
ValueFromPipelineByPropertyName
)]
[ValidateNotNullorEmpty()]
[Alias("modulename")]
[string]$Name,
[ValidateNotNullorEmpty()]
[string]$Gallery = "PSGallery"
)
Begin {
Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)"
$progParam = @{
Activity = $MyInvocation.MyCommand
Status = "Getting installed modules"
CurrentOperation = "Get-Module -ListAvailable"
PercentComplete = 25
}
Write-Progress @progParam
} #begin
Process {
$gmoParams = @{
ListAvailable = $True
}
if ($Name) {
$gmoParams.Add("Name", $Name)
}
$installed = Get-Module @gmoParams
if ($installed) {
$progParam.Status = "Getting online modules"
$progParam.CurrentOperation = "Find-Module -repository $Gallery"
$progParam.PercentComplete = 50
Write-Progress @progParam
$fmoParams = @{
Repository = $Gallery
ErrorAction = "Stop"
}
if ($Name) {
$fmoParams.Add("Name", $Name)
}
Try {
$online = Find-Module @fmoParams
}
Catch {
Write-Warning "Failed to find online module(s). $($_.Exception.message)"
}
$progParam.status = "Comparing $($installed.count) installed modules to $($online.count) online modules."
$progParam.percentComplete = 80
Write-Progress @progParam
$data = $online | Where-Object {$installed.name -contains $_.name} |
Select-Object -property Name,
@{Name = "OnlineVersion"; Expression = {$_.Version}},
@{Name = "InstalledVersion"; Expression = {
#save the name from the incoming online object
$name = $_.Name
$installed.Where( {$_.name -eq $name}).Version -join ","}
},
PublishedDate,
@{Name = "UpdateNeeded"; Expression = {
$name = $_.Name
#there could me multiple versions installed
$installedVersions = $installed.Where( {$_.name -eq $name}).Version | Sort-Object
foreach ($item in $installedVersions) {
If ([version]$_.Version -gt [version]$item) {
$result = $True
}
else {
$result = $False
}
}
$result
}
} | Sort-Object -Property Name
$progParam.PercentComplete = 100
$progParam.Completed = $True
Write-Progress @progparam
#write the results to the pipeline
$data
}
else {
Write-Warning "No local module or modules found"
}
} #Progress
End {
Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)"
} #end
} #close function
La función obtiene todos los módulos instalados actualmente, obtiene una lista de todos los módulos en la galería y luego compara la información de la versión. La función crea un objeto personalizado que representa cada módulo instalado.
Puede especificar un nombre de módulo con comodines:
O puedo buscar en todos los módulos.
Incluso podría usar esta función como medio para actualizar selectivamente:
Compare-Module | Out-Gridview -title "Select modules to update" -outputMode multiple |
Foreach {
Update-Module $_.name -force
}
O quizás quieras utilizar Save-Module en su lugar. La decisión es tuya.
Espero que le des este giro y me dejes saber lo que piensas. Como siempre, publique cualquier problema o solicitud en la sección de comentarios de la página de Gist.
¡Disfrutar!