返回消息,而不是powershell中msi的退出代码
有没有办法让msiexec返回错误/成功消息,而不是默认的退出代码?例如:返回消息,而不是powershell中msi的退出代码,powershell,error-handling,exit-code,windows-installer,Powershell,Error Handling,Exit Code,Windows Installer,有没有办法让msiexec返回错误/成功消息,而不是默认的退出代码?例如: msiexec /i "D:/path/installer.msi" 可能返回1603,引用说明了这一点 安装过程中发生致命错误 我希望返回消息,甚至返回错误代码error\u INSTALL\u FAILURE,而不是退出代码1603不,msi不能用消息本身替换错误代码。 正如Ansgar Wiechers所说,msi的目的是在您执行它的每台机器上,在同一个文件夹(例如C:\Windows\Temp)上创建一个日志文
msiexec /i "D:/path/installer.msi"
可能返回1603
,引用说明了这一点
安装过程中发生致命错误
我希望返回消息,甚至返回错误代码
error\u INSTALL\u FAILURE
,而不是退出代码1603
不,msi不能用消息本身替换错误代码。
正如Ansgar Wiechers所说,msi的目的是在您执行它的每台机器上,在同一个文件夹(例如C:\Windows\Temp)上创建一个日志文件。使用/l参数,您可以修改该文件中的输出。如果您需要一个全面的日志,您应该从
voicewarmupx
开始。MSI安装并不总是返回1603。1603的主要原因是自定义操作失败,Windows Installer不知道自定义操作代码失败的原因,并且该自定义操作代码不够健壮,无法处理其自身的错误并在导致安装失败(可能会回滚)之前提供消息。详细日志应该告诉您失败的原因
因此,如果是你的MSI,你有机会纠正它,否则你就要受MSI开发质量的摆布
此外,您的问题还包含一个矛盾:您说希望返回错误代码error\u INSTALL\u FAILURE而不是退出代码,但1603退出代码是error\u INSTALL\u FAILURE。注意:不确定投入到这个答案中的精力是否有实际用途,但是,演示各种高级PowerShell技术可能很有意思:使用自动$matches
变量进行高级正则表达式匹配,通过调用WebRequest
抓取网页,以及通过添加类型
调用Windows API
在下面找到函数friendlyMsiExec
,其中
- 刮取MSDN页面以获取已定义MSI错误代码(退出代码)的官方表格
- 如果失败-刮取不是最可靠的技术(页面结构和URL发生变化)-该函数将发出警告并使用硬编码表
- 同步调用
,在已删除/内置表中查找退出代码,并输出与退出代码对应的错误消息msiexec
> friendlyMsiExec /i "D:/path/installer.msi" # assume the exit code is 1603
A fatal error occurred during installation. (1603)
注:
- 函数返回后,退出代码将作为
可用$LASTEXITCODE
- 抓取不仅不是最健壮的,而且页面下载和解析也需要几秒钟,尽管在MSI安装的环境中,这可能不会有多大影响
- 退出代码也可能是常规的Windows API错误代码(“Winerror.h中的任何错误”),因此,作为一种回退,可以参考
Windows API函数,这得益于的自适应FormatMessage
函数友好型msiexec{
#尝试在MSDN页面上搜索错误代码(退出代码)的完整列表。
#注意:这不是最健壮的方法,因为网页不是为
#编程数据提取,页面格式可能会随时间而改变。
$htErrors=@{}
#表位于属性为“summary=“Table”的元素中。
$tbl=(调用WebRequest'https://msdn.microsoft.com/en-us/library/windows/desktop/aa376931(v=vs.85).aspx').ParsedHtml.getElementsByTagName('table')|?{$\u.getAttribute('summary')-eq'table'}
#使用正则表达式分析文本表示(.InnerText)。
$tbl.InnerText-split'\r?\n'|%{if($.-match)^(ERROR.+?)(\d+)(.+)$){$htErrors.Add([int]$matches[2],@($matches[1],$matches[3])}
如果($htErrors.Count-eq 0){#刮取失败,则使用硬编码表(当前截至2016年11月2日)。
写入警告“在MSDN页上清除错误代码失败,返回到硬编码表。”
$htErrors=@{
0='ERROR\u SUCCESS','操作已成功完成。'
13='错误\无效\数据','数据无效。'
87='ERROR\u INVALID\u PARAMETER','s其中一个参数无效。'
120='ERROR_CALL_NOT_IMPLEMENTED','当自定义操作尝试调用无法从自定义操作调用的函数时,将返回此值。该函数返回ERROR_CALL_NOT_IMPLEMENTED值。从Windows Installer 3.0版开始提供。'
1259='ERROR_APPHELP_BLOCK','如果Windows Installer确定某个产品可能与当前操作系统不兼容,它将显示一个对话框,通知用户并询问是否仍要尝试安装。如果用户选择不尝试安装,将返回此错误代码。'
1601='ERROR\u INSTALL\u SERVICE\u FAILURE','Windows Installer服务无法访问。请与技术支持人员联系以验证Windows Installer服务是否已正确注册。'
1602='ERROR\u INSTALL\u USEREXIT','用户取消安装'
1603='ERROR\u INSTALL\u FAILURE','安装过程中发生致命错误。'
1604='ERROR\u INSTALL\u SUSPEND','INSTALL suspended,complete'
1605='错误\未知\产品','此操作仅对当前安装的产品有效。'
1606='错误\未知\功能','功能标识符未注册。'
1607='错误\未知\组件','组件标识符未注册。'
1608='ERROR\u UNKNOWN\u PROPERTY','This is a UNKNOWN PROPERTY'
1609='错误\无效\句柄\状态','句柄处于无效状态。'
1610='ERROR\u BAD\u CONFIGURATION','此产品的配置数据已损坏。请与技术支持人员联系。'
1611='ERROR\u INDEX\u缺席','component限定符不存在。'
1612='ERROR\u INSTALL\u SOURCE\u缺席','thi的安装源
function friendlyMsiExec {
# Try to scrape the MSDN page for the complete list of error codes (exit codes).
# Note: This is not the most robust approach as web pages aren't designed for
# programmatic data extraction, and the format of the page may change over time.
$htErrors = @{}
# Table is in a <table> element with attritubte 'summary="table"'.
$tbl = (Invoke-WebRequest 'https://msdn.microsoft.com/en-us/library/windows/desktop/aa376931(v=vs.85).aspx').ParsedHtml.getElementsByTagName('table') | ? { $_.getAttribute('summary') -eq 'table' }
# Parse the text representation (.InnerText) using regular expressions.
$tbl.InnerText -split '\r?\n' | % { if ($_ -match "^(ERROR_.+?)(\d+)(.+)$") { $htErrors.Add([int] $matches[2], @( $matches[1], $matches[3] )) } }
if ($htErrors.Count -eq 0) { # Scraping failed, use hard-coded table (current as of 2 Nov 2016).
Write-Warning "Scraping the MSDN page for error codes failed, falling back to hard-coded table."
$htErrors = @{
0 = 'ERROR_SUCCESS', 'The action completed successfully.'
13 = 'ERROR_INVALID_DATA', 'The data is invalid.'
87 = 'ERROR_INVALID_PARAMETER', 'One of the parameters was invalid.'
120 = 'ERROR_CALL_NOT_IMPLEMENTED', 'This value is returned when a custom action attempts to call a function that cannot be called from custom actions. The function returns the value ERROR_CALL_NOT_IMPLEMENTED. Available beginning with Windows Installer version 3.0.'
1259 = 'ERROR_APPHELP_BLOCK', 'If Windows Installer determines a product may be incompatible with the current operating system, it displays a dialog box informing the user and asking whether to try to install anyway. This error code is returned if the user chooses not to try the installation.'
1601 = 'ERROR_INSTALL_SERVICE_FAILURE', 'The Windows Installer service could not be accessed. Contact your support personnel to verify that the Windows Installer service is properly registered.'
1602 = 'ERROR_INSTALL_USEREXIT', 'The user cancels installation.'
1603 = 'ERROR_INSTALL_FAILURE', 'A fatal error occurred during installation.'
1604 = 'ERROR_INSTALL_SUSPEND', 'Installation suspended, incomplete.'
1605 = 'ERROR_UNKNOWN_PRODUCT', 'This action is only valid for products that are currently installed.'
1606 = 'ERROR_UNKNOWN_FEATURE', 'The feature identifier is not registered.'
1607 = 'ERROR_UNKNOWN_COMPONENT', 'The component identifier is not registered.'
1608 = 'ERROR_UNKNOWN_PROPERTY', 'This is an unknown property.'
1609 = 'ERROR_INVALID_HANDLE_STATE', 'The handle is in an invalid state.'
1610 = 'ERROR_BAD_CONFIGURATION', 'The configuration data for this product is corrupt. Contact your support personnel.'
1611 = 'ERROR_INDEX_ABSENT', 'The component qualifier not present.'
1612 = 'ERROR_INSTALL_SOURCE_ABSENT', 'The installation source for this product is not available. Verify that the source exists and that you can access it.'
1613 = 'ERROR_INSTALL_PACKAGE_VERSION', 'This installation package cannot be installed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.'
1614 = 'ERROR_PRODUCT_UNINSTALLED', 'The product is uninstalled.'
1615 = 'ERROR_BAD_QUERY_SYNTAX', 'The SQL query syntax is invalid or unsupported.'
1616 = 'ERROR_INVALID_FIELD', 'The record field does not exist.'
1618 = 'ERROR_INSTALL_ALREADY_RUNNING', 'Another installation is already in progress. Complete that installation before proceeding with this install.'
1619 = 'ERROR_INSTALL_PACKAGE_OPEN_FAILED', 'This installation package could not be opened. Verify that the package exists and is accessible, or contact the application vendor to verify that this is a valid Windows Installer package.'
1620 = 'ERROR_INSTALL_PACKAGE_INVALID', 'This installation package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer package.'
1621 = 'ERROR_INSTALL_UI_FAILURE', 'There was an error starting the Windows Installer service user interface. Contact your support personnel.'
1622 = 'ERROR_INSTALL_LOG_FAILURE', 'There was an error opening installation log file. Verify that the specified log file location exists and is writable.'
1623 = 'ERROR_INSTALL_LANGUAGE_UNSUPPORTED', 'This language of this installation package is not supported by your system.'
1624 = 'ERROR_INSTALL_TRANSFORM_FAILURE', 'There was an error applying transforms. Verify that the specified transform paths are valid.'
1625 = 'ERROR_INSTALL_PACKAGE_REJECTED', 'This installation is forbidden by system policy. Contact your system administrator.'
1626 = 'ERROR_FUNCTION_NOT_CALLED', 'The function could not be executed.'
1627 = 'ERROR_FUNCTION_FAILED', 'The function failed during execution.'
1628 = 'ERROR_INVALID_TABLE', 'An invalid or unknown table was specified.'
1629 = 'ERROR_DATATYPE_MISMATCH', 'The data supplied is the wrong type.'
1630 = 'ERROR_UNSUPPORTED_TYPE', 'Data of this type is not supported.'
1631 = 'ERROR_CREATE_FAILED', 'The Windows Installer service failed to start. Contact your support personnel.'
1632 = 'ERROR_INSTALL_TEMP_UNWRITABLE', 'The Temp folder is either full or inaccessible. Verify that the Temp folder exists and that you can write to it.'
1633 = 'ERROR_INSTALL_PLATFORM_UNSUPPORTED', 'This installation package is not supported on this platform. Contact your application vendor.'
1634 = 'ERROR_INSTALL_NOTUSED', 'Component is not used on this machine.'
1635 = 'ERROR_PATCH_PACKAGE_OPEN_FAILED', 'This patch package could not be opened. Verify that the patch package exists and is accessible, or contact the application vendor to verify that this is a valid Windows Installer patch package.'
1636 = 'ERROR_PATCH_PACKAGE_INVALID', 'This patch package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer patch package.'
1637 = 'ERROR_PATCH_PACKAGE_UNSUPPORTED', 'This patch package cannot be processed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.'
1638 = 'ERROR_PRODUCT_VERSION', 'Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs in Control Panel.'
1639 = 'ERROR_INVALID_COMMAND_LINE', 'Invalid command line argument. Consult the Windows Installer SDK for detailed command-line help.'
1640 = 'ERROR_INSTALL_REMOTE_DISALLOWED', 'The current user is not permitted to perform installations from a client session of a server running the Terminal Server role service.'
1641 = 'ERROR_SUCCESS_REBOOT_INITIATED', 'The installer has initiated a restart. This message is indicative of a success.'
1642 = 'ERROR_PATCH_TARGET_NOT_FOUND', 'The installer cannot install the upgrade patch because the program being upgraded may be missing or the upgrade patch updates a different version of the program. Verify that the program to be upgraded exists on your computer and that you have the correct upgrade patch.'
1643 = 'ERROR_PATCH_PACKAGE_REJECTED', 'The patch package is not permitted by system policy.'
1644 = 'ERROR_INSTALL_TRANSFORM_REJECTED', 'One or more customizations are not permitted by system policy.'
1645 = 'ERROR_INSTALL_REMOTE_PROHIBITED', 'Windows Installer does not permit installation from a Remote Desktop Connection.'
1646 = 'ERROR_PATCH_REMOVAL_UNSUPPORTED', 'The patch package is not a removable patch package. Available beginning with Windows Installer version 3.0.'
1647 = 'ERROR_UNKNOWN_PATCH', 'The patch is not applied to this product. Available beginning with Windows Installer version 3.0.'
1648 = 'ERROR_PATCH_NO_SEQUENCE', 'No valid sequence could be found for the set of patches. Available beginning with Windows Installer version 3.0.'
1649 = 'ERROR_PATCH_REMOVAL_DISALLOWED', 'Patch removal was disallowed by policy. Available beginning with Windows Installer version 3.0.'
1650 = 'ERROR_INVALID_PATCH_XML', 'The XML patch data is invalid. Available beginning with Windows Installer version 3.0.'
1651 = 'ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT', 'Administrative user failed to apply patch for a per-user managed or a per-machine application that is in advertise state. Available beginning with Windows Installer version 3.0.'
1652 = 'ERROR_INSTALL_SERVICE_SAFEBOOT', 'Windows Installer is not accessible when the computer is in Safe Mode. Exit Safe Mode and try again or try using System Restore to return your computer to a previous state. Available beginning with Windows Installer version 4.0.'
1653 = 'ERROR_ROLLBACK_DISABLED', 'Could not perform a multiple-package transaction because rollback has been disabled. Multiple-Package Installations cannot run if rollback is disabled. Available beginning with Windows Installer version 4.5.'
1654 = 'ERROR_INSTALL_REJECTED', 'The app that you are trying to run is not supported on this version of Windows. A Windows Installer package, patch, or transform that has not been signed by Microsoft cannot be installed on an ARM computer.'
3010 = 'ERROR_SUCCESS_REBOOT_REQUIRED', 'A restart is required to complete the install. This message is indicative of a success. This does not include installs where the ForceReboot action is run. '
}
}
# Execute msiexec synchronously.
$psInfo = Start-Process -PassThru -NoNewWindow -Wait msiexec -ArgumentList $Args
# Get the exit code.
$ec = $psInfo.ExitCode
# Look up the exit code returned in the hashtable and extract the error *message*.
if ($htErrors[$ec]) {
# Use subscript [0] to extract the *symbolic name* instead.
$errMsg = $htErrors[$ec][1] # -replace '\r'
} else { # not found in table
# See if it's a Windows (system) error code.
# Helper type for getting Windows (system) error messages by error code.
# Returns $null if no message is found.
# Example:
# [net.same2u.pshelper.WinErrMsg]::Get(2) # -> "The system cannot find the file specified."
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace net.same2u.pshelper {
public static class WinErrMsg {
[DllImport("kernel32.dll")]
static extern int FormatMessage(int dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, System.Text.StringBuilder lpBuffer, int nSize, IntPtr Arguments);
public static string Get(int errCode) {
const int CAPACITY = 512;
const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
StringBuilder sb = new StringBuilder(CAPACITY);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, errCode, 0, sb, sb.Capacity, IntPtr.Zero);
// Remove trailing CRLF
int i = sb.Length;
if (i>0 && sb[i - 1] == 10) i--;
if (i>0 && sb[i - 1] == 13) i--;
sb.Length = i;
return sb.Length > 0 ? sb.ToString() : null;
}
}
}
'@
$errMsg = [net.same2u.pshelper.WinErrMsg]::Get($ec)
# Determine fallback message, if no match was found.
if (-not $errMsg) { $errMsg = "An unknown exit code was reported."}
}
# Set $LASTEXITCODE, so that the caller can inspect the exit code later.
Set-Variable -Scope 1 LASTEXITCODE $ec
# Output the message, suffixed with the exit code.
"$errMsg ($ec)"
}