At Citrix Synergy Berlin you will have the opportunity to learn specifics about how to setup your multi-forest domain with Citrix Provisioning Services 5.6 where you have the Provisioning Services infrastructure and target devices in separate forests. Learning labs will guide you through this topic and also other new features of Citrix Provisioning Services 5.6 such as vDisks updates with read-only stores. You will fall in love with its key features and to see how easy is to implement the XenDesktop’s Provisioning Services feature in your enterprise environment. Your initial step is to click on the link below and add SYN404D – Operating System delivery to desktops session to your agenda. This is a 3 hour session about the Citrix Provisioning Services and how to simplify your job.
Register for Synergy 2010 Berlin
Session: SYN404D – Operating System delivery to desktops
October 04, 9:00 am – 12:00 pm
October 05, 9:00 am – 12:00 pm
October 07, 2:00 pm – 5:00 pm
October 08, 1:00 pm – 4:00 pm
Elisabeth Teixeira
Principal Engineer - Worldwide Technical Readiness
Follow Me on twitter: @lizteixeira
Update
We have delivered the Tech Talk on Essentials for using Windows PowerShell with XenApp and XenDesktop and both the recording and presentation are now available for viewing. We also have a separate blog for the Q&A from the session.
Session Description
Learn how to simplify your XenApp and XenDesktop administration using simple but effective PowerShell scripts. This session will provide a high-level overview of the PowerShell SDK for XenDesktop 4 and XenApp 6, and will focus primarily on live demos of PowerShell scripts for automating various aspects of these environments.
Programming knowledge is not required – an administrator with a basic scripting background can leverage the knowledge gained in this session and put it to use within their own environment. We hope to see you there!
Reference Materials
Mike and I have started to put together a blog series on the XenDesktop and XenApp PowerShell SDKs to be used as reference materials for the Tech Talk. If you haven’t already seen them, feel free to check out the links below. We will be giving live demos of several of the scripts mentioned as part of these blogs.
XenDesktop 4 PowerShell SDK blog series – by Ed York
- Getting Started
- Retrieving the XenDesktop farm properties
- Creating a new desktop group
- Enabling/disabling a desktop group
- Updating the idle pool settings of a desktop group
- Adding virtual desktops to a desktop group
- Adding AD users and groups to a desktop group
- Disconnecting and stopping virtual desktop sessions
- Restarting virtual desktops and series wrap-up
XenApp 6 PowerShell SDK blog series – by Mike Bogobowicz
- Getting a XenApp Farm Inventory
- Checking XenApp Application Setting Consistency
- Checking Server Availability
About the Presenters
Ed York – Senior Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Ed on twitter: http://twitter.com/citrixedy
Mike Bogobowicz – Principal Consultant – Worldwide Consulting Solutions
Blog Site: http://community.citrix.com/blogs/citrite/michaelbog
Follow Mike on twitter: http://twitter.com/mcbogo
Thank you to all those that attended the Essentials for using Windows PowerShell with XenApp and XenDesktop Tech Talk on August 24, 2010 – we had a fantastic turnout! For those of you that missed it, both the recording and presentation have been posted.
Mike Bogobowicz and I co-presented this session where I led the XenDesktop PowerShell SDK side, and Mike let the XenApp PowerShell SDK side. This blog will focus on just the XenDesktop SDK questions that came from the session. Mike will have a separate blog post on the XenApp SDK questions.
XenDesktop SDK Q&A
Here’s the list of questions we received specific to the XenDesktop PowerShell SDK. In no particular order:
Q: Are you going to post the scripts you used in today’s session?
A: All the scripts we demonstrated are contained in the blog series that was posted prior to the session. You can find links to the blog series at the bottom of this article.
Q: What does “DDC” mean?
A: First, this is a great question!! If you are a XenApp admin that hasn’t touched XenDesktop, DDC is a brand new term. DDC stands for Desktop Delivery Controller. It is the component of XenDesktop 4 that brokers virtual desktops to end-users, much like how the XenApp Zone Data Collector (ZDC) brokers published applications to end-users.
Q: This looks a lot like the PowerShell SDK for XenServer, just different commands. Is it similiar?
A: Yes, I believe Engineering made the PowerShell SDKs for XenServer, XenDesktop, and XenApp similar in structure on purpose. In that way, once you learn one, learning the others will be much simpler.
Q: The 4th XenDesktop PowerShell script from the Tech Talk showed how to shut down a single virtual desktop session. How would you modify this script to interact with an entire Desktop Group or multiple users?
A: The key here is to play with the parameters of the Get-XdSession cmdlet. If you provide the -User parameter, you can get specific user sessions. If you provide the -Group parameter, you can get all sessions from a particular desktop group. If you don’t include either of these parameters, you’ll get back all sessions across the entire farm. To get started, I would encourage you to check out the full help details for this cmdlet.
Get-Help Get-XdSession -Full
Q: With the virtual desktop session shutdown script, is there a way to allow the user to prevent the shutdown?
A: I don’t believe so. Once you call the Stop-XdSession cmdlet to shut down the session, it’s going to perform an immediate shutdown of that virtual desktop. That’s why in the demo I mentioned sending a warning message to the user to give them a heads up of the shut down, perhaps 10 to 30 minutes prior for them to save their work.
Q: Do we need to provide some credential (i.e. username/password) in order to be able to run the PowerShell script from a remote domain machine?
A: You can execute all of the scripts I’m providing in the blog series from a remote domain machine. I did some additional research on this and it looks like your logged on account to that remote machine needs to be both a XenDesktop admin and have access to the XenDesktop database. This would make sense from a security perspective to not allow any domain user to manipulate your farm. So the security is performed with your logged on machine account. We don’t need to pass a XenDesktop credential to the XenDesktop cmdlets.
Q: Can you create a desktop group in a specific folder?
A: I checked the New-XdDesktopGroup cmdlet that is used for creating a new desktop group and I couldn’t find a parameter for specifying a folder as part of the desktop group creation process. It does appear, however, we can move a desktop group to a new folder immediately after it’s been created. You would use commands like below:
#************************************************************ #Move desktop group to a different folder #************************************************************ #Add the XenDesktop snap-in to the current Powershell session Add-PSSnapin "XdCommands" #Set up variables for the script $strDDCAddress = "10.10.10.56" $strDesktopGroupName = "Windows XP" $strTargetFolderName = "Folder1" #Get the target XenDesktop folder $xdfolder = Get-XdFolder -Name $strTargetFolderName -AdminAddress $strDDCAddress #Get a particular desktop group $xdgroup = Get-XdDesktopGroup -Name $strDesktopGroupName -AdminAddress $strDDCAddress -HostingDetails #Display the current folder assignment for the desktop group echo $xdgroup.Folder #Change the folder assignment for the desktop group $xdgroup.Folder = $xdfolder #Apply the change to the DDC Set-XdDesktopGroup $xdgroup #Verify the update echo $xdgroup.Folder
Q. Is it possible to enable the “User-driven desktop restart” setting for a desktop group as part of creating the desktop group with PowerShell?
A. Just as with the last question, I checked the New-XdDesktopGroup cmdlet for creating a new desktop group and couldn’t find a way to enable this setting as part of executing that command. However, you can enable this setting immediately after creating the new desktop group. You would use commands like below:
#************************************************************************************* #Enable "User-driven desktop restart" setting for a desktop group #************************************************************************************* #Add the XenDesktop snap-in to the current Powershell session Add-PSSnapin "XdCommands" #Set up variables for the script $strDDCAddress = "10.10.10.56" $strDesktopGroupName = "Windows XP" #Get a particular desktop group $xdgroup = Get-XdDesktopGroup -Name $strDesktopGroupName -AdminAddress $strDDCAddress -HostingDetails #Enable user-drive desktop restart $xdgroup.AllowUserDesktopRestart = $true #Apply the change to the DDC Set-XdDesktopGroup $xdgroup #Verify the update echo $xdgroup.AllowUserDesktopRestart
Q: If you have multiple DDCs, do you have to specify each, or just the master DDC to run against?
A: In a multiple DDC environment, if you point your scripts to the “master” DDC you should be fine. My XenDesktop farm only has one DDC so I can’t verify this one, but I’m thinking you might be able to point the scripts to any of the DDCs in the farm. If someone has a larger farm out there that can verify for us, please post a note at the bottom. Essentially, check out the scripts from the blog series and look for the -AdminAddress parameter I’ve been using for several of the XenDesktop cmdlets. If you have multiple DDCs, experiment putting the different IP addresses for that parameter and see if the script runs fine against each DDC in the farm.
Q: How can you check for disconnected sessions? Can you tell how long they’ve been disconnected?
A: The code snippet below explains how to get all the disconnected sessions for the XenDesktop farm. It looks like the properties of the $xdsession object will tell you the start time of the session, but not when it was disconnected.
#***************************************************************** #Checking for disconnected virtual desktop sessions #***************************************************************** #Add the XenDesktop snap-in to the current Powershell session Add-PSSnapin "XdCommands" #Set up variables for the script $strDDCAddress = "10.10.10.56" #Get all disconnected sessions for the XenDesktop farm $xdsession = Get-XdSession -AdminAddress $strDDCAddress -SessionDetails | where { $_.State -eq "Disconnected" } #Display the disconnected sessions echo $xdsession
Q: Can you monitor what is happening on the virtual desktop through PowerShell?? Or interact with a specific session (SendKeys style)?
A: The XenDesktop SDK doesn’t provide much in way of getting the details inside the session. In the Tech Talk, I demo’d how you can send messages to the session. You can also get some attributes for the session such as the client name and client IP that launched it. This blog goes into some of that. You can probably run other types of PowerShell scripts from within the virtual desktop session to get some additional metrics or details. Plus, there’s Citrix EdgeSight as well to have an agent running on the virtual desktop to collect performance metrics and other details!
Q: When doing an automated desktop deployment using MDT or other image deployment tool, what is the best way to have the desktop imported into it’s appropriate Desktop Group as part of the post install task sequence? These desktops are not pre-staged in AD and would prefer not to have the SDK installed on each VM. Can it execute a script on a remote server to do the import?
A: The XenDesktop PowerShell scripts do not need to be executed on the virtual desktops nor the DDC for that matter. They can be executed from any domain machine that can reach the DDC. You can use this blog for a sample script on adding virtual desktops to a desktop group. As part of your MDT automation process, you are going to want to install the virtual desktop agent (VDA) software on the virtual desktops prior to adding them to the desktop group. You’ll also want these machines added to your domain prior as well.
Q: Is it possible to create an advanced presentation for those comfortable with PowerShell and SDKs?
A: This is something that we’ve been discussing for a bit. Now that we have laid out the groundwork for the XenDesktop 4 SDK Primer, we can now think about adding in some more complex scripts to build on top of that knowledge. If you are experienced with the XenDesktop SDK and have some suggestions for what you would like to see, please post a comment below. For the more complex stuff, it’s always good to have a goal in mind for something practical that is needed out in the field.
Q: Do you cover VMware as a hypervisor in your blogs?
A: I didn’t cover VMware specifically, but the scripts I provided in the Tech Talk and blogs should also work with a VMware ESX host. If you are using VMware ESX to host virtual desktops, you are still considered to be using a VM-based desktop group. In the blogs I created, they were focused on interacting with VM-based desktop groups with XenServer as the host. My understanding is that the syntax should be very close if not identical. If anyone has used the XenDesktop PowerShell SDK for a VMware host, feel free to provide a comment at the bottom regarding your experience. Were the commands pretty much the same? Did you find any differences with using the SDK compared to my scripts with a XenServer host?
Tech Talk Resources
As a reminder, we based the Tech Talk on the blog series we posted prior to the session. You can find all the sample scripts we demonstrated in the Tech Talk within these blogs.
XenDesktop 4 PowerShell SDK Primer blog series – by Ed York
- Getting Started
- Retrieving the XenDesktop farm properties
- Creating a new desktop group
- Enabling/disabling a desktop group
- Updating the idle pool settings of a desktop group
- Adding virtual desktops to a desktop group
- Adding AD users and groups to a desktop group
- Disconnecting and stopping virtual desktop sessions
- Restarting virtual desktops and series wrap-up
XenApp 6 PowerShell SDK blog series – by Mike Bogobowicz
- Getting a XenApp Farm Inventory
- Checking XenApp Application Setting Consistency
- Checking Server Availability
About the Presenters
Ed York – Senior Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Ed on twitter: http://twitter.com/citrixedy
Mike Bogobowicz – Principal Consultant – Worldwide Consulting Solutions
Blog Site: http://community.citrix.com/blogs/citrite/michaelbog
Follow Mike on twitter: http://twitter.com/mcbogo
Have you thought about charging your “customers” for IT services you are providing? I bet you have and I thought about that model for quite some time.
The promise of cloud computing, virtualization, usage metering, and IT as a Service often spawn the thoughts of billing the end customer, i.e. business units in a corporation. This is a world where super flexible infrastructure can flip the switch on applications, server workloads, entire desktops and user accounts in a heart beat.
Niel Nicholaisen writes about the topic in this article?
Let me add a few of my own thoughts:
• IT departments can count on (or hope for) a small percentage of a company’s annual revenues as a budget for capex and opex. IT is asked to provide literally the entire workspace and infrastructure for all users and often has to do more with less compared to the previous year. In the healthcare industry, that number stands at roughly 3% of revenues in the US and only about 2% in Europe.
• IT departments often get frustrated, because they have to provide expensive and complicated applications to a handful of users that chew up a large portion of resources and expenditures to do so.
• With the dawn of desktop and broader application virtualization, IT departments are tempted to charge for their services on a per user or per application basis. $30 per month for a desktop, $20 per month for Internet access, $5 per month for anti virus, etc.
• The model is obviously tempting for two reasons: It discourages the use of complex and expensive applications and brings the true cost of computing back to the business and it also holds the promise of increasing the IT budget linearly with the services that are provided.
However, as Niel points out, this can alienate the users. First of all, as a user I may find that I get really shoddy service for the $70 per month or so for basic services per user. As a business, I don’t have the choice to go get my Internet access or email service from someplace else . Sometimes (as a business) I think I can, and I may go to a cloud-based email service or attempt to buy my own backup service, but all of that comes at the cost of increasing complexity and introducing expensive integration points.
Keep in mind that IT is just another corporate service. I am not getting charged for payroll processing, legal support, marketing support, etc. Larger companies tend to cross charge for internal consulting services and sometimes for recruiting activities, but that’s pretty much it.
So, here is my recommendation for IT: Go ahead and charge your business units. Be aware of the pushback this may generate. In order to prevent backlash, do the following:
• Be the best in the industry. That’s right. Users will be tempted to compare the service you are providing (at the price you are charging) to consumer-grade services that are available online and that are provided by much larger organizations with better economies of scale. The expectation for the quality of your service goes up as you start charging for it.
• Virtualize applications and desktops. This will not only centralize the data, but make cost more transparent and predictable. If you do this right, you can reduce costs. If you don’t, you can end up driving up your costs, so choose wisely.
• Consider using third party, cloud based services for certain types of apps. Just because you managed something in-house in the past, doesn’t mean that this is the best modality going forward. CRM and web hosting services are examples of apps that have been pushed (or elevated) to the cloud for a while now in the industry.
• Monitor your resource use and utilization to get a grip on the human cost of environment support. The smaller your organization, the more difficult this is going to be. After all, you can’t hire a fraction of a SQL Administrator.
• Ensure that you explain (via your executives) that you have much higher data availability and reliability standards to meet than any publicly available service and that the company is required to provide the services internally to maintain control and ensure compliance.
• Consider implementing a “Bring Your Own Computer” model. We’ve had it at my employer for a while and it’s great. I own the endpoint, and I can manage my computer just fine, thank you very much. I can now have my own desktop, anti-virus, and other consumer grade services to dabble around and get a corporate Windows 7 image (a virtual desktop) from IT with the key apps I need to do my work.
• Expect to get charged by your accountants for the support they may need to lend to you as part of this process ![]()
Questions? Comments? Let me know what you think and how you have been managing the cost of providing IT services.
Florian Becker
Twitter: @florianbecker
Virtualization Pulse: Tech Target Blog
Ask the Architect – Everything Healthcare
The last task that we’ll discuss in this blog series is how to automate the restarting (rebooting) of virtual desktops within XenDesktop. I’ve provided two different scripts in this article – one for restarting a single virtual desktop, the second for restarting multiple virtual desktops at the same time. As you’ll find in the scripts, they look almost identical, making this one of the more easier actions to perform.
This is the 9th and final blog in a series on how to use the XenDesktop 4 PowerShell SDK. In the first blog, I provided info on how to set up your XenDesktop PowerShell environment so that you could run these scripts. If you haven’t done that yet, please visit that article first. In the last blog, I discussed how you can disconnect and stop virtual desktop sessions using PowerShell. For a complete list of topics that I have covered in this blog series, see the bottom of this article.
PowerShell script for restarting a single virtual desktop
The sample script below demonstrates how to restart a single virtual desktop in the XenDesktop farm. Please note the two options provided here for retrieving a reference to the virtual desktop.
#************************************************************ #Restart a single virtual desktop #************************************************************ #Add the XenDesktop snap-in to the current PowerShell session Add-PSSnapin "XdCommands" #Set up variables for the script $strDDCAddress = "10.10.10.56" $strDesktopADName = "xpvda1" #Active Directory machine name $strDesktopVMName = "WINXP_XD4_VDA1" #Virtual Machine name #Option 1 - retrieve a particular virtual desktop by Active Directory machine name $desktop = Get-XdVirtualDesktop -AdminAddress $strDDCAddress -HostingDetails | where { $_.Name -match $strDesktopADName } #Option 2 - retrieve a particular virtual desktop by Virtual Machine name $desktop = Get-XdVirtualDesktop -AdminAddress $strDDCAddress -HostingDetails | where { $_.HostingName -match $strDesktopVMName } #Restart the virtual desktop Restart-XdVirtualDesktop -force -desktop $desktop
PowerShell script for restarting all virtual desktops from a desktop group
The sample script below demonstrates how to restart all virtual desktops for a desktop group at the same time.
#************************************************************ #Restart all virtual desktops in a desktop group #************************************************************ #Add the XenDesktop snap-in to the current PowerShell session Add-PSSnapin "XdCommands" #Set up variables for the script $strDDCAddress = "10.10.10.56" $strDesktopGroupName = "Windows XP" #Retrieve all virtual desktops within a desktop group $desktops = Get-XdVirtualDesktop -AdminAddress $strDDCAddress -Group $strDesktopGroupName -HostingDetails #Restart all virtual desktops within the group that are currently powered on Restart-XdVirtualDesktop -force -desktop $desktops
Analyzing the PowerShell Scripts
Both scripts above are almost identical so we’ll discuss them at the same time. The Get-XdVirtualDesktop cmdlet is used to get a reference to one or more virtual desktops. If you view the help on this cmdlet, you’ll find that it provides various switches (-Registered, -Unregistered, -Group) for performing filtering on the virtual desktops that are returned.
In the first script above, I provided two different ways for getting a reference to a single virtual desktop. The first approach looks for the virtual desktop based on the Active Directory machine name. The second approach looks for the virtual desktop based on the Virtual Machine name. You don’t need both of those statements in the script – I just provided both as it could help understand the cmdlet statement better. Feel free to experiment with them to find which works best for you.
The Get-XdVirtualDesktop cmdlet returns a XdVirtualDesktop object (or an array of them if there is more than one returned). You pass this object as a parameter to the Restart-XdVirtualDesktop cmdlet and that’s it! All the specified virtual desktops will be restarted (if they were already running).
Wrap-up
The blog series is now done! If you found the info within this series valuable or if would like to see some particular things on the XenDesktop PowerShell SDK in the future, feel free leave a comment. Be sure to also sign up for the TechTalk we are delivering on Tuesday, August 24 where you can see several of these PowerShell scripts in action!
Upcoming TechTalk
I will be leading a TechTalk with Mike Bogobowicz on Essentials for using Windows PowerShell with XenApp and XenDesktop on Tuesday, August 24 from 2pm to 3pm EST. If you interesting in learning more about these SDKs first hand and want to see the demos in action, you can sign up here. Feel free to also check out Mike’s blog on XenApp 6 PowerShell scripting here. We hope to see you at the TechTalk!
Blogs in this series
- Getting Started
- Retrieving the XenDesktop farm properties
- Creating a new desktop group
- Enabling/disabling a desktop group
- Updating the idle pool settings of a desktop group
- Adding virtual desktops to a desktop group
- Adding AD users and groups to a desktop group
- Disconnecting and stopping virtual desktop sessions
- Restarting virtual desktops and series wrap-up (this one)
Ed York – Senior Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Me on twitter: http://twitter.com/citrixedy
As part of my involvement with the Ask the Architect program, I try to venture out into our various Citrix SDKs from time to time to gain an understanding on what we are capable of automating. The XenDesktop 4 PowerShell SDK is something I’ve had on my list for some time to tackle. After all, XenDesktop is a huge focus of the company, PowerShell is the new de facto standard for scripting languages, and the blending of them together can have a huge impact on simplifying administration in a big way.
When I first started to learn the XenDesktop SDK, I didn’t realize that there was actually quite a bit already written about the topic. Many of you may have seen Christian Gehring’s blog on the XenDekstop 2.1 PowerShell SDK. He provides a great summary and some sample scripts for getting started. Paul Wilson also has some recent blogs on creating PowerShell scripts for a Hyper-V/XenDesktop environment.
So why the need for a new blog series? I think there is still quite a bit we can discuss and explore with the XenDesktop SDK. How many of you are XenDesktop admins that have a need for automating various configurations within the environment but you don’t have a background in PowerShell to get started? Or how many of you have seen some sample scripts, but are not quite sure how to customize them to fit your own needs? I’m going to take a different approach with this blog series to not restate what has already been stated, but to provide topics that can benefit those both new to PowerShell and those that already have had some experience with the XenDesktop SDK. In particular, the goals I have for this blog series are as follows:
- Demonstrate XenDesktop PowerShell scripts that can be executed on both the Desktop Delivery Controller (DDC) as well as any other domain member machine
- Provide additional insights on what the scripts are doing so that any XenDesktop admin can learn how to create their own scripts or modify the supplied scripts to suit their own environments
- Provide reference materials for the upcoming TechTalk that I will be delivering on August 24 on how to use the XenDesktop 4 PowerShell SDK. I will be co-hosting this TechTalk with Mike Bogobowicz and we will cover the essentials on the XenApp and XenDesktop PowerShell SDKs.
PowerShell Overview
In this day and age, most of us have heard about PowerShell. We may not have all used it directly before, but it’s something that we see pop up quite a bit on product installations. Both XenDesktop (all versions) and XenApp 6 use PowerShell as their SDK for automating configurations. Citrix Workflow Studio is heavily dependent on PowerShell for the core of how it executes workflows. Microsoft (who creates PowerShell) provides their own PowerShell commands for most (if not all) of their latest products. PowerShell is also pre-installed with Windows Server 2008 and Windows 7. A separate installer is available for earlier Windows operating systems such as Windows Server 2003 and Windows XP.
Essentially, PowerShell can be thought of as an object-oriented scripting language. Let’s break that statement down really quick.
- First – it’s a scripting language. Like other scripting languages before it (e.g. VBScript), you can create a custom script file that contains a series of PowerShell commands and the commands are executed from the top to the bottom much like how a book page or movie script is read. The key thing about scripting languages and what differentiates them from the core .NET languages (C#, VB.NET, etc.) is that they are not pre-compiled before they are executed. With a standard Windows program, you compile your source code into a binary file (EXE or DLL) first before you execute it. Compiled code can run faster than a non-compiled program since the instructions have already been translated into code that the OS can understand better. To summarize, PowerShell scripts are executed completely at run time, from the top to the bottom, much like how our older VBScripts run.
- Second – it’s an objected oriented language. As you will soon see in this blog series, many of the XenDesktop PowerShell commands (called cmdlets) will retrieve a configuration from XenDesktop and return it to you as an object. You can define your own variables to store this object within memory. Once you have the object stored inside a variable, you are free to view the properties of the object or call its methods. You can also use this object as a parameter into another PowerShell cmdlet. Being able to natively use and manipulate objects as part of a PowerShell script really simplifies the complexity and length of the script. This concept will be repeated over and over again in all of the scripts that we discuss in this blog series.
Getting Started with the XenDesktop 4 PowerShell SDK
So we know a little bit more about PowerShell, how do we get started with the XenDesktop 4 PowerShell SDK? The cool thing about this SDK is that you can execute XenDesktop PowerShell scripts from any domain member machine, not just the Desktop Delivery Controller (DDC). As long as your machine resides on the same domain as the DDC and the DDC is reachable, the scripts will run just fine. In fact, all of the scripts that I will share as part of this blog series were built and executed on a generic Windows Server 2003 domain member that had no other XenDesktop components on it other than the PowerShell SDK.
1. Determine which machine you want to run your scripts from. For me, the real choice was to either run on the DDC or run on another domain member machine. I chose a general domain member since I know that any script I produce there will also run on the DDC just fine. FYI – I’m finding that many of the XenDesktop scripts that have already been posted to the web will only run on the DDC in their current form. Just keep that in mind as you review the scripts.
2. Install the prereqs for the SDK (PowerShell 1.0 and the .NET Framework 3.5). The .NET Framework 3.5 can be found on the XenDesktop installation media. Powershell 1.0 can be found as a free download from the web here.
3. Insert the XenDesktop 4 installation media (ISO or CD) and select to install the Desktop Delivery Controller SDK. It’s a very simple install, just click Next through a few dialogs.
4. Launch PowerShell. There’s a couple ways you can open the PowerShell prompt to start writing your own XenDesktop scripts:
- Open the Desktop Delivery Controller SDK Shell from the Start window. – from the Start Window, if you navigate to All Programs –> Citrix –> Desktop Delivery Controller SDK –> Citrix Desktop Delivery Controller SDK Shell, a special PowerShell window will open that already contains the XenDesktop PowerShell snap-in pre-loaded. You can start using the XenDesktop cmdlets right away within this window.
- Open a generic PowerShell window and add the XenDesktop PowerShell snap-in manually. – I don’t know exactly why, but this is the route I always choose. Maybe it’s the feeling I have more control over my entire session. With this option, open a generic PowerShell window by navigating to All Programs –> Windows PowerShell 1.0 –> Windows PowerShell. At the PowerShell prompt, type the following command to load the XenDesktop PowerShell snap-in.
Add-PSSnapin "XdCommands"
No matter which of these options you choose, PowerShell needs to be allowed to execute scripts in order for the Add-PSSnapin “XdCommands” command to execute correctly. If you perform either of the above options and see some error messages, it mostly likely means that PowerShell has its execution policy set to Restricted. To get the current PowerShell execution policy, type the following command:
Get-ExecutionPolicy
If the above command returns Restricted, we need to relax the policy to something like RemoteSigned. Type the following command:
Set-ExecutionPolicy "RemoteSigned"
5. View the available XenDesktop cmdlets within PowerShell. At the PowerShell prompt, type the following command:
Get-Command -PSSnapin "XdCommands"
6. View the help on a specific XenDesktop cmdlet. For example, to get the details of the Get-XdFarm cmdlet, type one of the commands below. Notice that you can include an extra switch called -full to provide even more detail about the cmdlet. I would definitely recommend doing that when you start out. The pound symbol # just represents a comment. Statements with a leading # are ignored.
#Provide basic data about the cmdlet Get-Help Get-XdFarm #Provide comprehensive data about the cmdlet, including full parameter descriptions and sample scripts Get-Help Get-XdFarm -Full
In the next blog, we’ll take this to the next level and actually start to use the cmdlets to retrieve back information from the XenDesktop farm. Stay tuned!
Available Resources
I mentioned in the sections above about some existing resources on the XenDesktop PowerShell SDK. Whenever you get started with a new SDK, it’s always good to know what is already out there for you to leverage. If I missed any resources, feel free to post a comment and I’ll be sure to update my list…
- XenDesktop PowerShell SDK Download
- XenDesktop PowerShell SDK Support Forum
- XenDesktop 2.1 PowerShell SDK blog – Christian Gehring
- XenDesktop and Hyper-V PowerShell Scripts – Paul Wilson
Upcoming TechTalk
I will be leading a TechTalk with Mike Bogobowicz on Essentials for using Windows PowerShell with XenApp and XenDesktop on Tuesday, August 24 from 2pm to 3pm EST. If you interesting in learning more about these SDKs first hand and want to see the demos in action, you can sign up here. We hope to see you there!
Blogs in this series
I have a lot of blogs planned for this series, and my hope is to complete all of them prior to the TechTalk. Stay tuned for more blogs in this series coming very soon!
- Getting Started (this one)
- Retrieving the XenDesktop farm properties
- Creating a new desktop group
- Enabling/disabling a desktop group
- Updating the idle pool settings of a desktop group
- Adding virtual desktops to a desktop group
- Adding AD users and groups to a desktop group
- Disconnecting and stopping virtual desktop sessions
- Restarting virtual desktops and series wrap-up
Ed York – Senior Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Me on twitter: http://twitter.com/citrixedy
In another blog, I discussed Windows 7 services that you might wish to disable when going down the path of desktop virtualization. In this article, I’m now focusing on registry modification you will want to make to optimize Windows 7 for virtual desktops. I’ve broken it down into Recommended configurations, Standard Mode configurations (for Provisioning services), and Optional configurations.
As I learn more from upcoming Windows 7 implementations, I’ll be updating the following tables, so it might be worthwhile to stay updated with RSS or subscribe via Email. Now, for the good stuff…
Recommended Configurations
The following registry changes are recommended for all deployment scenarios and would almost always be desirable in a Windows 7 hosted VM-based VDI desktop implementation:
| Configuration | Optimizer | Registry Modification (in REG format) |
| Disable Last Access Timestamp | Yes | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem] “NtfsDisableLastAccessUpdate”=dword:00000001 |
| Disable Large Send Offload | No | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BNNS\Parameters] “EnableOffload”=dword:00000000 |
| Disable TCP/IP Offload | No | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] “DisableTaskOffload”=dword:00000001 |
| Increase Service Startup Timeout | No | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control] “ServicesPipeTimeout”=dword:0002bf20 |
| Hide Hard Error Messages | No | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows] “ErrorMode”=dword:00000002 |
| Disable CIFS Change Notifications | No | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer] “NoRemoteRecursiveEvents”=dword:00000001 |
| Disable Logon Screensaver | No | [HKEY_USERS\.DEFAULT\Control Panel\Desktop] “ScreenSaveActive”=”0″ |
Note: The Optimizer column indicates whether this registry change is included in the XenConvert Optimizer tool that is installed with the Provisioning Services target device software.
Standard Mode Recommended Configurations
The next set of registry changes are recommended for images deployed using standard mode vDisk images with Citrix Provisioning services. Standard mode images are unique in that they are restored to the original state at each reboot, deleting any newly written or modified data. In this scenario, certain processes are no longer efficient. These configurations may also apply when deploying persistent images and in many cases should be implemented in addition to the changes recommended in the preceding section.
| Configuration | Optimizer | Registry Modification (in REG format) |
| Disable Clear Page File at Shutdown | Yes | HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management] “ClearPageFileAtShutdown”=dword:00000000 |
| Disable Offline Files | Yes | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\NetCache] “Enabled”=dword:00000000 |
| Disable Background Defragmentation | Yes | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Dfrg\BootOptimizeFunction] “Enable”=”N” |
| Disable Background Layout Service | Yes | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\OptimalLayout] “EnableAutoLayout”=dword:00000000 |
| Disable Bug Check Memory Dump | Yes | [HKLM\SYSTEM\CurrentControlSet\Control\CrashControl] “CrashDumpEnabled”=dword:00000000 “LogEvent”=dword:00000000″ SendAlert”=dword:00000000 |
| Disable System Restore | Yes | [Software\Policies\Microsoft\Windows NT\SystemRestore] “DisableSR”=dword:00000001 |
| Disable Hibernation | Yes | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Power] “Heuristics”=hex:05,00,00,00,00,01,00,00,00,00,00,00,00,00,00,00,3f,42,0f,00 |
| Disable Memory Dumps | Yes | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CrashControl] “CrashDumpEnabled”=dword:00000000 “LogEvent”=dword:00000000 “SendAlert”=dword:00000000 |
| Disable Mach. Acct. Password Changes | Yes | [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters] “DisablePasswordChange”=dword:00000001 |
| Redirect Event Logs | No | Set appropriate path based on environment.HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\Application] “File”=”D:\EventLogs\Application.evtx” [HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\Security] “File”=”D:\EventLogs\Security.evtx” [HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\System] “File”=”D:\EventLogs\System.evtx” |
| Reduce Event Log Size to 64K | Yes | HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\Application] “MaxSize”=dword:00010000 [HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\Security] “MaxSize”=dword:00010000 [HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\System] “MaxSize”=dword:00010000 |
Optional Configurations
This last set of machine-based registry changes is optional regardless of whether the image is deployed as a persistent or standard image. In many cases, the following configurations should be implemented; however, these configurations should be analyzed for suitability to each unique environment.
| Configuration | Justification | Registry Modification (in REG format) |
| Disable Move to Recycle Bin | Although the recycle bin will be deleted on subsequent reboots, disabling this service altogether might pose a risk in that users will not be able to recover files during their session. Although this setting is part of the optimizer, it might be advantageous to not disable the Recycle Bin. | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\BitBucket] “UseGlobalSettings”=dword:00000001 “NukeOnDelete”=dword:00000001 |
Note: These are only recommendations. You should implement these at your own risk
Remember, you can stay current with this and other Windows 7 virtual desktop recommendations via the Virtualize My Desktop – Windows 7 site.
Daniel
Lead Architect – Worldwide Consulting Solutions
Follow Me on twitter: @djfeller
My Blog: Virtualize My Desktop
Questions, then email Ask The Architect

Speed. More speed. And to get more speed with desktop virtualization, we hear more and more about how important IOPS are to being able to support the virtual desktop. Not enough IOPS means slowness. No speed. I’ve had a few blogs about it and plan to have a few more. What I wanted to talk about was an interesting discussion I recently had with 3 Senior Architects within Citrix Consulting(Doug Demskis, Dan Allen and Nick Rintalan). There are 3 smart guys who I talk to fairly regularly and the discussions get quite interesting.
This particular discussion was no different. We were talking about the importance of IOPS, RAID configs, spindle speeds with regards to an enterprise’s SAN infrastructure. (Deciding if you are going to use a SAN for your virtual desktops is a completely different discussion that I’ve had before and Brian Madden had more recently). But for the sake of this article, let’s say you’ve decided “Yes, I will use my SAN.” If your organization already has an enterprise SAN solution, chances are that the solution has controllers with plenty of cache. Does this make the IOPS discussion a moot point? If we simply use an IOPS calculator (at least the ones I’ve seen) and do not take into account the caching capabilities of the SAN controllers, won’t we over-provision our virtual desktop environment and end up wasting more money/resources?
Many of us who are familiar with XenDesktop knows that changes made to the golden disk image, when delivered via Provisioning services, is stored in a PVS Write Cache. From numerous tests and implementations, we know that 80-90% of the IO activity from a virtual desktop will be writes. If we configure the SAN Controllers to be 75% write (assuming we have battery-backed write cache controllers), we allow the controllers to allocate more cache for write operations, thus helping to offload the write IO to the disk, which raises the number of effective IOPS the storage infrastructure can support. Think of the controller’s caching capabilities as a large buffer for our disks. If our disks can only support so many write operations, the controller cache stores the writes until the disk is able to write it to the platter. This cache allows the infrastructure to keep moving forward with new operations even though the previous operations were not written to the disk yet. They are all buffered. Just remember, we aren’t reducing the total number of IO operations, we are just buffering them with the controller cache.
Think about it another way. If we encounter a storm where each user will require 10MB of write operations and the storage controller has a 4GB cache, that one controller can support 400+ simultaneous users for this particular storm, and we haven’t even talked about the disk IOPS yet!!! With this scenario, wouldn’t a single disk spindle be able to support this particular storm because the controller is buffering everything? And what’s also interesting is those write operations are being flushed to disk continuously so the number of users the controller will be able to support would be much, much higher.
So if we have cache on our controllers, which most SAN controllers I’ve seen lately have, are we over designing the storage infrastructure by only focusing on IOPS? (this is assuming you are using SAN and not local disks on your hypervisor which I talk about a lot as well). Just remember that those write operations must eventually get written to disk. So if we know what our controller cache is capable of, and we know the amount of storage required for a particular storm (logon, boot, logoff, etc), can’t we support more users (and I mean a lot more users) on the SAN?
What do you think?
Daniel – Lead Architect – Worldwide Consulting Solutions
Follow Me on twitter: @djfeller
My Blog: Virtualize My Desktop
Questions, then email Ask The Architect
It almost sounds like I’m talking about personal finances. You better plan your cache appropriately or you will run out. I’m not talking about money; I’m talking about system memory (although if you plan poorly we will quickly be talking about money).
It comes down to this… system cache is a powerful feature allowing a server to service requests extremely fast because instead of accessing disks, blocks of data are retrieved from RAM. Provisioning services relies on fast access to the blocks within the disk image (vDisk) to stream to the target devices. The faster the requests are serviced, the faster the target will receive. Allocating the largest possible size for the system cache should allow Provisioning services to store more of the vDisk into RAM as opposed to going to the physical disk.
Not planning system cache appropriately is the 8th mistake made when deploying virtual desktops
10. Not calculating user bandwidth requirements
9. Not considering the user profile
8. Lack of Application Virtualization Strategy
7. Improper Resource Allocation
5. Managing the incoming storm
4. Not Optimizing the Desktop Image
Unfortunately, many environments are not configured optimally. Simply adding RAM to a Provisioning services server is not enough; the system must be configured appropriately.
| Parameter |
Description |
|---|---|
| Operating System |
The operating system plays a large role in how large the system cache can become. * Windows Server 2003/2008 x32: 960 MB * Windows Server 2003/2008/2008 R2 x64: 1 TB Because the 64 bit operating system can have a larger system cache, a larger portion of the vDisk can be stored in RAM, which is recommended. Windows 2008 is recommended over 2003 because of the improvements in the memory manager subsystem, which has shown some improvements. |
| RAM | 8-32GB of RAM The more RAM allocated for the server, the larger the system cache can become. The larger the cache means vDisks reads will be faster. If you have more vDisks, you will need more RAM. A quick estimate is to plan for 2GB of RAM/Cache for each vDisk you will host. If you want more details, then I recommend the great article: Advanced Memory and Storage Considerations for Provisioning Servicescreated by Dan Allen (Sr. Architect at Citrix). It goes into the details of how Windows deals with cache. |
| vDisk Storage |
The vDisk can be stored on just about any type of storage (iSCSI, Fiber, local, NFS, CIFS, etc). However, there are a few instances where the storage selected will have an impact on how the Provisioning services server’s operating system caches the vDisk blocks. 1. Network Drive: If the Provisioning services server sees the vDisk drive as a network drive via a UNC path, the server will not cache the file. 2. CIFS Share: If the storage infrastructure is a network CIFS share, Provisioning services will not cache the vDisk in memory. |
| Optimizations | In Windows Server 2003, large system cache must be enabled by configuring the server’s performance options, which is shown in the figure to the right. ![]() In Windows Server 2008, this setting is not required due to the enhancements in the memory allocation system. Windows 2008 utilizes a dynamic kernel memory assignment that reallocates portions of memory on-the-fly, while previous versions had these values hard set during startup. As Windows 2008 requires more system cache, the operating system will dynamically allocate. |
Daniel – Lead Architect – Worldwide Consulting Solutions
Follow Me on twitter: @djfeller
My Blog: Virtualize My Desktop
Questions, then email Ask The Architect
Have you ever had a need to generate a large number of user accounts within Active Directory and didn’t have the time to manually create them? If you are in the business of building test environments or training environments, this scenario may have happenned to you more than once in your career.
In a recent project, we had a need to create 600+ user accounts within our Active Directory domain to support a training class. I took the challenge of producing a simple and intuitive utilty that could do it for us, since I could probably code such an application much quicker than I could manually create the accounts. The end-result is the Active Directory User Creation Utility that I’m providing as part of this article. I figured others could use this as well so I wanted to provide this as a free download. The download is at the bottom of this article – feel free to give it a spin and let me know what you think. For those programmers out there that are just looking to understand how this utility was built, I’ve also provided the full source code as a separate download at the bottom of this article as well.
Launch and configure the utility
Double-click the CreateADUsers.exe file from the downloaded ZIP file to launch the utility. This application can be run from any domain member, it doesn’t have to be run on the Domain Controller. I believe the only requirements for use are that you should log onto your machine as a domain user that has rights to create objects within Active Directory. Your machine should also have the .NET Framework 3.5 installed.
If you have ever manually created user accounts within the Active Directory Users and Computers snap-in, the utility should be pretty self-explanatory. Just in case, the instructions for how to configure the utilty are provided below:
| Setting | Configuration |
|---|---|
| Domain (NetBIOS Name) | Specify the NetBIOS name for your domain |
| Domain (Distinguished Name) | Specify the FQDN for your domain |
| User OU | Specify the Active Directory OU where you want the accounts placed. Examples: To place within the Users OU, you can specify CN=Users;DC=mydomain;DC=com To place within the Departments/HR OU, you can specify something like OU=HR;OU=Departments;DC=mydomain;DC=com |
| Single Account or Multiple Accounts | Specify whether you looking to create a single account or multiple accounts |
| Username | If you specified a single account, this is the username for the account |
| User Prefix | If you specified multiple accounts, this is the user prefix for the accounts |
| Starting Index | If you specified multiple accounts, this is the starting index for the accounts. For example, a user prefix of User with a starting index of 1 will create the accounts User1, User2, User3,… |
| Quantity | If you specified multiple accounts, this is the number of accounts to create |
| Password Never Expires | Specify whether to enable/disable the Password Never Expires attribute on the user accounts |
| User Cannot Change Password | Specify whether to enable/disable the User Cannot Change Password attribute on the user accounts |
| Static Password or Random Password | Specify whether to define a static password across all auto-generated accounts or define a random password for each account |
| Password | If you specified a static password, this is the user-defined password for the accounts |
| Password Length | If you specified a random password, this is the number of characters to include in the password |
| Require Capital Letter | If you specified a random password, this indicates whether the random password should include at least one capital letter |
| Require Lower Case Letter | If you specified a random password, this indicates whether the random password should include at least one lower case letter |
| Require Number | If you specified a random password, this indicates whether the random password should include at least one number |
| Store username and password details in text file | Specify whether you want to place the generated account details within a text file. This is recommended if using random passwords since this will be the only way to get the passwords for those accounts |
| Text File Name | Specify the name of the text file that will contain the generated account details. The default name is Accounts.txt |
| Text File Location | Specify the location where the text file will be saved. |
Run the utility
When you click the Create Users button, the utility will attempt to create the requested number of accounts in the specified OU within Active Directory. If you requested a large number of accounts, it may take a few minutes. A message box will be displayed with the status of the request. An event log entry is also created with additional details and is recommended to check if you run into any issues.
If you specified random passwords for the accounts, you will definitely need to check out the Accounts.txt file that is generated so you can get the passwords for those accounts. You should record these passwords in the proper location and delete this file for security purposes ![]()
Verify the Active Directory accounts have been created
Finally, open the Active Directory Users and Computers snap-in and verify the accounts were created in the proper OU. Feel free to modify the accounts further with profile information or other details. The accounts will be easily visible since the text Auto-generated account will be shown in the description field.
Key source code
Many of you may want to just incorporate this functionality into an existing application that you are building. I provided the full source code as a separate download at the bottom of this article. It’s a Visual Studio 2008 project. If you just wanted to skim the source code, here’s the key code snippets to look at. I’m leveraging the PrincipalContext and UserPrincipal objects provided in the .NET Framework 3.5 library to communicate with Active Directory.
Here are the includes for the project:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.DirectoryServices; using System.DirectoryServices.AccountManagement; using System.IO;
Here is the function that creates the Active Directory accounts:
private void btnCreateUsers_Click(object sender, EventArgs e) { //************************************************** //Define local variables //************************************************** StreamWriter l_objWriter = null; string l_strMessage = ""; string l_strErrorAccountList = ""; int l_intSuccessAttempts = 0, l_intErrorAttempts = 0; try { //************************************************** //Grab values from form //************************************************** string l_strDomain = txtDomain.Text.Trim(); string l_strDomainDN = txtDomainDN.Text.Trim(); string l_strUserOU = txtUserOU.Text.Trim(); string l_strUserPrefix = txtUserPrefix.Text.Trim(); string l_strUsername = "", l_strPassword = ""; int l_intQuantity = Convert.ToInt32(txtQuantity.Text.Trim()); int l_intStartingIndex = Convert.ToInt32(txtStartingIndex.Text.Trim()); int l_intPasswordLength = Convert.ToInt32(txtPasswordLength.Text.Trim()); bool l_blnPasswordNeverExpires = chkPasswordNeverExpires.Checked; bool l_blnUserCannotChangePassword = chkUserCannotChangePassword.Checked; bool l_blnRequireCapital = chkRequireCapital.Checked; bool l_blnRequireLowerCase = chkRequireLowerCase.Checked; bool l_blnRequireNumber = chkRequireNumber.Checked; string l_strTextFileName = txtTextFileName.Text.Trim(); string l_strTextFileLocation = txtTextFileLocation.Text.Trim(); string l_strTextFileFullPath = l_strTextFileLocation + "\\" + l_strTextFileName; //****************************************************************** //Check whether to create single account or multiple accounts //****************************************************************** if (rdoSingleAccount.Checked) //Create single account { //Create user object PrincipalContext l_objContext = new PrincipalContext(ContextType.Domain, l_strDomain, l_strUserOU); UserPrincipal l_objNewUser = new UserPrincipal(l_objContext); //Set username and password l_strUsername = txtUsername.Text.Trim(); if (rdoStaticPassword.Checked) l_strPassword = txtPassword.Text.Trim(); else l_strPassword = this.GenerateRandomPassword(l_intPasswordLength, l_blnRequireCapital, l_blnRequireLowerCase, l_blnRequireNumber); l_objNewUser.SamAccountName = l_strUsername; l_objNewUser.SetPassword(l_strPassword); //Assign user properties l_objNewUser.UserPrincipalName = l_strUsername + "@" + l_strDomainDN; l_objNewUser.DisplayName = l_strUsername; l_objNewUser.Description = "Auto-generated account"; l_objNewUser.GivenName = l_strUsername; //first name l_objNewUser.PasswordNeverExpires = l_blnPasswordNeverExpires; l_objNewUser.UserCannotChangePassword = l_blnUserCannotChangePassword; l_objNewUser.Enabled = true; //Check if user already exists within Active Directory UserPrincipal usr = UserPrincipal.FindByIdentity(l_objContext, l_strUsername); if (usr == null) //User not found. Proceed with save { //Save user to the directory l_objNewUser.Save(); l_intSuccessAttempts++; } else //User already exists { if (l_strErrorAccountList == "") l_strErrorAccountList = l_strUsername; else l_strErrorAccountList += ", " + l_strUsername; l_intErrorAttempts++; } //Check if account details should be stored in text file if (chkStoreInTextFile.Checked) { //Save account details to file l_objWriter = new StreamWriter(l_strTextFileFullPath, false); l_objWriter.WriteLine("1," + l_strUsername + "," + l_strPassword); l_objWriter.Close(); } } else //Create multiple accounts { //Create the specified number of user accounts for (int index = 1; index <= l_intQuantity; index++) { //Create user object PrincipalContext l_objContext = new PrincipalContext(ContextType.Domain, l_strDomain, l_strUserOU); UserPrincipal l_objNewUser = new UserPrincipal(l_objContext); //Set username and password l_strUsername = l_strUserPrefix + l_intStartingIndex.ToString(); if (rdoStaticPassword.Checked) l_strPassword = txtPassword.Text.Trim(); else l_strPassword = this.GenerateRandomPassword(l_intPasswordLength, l_blnRequireCapital, l_blnRequireLowerCase, l_blnRequireNumber); l_objNewUser.SamAccountName = l_strUsername; l_objNewUser.SetPassword(l_strPassword); //Assign user properties l_objNewUser.UserPrincipalName = l_strUsername + "@" + l_strDomainDN; l_objNewUser.DisplayName = l_strUsername; l_objNewUser.Description = "Auto-generated account"; l_objNewUser.GivenName = l_strUsername; //first name l_objNewUser.PasswordNeverExpires = l_blnPasswordNeverExpires; l_objNewUser.UserCannotChangePassword = l_blnUserCannotChangePassword; l_objNewUser.Enabled = true; //Check if user already exists within Active Directory UserPrincipal usr = UserPrincipal.FindByIdentity(l_objContext, l_strUsername); if (usr == null) //User not found. Proceed with save { //Save user to the directory l_objNewUser.Save(); l_intSuccessAttempts++; //Check if account details should be stored in text file if (chkStoreInTextFile.Checked) { //Save account details to file if (l_objWriter == null) l_objWriter = new StreamWriter(l_strTextFileFullPath, false); l_objWriter.WriteLine(index + "," + l_strUsername + "," + l_strPassword); } } else //User already exists { if (l_strErrorAccountList == "") l_strErrorAccountList = l_strUsername; else l_strErrorAccountList += ", " + l_strUsername; l_intErrorAttempts++; } //Increment starting index l_intStartingIndex++; //Close writer if this was the last check if (chkStoreInTextFile.Checked && index == l_intQuantity && l_objWriter != null) l_objWriter.Close(); } } //Write event log entry and display status to user if (l_intSuccessAttempts > 0) { l_strMessage += "Successfully created " + l_intSuccessAttempts.ToString() + " account(s).\r\n"; } if (l_intErrorAttempts > 0) { l_strMessage += "Could not create " + l_intErrorAttempts.ToString() + " account(s): " + l_strErrorAccountList + "\r\n\r\n"; l_strMessage += "If any accounts were not created, they most likely already exist within Active Directory."; } System.Diagnostics.EventLog.WriteEntry("CreateADUsers", l_strMessage, EventLogEntryType.Information, 1001); MessageBox.Show("Task Completed!\r\n" + l_strMessage, "Create Users Task"); } catch (Exception objException) { //Write event log entry System.Diagnostics.EventLog.WriteEntry("CreateADUsers", "Error creating user within application.\r\n\r\nAdditional details:\r\n" + objException.Message, EventLogEntryType.Error, 1002); MessageBox.Show("Error! Please check event viewer...", "Create Users Task"); } }
Here is the function that generates the random password:
public string GenerateRandomPassword(int p_intPasswordLength, bool p_blnRequireCapital, bool p_blnRequireLowerCase, bool p_blnRequireNumber) { //Define available characters for password string[] l_strCapitals = { "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" }; string[] l_strLowerCases = { "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z" }; string[] l_strNumbers = { "1","2","3","4","5","6","7","8","9","0" }; string[] l_strCharacters = { "A","B","C","D","E","F","G", "H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y", "Z","1","2","3","4","5","6","7","8","9","0","a","b","c","d","e","f","g","h", "i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}; //Define additional variables string l_strPassword = ""; Random rGen = new Random(); int l_intPosition = 0; //Check if capital is required... if (p_blnRequireCapital && p_intPasswordLength > 0) { l_intPosition = rGen.Next(0, 25); l_strPassword += l_strCapitals[l_intPosition]; p_intPasswordLength = p_intPasswordLength - 1; //Adjust remaining password length } //Check if lower case is required... if (p_blnRequireLowerCase && p_intPasswordLength > 0) { l_intPosition = rGen.Next(0, 25); l_strPassword += l_strLowerCases[l_intPosition]; p_intPasswordLength = p_intPasswordLength - 1; //Adjust remaining password length } //Check if number is required... if (p_blnRequireNumber && p_intPasswordLength > 0) { l_intPosition = rGen.Next(0, 9); l_strPassword += l_strNumbers[l_intPosition]; p_intPasswordLength = p_intPasswordLength - 1; //Adjust remaining password length } //Generate remaining password characters for (int i = 1; i <= p_intPasswordLength; i++) { l_intPosition = rGen.Next(0, 60); l_strPassword += l_strCharacters[l_intPosition]; } //Return password return l_strPassword; }
Download the utility and full source code
The utility and full source code are provided below:
Ed York – Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Me on twitter: http://twitter.com/citrixedy




