diff --git a/3541.pdf b/3541.pdf new file mode 100644 index 0000000..0f52701 Binary files /dev/null and b/3541.pdf differ diff --git a/3542.pdf b/3542.pdf new file mode 100644 index 0000000..e1e57ee Binary files /dev/null and b/3542.pdf differ diff --git a/9781590598368.jpg b/9781590598368.jpg new file mode 100644 index 0000000..74a1f5a Binary files /dev/null and b/9781590598368.jpg differ diff --git a/ADprep.vsd b/ADprep.vsd new file mode 100644 index 0000000..463ef81 Binary files /dev/null and b/ADprep.vsd differ diff --git a/CommandLine.cs b/CommandLine.cs new file mode 100644 index 0000000..e4a1ec4 --- /dev/null +++ b/CommandLine.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Specialized; +using System.Text.RegularExpressions; + +namespace CommandLine.Utility +{ + /// + /// Arguments class + /// + public class Arguments + { + // Variables + private StringDictionary Parameters; + + // Constructor + public Arguments(string[] Args) + { + Parameters = new StringDictionary(); + Regex Spliter = new Regex(@"^-|^/|=|:", + RegexOptions.IgnoreCase|RegexOptions.Compiled); + + Regex Remover = new Regex(@"^['""]?(.*?)['""]?$", + RegexOptions.IgnoreCase|RegexOptions.Compiled); + + string Parameter = null; + string[] Parts; + + // Valid parameters forms: + // {-,/,--}param{ ,=,:}((",')value(",')) + // Examples: + // -param1 value1 /param2:"Test-:-work" + // /param3=happy -param4 '--=nice=--' + foreach(string Txt in Args) + { + // Look for new parameters (-,/ or --) and a + // possible enclosed value (=,:) + Parts = Spliter.Split(Txt,3); + + switch(Parts.Length) + { + // Found a value (for the last parameter + // found (space separator)) + case 1: + if(Parameter != null) + { + if(!Parameters.ContainsKey(Parameter)) + { + Parts[0] = + Remover.Replace(Parts[0], "$1"); + Parameters.Add(Parameter, Parts[0]); + } + Parameter=null; + } + // else Error: no parameter waiting for a value (skipped) + break; + + // Found just a parameter + case 2: + // The last parameter is still waiting. + // With no value, set it to true. + if(Parameter!=null) + { + if(!Parameters.ContainsKey(Parameter)) + Parameters.Add(Parameter, "true"); + } + Parameter=Parts[1]; + break; + + // Parameter with enclosed value + case 3: + // The last parameter is still waiting. + // With no value, set it to true. + if(Parameter != null) + { + if(!Parameters.ContainsKey(Parameter)) + Parameters.Add(Parameter, "true"); + } + + Parameter = Parts[1]; + + // Remove possible enclosing characters (",') + if(!Parameters.ContainsKey(Parameter)) + { + Parts[2] = Remover.Replace(Parts[2], "$1"); + Parameters.Add(Parameter, Parts[2]); + } + + Parameter=null; + break; + } + } + // In case a parameter is still waiting + if(Parameter != null) + { + if(!Parameters.ContainsKey(Parameter)) + Parameters.Add(Parameter, "true"); + } + } + + // Retrieve a parameter value if it exists + // (overriding C# indexer property) + public string this [string Param] + { + get + { + return(Parameters[Param]); + } + } + } +} diff --git a/DeployLCS.vsd b/DeployLCS.vsd new file mode 100644 index 0000000..76a7f33 Binary files /dev/null and b/DeployLCS.vsd differ diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..b5fc7de --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,27 @@ +Freeware License, some rights reserved + +Copyright (c) 2007 Rui Maximo and Andrew Edney + +Permission is hereby granted, free of charge, to anyone obtaining a copy +of this software and associated documentation files (the "Software"), +to work with the Software within the limits of freeware distribution and fair use. +This includes the rights to use, copy, and modify the Software for personal use. +Users are also allowed and encouraged to submit corrections and modifications +to the Software for the benefit of other users. + +It is not allowed to reuse, modify, or redistribute the Software for +commercial use in any way, or for a user’s educational materials such as books +or blog articles without prior permission from the copyright holder. + +The above copyright notice and this permission notice need to be included +in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..8c8832b --- /dev/null +++ b/Program.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CommandLine.Utility; + +namespace sipchange +{ + using System.Management; + using System.Collections; + using System.Collections.Specialized; + using System.DirectoryServices; + using System.Text.RegularExpressions; + + class Program + { + static string sQuery; + static string sQueryContacts; + static string SourceDomainURI; + static string TargetDomainURI; + + public Program() + { + // query string to return instance ID of user enabled for LCS using WMI + sQuery = "select * from MSFT_SIPESUserSetting where UserDN = '"; + // query string to return all contacts given a user's instance ID + sQueryContacts = "select * from MSFT_SIPESUserContactData where UserInstanceID = '"; + } + + static void Main(string[] args) + { + if (args.Length == 0) + { + Console.WriteLine("\ncommand-line arguments are required."); + return; + } + + Arguments CommandLine = new Arguments(args); + + if (CommandLine["?"] != null) + { + Console.WriteLine("\ncommand-line arguments:"); + Console.WriteLine("\t/source:\t\t- SIP domain to match"); + Console.WriteLine("\t/target:\t\t- SIP domain to change"); + return; + } + if (CommandLine["source"] != null) + { + SourceDomainURI = CommandLine["source"]; + } + if (CommandLine["target"] != null) + { + TargetDomainURI = CommandLine["target"]; + } + + DirectoryEntry deRoot = null; + try + { + DirectoryEntry deRootDSE = new DirectoryEntry("LDAP://RootDSE"); + string sRootDomain = "LDAP://" + deRootDSE.Properties["rootDomainNamingContext"].Value.ToString(); + deRoot = new DirectoryEntry(sRootDomain); + } + catch(Exception e) + { + Console.WriteLine("Failed to query Active Directory"); + Console.WriteLine(e.Message); + return; + } + + // Instantiate class. + Program SipDomain = new Program(); + + string userDN = null; + try + { + DirectorySearcher Users = new DirectorySearcher(deRoot, "(&(objectCategory=person)(objectCategory=user)(msRTCSIP-UserEnabled=TRUE))"); + + foreach(SearchResult user in Users.FindAll()) + { + // Obtain DN of user by removing the first 7 characters "LDAP://". + userDN = user.Path.Substring(7); + SipDomain.ChangeSIPdomain(userDN); + Console.WriteLine(); + } + } + catch (Exception e) + { + Console.WriteLine(e.Message); + return; + } + } + + public void ChangeSIPdomain(string userDN) + { + try + { + // Query for user's instance ID + ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(sQuery + userDN + "'"); + ManagementObjectCollection oCollection = oSearcher.Get(); + + foreach (ManagementObject user in oCollection) + { + Console.Write(user["PrimaryURI"].ToString()); + + if(Regex.IsMatch(user["PrimaryURI"].ToString(), SourceDomainURI)) + { + // Modify user SIP URI domain portion + string URI = Regex.Replace(user["PrimaryURI"].ToString(), @"@[-\w.]+", "@" + TargetDomainURI); + Console.Write(" -> " + URI); + user["PrimaryURI"] = URI; + // Commit changes + //user.Put(); + } + Console.WriteLine(); + + // Check whether user is unassigned + if (user["HomeServerDN"] == null) + { + Console.WriteLine("WARNING: this user is unassigned"); + // If the user is unassigned, then it won't be possible to read their contact list + return; + } + + UpdateContactsURI(user["InstanceID"].ToString()); + } + } + catch (Exception e) + { + Console.WriteLine("ChangeSIPdomain(): " + e.Message); + } + } + + private void UpdateContactsURI(string InstanceID) + { + try + { + ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(sQueryContacts + InstanceID + "'"); + ManagementObjectCollection oCollection = oSearcher.Get(); + + // Check whether user has any contacts in their contact list + if (oCollection.Count == 0) + { + return; + } + + foreach (ManagementObject contact in oCollection) + { + if (Regex.IsMatch(contact.GetPropertyValue("SIPURI").ToString(), SourceDomainURI)) + { + string URI = Regex.Replace(contact.GetPropertyValue("SIPURI").ToString(), @"@[-\w.]+", "@" + TargetDomainURI); + // Display only contacts that are modified + Console.WriteLine("\tcontact: " + contact.GetPropertyValue("SIPURI") + " -> " + URI); + contact.SetPropertyValue("SIPURI", URI); + // Commit change + //contact.Put(); + } + } + } + catch (Exception e) + { + Console.WriteLine("WARNING: unable to contact user\'s home server to read contact list"); + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..5695d60 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +#Apress Source Code + +This repository accompanies [*Pro LCS*](http://www.apress.com/9781590598368) by Rui Maximo and Andrew Edney (Apress, 2007). + +![Cover image](9781590598368.jpg) + +Download the files as a zip using the green button, or clone the repository to your machine using Git. + +##Releases + +Release v1.0 corresponds to the code in the published book, without corrections or updates. + +##Contributions + +See the file Contributing.md for more information on how you can contribute to this repository. diff --git a/configure.vbs b/configure.vbs new file mode 100644 index 0000000..a2172ca --- /dev/null +++ b/configure.vbs @@ -0,0 +1,104 @@ +On Error Resume Next + +set WshShell = WScript.CreateObject("WScript.Shell") + +' +' Obtain currently logged on user's DN +' stored in the value: ADSysInfo.UserName +' +Set ADSysInfo = CreateObject("ADSystemInfo") + +' +' Query user's SIP URI and home server DN +' using the following WMI class: +' +' class MSFT_SIPESUserSetting +' { +' string DisplayName; +' boolean Enabled; +' string HomeServerDN; +' [key] string InstanceID; +' string PrimaryURI; +' string TargetServerDNIfMoving; +' string UserDN; +' }; +' +Set oUsers = GetObject("winmgmts:\\").ExecQuery("SELECT * FROM MSFT_SIPESUserSetting WHERE UserDN = '" & ADSysInfo.UserName & "'") +' Since the user DN is unique, we're expecting a single result. +for each User in oUsers + sipURI = User.PrimaryURI + poolDN = User.HomeServerDN +next + +' Exit if user is not enabled for Live Communications. +if IsEmpty(sipURI) then + Wscript.echo "ERROR: user is not enabled for Live Communications" + Wscript.Quit +end if + +' Exit if user is orphaned. +if IsNull(poolDN) then + Wscript.echo "ERROR: user is not assigned to a home server" + Wscript.Quit +end if + +' +' Convert home server DN into FQDN +' using the following WMI class: +' +' class MSFT_SIPPoolSetting +' { +' string BackEndDBPath; +' [key] string InstanceID; +' uint32 MajorVersion; +' uint32 MinorVersion; +' string PoolDisplayName; +' string PoolDN; +' string PoolFQDN; +' string [] PoolMemberList; +' string PoolType; +' }; +' +Set oServers = GetObject("winmgmts:\\").ExecQuery("SELECT * FROM MSFT_SIPPoolSetting WHERE PoolDN = '" & poolDN & "'") +' Since the pool DN is unique, we're only expecting a single FQDN. +for each HS in oServers + poolFQDN = HS.PoolFQDN +next + +' Exit if user's home server FQDN can not be determined. +if IsEmpty(poolFQDN) then + Wscript.echo "ERROR: failed to determine user's home server FQDN" + Wscript.Quit +end if + +' +' Retrieve user's domain +' +domain = WshShell.ExpandEnvironmentStrings("%USERDOMAIN%") + +' +' Parse the SIP URI into the format: +' 'sip:user@company.com' -> 'user@company.com %domain%\user' +' where %domain% is the user's domain name +' +Set myRegExp = New RegExp +myRegExp.IgnoreCase = True +myRegExp.Global = True +myRegExp.Pattern = "sip:([^~]+)@([^~]+)" +replaceString = "$1@$2 " & domain & "\$1" +userURI = myRegExp.Replace(sipURI, replaceString) + +' +' Configure Communicator registry keys +' +WshShell.RegWrite "HKCU\Software\Microsoft\Communicator\UserMicrosoft RTC Instant Messaging", userURI, "REG_SZ" +WshShell.RegWrite "HKCU\Software\Microsoft\Communicator\ServerAddress", poolFQDN, "REG_SZ" +WshShell.RegWrite "HKCU\Software\Microsoft\Communicator\ConfigurationMode", 1, "REG_DWORD" +' Set type to 2 for TCP or set type to 4 for TLS +const TransportType = 2 +WshShell.RegWrite "HKCU\Software\Microsoft\Communicator\Transport", TransportType, "REG_DWORD" + +' +' Start Communicator.exe so user doesn't experience any delays +' +WshShell.Run "Communicator.exe", 1 diff --git a/contributing.md b/contributing.md new file mode 100644 index 0000000..f6005ad --- /dev/null +++ b/contributing.md @@ -0,0 +1,14 @@ +# Contributing to Apress Source Code + +Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. + +## How to Contribute + +1. Make sure you have a GitHub account. +2. Fork the repository for the relevant book. +3. Create a new branch on which to make your change, e.g. +`git checkout -b my_code_contribution` +4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. +5. Submit a pull request. + +Thank you for your contribution! \ No newline at end of file diff --git a/installCommunicator.EXE b/installCommunicator.EXE new file mode 100644 index 0000000..278b19e Binary files /dev/null and b/installCommunicator.EXE differ diff --git a/installCommunicator.SED b/installCommunicator.SED new file mode 100644 index 0000000..59a24a5 --- /dev/null +++ b/installCommunicator.SED @@ -0,0 +1,41 @@ +[Version] +Class=IEXPRESS +SEDVersion=3 +[Options] +PackagePurpose=InstallApp +ShowInstallProgramWindow=0 +HideExtractAnimation=0 +UseLongFileName=1 +InsideCompressed=0 +CAB_FixedSize=0 +CAB_ResvCodeSigning=0 +RebootMode=N +InstallPrompt=%InstallPrompt% +DisplayLicense=%DisplayLicense% +FinishMessage=%FinishMessage% +TargetName=%TargetName% +FriendlyName=%FriendlyName% +AppLaunched=%AppLaunched% +PostInstallCmd=%PostInstallCmd% +AdminQuietInstCmd=%AdminQuietInstCmd% +UserQuietInstCmd=%UserQuietInstCmd% +SourceFiles=SourceFiles +[Strings] +InstallPrompt= +DisplayLicense= +FinishMessage= +TargetName=C:\work\book\Apress\chapter 6\installCommunicator.EXE +FriendlyName=Communicator Configurator +AppLaunched=msiexec.exe /i Communicator.msi /q +PostInstallCmd=wscript.exe configure.vbs +AdminQuietInstCmd= +UserQuietInstCmd= +FILE0="Communicator.msi" +FILE1="configure.vbs" +[SourceFiles] +SourceFiles0=c:\temp\ +SourceFiles1=C:\work\book\Apress\chapter 6\ +[SourceFiles0] +%FILE0%= +[SourceFiles1] +%FILE1%= diff --git a/lcsutil.cs b/lcsutil.cs new file mode 100644 index 0000000..94e4870 --- /dev/null +++ b/lcsutil.cs @@ -0,0 +1,462 @@ +#define LIMIT + +namespace lcsutil +{ + using System; + using System.Management; + using System.Collections; + using System.Collections.Specialized; + using System.DirectoryServices; + using System.Text.RegularExpressions; + using CommandLine.Utility; + + /// + /// Summary description for BulkConfigUsers. + /// + class BulkConfigUsers + { + enum cmd {LCS, FED, REMOTE, PIC, ARCHIVE, RCC, MEETING}; + static string sQuery; + static bool LcsValue, FederationValue, RemoteAccessValue, PicValue; + private + string AppendURI = null; + string ServerDN = null; + string domainURI = null; + static string ArchiveValue = null; + + public BulkConfigUsers() + { + // string query to return instance ID of user enabled for LCS using WMI + sQuery = "select * from MSFT_SIPESUserSetting where UserDN = '"; + } + + /// + /// The main entry point for the application. + /// + [STAThread] + static int Main(string[] args) + { + if(args.Length == 0) + { + Console.WriteLine("\nNo arguments were provided."); + (new BulkConfigUsers()).Usage(); + return 0; + } + + // Bit field to store list of command operations to perform. + BitArray Op = new BitArray(7, false); + // store list of users to configure. + Array users = null; + // Active Directory group to configure. + string group = null; + // Active Directory DN to search users to configure. + string containerDN = null; + + Arguments CommandLine = new Arguments(args); + + // Instantiate class. + BulkConfigUsers BulkConfig = new BulkConfigUsers(); + + if(CommandLine["?"] != null) + { + BulkConfig.Usage(); + return 0; + } + if(CommandLine["users"] != null) + { + char[] separator = {','}; + users = CommandLine["users"].Split(separator); + } + if(CommandLine["group"] != null) + { + group = CommandLine["group"]; + Console.WriteLine("group name: '" + group+ "'"); + } + if(CommandLine["container"] != null) + { + containerDN = CommandLine["container"]; + } + if(CommandLine["append"] != null) + { + BulkConfig.SetUriAppendString(CommandLine["append"]); + } + if(CommandLine["server"] != null) + { + bool bResult = BulkConfig.SetHomeServer(CommandLine["server"]); + } + if(CommandLine["domain"] != null) + { + BulkConfig.SetDomainURI(CommandLine["domain"]); + } + if(CommandLine["lcs"] != null) + { + Op.Set((int)cmd.LCS, true); + if(CommandLine["lcs"] == "y") + LcsValue = true; + else if(CommandLine["lcs"] == "n") + LcsValue = false; + else + { + Console.WriteLine("\nMissing parameter: y | n"); + BulkConfig.Usage(); + return 0; + } + } + if(CommandLine["fed"] != null) + { + Op.Set((int)cmd.FED, true); + if(CommandLine["fed"] == "y") + FederationValue = true; + else if(CommandLine["fed"] == "n") + FederationValue = false; + else + { + Console.WriteLine("\nMissing parameter: y | n"); + BulkConfig.Usage(); + return 0; + } + } + if(CommandLine["remote"] != null) + { + Op.Set((int)cmd.REMOTE, true); + if(CommandLine["remote"] == "y") + RemoteAccessValue = true; + else if(CommandLine["remote"] == "n") + RemoteAccessValue = false; + else + { + Console.WriteLine("\nMissing parameter: y | n"); + BulkConfig.Usage(); + return 0; + } + } + if(CommandLine["pic"] != null) + { + Op.Set((int)cmd.PIC, true); + if(CommandLine["pic"] == "y") + PicValue = true; + else if(CommandLine["pic"] == "n") + PicValue = false; + else + { + Console.WriteLine("\nMissing parameter: y | n"); + BulkConfig.Usage(); + return 0; + } + } + + /// Validate command-line arguments. + if(users == null && group == null && containerDN == null) + { + Console.WriteLine("\nMissing argument: list of users, group or container name."); + BulkConfig.Usage(); + return 0; + } + + Console.WriteLine(); +#if LIMIT + int count = 0; // used only for trial version + int limit = 5; // trial version limit +#endif + + if(containerDN != null) + { + try + { + // Query all users under a container from a local GC since all SIP related + // information of users are marked for GC replication. + DirectoryEntry deContainer = new DirectoryEntry("GC://" + containerDN); + DirectorySearcher srchUsers = new DirectorySearcher(deContainer); + srchUsers.SearchScope = SearchScope.Subtree; + srchUsers.Filter = ("(&(objectCategory=person)(objectClass=user))"); + + // Find all users under an Active Directory container. + foreach(SearchResult user in srchUsers.FindAll()) + { + BulkConfig.ConfigureUser(user.Path.Substring(5), Op); +#if LIMIT + count++; + if(count > limit) + { + Console.WriteLine("You have reached the maximum usage of this trial version"); + break; + } +#endif + } + } + catch(Exception e) + { + Console.WriteLine(e.Message); + return 0; + } + return 1; + } + + DirectoryEntry deRoot = null; + + try + { + DirectoryEntry deRootDSE = new DirectoryEntry("LDAP://RootDSE"); + string sRootDomain = "LDAP://" + deRootDSE.Properties["rootDomainNamingContext"].Value.ToString(); + deRoot = new DirectoryEntry(sRootDomain); + } + catch(Exception e) + { + Console.WriteLine("Failed to query Active Directory"); + Console.WriteLine(e.Message); + return 0; + } + + if(group != null) + { + string sGroup = null; + + try + { + // Query all users members of a group from a local GC since all SIP related + // information of users are marked for GC replication. + DirectorySearcher srchGroup = new DirectorySearcher(deRoot); + srchGroup.SearchScope = SearchScope.Subtree; + srchGroup.Filter = ("(&(objectCategory=group)(name=" + group + "))"); + + // Obtain DN of group. + sGroup = srchGroup.FindOne().Path; + } + catch(Exception e) + { + Console.WriteLine(e.Message); + return 0; + } + + // Find all users member of group. + DirectoryEntry deGroup = new DirectoryEntry(sGroup); + foreach(object userDN in deGroup.Properties["member"] ) + { + BulkConfig.ConfigureUser(userDN.ToString(), Op); + count++; + if(count > limit) + { + Console.WriteLine("You have reached the maximum usage of this trial version"); + break; + } + } + } + else if(users != null) + { + foreach(string user in users) + { + string userDN = null; + try + { + DirectorySearcher srchUser = new DirectorySearcher(deRoot,"(&(objectCategory=user)(cn=" + user + "))"); + + // Obtain DN of user by removing the first 7 characters "LDAP://". + userDN = srchUser.FindOne().Path.Substring(7); + } + catch(Exception e) + { + Console.WriteLine(e.Message); + return 0; + } + + BulkConfig.ConfigureUser(userDN, Op); + count++; + if(count > limit) + { + Console.WriteLine("You have reached the maximum usage of this trial version"); + break; + } + } + } + + return 1; + } + + public bool SetHomeServer(string fqdn) + { + try + { + // Determine DN of homeserver + string sQuery = "select * from msft_sippoolsetting where PoolFQDN='"; + ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(sQuery + fqdn + "'"); + + foreach(ManagementObject mo in oSearcher.Get()) + { + ServerDN = mo["PoolDN"].ToString(); + } + return true; + } + catch(Exception e) + { + Console.WriteLine("\nUnable to query server DN: " + e.Message); + return false; + } + } + + public bool SetUriAppendString(string append) + { + AppendURI = append; + return true; + } + + public bool SetDomainURI(string domain) + { + domainURI = String.Copy(domain); + return true; + } + + public void CreateLcsAccount(string userDN, BitArray Op) + { + Console.WriteLine("create user"); + + // Use ADSI to access the user object + DirectoryEntry deUser = new DirectoryEntry("LDAP://" + userDN); + string URI = null; + + // Default is to use the email address as the user's SIP URI + // if present; otherwise, use the SAM account name + if(deUser.Properties["mail"].Value != null) + { + URI = deUser.Properties["mail"].Value.ToString(); + } + else + { + URI = deUser.Properties["samAccountName"].Value.ToString(); + } + + ManagementClass mgmtClass = new ManagementClass("root/cimv2", + "MSFT_SIPESUserSetting", new ObjectGetOptions()); + + ManagementObject oUser = mgmtClass.CreateInstance(); + oUser["UserDN"] = userDN; + oUser["DisplayName"] = null; // this attribute must be null on creation + oUser["PrimaryURI"] = "sip:" + URI; + oUser["HomeServerDN"] = ServerDN; + oUser["Enabled"] = true; + + this.Configure(oUser, Op); + } + + public void Configure(ManagementObject user, BitArray Op) + { + if(Op.Get((int)cmd.LCS)) + { + if(LcsValue == true && ServerDN == null && user["HomeServerDN"] == null) + { + // do nothing - can not enable a user for Live Communications Server + // if they are not homed on a pool + Console.WriteLine("User can not enabled for LCS without specifying a server fqdn"); + } + else + { + if(ServerDN != null) + { + user["HomeServerDN"] = ServerDN; + } + user["Enabled"] = LcsValue; + } + } + else if(Op.Get((int)cmd.REMOTE)) + { + user["EnabledForInternetAccess"] = RemoteAccessValue; + } + else if(Op.Get((int)cmd.FED)) + { + user["EnabledForFederation"] = FederationValue; + } + else if(Op.Get((int)cmd.PIC)) + { + user["PublicNetworkEnabled"] = PicValue; + } + else + { + if(domainURI != null) + { + // Modify user SIP URI domain portion if one is provided + string URI = Regex.Replace(user["PrimaryURI"].ToString(), @"@[-\w.]+", "@"+domainURI); + user["PrimaryURI"] = URI; + } + else if(AppendURI != null) + { + // Modify the user SIP URI name portion by appending + string URI = Regex.Replace(user["PrimaryURI"].ToString(), @"@", AppendURI+"@"); + user["PrimaryURI"] = URI; + } + else + { + Console.WriteLine("Invalid configuration operation requested"); + } + } + try + { + // Commit changes + user.Put(); + Console.WriteLine(user["DisplayName"].ToString() + ": success"); + } + catch(Exception e) + { + Console.WriteLine(e.Message); + Console.WriteLine(); + } + } + + public void ConfigureUser(string userDN, BitArray Op) + { + try + { + // Query for user's instance ID + ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(sQuery + userDN + "'"); + ManagementObjectCollection oCollection = oSearcher.Get(); + + Console.WriteLine(userDN); + int iCount = 0; + + foreach(ManagementObject mo in oCollection) + { + Configure(mo, Op); + iCount++; + } + + if(iCount == 0) + { + // User is not enabled for LCS; therefore, the LCS WMI provider + // does not find the user in the LCS database. + if(ServerDN != null) + { + CreateLcsAccount(userDN, Op); + } + else + { + Console.WriteLine(userDN + " can not be enabled for LCS"); + } + } + } + catch(Exception e) + { + Console.WriteLine(e.Message); + Console.WriteLine(); + } + } + + public void Usage() + { + Console.WriteLine("\nLCS Utility"); + Console.WriteLine("\ncommand-line arguments:"); + Console.WriteLine("\t/users:\t\t- list of users separated by commas"); + Console.WriteLine("\t/group:\t\t- group name"); + Console.WriteLine("\t/container:\t- DN"); + + Console.WriteLine("\n\tModifiers:"); + Console.WriteLine("\t/append:\t- append to user name portion of user's SIP URI"); + Console.WriteLine("\t/server:\t\t- server name (fqdn) to home users"); + Console.WriteLine("\t/domain:\t- modify domain portion of user's SIP URI"); + + Console.WriteLine("\n\tOperations:"); + Console.WriteLine("\t/lcs:y|n\t\t- enable or disable user for LCS"); + Console.WriteLine("\t/fed:y|n\t\t- enable or disable user for federation"); + Console.WriteLine("\t/remote:y|n\t\t- enable or disable user for remote access"); + Console.WriteLine("\t/pic:y|n\t\t- enable or disable user for public IM"); + Console.WriteLine(); + } + } +} diff --git a/lcsutil.csproj b/lcsutil.csproj new file mode 100644 index 0000000..e80fa22 --- /dev/null +++ b/lcsutil.csproj @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lcsutil.exe b/lcsutil.exe new file mode 100644 index 0000000..4511c36 Binary files /dev/null and b/lcsutil.exe differ diff --git a/sipchange.csproj b/sipchange.csproj new file mode 100644 index 0000000..ef3c40f --- /dev/null +++ b/sipchange.csproj @@ -0,0 +1,50 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {F86FEA87-E418-47F9-B458-5830027BA0D6} + Exe + Properties + sipchange + sipchange + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sipchange.exe b/sipchange.exe new file mode 100644 index 0000000..bd2e564 Binary files /dev/null and b/sipchange.exe differ diff --git a/topology handout.vsd b/topology handout.vsd new file mode 100644 index 0000000..f34f5d0 Binary files /dev/null and b/topology handout.vsd differ