I am writing a few automated web tests using C# Watin framework.
I was hoping anyone can help me out,
How do i open new IE instance in "in private" browse mode? (i.e incognito mode)
The need for "in private" browsing, is because some of the tests, require log in. (and i run a few in parallel)
I could not find any resources on the matter. (other than half patch i found in some forum)
Thanks for your help!
The only solution i was able to find, is to open IE instance via command in incognito mode, then attach Watin to it.
//gen random url so we can find the window later
Random rnd = new Random();
int id = rnd.Next(1000, 10000);
string url = "id" + id+".com";
//opening explorer
Process.Start("IExplore.exe", "-private -nomerge " + url);
browser = Browser.AttachTo<IE>(Find.ByUrl(new Regex(url)));
browser.GoTo("http://www.google.com");
I downloaded WatiN source codes, opened IE.cs and edited the method CreateIExploreInNewProcess
private static Process CreateIExploreInNewProcess()
{
var arguments = "about:blank";
if (GetMajorIEVersion() >= 8 && Settings.MakeNewIe8InstanceNoMerge)
arguments = "-nomerge " + arguments;
if (Settings.OpenInIncognitoMode == true)
{
arguments = "-private " + arguments;
}
var m_Proc = Process.Start("IExplore.exe", arguments);
if (m_Proc == null) throw new WatiNException("Could not start IExplore.exe process");
return m_Proc;
}
Then, added this to Settings.cs:
/// <summary>
/// Gets or sets a value indicating whether the browser will be opened in incognito mode.
/// </summary>
/// <value>
/// <c>true</c> if IE instance needs to be opened in incognito mode, otherwise <c>false</c>.
/// </value>
public static bool OpenInIncognitoMode
{
get { return Instance.OpenInIncognitoMode; }
set { Instance.OpenInIncognitoMode = value; }
}
After that, added this to ISettings.cs
/// <summary>
/// Gets or sets a value indicating whether the browser will be opened in incognito mode.
/// </summary>
/// <value>
/// <c>true</c> if IE instance needs to be opened in incognito mode, otherwise <c>false</c>.
/// </value>
bool OpenInIncognitoMode { get; set; }
Finally, edited DefaultSettings.cs like this:
private struct settingsStruct
{
...
...
public bool makeNewIe8InstanceNoMerge;
public bool closeExistingFireFoxInstances;
public bool incognitoMode;
}
public bool OpenInIncognitoMode
{
get { return settings.incognitoMode; }
set { settings.incognitoMode = value; }
}
private void SetDefaults()
{
settings = new settingsStruct
{
...
...
makeNewIe8InstanceNoMerge = true,
closeExistingFireFoxInstances = true,
incognitoMode = false
};
}
Compile it and add the new DLL to your project. After this, all you need to do in your project is this:
Settings.OpenInIncognitoMode = true;
var browser = new IE(url, true);
The trick is to pass the argument -private to the call of IExplore.exe like here:
string argument = "-private -nomerge about:blank";
process = Process.Start("IExplore.exe", argument);
if (process == null)
throw new InvalidOperationException("The IExplore.exe process can't be started");
Thread.Sleep(3000);
handle = process.MainWindowHandle.ToInt32();
var allBrowsers = new SHDocVw.ShellWindows();
if (handle != 0)
{
foreach (InternetExplorer browser in allBrowsers)
if (browser.HWND == handle)
{
ie = browser;
iehandle = (IntPtr)ie.HWND;
break;
}
}
Related
I currently have an application (.Net Frameowork) that gets triggered via CMD request. I would like to only have one instance of the application running and I would like to handle the arguments being passed in. Right now I have the application identifying if there is a currently running instance.
Example:
cmd ReceiptApplication.exe -r:blah -c:foo
cmd ReceiptApplication.exe -r:blah2 -c:foo2
The second request would pass blah2 and foo2 to the currently running process of ReceiptApplication.exe and kill the second application.
What is the process or pattern for passing the parameters?
using System.Linq;
using System.Windows;
namespace ReceiptApplication
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
/// <summary>
/// Startup the application,
/// Process:
/// Get the arguments passed in
/// Validate the arguments
/// check to see if there is a running instance of the application
/// if there is a running app
/// Pass the arguments to the running application
/// kill the current application.
/// else
/// process the request
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Application_Startup(object sender, StartupEventArgs e)
{
string receiptID = GetArgument(e.Args, "-r");
string creditUnionFile = GetArgument(e.Args, "-c");
if(receiptID == null || creditUnionFile == null)
{
System.Windows.Forms.Application.Exit();
}
if (AppCurrntlyRunning())
{
//pass arguments to the current running application
Process alreadyRunningApplication = GetOriginalProcess();
var streamWriter = alreadyRunningApplication.StandardInput;
streamWriter.WriteLine("-r:blah -c:yay");
//kill this one
System.Windows.Forms.Application.Exit();
}
MessageBox.Show("Starting UI!");
MainWindow wnd = new MainWindow();
wnd.PullReceipt(receiptID, creditUnionFile);
wnd.Show();
}
}
}
If you want to pass information to your application during runtime you could use the standard input stream. This is how it's done: How to write to stdin in C#
Then in your running application you can read the written data with Console.ReadLine();
On the linked answer on how to write to stdin in C# mind that instead of starting a new application you want to store a reference to your already running one:
//DON'T do this
//var process = new Process();
//process.StartInfo = startInfo;
//process.Start();
//DO this
var processes = Process[] localByName = Process.GetProcessesByName("The Title Of My Application"); //This should give back multiple processes if you start your application for a second time so be mindful about that
Process alreadyRunningApplication;
if(processes.Length > 1)
{
if (processes[0].Id == Process.GetCurrentProcess.Id)
{
alreadyRunningApplication = processes[1];
}
else
{
alreadyRunningApplication = processes[0];
}
var streamWriter = alreadyRunningApplication.StandardInput;
streamWriter.WriteLine("I'm supplying input!");
}
else
{
//If we get into this else, it means this instance is the first running instance so your normal program behavior should go here for example using Console.ReadLine();
}
I would like to have a IWebDriver of an already opened browser like Chrome. Because then I need to automate a form authentication and/or a basic authentication.
I thought that this
IWebDriver driver = new RemoteWebDriver(new System.Uri("http://localhost:4445/wd/hub"), new ChromeOptions());
would do the trick but it only opens another chrome window. Instead I would like to "read" an already opened one.
Is it possible with selenium? O r should I use another library?
As per the Selenium Issues page:
https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/18
The issue was closed and marked as not feasible
The process of connecting to an existing browser would be on a per-browser basis.
Doing it in IE might be easy, but doing it in Chrome or Firefox would be problematic.
Eg:
Chrome actually receives the commands from Selenium via network / tcp json requests to a specific port.
When Selenium driver stops running - it loses the port number for the Chrome debugging port.
The port may still be open, but it could be anything between 10000 and 30000 etc
Even if you solve it for Chrome, it would then require another bespoke solution for Firefox.
Unless your authentication has a 'Captcha' or bot check in place, I would suggest just automating the authentication stage.
Generally speaking - it is a good practice for Automated tests to be self-contained and not rely on outside interference or external tests.
A browser should start at the start of the test and be terminated at the end of the test.
Assuming you are using Selenium for testing and not for malicious purposes.
Selenium will not be helpful to you at this stage.
If however, you can live with your answer / solution being on Chrome but not the other browsers.
public static Chrome StartChromeDriver(int port)
{
try
{
string Path = Registry.Installation.GetChromeExecutable();
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo(Path);
string args = "--remote-debugging-port="+ port.ToString()+" --user-data-dir=remote-profile";
psi.Arguments = args;
psi.Verb = "runas";
p.StartInfo = psi;
p.Start();
return new Chrome("http://localhost:" + port.ToString());
}
catch (Exception ee)
{
Console.WriteLine(ee.ToString());
return null;
}
}
This will start a chrome process with the debugging port opened to the number you provide.
(You can keep track of this, and reconnect and re-issue commands to the running chrome instance)
public dynamic EnablePage()
{
json = #"{""id"":12345,""method"":""Page.enable""}";
Thread.Sleep(1000);
return this.SendCommand(json);
}
public dynamic EnableRuntime()
{
json = #"{""id"":12345,""method"":""Runtime.enable""}";
Thread.Sleep(1000);
return this.SendCommand(json);
}
public dynamic EnableNetwork()
{
json = #"{""id"":12345,""method"":""Network.enable""}";
Thread.Sleep(1000);
return this.SendCommand(json);
}
This is some code I had lying around.
I was very bored one day and decided to reinvent the wheel with Chrome automation. Basically - this code is how you could automate Chrome without using Selenium at all.
It does have a dependency on WebSockets4Net
But that being said - it could probably be refactored to use TcpClient.
All the commands that are issued to Chrome, are done in the form of a json request.
Eg: the following json command would tell chrome to execute the following javascript - essentially navigating to the url provided.
{
"method": "Runtime.evaluate",
"params": {
"expression": "document.location='urlhere'",
"objectGroup": "console",
"includeCommandLineAPI": true,
"doNotPauseOnExceptions": false,
"returnByValue": false
},
"id": 1
}
public dynamic SendCommand(string cmd)
{
if (EventHandler == null)
{
EventHandler = new Events();
EventHandler.OnNavigateStart += new Events.OnPageNavigateStart(EventHandler_OnNavigateStart);
EventHandler.OnNavigateEnd += new Events.OnPageNavigateEnded(EventHandler_OnNavigateEnd);
}
WebSocket4Net.WebSocket j = new WebSocket4Net.WebSocket(this.sessionWSEndpoint);
ManualResetEvent waitEvent = new ManualResetEvent(false);
ManualResetEvent closedEvent = new ManualResetEvent(false);
dynamic message = null;
byte[] data;
Exception exc = null;
j.Opened += delegate(System.Object o, EventArgs e)
{
j.Send(cmd);
};
j.MessageReceived += delegate(System.Object o, WebSocket4Net.MessageReceivedEventArgs e)
{
message = e.Message;
EventHandler.ParseEvents(e);
waitEvent.Set();
};
j.Error += delegate(System.Object o, SuperSocket.ClientEngine.ErrorEventArgs e)
{
exc = e.Exception;
waitEvent.Set();
};
j.Closed += delegate(System.Object o, EventArgs e)
{
closedEvent.Set();
};
j.DataReceived += delegate(object sender, WebSocket4Net.DataReceivedEventArgs e)
{
data = e.Data;
waitEvent.Set();
};
j.Open();
waitEvent.WaitOne();
if (j.State == WebSocket4Net.WebSocketState.Open)
{
j.Close();
closedEvent.WaitOne();
j = null;
}
if (exc != null)
throw exc;
serializer = null;
serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { converter });
dynamic obj = serializer.Deserialize(message, typeof(object));
message = null;
data = null;
return obj;
}
To demonstrate how this could be used practically - you can implement page-object and create 'types' that encapsulate objects on screen.
For instance:
public class Link : Base.Element
{
public Link(string XPath)
{
this.XPath = String.Copy(XPath);
}
/// <summary>
/// Overriding it - just in case we need to handle clicks differently
/// </summary>
/// <returns></returns>
public virtual bool Click()
{
Sync();
Console.WriteLine(Chrome.Driver.Eval("document.evaluate('" + XPath.Replace("'", "\\\\'") + "', document.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotItem(0).click();"));
return true;
}
public virtual bool WaitForExistance(int iTimeout)
{
return base.WaitForExistance(iTimeout);
}
public virtual bool Exists()
{
return base.Exists();
}
public virtual string GetText()
{
Sync();
dynamic dval = Chrome.Driver.Eval("document.evaluate('" + XPath.Replace("'", "\\\\'") + "', document.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotItem(0).innerText");
return dval.result.result.value;
}
}
Be warned - there were memory leaks in WebSockets4Net when I was using this code - so the application eventually had to be restarted.
Perhaps if WebSockets4Net is removed and replaced - it will work better.
I want to kill a running IIS Instance programmatically that is occupying a specific port, but it seems there is no way to figure out what IIS Instance is using a specific port.
netstat.exe just shows that the process is having the PID 4, but that's the system process. "netsh http show urlacl" does not display the occupied port at all.
The IIS Express Tray program knows this somehow. When I try to start another IIS Express instance while the port is occupied I get the following error:
"Port '40000' is already being used by process 'IIS Express' (process ID '10632').
Anyone got a clue how I can get this information?
It seems like the PID is 4 (System) because the actual listening socket is under a service called http.
I looked at what iisexpresstray.exe was using to provide a list of all running IISExpress applications. Thankfully it's managed .NET code (all in iisexpresstray.dll) that's easily decompiled.
It appears to have at least three different ways of getting the port number for a process:
Reading /port from the command-line arguments (unreliable as we know)
Running netsh http show servicestate view=requestq and parsing the output
Calling Microsoft.Web.RuntimeStatusClient.GetWorkerProcess(pid) and parsing the site URL
Unfortunately, most of the useful stuff in iisexpresstray.dll like the IisExpressHelper class is declared internal (although I imagine there're tools to generate wrappers or copy the assembly and publicize everything).
I opted to use Microsoft.Web.dll. It was in my GAC, though for some reason wasn't appearing in the list of assemblies available to add as a reference in Visual Studio, so I just copied the file out from my GAC. Once I had Microsoft.Web.dll it was just a matter of using this code:
using (var runtimeStatusClient = new RuntimeStatusClient())
{
var workerProcess = runtimeStatusClient.GetWorkerProcess(process.Id);
// Apparently an IISExpress process can run multiple sites/applications?
var apps = workerProcess.RegisteredUrlsInfo.Select(r => r.Split('|')).Select(u => new { SiteName = u[0], PhysicalPath = u[1], Url = u[2] });
// If we just assume one app
return new Uri(apps.FirstOrDefault().Url).Port;
}
You can also call RuntimeClient.GetAllWorkerProcesses to retrieve only actual worker processes.
I looked into RegisteredUrlsInfo (in Microsoft.Web.dll) as well and found that it's using two COM interfaces,
IRsca2_Core (F90F62AB-EE00-4E4F-8EA6-3805B6B25CDD)
IRsca2_WorkerProcess (B1341209-7F09-4ECD-AE5F-3EE40D921870)
Lastly, I read about a version of Microsoft.Web.Administration apparently being able to read IISExpress application info, but information was very scarce, and the one I found on my system wouldn't even let me instantiate ServerManager without admin privileges.
Here is a C# implementation of calling netsh.exe as recommended within the answer by #makhdumi:
Usage:
static public bool TryGetCurrentProcessRegisteredHttpPort(out List<int> ports, out Exception ex)
{
NetshInvoker netsh = new NetshInvoker();
return netsh.TryGetHttpPortUseByProcessId(Process.GetCurrentProcess().Id, out ports, out ex);
}
Implementation:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace YourCompanyName.Server.ServerCommon.Utility
{
/// <summary>
/// Invoke netsh.exe and extract information from its output.
/// Source: #crokusek, https://stackoverflow.com/questions/32196188
/// #GETah, https://stackoverflow.com/a/8274758/538763
/// </summary>
public class NetshInvoker
{
const string NetshHttpShowServiceStateViewRequestqArgs = "http show servicestate view=requestq";
public NetshInvoker()
{
}
/// <summary>
/// Call netsh.exe to determine the http port number used by a given windowsPid (e.g. an IIS Express process)
/// </summary>
/// <param name="windowsPid">For example an IIS Express process</param>
/// <param name="port"></param>
/// <param name="ex"></param>
/// <returns></returns>
public bool TryGetHttpPortUseByProcessId(Int32 windowsPid, out List<Int32> ports, out Exception ex)
{
ports = null;
try
{
if (!TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out ex))
return false;
if (!pidToUrlMap.TryGetValue(windowsPid, out List<string> urls))
{
throw new Exception(String.Format("Unable to locate windowsPid {0} in '{1}' output.",
windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
}
if (!urls.Any())
{
throw new Exception(String.Format("WindowsPid {0} did not reference any URLs in '{1}' output.",
windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
}
ports = urls
.Select(u => new Uri(u).Port)
.ToList();
return true;
}
catch (Exception ex_)
{
ex = ex_;
return false;
}
}
private bool TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out Exception ex)
{
if (!TryExecNetsh(NetshHttpShowServiceStateViewRequestqArgs, out string output, out ex))
{
pidToUrlMap = null;
return false;
}
bool gotRequestQueueName = false;
bool gotPidStart = false;
int currentPid = 0;
bool gotUrlStart = false;
pidToUrlMap = new Dictionary<int, List<string>>();
foreach (string line in output.Split('\n').Select(s => s.Trim()))
{
if (!gotRequestQueueName)
{
gotRequestQueueName = line.StartsWith("Request queue name:");
}
else if (!gotPidStart)
{
gotPidStart = line.StartsWith("Process IDs:");
}
else if (currentPid == 0)
{
Int32.TryParse(line, out currentPid); // just get the first Pid, ignore others.
}
else if (!gotUrlStart)
{
gotUrlStart = line.StartsWith("Registered URLs:");
}
else if (line.ToLowerInvariant().StartsWith("http"))
{
if (!pidToUrlMap.TryGetValue(currentPid, out List<string> urls))
pidToUrlMap[currentPid] = urls = new List<string>();
urls.Add(line);
}
else // reset
{
gotRequestQueueName = false;
gotPidStart = false;
currentPid = 0;
gotUrlStart = false;
}
}
return true;
}
private bool TryExecNetsh(string args, out string output, out Exception exception)
{
output = null;
exception = null;
try
{
// From #GETah, https://stackoverflow.com/a/8274758/538763
Process p = new Process();
p.StartInfo.FileName = "netsh.exe";
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
output = p.StandardOutput.ReadToEnd();
return true;
}
catch (Exception ex)
{
exception = ex;
return false;
}
}
}
}
In my case I just output "Command line" column in Task manager and it's getting obvious, which IISExpress is that:
You can run below command to get the information of the executable and its PID
netstat -a -n -o -b | find "iisexpress.exe"
I have a button that says "Open in browser". I would like to rename it to "Open" and show default browser's icon next to it.
If default browser is firefox, then I want firefox icon in my button.
If default browser is chrome, then I want chrome icon.
How can I get the default browsers icon?
If it's different for every version of windows, then I need window 7 version.
Embed a blank htm or html file with your application (or create it)
Then call the Icon.ExtractAssociatedIcon method on this file.
It will return default browser icon .
I have changed the code a bit and here is my version.
using System;
using Microsoft.Win32;
using System.Drawing;
namespace Namespace
{
public static class DefaultSystemBrowser
{
private static bool initialized = false;
private static string path = null;
public static string Path
{
get
{
CheckForErrors();
return path;
}
}
public static Icon Icon
{
get {
CheckForErrors();
return Icon.ExtractAssociatedIcon( path );
}
}
public static Bitmap Bitmap
{
get
{
CheckForErrors();
return Icon.ExtractAssociatedIcon( path ).ToBitmap();
}
}
private static void CheckForErrors()
{
if ( !initialized )
throw new InvalidOperationException( "You can't use DefaultSystemBrowser class before you call Determine()." );
if ( ErrorMessage != null )
throw new InvalidOperationException( "You can't use DefaultSystemBrowser class if call to Determine() resulted in error." );
}
/// <summary>
/// Null if no error occured, error description otherwise.
/// </summary>
public static string ErrorMessage
{
get;
private set;
}
/// <summary>
/// Finds out all information about current default browser. You can call this method every time you want to find out default browser.
/// </summary>
public static void Determine()
{
path = String.Empty;
initialized = true;
RegistryKey regKey = null;
ErrorMessage = null;
try
{
//set the registry key we want to open
regKey = Registry.ClassesRoot.OpenSubKey( "HTTP\\shell\\open\\command", false );
//get rid of the enclosing quotes
path = regKey.GetValue( null ).ToString().ToLower().Replace( "" + (char) 34, "" );
//check to see if the value ends with .exe (this way we can remove any command line arguments)
if ( !path.EndsWith( "exe" ) )
//get rid of all command line arguments (anything after the .exe must go)
path = path.Substring( 0, path.LastIndexOf( ".exe" ) + 4 );
initialized = true;
}
catch ( Exception ex )
{
ErrorMessage = string.Format( "ERROR: An exception of type: {0} occurred in method: {1} in the following module: {2}", ex.GetType(), ex.TargetSite, typeof( DefaultSystemBrowser ) );
}
finally
{
//check and see if the key is still open, if so
//then close it
if ( regKey != null )
regKey.Close();
}
}
}
}
Here is how I am using the code:
DefaultSystemBrowser.Determine();
if ( DefaultSystemBrowser.ErrorMessage == null )
{
btnOpenInBrowser.Image = DefaultSystemBrowser.Bitmap;
}
else
{
btnOpenInBrowser.Image = Properties.Resources.firefox_24_noshadow;
}
how to get the application pool name for a specific website IIS 6 programmatic using C#
EDIT:
I already used the methods of DirectoryServices namespace but the application pool name isn't retrieved correctly unless it was explicitly set by using the same code. Which means if u add a website manually using the iis manager and set an application pool, those codes won't work (it will always return DefaultAppPool) more over when I create an application using sharepoint and set a different appPool those methods dont work.
I don't agree with you. I coded up a test app and I get the correct AppPool name from it, even if I set the AppPool manually using IIS Manager.
To make sure, I have tested once, name name was ok; then, I popep up the IIS Manager, changed the AppPool, executed iisreset, and ran the test app again - the AppPool name I got was correct again. I don't how your code looked like, but mine is like this:
using System;
using System.IO;
using System.DirectoryServices;
class Class
{
static void Main(string[] args)
{
DirectoryEntry entry = FindVirtualDirectory("<Server>", "Default Web Site", "<WantedVirtualDir>");
if (entry != null)
{
Console.WriteLine(entry.Properties["AppPoolId"].Value);
}
}
static DirectoryEntry FindVirtualDirectory(string server, string website, string virtualdir)
{
DirectoryEntry siteEntry = null;
DirectoryEntry rootEntry = null;
try
{
siteEntry = FindWebSite(server, website);
if (siteEntry == null)
{
return null;
}
rootEntry = siteEntry.Children.Find("ROOT", "IIsWebVirtualDir");
if (rootEntry == null)
{
return null;
}
return rootEntry.Children.Find(virtualdir, "IIsWebVirtualDir");
}
catch (DirectoryNotFoundException ex)
{
return null;
}
finally
{
if (siteEntry != null) siteEntry.Dispose();
if (rootEntry != null) rootEntry.Dispose();
}
}
static DirectoryEntry FindWebSite(string server, string friendlyName)
{
string path = String.Format("IIS://{0}/W3SVC", server);
using (DirectoryEntry w3svc = new DirectoryEntry(path))
{
foreach (DirectoryEntry entry in w3svc.Children)
{
if (entry.SchemaClassName == "IIsWebServer" &&
entry.Properties["ServerComment"].Value.Equals(friendlyName))
{
return entry;
}
}
}
return null;
}
}
Sorry for my lousy english.
Hope I've helped.
The classes in the System.DirectoryServices namespace will help you get that information.
Check this article by Rick Strahl for an example:
/// <summary>
/// Returns a list of all the Application Pools configured
/// </summary>
/// <returns></returns>
public ApplicationPool[] GetApplicationPools()
{
if (ServerType != WebServerTypes.IIS6 && ServerType != WebServerTypes.IIS7)
return null;
DirectoryEntry root = this.GetDirectoryEntry("IIS://" + this.DomainName + "/W3SVC/AppPools");
if (root == null)
return null;
List<ApplicationPool> Pools = new List<ApplicationPool>();
foreach (DirectoryEntry Entry in root.Children)
{
PropertyCollection Properties = Entry.Properties;
ApplicationPool Pool = new ApplicationPool();
Pool.Name = Entry.Name;
Pools.Add(Pool);
}
return Pools.ToArray();
}
/// <summary>
/// Create a new Application Pool and return an instance of the entry
/// </summary>
/// <param name="AppPoolName"></param>
/// <returns></returns>
public DirectoryEntry CreateApplicationPool(string AppPoolName)
{
if (this.ServerType != WebServerTypes.IIS6 && this.ServerType != WebServerTypes.IIS7)
return null;
DirectoryEntry root = this.GetDirectoryEntry("IIS://" + this.DomainName + "/W3SVC/AppPools");
if (root == null)
return null;
DirectoryEntry AppPool = root.Invoke("Create", "IIsApplicationPool", AppPoolName) as DirectoryEntry;
AppPool.CommitChanges();
return AppPool;
}
/// <summary>
/// Returns an instance of an Application Pool
/// </summary>
/// <param name="AppPoolName"></param>
/// <returns></returns>
public DirectoryEntry GetApplicationPool(string AppPoolName)
{
DirectoryEntry root = this.GetDirectoryEntry("IIS://" + this.DomainName + "/W3SVC/AppPools/" + AppPoolName);
return root;
}
/// <summary>
/// Retrieves an Adsi Node by its path. Abstracted for error handling
/// </summary>
/// <param name="Path">the ADSI path to retrieve: IIS://localhost/w3svc/root</param>
/// <returns>node or null</returns>
private DirectoryEntry GetDirectoryEntry(string Path)
{
DirectoryEntry root = null;
try
{
root = new DirectoryEntry(Path);
}
catch
{
this.SetError("Couldn't access node");
return null;
}
if (root == null)
{
this.SetError("Couldn't access node");
return null;
}
return root;
}
In brief, there's 2 ways of doing this that spring to mind.
The less sophisticated way is knowing that, IIS6's settings are stored in the MetaBase which is just an Xml file:
C:\WINDOWS\system32\inetsrv\MetaBase.xml
You can just use Linq2Xml and parse the Xml looking for the sites name or Id, The AppPoolId attribute contains the name of the AppPool
The proper way is to use System.DirectoryServices