我有一个配置文件,需要在每个服务器的基础上进行修改,这样一旦服务器安装了我们的软件,客户端安装程序的配置文件就会被设置成与该服务器的特定设置相匹配,然后复制到web上的公用文件夹进行部署。
由于我正在更改配置文件,所以我还必须重新构建*.manifest和*.application文件,据我所知,我唯一真正的选择是使用Win7 SDK中的Mage.exe。为了用修改后的配置文件中的正确哈希来修复*.manifest文件,我运行了以下命令:
mage -new应用-fd ".\Application Files\_1___0“-ToFile .\Application Files\_1___0\.exe.manifest -Name”-Version "1.0.0.0“-CertFile "key.pfx”-password“
然后,为了使用修改后的*.application文件中的正确哈希来修复*.manifest文件,我运行:
Http:////Application -new部署-I t -t ".application“-v 1.0.0.0”-appManifest ".\Application Files\_1___0\.exe.manifest“-pu”-pu文件/_1_0/.-pu“-CertFile”key.pfx -password“”
现在,这一切都成功了,我得到了文件已成功签名的消息。不过,当我试图安装客户端应用程序时,很明显,当我收到消息的错误日志时,有些地方出了问题:
+ Deployment manifest is not semantically valid.
+ Deployment manifest requires <deployment> section.在查看*.application文件时,它在“部署”节点下有一些附加信息,直接来自VS2008的发布特性的同一个文件没有这些信息:
<deployment install="true">
<subscription>
<update>
<expiration maximumAge="0" unit="days" />
</update>
</subscription>
<deploymentProvider codebase="http://<hostaddress>/<path>/Application Files/<appName>_1_0_0_0/<appName>.exe.manifest" />
</deployment>VS2008发布版本只包含:
<deployment install="true" />当我移除附加信息并将部署节点设置为一个自终止节点时,然后重新对文件进行签名,一切都按预期的方式工作。
这是一个已知的问题吗?是否有任何方法可以让Mage在没有部署节点中的额外信息的情况下创建文件,这样它才能正常工作?
编辑:作为一种临时解决方案,我正在将文件加载到一个XmlDocument中,并修改它们以适应,然后重新对文件进行签名。此外,我现在面临的问题是,到目前为止还无法确定如何向部署中添加图标,因此开始菜单项将获得一个图标,而不是泛型图标。
发布于 2010-02-26 16:54:02
这是我的实现。我花了很多时间在这段代码上,我仍然没有找到所有正确的选项,让Mage处理所有生成的.application文件而不进行干预。我要说的是,可能会对这段代码进行很多优化。然而,这仍然可以作为一个跳板来帮助某人。
为了使下面的方法工作,您必须至少从VS中的ClickOnce中部署一次,然后将.application文件从该部署中保存下来。必须删除部署文件夹中的.application和.manifest。
在我将所有应用程序文件移到Config.Instance.ServerSettings.ClientLocation + "<AppName>_<version>"之后
DirectoryInfo filedir = new DirectoryInfo(Config.Instance.ServerSettings.ClientLocation);
if (filedir.Exists)
{
FileInfo[] files = filedir.GetFiles();
// Find the current .application file.
FileInfo appinfo = null;
foreach (FileInfo fi in files)
{
if (fi.Name == "<AppName>.application")
{
appinfo = fi;
break;
}
}
if (appinfo != null)
{
XmlDocument applocinfo = new XmlDocument();
applocinfo.Load(appinfo.FullName);
// Get the location of the files from the .application file.
string codebase = applocinfo["asmv1:assembly"]["dependency"]["dependentAssembly"].Attributes["codebase"].Value.Replace("AppName.exe.manifest", "");
XmlDocument xDoc = new XmlDocument();
xDoc.Load(Path.Combine(Path.Combine(filedir.FullName, codebase), "AppName.exe.config"));
foreach (XmlNode xn in xDoc["configuration"]["appSettings"].ChildNodes)
{
if (xn.Attributes != null && xn.Attributes["key"] != null && xn.Attributes["key"].Value == "Clnt_Host")
{
// Here is where I'm modifying my config file, the whole purpose in this wretched deployment process.
xn.Attributes["value"].Value = Config.Instance.ClientSettings.Host;
break;
}
}
xDoc.Save(Path.Combine(Path.Combine(filedir.FullName, codebase), "<AppName>.exe.config"));
Process p = new Process();
p.StartInfo = new ProcessStartInfo(Path.Combine(filedir.FullName, "Mage.exe"));
p.StartInfo.WorkingDirectory = filedir.FullName;
FileInfo fi = new FileInfo(Path.Combine(Path.Combine(filedir.FullName, codebase.TrimStart('.')), "<AppName>.exe.manifest"));
if (fi.Exists)
fi.Delete();
// Write a new .manifest file as an Application file. (-new Application -ToFile ".\codebase\<AppName.exe.manifest")
// Include the files from the codebase directory in the manifest (-fd ".\codebase\")
// Give the application a name to use in the start menu (-name "<AppName>")
// Assign a version number to the deployment (-Version "<version>")
// Give the application an icon to use in the start menu (-IconFile "64x64.ico")
// Sign the manifest (-CertFile "<KeyName>.pfx -Password <password>)
p.StartInfo.Arguments = "-new Application -fd \".\\" + codebase.TrimEnd('\\') + "\" -ToFile \".\\" + Path.Combine(codebase, "<AppName>.exe.manifest") + "\" -Name \"<AppName>\" -Version \"" + codebase.Substring(codebase.IndexOf('_') + 1, codebase.Length - (codebase.IndexOf('_') + 1)).Replace('_', '.').TrimEnd('\\') + "\" -CertFile \"<KeyName>.pfx\" -Password <Password> -IconFile \"64x64.ico\"";
while (p.StartInfo.Arguments.Contains(".\\.\\"))
p.StartInfo.Arguments = p.StartInfo.Arguments.Replace(".\\.\\", ".\\");
Logger.Instance.LogInfo("Starting application: " + p.StartInfo.FileName + "\n\tWith arguments: " + p.StartInfo.Arguments, Logger.InfoType.Information);
p.Start();
while (!p.HasExited)
{
Thread.Sleep(100);
}
// Make a new deployment manifest (-new Deployment -t "<AppName>.application")
// Make the application available offline (-I t)
// Use the files from the .manifest we just made (-AppManifest ".\codebase\<AppName>.exe.manifest")
p.StartInfo.Arguments = "-new Deployment -I t -t \"<AppName>.application\" -v \"" + codebase.Substring(codebase.IndexOf('_') + 1, codebase.Length - (codebase.IndexOf('_') + 1)).Replace('_', '.').TrimEnd('\\') + "\" -AppManifest \".\\" + codebase + "<AppName>.exe.manifest\" -pu \"http://" + Config.Instance.ClientSettings.Host + "/client/" + codebase.Replace('\\', '/') + "<AppName>.exe.manifest\"";
while (p.StartInfo.Arguments.Contains(".\\.\\"))
p.StartInfo.Arguments = p.StartInfo.Arguments.Replace(".\\.\\", ".\\");
Logger.Instance.LogInfo("Starting application: " + p.StartInfo.FileName + "\n\tWith arguments: " + p.StartInfo.Arguments, Logger.InfoType.Information);
p.Start();
while (!p.HasExited)
{
Thread.Sleep(100);
}
xDoc = new XmlDocument();
xDoc.Load(Path.Combine(filedir.FullName, "<AppName>.application"));
// Add to the Deployment manifest (.application) to make the application
// have a minimum required version of the current version,and makes a
// subscription so that the application will always check for updates before
// running.
if (xDoc["asmv1:assembly"]["deployment"]["subscription"] != null)
{
xDoc["asmv1:assembly"]["deployment"].RemoveChild(xDoc["asmv1:assembly"]["deployment"]["subscription"]);
xDoc["asmv1:assembly"]["deployment"].RemoveChild(xDoc["asmv1:assembly"]["deployment"]["deploymentProvider"]);
XmlAttribute node = xDoc.CreateAttribute("minimumRequiredVersion");
node.Value = codebase.Substring(codebase.IndexOf('_') + 1, codebase.Length - (codebase.IndexOf('_') + 1)).Replace('_', '.').TrimEnd('\\');
xDoc["asmv1:assembly"]["deployment"].Attributes.Append(node);
xDoc["asmv1:assembly"]["deployment"].InnerXml = "<subscription><update><beforeApplicationStartup /></update></subscription>";
}
xDoc.Save(Path.Combine(filedir.FullName, "<AppName>.application"));
// Sign the deployment manifest (.application) (-Sign "\<AppName>.application" -CertFile "<AppName>.key" -Password <password>
p.StartInfo.Arguments = "-Sign \"<AppName>.application\" -CertFile \"<AppName>.pfx\" -Password <password>";
while (p.StartInfo.Arguments.Contains(".\\.\\"))
p.StartInfo.Arguments = p.StartInfo.Arguments.Replace(".\\.\\", ".\\");
Logger.Instance.LogInfo("Starting application: " + p.StartInfo.FileName + "\n\tWith arguments: " + p.StartInfo.Arguments, Logger.InfoType.Information);
p.Start();
while (!p.HasExited)
{
Thread.Sleep(100);
}
}
}发布于 2014-08-28 17:01:05
如果您的目标是在不同环境之间修改应用程序清单,我不知道为什么要创建一个新的应用程序清单。修改你现在的那个。我正在发布一个powershell脚本,它能满足你的需要,还有更多.在我的例子中,我有一个安装引导程序,但是您需要的相关代码位于底部。
对于安装引导程序,您不能辞职签名引导程序,所以我必须找到第三方dll才能解除签名。( http://forum.xda-developers.com/showthread.php?t=416175 )如果有一天它从网络上消失,我就让她的母亲负责源代码管理:)
找到#Begin Resigning various Manifests部分
$root = "$PSScriptRoot"
$ToolsPath = "C:\Tools"
$CertFile = $ToolsPath + "\my cert.pfx"
$CertPassword = "wouldn't you like to know"
#Update the setup.exe bootstrappers update url
Start-Process "$PSScriptRoot\setup.exe" -ArgumentList "-url=`"$ClickOnceUpdateUrl`"" -Wait
#The bootstrappers signature is now invalid since we updated the url
#We need to remove the old signature
Start-Process 'C:\Tools\delcert.exe' -ArgumentList "`"$root\setup.exe`"" -Wait
Write-Host "$root [writeline]"
#Resign with signtool
Invoke-Expression 'C:\Tools\signtool.exe sign /d "My Company" /f "$CertFile" /p "$CertPassword" "$root\setup.exe"'
#update config properties
$CodeBasePath = Convert-Path "$PSScriptRoot\Application Files\MyProduct_*"
$ConfigPath = $CodeBasePath + "\MyProduct.dll.config.deploy"
[xml] $xml = Get-Content $ConfigPath
$Endpoint = $xml.SelectSingleNode('/configuration/appSettings/add[@key="MailCheckerEndpoint"]')
$Endpoint.value = $MailCheckerEndpoint
$ApiEndpoint = $xml.SelectSingleNode('/configuration/appSettings/add[@key="MyApi:ApiBaseUrl"]')
$ApiEndpoint.value = $MyProductApiEndpoint
$xml.Save($ConfigPath)
#Begin Resigning various Manifests
$AppManifestPath = Convert-Path "Application Files\MyCompany_*\MyCompany.dll.manifest"
#Need to resign the application manifest, but before we do we need to rename all the files back to their original names (remove .deploy)
Get-ChildItem "$CodeBasePath\*.deploy" -Recurse | Rename-Item -NewName { $_.Name -replace '\.deploy','' }
#Resign application manifest
Invoke-Expression 'C:\Tools\mage.exe -update "$CodeBasePath\MyCompany.dll.manifest" -certFile "$CertFile" -password "$CertPassword" -if "Application Files\MyCompany_1_2_35_0\Resources\ID.ico"'
#Regisn deployment manifests in root and versioned folder
Invoke-Expression 'C:\Tools\mage.exe -update "$CodeBasePath\MyCompany.vsto" -certFile "$CertFile" -password "$CertPassword" -appManifest "$AppManifestPath" -pub "My Company" -ti "http://timestamp.globalsign.com/scripts/timstamp.dll"'
Invoke-Expression 'C:\Tools\mage.exe -update "$root\MyComapny.vsto" -certFile "$CertFile" -password "$CertPassword" -appManifest "$AppManifestPath" -pub "My company" -ti "http://timestamp.globalsign.com/scripts/timstamp.dll"'
#Rename files back to the .deploy extension, skipping the files that shouldn't be renamed
Get-ChildItem -Path "Application Files\*" -Recurse | Where-Object {!$_.PSIsContainer -and $_.Name -notlike "*.manifest" -and $_.Name -notlike "*.vsto"} | Rename-Item -NewName {$_.Name + ".deploy"}https://stackoverflow.com/questions/2313658
复制相似问题