Skip to content

Instantly share code, notes, and snippets.

@guitarrapc
Last active June 15, 2016 22:40
Show Gist options
  • Save guitarrapc/7dc6c33854028345ee6d to your computer and use it in GitHub Desktop.
Save guitarrapc/7dc6c33854028345ee6d to your computer and use it in GitHub Desktop.
PowerShell WebPlatformInstaller Module (rough)
#region Initializer
function New-WebPlatformInstaller
{
[OutputType([Void])]
[CmdletBinding()]
param()
try
{
[reflection.assembly]::LoadWithPartialName("Microsoft.Web.PlatformInstaller") > $null
}
catch
{
}
$script:WebPI = @{}
}
New-WebPlatformInstaller
#endregion
#region Constructor
function New-WebPlatformInstallerProductManager
{
[OutputType([Void])]
[CmdletBinding()]
param()
if ($null -eq $WebPI){ New-WebPlatformInstaller }
$productManager = New-Object Microsoft.Web.PlatformInstaller.ProductManager
$productManager.Load()
$WebPI.productManager = $productManager
Write-Verbose "Remove Blank Keywords Products / IIS Components (Windows Feature)"
$WebPI.productManagerProducts = $WebPI.productManager.Products | where Keywords | where Title -notlike 'IIS:*'
$WebPI.productManagerProductsIISComponent = $WebPI.productManager.Products | where Keywords | where Title -like 'IIS:*'
}
function New-WebPlatformInstallerInstallManager
{
[OutputType([Void])]
[CmdletBinding()]
param()
if ($null -eq $WebPI){ New-WebPlatformInstaller }
$WebPI.installManager = New-Object Microsoft.Web.PlatformInstaller.InstallManager
}
#endregion
#region Product
function Get-WebPlatformInstallerProduct
{
<#
.Synopsis
Get WebPlatformInstaller Packages.
.DESCRIPTION
This function will return Product information for WebPlatform Installer.
You can select 2 mode.
1. -ProductId will give you availability to filter package.
2. Omit -ProductId will return all packages.
Make sure No keyword items and IIS Components (Windows Feature) will never checked.
.EXAMPLE
Get-WebPlatformInstallerProduct -ProductId WDeploy
# Returns WDeploy Product information
.EXAMPLE
Get-WebPlatformInstallerProduct
# Returns All Product information
#>
[OutputType([Microsoft.Web.PlatformInstaller.Product[]])]
[CmdletBinding(DefaultParameterSetName = "Any")]
param
(
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1, ValueFromPipeline = 1)]
[string[]]$ProductId,
[switch]$Force
)
begin
{
if (($null -eq $WebPI.productManagerProducts) -or $Force){ New-WebPlatformInstallerProductManager }
# Initialize
if ($PSBoundParameters.ContainsKey('ProductId'))
{
$result = $null
$private:productManagerDic = New-Object 'System.Collections.Generic.Dictionary[[string], [Microsoft.Web.PlatformInstaller.Product]]' ([StringComparer]::OrdinalIgnoreCase)
$WebPI.productManagerProducts | %{$productManagerDic.Add($_.ProductId, $_)}
}
}
process
{
if (-not $PSBoundParameters.ContainsKey('ProductId'))
{
Write-Verbose ("Searching All Products.")
return $WebPI.productManagerProducts | sort ProductId
}
foreach ($id in $ProductId)
{
# Search product by ProductId
Write-Verbose ("Searching ProductId : '{0}'" -f $id)
$isSuccess = $productManagerDic.TryGetValue($id, [ref]$result)
if ($isSuccess){ $result; continue; }
if ($id -in $WebPI.productManagerProductsIISComponent.ProductId){ [Console]::WriteLine("ProductId '{0}' will skip as it detected IIS Component." -f $id); continue; }
throw New-Object System.InvalidOperationException ("WebPlatform Installation could not found package '{0}' as valid ProductId. Please select from '{1}'" -f $id, (($WebPI.productManagerProducts.ProductId | sort) -join "', '"))
}
}
}
function Test-WebPlatformInstallerProductIsInstalled
{
<#
.Synopsis
Test target Package is already installed or not.
.DESCRIPTION
This function will check desired Package is already installed or not yet by Boolean.
$true : Means already installed.
$false : Means not yet installed.
Pass ProductId which you want to check.
.EXAMPLE
Test-WebPlatformInstallerProductIsInstalled -ProductId WDeploy
# Check WDeploy is installed or not.
#>
[OutputType([bool])]
[CmdletBinding(DefaultParameterSetName = "Any")]
param
(
[parameter(Mandatory = 1, Position = 0, ValueFromPipelineByPropertyName = 1, ValueFromPipeline = 1)]
[string[]]$ProductId
)
# Not use Cached Value
$result = Get-WebPlatformInstallerProduct -ProductId $ProductId | % {$_.IsInstalled($false)}
Write-Verbose $result
return $result
}
#endregion
#region Install
function Install-WebPlatformInstallerProgram
{
<#
.Synopsis
Install target Package.
.DESCRIPTION
This function will install desired Package.
If Package is already installed, then skip it.
.EXAMPLE
Install-WebPlatformInstallerProgram -ProductId WDeploy
# Install WDeploy
#>
[OutputType([void])]
[CmdletBinding()]
param
(
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1, ValueFromPipeline = 1)]
[string[]]$ProductId,
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1)]
[ValidateSet('en', 'fr', 'es', 'de', 'it', 'ja', 'ko', 'ru', 'zh-cn', 'zh-tw', 'cs', 'pl', 'tr', 'pt-br', 'he', 'zh-hk', 'pt-pt')]
[string]$LanguageCode = 'en'
)
process
{
Write-Verbose "Checking Product is already installed."
$ProductId `
| % {
if(Test-WebPlatformInstallerProductIsInstalled -ProductId $_){ [Console]::WriteLine("Package '{0}' already installed. Skip installation." -f $_); return; }
$productIdList.Add($_)
}
}
end
{
if (($productIdList | measure).count -eq 0){ return; }
try
{
# Prerequisites
Write-Verbose "Get Product"
[Microsoft.Web.PlatformInstaller.Product[]]$product = Get-WebPlatformInstallerProduct -ProductId $productIdList
if ($null -eq $product){ throw New-Object System.NullReferenceException }
# Install
# InstallByNET -LanguageCode $LanguageCode -product $product
InstallByWebPICmd -Name $ProductId
}
catch
{
throw $_
}
finally
{
if ($null -ne $WebPI.installManager){ $WebPI.installManager.Dispose() }
}
}
begin
{
# Initialize
if ($null -eq $WebPI.productManager){ New-WebPlatformInstallerProductManager }
$productIdList = New-Object 'System.Collections.Generic.List[string]'
function ShowInstallerContextStatus
{
if ($null -ne $WebPI.installManager.InstallerContexts){ $WebPI.installManager.InstallerContexts | Out-String -Stream | Write-Verbose }
}
function WatchInstallationStatus
{
[OutputType([bool])]
[CmdletBinding()]
param
(
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1)]
[string]$ProductId,
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1)]
[Microsoft.Web.PlatformInstaller.InstallationState]$PreStatus,
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1)]
[Microsoft.Web.PlatformInstaller.InstallationState]$PostStatus
)
# Skip
if ($postStatus -eq $preStatus)
{
Write-Verbose "Installation not begin"
return $false
}
# Monitor
ShowInstallerContextStatus
while($postStatus -ne [Microsoft.Web.PlatformInstaller.InstallationState]::InstallCompleted)
{
Start-Sleep -Milliseconds 100
$postStatus = $WebPI.installManager.InstallerContexts.InstallationState
}
ShowInstallerContextStatus
$logfiles = $WebPI.installManager.InstallerContexts.Installer.LogFiles
$latestLog = ($logfiles | select -Last 1)
[Console]::WriteLine(("'{0}' Installation completed. Check Log file at '{1}'" -f ($ProductId -join "', '"), $latestLog))
Write-Verbose ("Latest Log file is '{0}'." -f (Get-Content -Path $latestLog -Encoding UTF8 -Raw))
return $true
}
function InstallByNET
{
[OutputType([void])]
[CmdletBinding()]
param
(
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1)]
[string]$LanguageCode,
[parameter(Mandatory = 0, Position = 0, ValueFromPipelineByPropertyName = 1)]
[Microsoft.Web.PlatformInstaller.Product[]]$product
)
# Initialize
New-WebPlatformInstallerInstallManager
$installer = New-Object 'System.Collections.Generic.List[Microsoft.Web.PlatformInstaller.Installer]'
# Get Language
[Microsoft.Web.PlatformInstaller.Language]$language = $WebPI.productManager.GetLanguage($LanguageCode)
$product `
| % {
Write-Verbose "Get Installer"
$x = $_.GetInstaller($language)
if ($null -eq $x.InstallerFile){ [Console]::WriteLine("Package '{0}' detected as no Installer to install. Skip Installation." -f $_.ProductId); return; }
$installer.Add($x)
$WebPI.InstallManager.Load($installer)
Write-Verbose "Donwload Installer"
ShowInstallerContextStatus
$failureReason = $null
$success = $WebPI.InstallManager.InstallerContexts | %{ $WebPI.installManager.DownloadInstallerFile($_, [ref]$failureReason) }
if ((-not $success) -and $failureReason){ throw New-Object System.InvalidOperationException ("Donwloading '{0}' Failed Exception!! Reason : {1}" -f ($ProductId -join "' ,'"), $failureReason ) }
Write-Verbose "Show Donwloaded Installer Status"
ShowInstallerContextStatus
# Get Status
[Microsoft.Web.PlatformInstaller.InstallationState]$preStatus = $WebPI.installManager.InstallerContexts.InstallationState
Write-Verbose "Start Installation with StartInstallation()"
$WebPI.installManager.StartInstallation()
if (WatchInstallationStatus -ProductId $_.ProductId -PreStatus $preStatus -PostStatus $WebPI.installManager.InstallerContexts.InstallationState){ return; }
Write-Verbose "Start Installation with StartApplicationInstallation()"
$WebPI.installManager.StartApplicationInstallation()
if (WatchInstallationStatus -ProductId $_.ProductId -PreStatus $preStatus -PostStatus $WebPI.installManager.InstallerContexts.InstallationState){ return; }
Write-Verbose "Start Installation with StartSynchronousInstallation()"
$installResult = $WebPI.installManager.StartSynchronousInstallation()
if (WatchInstallationStatus -ProductId $_.ProductId -PreStatus $preStatus -PostStatus $WebPI.installManager.InstallerContexts.InstallationState){ return; }
}
}
function InstallByWebPICmd
{
[OutputType([Void])]
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[System.String[]]$Name
)
end
{
foreach ($x in $Name)
{
Write-Verbose ("Installing package '{0}'" -f $x)
[string]$arguments = @(
"/Install",
"/Products:$x",
"/AcceptEula",
"/SuppressReboot"
)
Invoke-WebPICmd -Arguments $arguments
}
}
begin
{
Write-Verbose "Start Installation with WebPICmd"
function Invoke-WebPICmd
{
[OutputType([System.String])]
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[System.String]$Arguments
)
$fileName = "$env:ProgramFiles\Microsoft\Web Platform Installer\WebpiCmd-x64.exe"
if (!(Test-Path -Path $fileName)){ throw New-Object System.InvalidOperationException ("Web Platform Installer not installed exception!") }
try
{
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = $fileName
$psi.Arguments = $Arguments
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
$process.Start() > $null
$output = $process.StandardOutput.ReadToEnd()
$process.StandardOutput.ReadLine()
$process.WaitForExit()
return $output
}
catch
{
$outputError = $process.StandardError.ReadToEnd()
throw $_ + $outputError
}
finally
{
if ($null -ne $psi){ $psi = $null}
if ($null -ne $process){ $process.Dispose() }
}
}
}
}
}
}
#endregion
@guitarrapc
Copy link
Author

Usage

Test-WebPlatformInstallerProductIsInstalled

Test-WebPlatformInstallerProductIsInstalled [-ProductId] <String[]> [<CommonParameters>]

Get-WebPlatformInstallerProduct

Get-WebPlatformInstallerProduct [[-ProductId] <String[]>] [-Force] [<CommonParameters>]

Install-WebPlatformInstallerProgram

Install-WebPlatformInstallerProgram [[-ProductId] <String[]>] [[-LanguageCode] <String>] [<CommonParameters>]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment