转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/
本来的想法是做一个可以自动卸载并且部署新solution到SharePoint farm的tool。但是最后只做到retract成功和remove solution之前这个阶段。因为一个原因(等待solution retracted的过程中出现CLR方面的问题)导致不能将整个过程连续起来,这是相关的博问,希望有高手可以解惑。
下面的tool将会根据SharePoint solution wsp文件名自动识别solution,并在相应的站点deactive相应的site collection级别的solution feature,然后在SharePoint farm中卸载相应的solution。
图形界面:
选择Web Application,选择其下的Site Collection,然后填写登陆SharePoint Site的用户名和密码,选择要卸载的wsp文件。之后点击OK,就会自动进行卸载。
待完成的部分(已经都注释掉了)用是从等待retract成功开始,然后remove solution,deploy solution,以及active feature的过程。难点主要是等待solution retract成功。希望SharePoint方面专家可以帮助解决这个问题。相关的详细异常信息,请见博问。
代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using System.IO; using OpenQA.Selenium; using OpenQA.Selenium.IE; using OpenQA.Selenium.Support; using OpenQA.Selenium.Support.UI; using Selenium; using System.Net; using System.Runtime.InteropServices; using System.Globalization; namespace SharePoint_Solution_Auto_Deploy { public partial class MainForm : Form { //To make the GetForegroundWindow possible. [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern IntPtr GetForegroundWindow(); //Form entry. public MainForm() { InitializeComponent(); getSPWebApps(); } //Add web apps to the combobox. private void getSPWebApps() { try { SPSecurity.RunWithElevatedPrivileges(() => { foreach (SPWebApplication webApp in SPWebService.ContentService.WebApplications) { WebAppComBox.Items.Add(webApp.Name); } }); } catch (Exception ex) { WriteLog(ex); } } //Web application. private void WebAppsComBox_SelectedIndexChanged(object sender, EventArgs e) { WebAppComBox.Text = WebAppComBox.SelectedItem.ToString(); SPWebApplicationCollection webApps = SPWebService.ContentService.WebApplications; SPWebApplication webApp = webApps[WebAppComBox.Text]; getSPSites(webApp); } //Site. private void getSPSites(SPWebApplication webApp) { SPSiteCollection sites = webApp.Sites; //Clear old items from the combox first and then add the new items into it. SiteComBox.Items.Clear(); foreach (SPSite site in sites) { SiteComBox.Items.Add(site.Url.ToString()); } } //Write log method. private static void WriteLog(Exception ex) { string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\SeleniumAutoTest.txt"; if (File.Exists(@logUrl)) { using (FileStream fs = new FileStream(logUrl, FileMode.Append)) { using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)) { try { sw.Write(ex); } catch (Exception ex1) { WriteLog(ex1); } finally { sw.Close(); fs.Close(); } } } } else { using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew)) { using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)) { try { sw.Write(ex); } catch (Exception ex1) { WriteLog(ex1); } finally { sw.Close(); fs.Close(); } } } } } //Select the wsp file action. private void select_wsp_button_Click(object sender, EventArgs e) { OpenFileDialog wspFile = new OpenFileDialog(); if (wspFile.ShowDialog() == DialogResult.OK) { WspText.Text = wspFile.FileName; } } //Retract and deploy action. private void ok_button_Click(object sender, EventArgs e) { //1.Login site and deactive the feature. IWebDriver iw = new InternetExplorerDriver(); iw = login(iw, SiteComBox.Text.ToString(), UserNameText.Text.ToString(), PwdText.Text.ToString()); INavigation navi = iw.Navigate(); //Go to the site collection features page. navi.GoToUrl(SiteComBox.Text.ToString() + "/_layouts/15/ManageFeatures.aspx?Scope=Site"); //Judge the feature category by the name wsp file selected. string category; var wspPath = WspText.Text.ToString().Split(new Char[] { '\\' }); category = wspPath[wspPath.Count() - 1]; //MessageBox.Show(category.ToString()); //Deactive the feature. deactivateFeature(iw, category); //2.If has solution, retract first. string solutionPageUrl = "http://wdsinpexca:10000/_admin/Solutions.aspx"; navi.GoToUrl(solutionPageUrl); iw.FindElement(By.LinkText(category.ToLower())).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRetractSolution_LinkText"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRetractSolution_LinkText")).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_ctl02_RptControls_BtnSubmit"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_ctl02_RptControls_BtnSubmit")).Click(); //During the retracting period, there will be a down. Let's sleep to get over it. //Thread.Sleep(300000); //Back to the wsp page. iw.FindElement(By.LinkText(category.ToLower())).Click(); iw.Navigate().Refresh(); //Wait for the solution retracted. //waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRemoveSolution_LinkText"); //iw.FindElement(By.Id("ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRemoveSolution_LinkText")).Click(); //Click OK in the popup window. //IntPtr myPtr = GetForegroundWindow(); //if (myPtr != IntPtr.Zero) //{ // System.Windows.Forms.SendKeys.SendWait("{ENTER}"); //} //3.Deploy the solution to the web app. //4.Active the site wsp feature. } //Deactive the feature accourding to the wsp solution category. private void deactivateFeature(IWebDriver iw,string category) { if (category == "APPSSP2013MISite.wsp") { //Deactive the MISITE feature. waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_divFeatureStatus"); string featureStatus = iw.FindElement(By.Id("ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_divFeatureStatus")).GetAttribute("featurestatus").ToString(); if (featureStatus == "Active") { waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_btnActivate"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_btnActivate")).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_lnkbtnDeactivate"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_lnkbtnDeactivate")).Click(); } } //Other solutions can be extended here. } //Wait until page-element loaded method. private static void waitUntilPageLoaded(IWebDriver iw, string element) { try { iw.FindElement(By.Id(element)); } catch (Exception ex) { WriteLog(ex); //Refresh the current page. //iw.Navigate().Refresh(); Thread.Sleep(1000); waitUntilPageLoaded(iw, element); } } //Login SP site method. public static IWebDriver login(IWebDriver driver, string url,string userName,string pwd) { INavigation navigation = driver.Navigate(); navigation.GoToUrl(url); //driver.FindElement(By.Id("overridelink")).Click(); IntPtr myPtr = GetForegroundWindow(); //IntPtr hWnd = FindWindow(null, "abc"); if (myPtr != IntPtr.Zero) { //Send message to the window. System.Windows.Forms.SendKeys.SendWait(userName); System.Windows.Forms.SendKeys.SendWait("{TAB}"); System.Windows.Forms.SendKeys.SendWait(pwd); System.Windows.Forms.SendKeys.SendWait("{ENTER}"); } return driver; } } }
因为不知道怎么一气呵成,于是我把Retract和Retract之后的事情拆开来做,就有了下面的:
代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using System.IO; using OpenQA.Selenium; using OpenQA.Selenium.IE; using OpenQA.Selenium.Support; using OpenQA.Selenium.Support.UI; using Selenium; using System.Net; using System.Runtime.InteropServices; using System.Globalization; using System.Management.Automation; using System.Management.Automation.Runspaces; namespace SharePoint_Solution_Auto_Deploy { public partial class MainForm : Form { //To make the GetForegroundWindow possible. [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern IntPtr GetForegroundWindow(); //Form entry. public MainForm() { InitializeComponent(); getSPWebApps(); } //Add web apps to the combobox. private void getSPWebApps() { try { SPSecurity.RunWithElevatedPrivileges(() => { foreach (SPWebApplication webApp in SPWebService.ContentService.WebApplications) { WebAppComBox.Items.Add(webApp.Name); } }); } catch (Exception ex) { WriteLog(ex); } } //Web application. private void WebAppsComBox_SelectedIndexChanged(object sender, EventArgs e) { WebAppComBox.Text = WebAppComBox.SelectedItem.ToString(); SPWebApplicationCollection webApps = SPWebService.ContentService.WebApplications; SPWebApplication webApp = webApps[WebAppComBox.Text]; getSPSites(webApp); } //Site. private void getSPSites(SPWebApplication webApp) { SPSiteCollection sites = webApp.Sites; //Clear old items from the combox first and then add the new items into it. SiteComBox.Items.Clear(); foreach (SPSite site in sites) { SiteComBox.Items.Add(site.Url.ToString()); } } //Write log method. private static void WriteLog(Exception ex) { string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\SeleniumAutoTest.txt"; if (File.Exists(@logUrl)) { using (FileStream fs = new FileStream(logUrl, FileMode.Append)) { using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)) { try { sw.Write(ex); } catch (Exception ex1) { WriteLog(ex1); } finally { sw.Close(); fs.Close(); } } } } else { using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew)) { using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)) { try { sw.Write(ex); } catch (Exception ex1) { WriteLog(ex1); } finally { sw.Close(); fs.Close(); } } } } } //Select the wsp file action. private void select_wsp_button_Click(object sender, EventArgs e) { OpenFileDialog wspFile = new OpenFileDialog(); if (wspFile.ShowDialog() == DialogResult.OK) { WspText.Text = wspFile.FileName; } } //Retract and deploy action. private void ok_button_Click(object sender, EventArgs e) { if (WebAppComBox.Text == "" || SiteComBox.Text == "" || UserNameText.Text == "" || PwdText.Text == "" || WspText.Text == "" || CAText.Text == "") { MessageBox.Show("You can not leave any box blank. Please check your input."); } else { //1.Login site and deactive the feature. IWebDriver iw = new InternetExplorerDriver(); iw = login(iw, SiteComBox.Text.ToString(), UserNameText.Text.ToString(), PwdText.Text.ToString()); INavigation navi = iw.Navigate(); //Go to the site collection features page. navi.GoToUrl(SiteComBox.Text.ToString() + "/_layouts/15/ManageFeatures.aspx?Scope=Site"); //Judge the feature category by the name wsp file selected. string category; var wspPath = WspText.Text.ToString().Split(new Char[] { '\\' }); category = wspPath[wspPath.Count() - 1]; //MessageBox.Show(category.ToString()); //Deactive the feature. deactivateFeature(iw, category); //2.If has solution, retract first. string solutionPageUrl = CAText.Text + "/_admin/Solutions.aspx"; navi.GoToUrl(solutionPageUrl); iw.FindElement(By.LinkText(category.ToLower())).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRetractSolution_LinkText"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRetractSolution_LinkText")).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_ctl02_RptControls_BtnSubmit"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_ctl02_RptControls_BtnSubmit")).Click(); //During the retracting period, there will be a down. Let's sleep to get over it. //Thread.Sleep(300000); //Back to the wsp page. iw.FindElement(By.LinkText(category.ToLower())).Click(); iw.Navigate().Refresh(); iw.Close(); } } //Deactive the feature accourding to the wsp solution category. private void deactivateFeature(IWebDriver iw,string category) { if (category == "APPSSP2013MISite.wsp") { //Deactive the MISITE feature. waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_divFeatureStatus"); string featureStatus = iw.FindElement(By.Id("ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_divFeatureStatus")).GetAttribute("featurestatus").ToString(); if (featureStatus == "Active") { waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_btnActivate"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_featact_rptrFeatureList_ctl21_ctl00_btnActivate")).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_lnkbtnDeactivate"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_lnkbtnDeactivate")).Click(); } } //Other solutions can be extended here. } //Wait until page-element loaded method. private static void waitUntilPageLoaded(IWebDriver iw, string element) { try { iw.FindElement(By.Id(element)); } catch (Exception ex) { WriteLog(ex); //Refresh the current page. //iw.Navigate().Refresh(); Thread.Sleep(1000); waitUntilPageLoaded(iw, element); } } //Login SP site method. public static IWebDriver login(IWebDriver driver, string url,string userName,string pwd) { INavigation navigation = driver.Navigate(); navigation.GoToUrl(url); //driver.FindElement(By.Id("overridelink")).Click(); IntPtr myPtr = GetForegroundWindow(); //IntPtr hWnd = FindWindow(null, "abc"); if (myPtr != IntPtr.Zero) { //Send message to the window. System.Windows.Forms.SendKeys.SendWait(userName); System.Windows.Forms.SendKeys.SendWait("{TAB}"); System.Windows.Forms.SendKeys.SendWait(pwd); System.Windows.Forms.SendKeys.SendWait("{ENTER}"); } return driver; } //Remove the solution from the farm. private void remove_button_Click(object sender, EventArgs e) { if (WspText.Text == "" || CAText.Text == "") { MessageBox.Show("You can not leave the 'WSP' and 'Central Admin' box blank."); } else { IWebDriver iw = new InternetExplorerDriver(); INavigation navi = iw.Navigate(); navi.GoToUrl(CAText.Text + "/_admin/Solutions.aspx"); waitUntilPageLoaded(iw, "__gvctl00_PlaceHolderMain_GvItems__div"); string category; var wspPath = WspText.Text.ToString().Split(new Char[] { '\\' }); category = wspPath[wspPath.Count() - 1]; iw.FindElement(By.LinkText(category.ToLower())).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRemoveSolution_LinkText"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkRemoveSolution_LinkText")).Click(); //Click OK in the popup window. IntPtr myPtr = GetForegroundWindow(); if (myPtr != IntPtr.Zero) { System.Windows.Forms.SendKeys.SendWait("{ENTER}"); } iw.Close(); } } //Deploy the solution. private void deploy_button_Click(object sender, EventArgs e) { if (WspText.Text == "" || CAText.Text == "") { MessageBox.Show("You can not leave the 'WSP' and 'Central Admin' box blank."); } else { //Open the PowerShell. SPSecurity.RunWithElevatedPrivileges(() => { using (Runspace runspace = RunspaceFactory.CreateRunspace()) { //MessageBox.Show("Run PowerShell."); runspace.Open(); PowerShell ps = PowerShell.Create(); ps.Runspace = runspace; Pipeline pipeline = runspace.CreatePipeline(); pipeline.Commands.AddScript("Add-PSSnapin microsoft.sharepoint.powershell"); string cmd = "Add-SPSolution " + WspText.Text.ToString(); pipeline.Commands.AddScript(cmd); pipeline.Invoke(); } }); //Go to the solution-deploy page. IWebDriver iw = new InternetExplorerDriver(); INavigation navi = iw.Navigate(); navi.GoToUrl(CAText.Text + "/_admin/Solutions.aspx"); waitUntilPageLoaded(iw, "__gvctl00_PlaceHolderMain_GvItems__div"); string category; var wspPath = WspText.Text.ToString().Split(new Char[] { '\\' }); category = wspPath[wspPath.Count() - 1]; iw.FindElement(By.LinkText(category.ToLower())).Click(); waitUntilPageLoaded(iw, "ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkDeploySolution_LinkText"); iw.FindElement(By.Id("ctl00_PlaceHolderMain_solutionStatusToolBar_RptControls_LinkDeploySolution_LinkText")).Click(); iw.FindElement(By.Id("ctl00_PlaceHolderMain_ctl02_RptControls_BtnSubmit")).Click(); } } } }
至此,Deactivate Feature,Retract Solution,Remove Solution,Deploy Solution的过程就已经封装好了。至于Active Feature由于界面大小有限就不写了,和Deactivate Feature的过程是一样的。