### Archive

Posts Tagged ‘script’

# Description

Installing Skype for Business and Lync servers is usually boring if you’re a consultant who does it often. Making sure the server specs are right, installing OS features, configuring NICs, etc. It’s even more boring if you’re building a bunch of servers at one time. There’s always a chance for human error, too. So why not automate as much as possible? That’s what I was after when I built the Lync Server 2010 prereq script, then the Lync Server 2013 prereq script. And it’s certainly what I’m after for Skype for Business Server 2015. This time, however, I opted to not have a separate script for Skype for Business. Many of the requirements are the same, or just slightly different, than Lync Server 2013. So I just added the Skype for Business functionality to the 2013 script, and updated everything as a whole.

This version also uses my new method of checking for updates, as mentioned in Function: Get-UpdateInfo – Making It Easy for Your Users to Get the Latest Version of Your Scripts. When a new version is available, you’ll get a pop-up notifying you.

If you’re aware of a third-party product, or even Microsoft product, that is a good match for Skype for Business servers, let me know. I’m happy to take a look and see if it would make a good addition to the script.

Super big thanks to my beta testers for supplying bug reports, suggestions, and comments.

# Syntax

C:\Set-CsFeatures.ps1 [-TargetFolder <String>] [-WindowsSource <String>] [-SQLPath <String>] [-InitialMenuOption <Int32>] [-IncludeSSMS ] [-IncludeTelnet ] [-IncludeFW ] [-IncludeHighPower ] [-IncludeStandard ] [-GetInfoFromRegistry ] [-OWASOveride ] [-DownloadOnly ] [-SkipCoreCheck ] [-Tail ] [-Skype4b ] [-SkipUpdateCheck ] [-DisableAutoUpdates ] [-IncludeLanguagePack ] [-SkipEdgeNicConfig ] [-WhatIf ] [-Confirm ] [-IncludeTotalCount ] [-Skip <UInt64>] [-First <UInt64>] [<CommonParameters>]

C:\Set-CsFeatures.ps1 [-TargetFolder <String>] [-GetInfoFromRegistry ] [-OWASOveride ] [-DownloadAll ] [-SkipCoreCheck ] [-Tail ] [-Skype4b ] [-WhatIf ] [-Confirm ] [-IncludeTotalCount ] [-Skip <UInt64>] [-First <UInt64>] [<CommonParameters>]

C:\Set-CsFeatures.ps1 [-GetInfoFromRegistry ] [-ClearRunningStatus ] [-WhatIf ] [-Confirm ] [-IncludeTotalCount ] [-Skip <UInt64>] [-First <UInt64>] [<CommonParameters>]

C:\Set-CsFeatures.ps1 [-GetInfoFromRegistry ] [-Skype4b ] [-WhatIf ] [-Confirm ] [-IncludeTotalCount ] [-Skip <UInt64>] [-First <UInt64>] [<CommonParameters>]

# Examples

.\Set-CsFeatures.ps1 -Skype4b

Runs script in Skype for Business mode. Options chosen while running in this mode are tailored to Skype for Business. Not specifying this option will cause a pop-up prompt when the script starts, allowing a user to choose the desired mode.

.\Set-CsFeatures.ps1

Runs script with default values.

.\Set-CsFeatures.ps1 -WindowsSource "d:"

Runs script with the location defined for the Windows Server 2012/2012 R2 installation files.

.\Set-CsFeatures.ps1 -SQLPath "d:\sqlexpress"

Runs the script and installs any required SQL Express instances in the specified location.

.\Set-CsFeatures.ps1 -TargetFolder "d:\installbits"

Runs the script, and saves any downloaded files and written logs in the specified location instead of the default “c:\_install”.

.\Set-CsFeatures.ps1 -InitialMenuOption 3

Runs the script, and automatically starts option 3 (Front End server). Once it’s finished with that option, the script functions as normal, and displays the menu. NOTE: only options from the main menu can be specified. Options in sub-menus are not available with -InitialMenuOption.

.\Set-CsFeatures.ps1 -tail

Runs script with default values, but also shows an additional PowerShell window showing a live running log file.

# Parameters

-TargetFolder

Defines the location for any downloaded files. Defaults to “c:\_install”. Additionally, log files generated by this script are located in a sub-folder of TargetFolder called “logs”. TargetFolder does not support paths with spaces, but does support non-hidden UNC paths.

-WindowsSource

Defines the location of the Windows Server installation files. This is needed to install .Net 3.5 since those files are not installed on the server by default. Defaults to first detected CD-ROM/DVD drive. This can be a local file path, path to an .ISO file, or a non-hidden UNC path.

-SQLPath

Defines the desired installation path for SQL Express. Defaults to “c:\Program Files\Microsoft SQL Server”.

-InitialMenuOption

Allows you to start the script with the option you want, without first displaying the menu.

-IncludeSSMS

If specified, will include SQL Server Management Studio automatically when prerequisites are installed for any server that has SQL Express instances. If not specified, a prompt will appear.

-IncludeTelnet

If specified, will include Telnet automatically when prerequisites for Front End servers, Director servers, Mediation servers, Edge servers, and/or Persistent Chat servers are installed. If not specified, a prompt will appear.

-IncludeFW

If specified, will include the firewall rules for Get-CsConnections automatically when prerequisites for Front End servers are installed. If not specified, a prompt will appear.

-IncludeHighPower

If specified, tells the script to automatically set the Power Config on the server to High Power. This is instead of the script prompting. This option is available for all server roles.

-IncludeStandard

If specified, tells the script to include the extra SQL Express instance required for Standard Edition front end servers. This is instead of the script prompting.

-GetInfoFromRegistry

This value is only used during mid-prereq reboots. It is automatically set and read by the script, and should never be manually specified.

-OWASOveride

Don’t use this parameter. It’s for internal testing only. Using it can render the server unusable.

-DownloadOnly

-DownloadAll

Tells this script to not install or configure anything – just download ALL of the files. This is useful if you’re going to be building servers that do not have Internet access and want to fetch the files beforehand from a desktop computer. The big difference between this option and -DownloadOnly, is that this option downloads ALL files needed for ALL options, whereas -DownloadOnly allows a user to download files for specific options they choose.

-ClearRunningStatus

This switch forces the running status to be reset. This option should ONLY be used if the script exits/aborts dirty, and attempts to run the script again yield a “Script is already running” message.

-SkipCoreCheck

When specified, skips the check for Server Core. It is not meant to be called manually, as it’s used when the script needs to restart after a server reboot.

-Tail

When specified, opens another PowerShell session and tails the log file, similar to *nix. This is really only beneficial during troubleshooting.

-Skype4b

When specified, uses values specific to Skype For Business Server 2015 for prerequisites. If this option is NOT specified a pop-up will appear, asking which mode the script should operate in: Lync Server 2013 or Skype for Business Server 2015.

-SkipUpdateCheck

When specified, skips the check for a newer version of the script. This option is included mainly for when the script reboots the server.

-DisableAutoUpdates

When specified, skips the prompt and automatically disables auto updates for Windows Server. If not specified, a prompt is displayed.

-IncludeLanguagePack

When specified, skips the prompt for the installation of the Office Online Server English language pack. If not specified, a prompt is displayed.

-SkipEdgeNicConfig

When specified, skips the configuration of the NICs on edge servers. This requires that you manually complete those steps.

-SkipAutoStart

When specified, will not automatically restart the script after a required reboot. The ONLY time this should be used is if you need to do something before the script starts again, like manually mounting an ISO file that the script needs.

# Installation

No installation is necessary.

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

# Known Issues

The only issue I’m aware of at the release of the latest version is that pinning shortcuts to the taskbar in Windows Server 2016 doesn’t seem to be working. If you come across something, please let me know. Contact info is in the header of the script, and the script also has option 96, ‘how to report a bug’ that will tell you what information is critical when reporting a problem.

Question: Does this script support Windows Server 2016?

Answer: Yes – starting with version 4.20, prerequisites for Windows Server 2016 are included.

Question: Why doesn’t this script support Windows Server 2008 R2 and earlier?

Answer: I get asked this all the time. There are several reasons. The first is that out of the box, Server 2008 R2 has PowerShell 2.0 installed, and this script is written in PowerShell 3.0. Requiring you to upgrade to PowerShell 3.0 first, before running a script that installs prerequisites, seems counter-intuitive. And converting the script to just use PowerShell 2.0 is taking a step backwards, especially considering that the current version of PowerShell is 5.0, and even as this is written, 5.1 is in preview.

Next is sheer time. I test changes I make. And then I test them again. And then I choose different options and combinations and test them. Testing on just Server 2012 and Server 2012 R2 is exhausting. Adding Server 2008 R2 would mean even more testing, plus I’d have to add those resources in my already overtaxed test labs. That would slow down my ability to add new features and test fixes.

Third is that Server 2008 R2 is three versions back. Get with the times already!

Question: Does the script support Windows Server 2016?

Answer: No, and the primary reason is that Lync Server 2013 and Skype for Business Server 2015 are not supported on Windows Server 2016. Once they are supported on Windows Server 2016 (and it will likely only be Skype for Business Server 2015 that’s supported), I’ll adjust the script as needed. I’ve already done some preliminary work.

Question: Can you add feature x?

Answer: I LOVE getting feature requests. Seriously! Best method to suggest features is to send me an email. My email address is in the comment section at the top of every script I publish. Please be detailed in what you’d like to see, as well as any scenarios you’d use the option (so I can try to duplicate testing). This also goes for additional tools, whether Microsoft or third-party.

Question: How do I submit bug reports?

Question: What if my server doesn’t have Internet access?

Question: When I run the script again, I get “Script already running”

Answer: This is because the script didn’t exit gracefully. Many reasons this can happen, such as rebooting the server while it’s still running. If you’re positive it’s not running anywhere else (including by other users logged into the same server), run the script with the -ClearRunningStatus switch to clear that flag. Then run it as normal.

Question: Is there an option to specify where (i.e. path) all of the various tools are installed?

Answer: No. And not for a lack of trying. Some tools don’t support automated installs with a specified path. And some of those that DO, actually still dump some core files in a “default” location. The more I tried to come up with the solution, the more I realized that it would entail a substantial amount of overhead in the script.

Question: Why does the script report an unsupported version of .NET Framework?

Answer: Because Lync Server 2013 and Skype for Business Server 2015 don’t support the version detected. Once they do, I’ll adjust the script accordingly.

v4.8 – 03-10-2018 – Set-CsFeatures.v4.8.zip

v4.7 – 02-23-2018 – Set-CsFeatures.v4.7.zip

v4.6 – 01-19-2018 – Set-CsFeatures.v4.6.zip

v4.5 – 12-21-2017 – Set-CsFeatures.v4.5.zip

v4.4 – 11-12-2017 – Set-CsFeatures.v4.40.zip

v4.30 – 10-11-2017 – Set-CsFeatures.v4.30.zip

v4.20 – 09-04-2017 – Set-CsFeatures.v4.20.zip

v4.10 – 05-15-2017 – Set-CsFeatures.v4.10.zip

v4.09 – 05-13-2017 – Set-CsFeatures.v4.09.zip

v4.08 – 04-19-2017 – Set-CsFeatures.v4.08.zip

v4.07 – 04-14-2017 – Set-CsFeatures.v4.07.zip

v4.06 – 02-05-2017 – Set-CsFeatures.v4.06.zip

v4.05 – 11-04-2016 – Set-CsFeatures.v4.05.zip

v4.04 – 11-02-2016 – Set-CsFeatures.v4.04.zip

v4.03 – 11-01-2016 – Set-CsFeatures.v4.03.zip

v4.02 – 10-28-2016 – Set-CsFeatures.v4.02.zip

v4.01 – 10-25-2016 – Set-CsFeatures.v4.01.zip

v4.0 – 10-24-2016 – Set-CsFeatures.v4.0.zip

# Changelog

See the changelog for information on what’s changed/included in each version.

# Description

As a PowerShell developer, you always want your users to have the latest version of a script. It makes support a lot easier, while also making sure that users have the latest features and bug fixes. But how to encourage that? Well, for me, users of my scripts are typically not within the same environment as me. So Group Policy Objects, logon scripts, etc, aren’t a solution. Having the script automatically check for an update is much easier, and doesn’t require anything from the user1. So let’s take a look at a quick and easy method.

First, we need a repository where the update information will be held. XML is perfect for this. In this example, I created the following file, and saved it as version.xml:

<?xml version="1.0"?>
<catalog>
<article id="1697">
<title>Set-CsFeatures.ps1</title>
<author>Pat Richard</author>
<version>3.9.57</version>
<publish_date>2016-10-08</publish_date>
<description>Installs all required Windows 2012/Windows 2012 R2 components & optional tools.</description>
</article>
</catalog>

This file can reside anywhere. A file path, a web site, wherever. I chose a website for the reasons I mentioned above. You can see the above file in action at http://www.ucunleashed.com/downloads/version.xml. Some key points to the file. Each article I publish going forward will have it’s own “article” node. The ID I chose to tie to it is also the ID of the article’s URL, for consistency sake. In this example, 1697 is the prereq script seen at http://www.ucunleashed.com/1697. The version value is the version of the latest general availability (“GA”) build. We’ll query that value, compare it against the version of the script running the query, and see if it’s newer. Note that there is some other info in the XML file, and that’s irrelevant to what we’re discussing here.

[xml] $xml = (New-Object System.Net.WebClient).DownloadString("http://www.ucunleashed.com/downloads/version.xml")$Ga = ($xml.catalog.article | Where-Object {$_.id -eq $article}).version  We supply the$article value when making the call. After that, it’s a simple comparison. In the prereq script, near the beginning, I assign a variable, $version, with a value. Let’s say it’s “3.9.55”. We compare$Ga against $Version $Ga -gt $Version  If it’s true, we know a newer version exists. If it’s false, we know the currently running script is the latest version. In theory, we could also use this to alert of a regression in case we needed to downgrade (gasp!). So let’s put this together. We assign a variable,$xml, to the results of downloading an xml file. Then, we assign $ga to the value of “version” for the specific node within the xml file that contains the info for the article. Lastly, we do our comparison and give some output if there is an update. [xml]$xml = (New-Object System.Net.WebClient).DownloadString("http://www.ucunleashed.com/downloads/version.xml")
$Ga = ($xml.catalog.article | Where-Object {$_.id -eq$article}).version
if ($Ga -gt$Version){Write-Output "A new version is available!"}

Now, obviously, we can pretty this up a bit. But before we do that, let’s think of issues we could run into. The big one is making sure we have an Internet connection to use to check the XML file. As much as we can often assume there will be one, a LOT of organizations block Internet access to servers as part of their security posture. So we shouldn’t assume. We can check using the following:

[bool] $HasInternetAccess = ([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet) And then using an IF loop against$HasInternetAccess. So let’s throw this all into a function we can incorporate into our scripts and modules:

function Get-UpdateInfo {
[CmdletBinding(SupportsShouldProcess, SupportsPaging)]
param (
# Article/script to check for updates
[parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
[string] $article ) [bool]$HasInternetAccess = ([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet)
if ($HasInternetAccess){ [xml]$xml = (New-Object System.Net.WebClient).DownloadString("http://www.ucunleashed.com/downloads/version.xml")
$Ga = ($xml.catalog.article | Where-Object {$_.id -eq$article}).Version
if ($Ga -gt$version){
Write-Log -Level Warn -Message "Outdated version. Version $Ga is latest version. Prompting user" -NoConsole$wshell = New-Object -ComObject Wscript.Shell -ErrorAction Stop
$updatePrompt =$wshell.Popup("A new version ($ga) of the script is available. Would you like to download it?",0,"A new version is available",68) if ($updatePrompt -eq 6){
Start-Process "http://www.ucunleashed.com/$article" } } }else{ Write-Output "No Internet connectivity. Unable to check online for update info." } } # end function function Get-UpdateInfo Here we incorporate a simple ComObject popup message to ask if the user wants to download the new version. Since we have assigned the GA number to$ga, we can use that in the popup text, as well, as shown in the image at the beginning of this article. If $updatePrompt is “6”, then the user clicked “Yes” on the popup, and we can take action such as opening a browser window and navigating to the articles page. Or we could download a file, or any of a number of actions. If$updatePrompt is “7”, then the user clicked “No”.

So, as you can see, it’s really not that hard to add an update checker to your scripts. When you release a new version, simply update the XML file to reflect accordingly.

Note: Take care in what kind of characters are in the XML file. Some special characters, such an ampersand (“&”), aren’t handled very well. When in doubt, open a browser window and navigate to the file.

1 – Depending on the action you require once it’s known an update is available.

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

Categories: PowerShell Tags:

# Description

Some Lync 2013/Skype for Business 2015 policies have few parameters, like User Services Policies. Others, like Conferencing Policies, have a considerable number of parameters. Often, organizations need to have different policies for different groups of people. Many times, there is only one or two settings that are different. Creating a new policy based on an existing policy can be time-consuming. There are some cool utilities like Kevin Peters’ cool StareCompare, which shows where policy settings are different between two policies. But what if it was just easier to “clone” an existing policy to a new policy, and then just change the few settings that need changing? NextHop has a nice article on how to just that. You export the current policy to an XML file, edit the file, then import it into a new policy. Must faster, but still requires some manual editing of an XML file. Ya know why I don’t like that method? Not enough PowerShell! So what I did was write a script that automates that method, and allows you to clone an existing policy to a new policy in one step. The script exports the existing “source” policy, updates the XML, then imports into the “target” policy. One command to make life easier. Then you can use the appropriate “set” cmdlet to tweak the new policy. And it works with all Lync 2013/Skype for Business 2015 policy types, including Archiving, Client, ClientVersion, Conferencing, ExternalAccess, HostedVoicemail, Location, Mobility, NetworkInterSite, PersistentChat, Pin, Presence, UserServices, Voice, and VoiceRouting. The script only works with Lync Server 2013/Skype for Business 2015 policies, and only runs on PowerShell 3.0 or higher (Windows Server 2012 or later).

The script supports Get-Help, so run that if you need additional info.

# Syntax

New-CsClonedPolicy.ps1 [[-ExportFolder] ] [[-ExportFile] ] [[-SourcePolicyName] ] [[-TargetPolicyName] ] [[-PolicyType] ]
[[-Description] ] []

An example would be

New-CsClonedPolicy.ps1 -SourcePolicyName global -TargetPolicyName "new policy" -PolicyType ConferencingPolicy

This would clone the global conferencing policy into a new policy called “new policy”. Acceptable values for PolicyType are “ArchivingPolicy”, “ClientPolicy”, “ClientVersionPolicy”, “ConferencingPolicy”, “ExternalAccessPolicy”, “HostedVoicemailPolicy”, “LocationPolicy”, “MobilityPolicy”, “NetworkInterSitePolicy”, “PersistentChatPolicy”, “PinPolicy”, “PresencePolicy”, “UserServicesPolicy”, “VoicePolicy”, and “VoiceRoutingPolicy”

When specifying a TargetName, keep one thing in mind. Using just a string value will create a user level policy. If you need to create a site level policy, specify “site:”, such as “site:Redmond” to create a policy for the Redmond site.

# Installation

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

v1.3 – 02-03-2017 – New-CsClonedPolicy.v1.3.zip

v1.2 – 06-10-2014 – New-CsClonedPolicy.v1.2.zip

v1.1 – 02-08-2014 – New-CsClonedPolicy.v1.1.zip

v1.0 – 09-03-2013 – New-CsClonedPolicy.v1.0.zip

# Changelog

See the changelog for information on what’s changed/included in each version.

## Script: Set-Cs2013Features.ps1 – Easily Install Prerequisites and Tools for Microsoft Lync Server 2013

Note: This script is now deprecated. Please see the newer Script: Set-CsFeatures.ps1 – Easily Install Prerequisites and Tools for Lync Server 2013 and Skype for Business Server 2015 script for the latest version.

# Description

This script will assist in getting servers ready for the installation of Microsoft Lync Server 2013 on Windows Server 2012 and Windows Server 2012 R2. This includes the operating system prerequisites, SQL Express (where necessary), Silverlight, and more. Some post installation options are also available, and include Microsoft tools such as the debugging tools, the Best Practices Analyzer (BPA), Connectivity Analyzer, and more. Where the script needs files available online, it will automatically download them. More options will be added as I have time, and can properly test. This includes Edge, Director, Front End, Office Web Apps, Persistent Chat, and Mediation server prerequisites, and more tools. If you have suggestions, please feel free to comment below.

In the event that the server needs to be rebooted before prereqs can continue, it will automatically restart the script and continue after you reboot and login again.

The current options are:

1. Director – Installs the OS prerequisites and SQL Express instances required to install this role.

2. Edge – Installs the OS prerequisites and SQL Express instances required for this role. It also verifies the server is not domain joined, then goes through the process of setting the primary DNS suffix (same as option 50-13). Also configures NICs to remove DNS and gateway from the internal NIC, remove dynamic registration in external NIC, and prompt to disable both lmhosts and NetBIOS over TCP/IP.

3. Front End – includes the Operating System prerequisites, Microsoft Silverlight, as well as the installation of SQL Express SP2 and creation of the various required instances. The SQL Express installs are done because Lync Server installs the RTM version by default. So installing the SP2 version saves a long update later. Note that each instance takes 3-5 minutes to install – longer on slower machines. Enterprise edition servers have two instances, RTCLocal and LyncLocal, and Standard edition servers also have the RTC instance. Choosing the Front End option will ask if it’s a Standard Edition server. This option will also prompt (if the firewall is enabled) if you’d like the required firewall exceptions created for my Get-CsConnections.ps1 script. This option will also prompt if the Lync Room System Admin Portal will be installed. If you select Yes, the ASP.NET MVC 4 for Visual Studio 2010 SP1 and Visual Web Developer 2010 SP1 prerequisite for that is installed.

4. Mediation – Installs the OS prerequisites required and the RTCLocal SQL instance.

5. Office Web App – Installs the OS prerequisites required, then installs the Office Web App binaries, and then prompts to install the English language pack, followed by the most recent cumulative update. Almost everything needed to deploy an Office Web Apps server. This option also verifies that Windows Update settings are NOT set to automatic, as that is not recommended.

6. Persistent Chat – Installs the OS prerequisites and SQL instance required for this role.

7. Lync Server 2013 Resource Kit – tools that make troubleshooting and administrating a Lync environment easier, such as Address Book config, etc.

8. Lync Server 2013 Persistent Chat Resource Kit – tools useful for Persistent Chat environments.

9. Lync Server 2013 Debugging Tools – includes the logging tools such as OCSLogger and Snooper. Helpful for troubleshooting.

10. Lync Server 2013 Stress and Performance Tool – prepare, define, and validate performance

11. Lync Server 2013 Best Practices Analyzer – this tool helps identify any issues from a best practices perspective

12. Lync Server Connectivity Analyzer – identifies any issues that may result in connectivity problems for mobility clients including the Lync Windows Store app

15. Launch Windows Update

16. SCOM Watcher Node prerequisites

17. Custom PortQryUI. PortQryUI is installed, along with a custom config file that adds Lync related options.

18. Install Microsoft Message Analyzer (formerly NetMon)

19. Add custom Scheduler simple URL – if you’d like to have a simple URL for the scheduler app, such as scheduler.contoso.com, this option will handle the configuration of that. Note that this option requires that the simple URL provided be in the Subject Alternative Names (SAN) list of the certificate on your Front End servers. See Understanding the Lync Web Scheduler for additional info.

20. Install SQL Server 2012 Management Studio

21. ARR (“Pirate Proxy”) prerequisites. This installs the Windows features, and downloads the Web installer. It also verifies the server is not domain joined, then goes through the process of setting the primary DNS suffix (same as option 50-13). Also configures NICs to remove DNS and gateway from the internal NIC, remove dynamic registration in external NIC, and prompt to disable both lmhosts and NetBIOS over TCP/IP.

24. Microsoft Unified Communications Managed API 4.0, Runtime (UCMA 4.0) – this is required if you’re going to run sefautil.exe from the resource kit. It’s still recommended that sefautil.exe be used on a dedicated box.

28. Configure Skype Federation. This removes the MSN Public Provider and adds the Skype Public Provider, complete with icon. Download includes the Lync-Skype Provisioning Guide. See http://blogs.technet.com/b/lync/archive/2013/05/23/lync-skype-connectivity-available-today.aspx for more info.

30. Wireshark. This downloads the installer, and two compiled macro exe files and runs them. The first installs WireShark, and the second configures WireShark for optimized Lync tracing, including the steps recommended by Matt Landis (Getting Started With Lync and Wireshark: Tips & Quirks) and Jeff Schertz (Wireshark Capture Tips). That config includes:

1. adds Source Port (resolved) column
2. adds Destination Port (resolved) column
4. Configures RTP protocol “Try to decode RTP outside of conversations”
5. Configures SIP protocol for ports 5060-5068 (instead of WireShark’s default of 5060)
6. Sets the time format to human readable format

31. Enable Photo URL option. Enables the photo URL option in the client. See http://www.lynclog.com/2013/11/lync-2013-client-and-and-pictures-from.html for more info.

34. Lync Room System (LRS) Admin portal prerequisites.

36. Create Lync file share on local computer. This creates a file share on the local computer called “LyncShare”, and assigns the basic NTFS and share rights. This can then be added to the Lync Topology Builder.

1. Install/Update Lync Server 2013 Documentation Help
2. Create scheduled task to automatically update PowerShell help files daily. I discuss this in Function: New-PSUpdateHelpScheduledTask – Auto Update PowerShell Help
3. Install telnet client
4. Disable automatic updates. The automatic updating of Lync servers isn’t recommended due to the additional manual steps that must take place. And it’s not supported at all on Office Web Apps servers.
5. Set recovery of Lync and/or OWAS services to “restart”. See Set recovery of Lync services to “restart” for more info.
6. Set fabric logging to circular. See Tom’s excellent article at Check your lync server windows fabric log size with PowerShell
7. Disable Server Manager on logon. For those of you who hate that it always pops up when logging in.
8. Upgrade to PowerShell v4.0. This is for Windows Server 2012 RTM (not R2) boxes that still have the default PowerShell v3.0 on them. Upgrading PowerShell both before and after Lync Server is installed is supported.
9. Fix Control Panel font. Reverts the font in the Control Panel back to the original Segoe UI. See Resetting the Font in Lync Server Control Panel – Goodbye Times New Roman!
10. Set server power plan to “High Performance”. See http://www.ucunleashed.com/2558
11. Open HOSTS file in notepad for editing. This is convenient on edge servers.
12. Configure edge static routing – adds the static routes for all private address ranges to use the internal NIC. The user is prompted with a list of NICs discovered, and asked to pick which will be used for the internal connection. Once picked, the script will determine if there is already a gateway defined. If so, it will use that IP address to create the static routes. If there is no default gateway assigned, the user is prompted to enter the gateway that the static routes should use. The DNS server config is removed from the internal NIC. The gateway on the internal NIC is removed. A prompt will appear, and if accepted, lmhosts lookup is disabled on all NICs. Another prompt will appear, and if accepted, NetBIOS over TCP/IP is disabled.
13. Configure primary DNS suffix. This prompts for a domain name, assigns it as the primary DNS suffix, then reboots. This configuration is required for edge and ARR (reverse proxy) servers.

60. Desktop shortcuts menu. This is basically an enhanced menu driven version of Create a Shutdown/Restart/Logoff Windows 8 Tile for the Start menu (PowerShell) that puts easy to reach tiles on the Start screen. The available tiles are:

1. Logoff
2. Restart
3. Shutdown
4. Windows Update
5. Lync Server Management Shell
6. Lync Server Deployment Wizard
7. Lync Server Control Panel
8. Exchange UM Integration Utility (OcsUmUtil)
9. Snooper
10. OCSLogger Logging Tool
11. Lync Server Topology Builder
12. Certificate Management (local machine)
13. Active Directory Users and Computers (ADUC)
14. Microsoft Message Analyzer
15. Notepad Desktop Shortcut for Edge servers to open the HOSTS file

1. Lync Server Management Shell
2. Lync Server Deployment Wizard
3. Lync Server Control panel
4. Exchange UM Integration Utility (OcsUmUtil)
5. Snooper
6. OCSLogger Logging Tool
7. Lync Server Topology Builder
8. REMOVE shortcut for PowerShell
9. Certificate Management (local machine)
10. Active Directory Users and Computers (ADUC)
11. Microsoft Message Analyzer
12. REMOVE Windows App Store shortcut (Windows Server 2012 R2)

2. Lync Server 2013 Watcher Node
3. Lync Server 2013 Management Pack & Documentation
5. Lync Server SDN API 2.1 (includes the API installer, the management utility, the docs, and the .chm file)
7. Event Zero connector

1. Disable SSL 2.0
2. Disable SSL 3.0
3. EnableSessionTicket: Event IDs 32402, 61045 are logged in Lync Server 2013 Front End servers that are installed on Windows Server 2012 R2 (KB 2901554)

Note: The installation of some Lync Server 2013 roles requires some .Net 3.5 components, which are not installed in Windows Server 2012 by default. So the script will need to know where your Server 2012 installation media is. The script defaults to the CD-ROM/DVD-ROM drive with the lowest drive letter (typically D: or E:), but can be configured for other locations.

The script will also create a log file that can be used for troubleshooting. The log file is created in a logs folder inside the $TargetFolder (by default, c:\_install). This log file should be included when reporting any bugs. # Syntax C:\Set-Cs2013Features.ps1 [-TargetFolder ] [-Win2012Source ] [-SQLPath ] [-InitialMenuOption ] [-IncludeSSMS] [-IncludeTelnet] [-IncludeFW] [-IncludeHighPower] [-IncludeStandard] [-DownloadOnly] [-Tail] [-WhatIf] [-Confirm] [-IncludeTotalCount] [-ClearRunningStatus] []  # Examples Set-Cs2013Features.ps1 This will launch the script with the default options for Enterprise edition servers Set-Cs2013Features.ps1 -Win2012Source e: This will launch the script using the e: drive for the source of the Windows Server 2012 installation files Set-Cs2013Features.ps1 -sqlpath "d:\sqlexpress" This will install any related SQL Express instances to the specified path # Parameters -TargetFolder Defines the location for any downloaded files. Defaults to “c:\_install”. Additionally, log files generated by this script are located in a subfolder of TargetFolder called “logs”. TargetFolder does not support paths with spaces. UNC paths are acceptable provided they are not hidden, such as \\server\share$.

-Win2012Source <String>

Defines the location of the Windows Server 2012 installation files. This is needed to install .Net 3.5 since those files are not installed on the server by default. Defaults to first detected CD-ROM/DVD drive. UNC paths are acceptable provided they are not hidden, such as \\server\share$. Unmounted .ISO images are also supported. -SQLPath Defines the desired installation path for SQL Express. Defaults to “c:\Program Files\Microsoft SQL Server” -InitialMenuOption Allows you to start the script with the option you want, without first displaying the menu. -IncludeSSMS [] If specified, will include SQL Server Management Studio automatically when prereqs for Front End servers are installed. If not specified, a prompt will appear. -IncludeTelnet [] If specified, will include Telnet automatically when prereqs for Front End servers, Director servers, Mediation servers, Edge servers, and/or Persistent Chat servers are installed. If not specified, a prompt will appear. -IncludeFW [] If specified, will include the firewall rules for Get-CsConnections automatically when prereqs for Front End servers are installed. If not specified, a prompt will appear. -IncludeHighPower [] If specified, tells the script to automatically set the Power Config on the server to High Power. This is instead of the script prompting. -IncludeStandard [] If specified, tells the script to include the extra SQL Express instance required for Standard Edition front end servers. This is instead of the script prompting. -GetInfoFromRegistry [] This value is only used during mid-prereq reboots. It is automatically set and read by the script, and should not be manually specified. -DownloadOnly [] Tells this script to not install or configure anything – just download the files for the option you select. This is useful if you’re going to be building servers that do not have Internet access and want to fetch the files beforehand. -DownloadAll [] Tells this script to not install or configure anything – just download ALL of the files. This is useful if you’re going to be building servers that do not have Internet access and want to fetch the files beforehand. Note that a complete set of files is currently around 3.8GB. -Tail Shows a tail of the log file as it’s written. It automatically restarts if the script reboots the server, too. Really only beneficial for troubleshooting. -ClearRunningStatus Resets the warning flag if the script didn’t close gracefully and you get the “The script is already running” error. # Installation # WARNING! An issue has been identified in Windows Server 2012 servers that are built as Server Core, but converted later to Server with GUI. Installation of Windows Features, either manually or via a script, fail if Windows Updates are installed BEFOREHAND. That being the case, this script cannot be used in such scenarios. I’m working on detecting (if possible) servers that are converted, as well as researching why they fail. Thanks to John for pointing it out. It’s likely that the issue detailed here is the cause. Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet. # Donations I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab. # Frequently Asked Questions Question: Why doesn’t this script support Windows Server 2008 R2? Answer: I get asked this all the time. There are several reasons. The first is that out of the box, Server 2008 R2 has PowerShell 2.0 installed, and this script is written in PowerShell 3.0. Requiring you to upgrade to PowerShell 3.0 first, before running a script that installs prerequisites, seems counter-intuitive. And converting the script to just use PowerShell 2.0 is taking a step backwards, especially considering that the current version of PowerShell is 4.0, and even as this is written, 5.0 is in preview. Next is sheer time. I test changes I make. And then I test them again. And then I choose different options and combinations and test them. Testing on just Server 2012 and Server 2012 is exhausting. Adding Server 2008 R2 would mean even more testing, plus I’d have to add those resources in my already overtaxed test labs. That would slow down my ability to add new features and test fixes. Third is that Server 2008 R2 is two versions back. Get with the times already! Question: Can you add feature x? Answer: I LOVE getting feature requests. Seriously! Best method to suggest features is to send me an email. My email address is in the comment section at the top of every script I release. Please be detailed in what you’d like to see, as well as any scenarios you’d use the option (so I can try to duplicate testing). Question: How do I submit bug reports? Answer: Email is best. Grab my email address from the comment section at the top of the script. Please be VERY detailed. Please include screen shots if possible, and ALWAYS include the log file (by default, it’s in c:\_install\logs). If you’re not using the latest version of the script, please download it and see if you can duplicate the problem before reporting it. Question: What if my server doesn’t have Internet access? Answer: Fear not. Download the required files using either the -DownloadOnly or -DownloadAll options from another machine and place them in the TargetFolder, which is c:\_install by default. The script looks to see if the file is available locally before attempting to download. Question: When I run the script again, I get “Script already running” Answer: This is because the script didn’t exit gracefully. Many reasons this can happen, such as rebooting the server while it’s still running. If you’re positive it’s not running anywhere else (including by other users logged into the same server), run the script with the -ClearRunningStatus switch to clear that flag. Then run it as normal. # Download v3.8 – 03-25-2015 – Set-Cs2013Features.v3.8.zip v3.7 – 02-27-2015 – Set-Cs2013Features.v3.7.zip v3.6 – 02-12-2015 – Set-Cs2013Features.v3.6.zip v3.5 – 02-02-2015 – Set-Cs2013Features.v3.5.zip v3.4 – 01-26-2015 – Set-Cs2013Features.v3.4.zip v3.3 – 01-07-2015 – Set-Cs2013Features.v3.3.zip v3.2 – 12-22-2014 – Set-Cs2013Features.v3.2.zip v3.1 – 10-24-2014 – Set-Cs2013Features.v3.1.zip v3.0 – 10-06-2014 – Set-Cs2013Features.v3.0.zip v2.9 – 09-22-2014 – Set-Cs2013Features.v2.9.zip v2.8 – 08-13-2014 – Set-Cs2013Features.v2.8.zip v2.7 – 06-26-2014 – Set-Cs2013Features.v2.7.zip v2.6 – 06-10-2014 – Set-Cs2013Features.v2.6.zip v2.5 – 05-24-2014 – Set-Cs2013Features.v2.5.zip v2.4 – 04-29-2014 – Set-Cs2013Features.v2.4.zip v2.3 – 02-08-2014 – Set-Cs2013Features.v2.3.zip v2.2 – 01-20-2014 – Set-Cs2013Features.v2.2.zip v2.1 – 12-17-2013 – Set-Cs2013Features.v2.1.zip v2.0 – 11-26-2013 – Set-Cs2013Features.v2.0.zip v1.9 – 10-28-2013 – Set-Cs2013Features.v1.9.zip v1.8 – 08-01-2013 – Set-Cs2013Features.v1.8.zip v1.7 – 05-31-2013 – Set-Cs2013Features.v1.7.zip v1.6 – 05-24-2013 – Set-Cs2013Features.v1.6.z1p v1.5 – 05-10-2013 – Set-Cs2013Features.v1.5.zip v1.4 – 05-03-2013 – Set-CsLync2013Prerequisites.v1.4.zip v1.3 – 04-29-2013 – Set-CsLync2013Prerequisites.v1.3.zip v1.2 – 04-01-2013 – Set-CsLync2013Prerequisites.v1.2.zip v1.1 – 02-28-2013 – Set-CsLync2013Prerequisites.v1.1.zip v1.0 – 02-08-2013 – Set-CsLync2013Prerequisites.v1.0.zip # Changelog See the changelog for information on what’s changed/included in each version. ## Script: New-ExpiringCertificatesReminder.ps1 – Receive a Reminder When Certificates Have Expired/Are Expiring September 14th, 2012 2 comments # Detailed Description Sometimes we’re so deep in projects or putting out fires that some things just get forgotten, or we don’t get that far down the “to-do” list. Some of those things aren’t that big of a deal and don’t impact users. Other tasks can have drastic impact. Such as forgetting to renew your server certificates. It’s true that some services like the phenomenal Digicert will remind-you-to-death about certs that are expiring. But not all services do that, or they do it once and are forgotten. Other certs, like internal certs, don’t generate a reminder – and some environments don’t allow, or aren’t configured to automatically renew internal certificates. So this lazy, forgetful guy decided to do something about that. A script was born. This script monitors certificates in the Local Machine store on the local server, and sends a reminder when a cert is expiring soon, or has already expired. An example is shown below. Sample email about an expired certificate # Installation Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet. Download the script and ImageFiles.zip files from the DOWNLOAD section below. Copy the image files to a location available to all users who will receive the reminder email. I suggest a web server with public access. NOTE: These images are the SAME files and names as the ones for New-PasswordReminder.ps1, so you can use the same path if you use both scripts. Open the script in a text editor and edit the variables in the param block to suit your needs. At a bare minimum, you need to adjust: •$Company – this should be your company name
• $PSEmailServer – this is the email server the script will send the emails to •$EmailFrom – this is the SMTP address that the emails will come FROM
• $EmailTo – set this to the SMTP address of the user/distribution group that should receive the reminder emails •$HelpDeskPhone – if not empty, this appears in the email message
• $HelpDeskURL – if not empty, should be a URL to a web version of the email. If blank, the “If this email does not appear…” and “This email was sent by…” lines shown in the above example are not included. •$ImagePath – where the images are stored. This should be publicly reachable for users checking email from mobile devices and web clients

optionally, adjust $threshold from the default 15 to indicate how many days in advance the script should start reminding about an expiring certificate. Save the script. If you don’t already have a Receive Connector in Exchange to allow PowerShell scripts to send email, create one using the information at Creating A Receive Connector To Use For Sending Email From PowerShell. If you have certs that are already expired, or are expiring soon, you can manually run the script to test. To do that, open PowerShell and type New-ExpiringCertificatesReminder.ps1 Once everything is done, you can run the script in Install mode: New-ExpiringCertificatesReminder.ps1 -Install and the script will prompt for the user password, then automatically create a scheduled task on the local server to run every day at 7:30am. You can open the Scheduled Tasks GUI and adjust parameters as needed, but I’ve found the defaults to be fine. Repeat on any other servers you’d like to monitor. # Donations I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab. # Download v1.3 – 02-13-2017 – New-ExpiringCertificatesReminder.v1.3.zip v1.2 – 01-27-2014 – New-ExpiringCertificatesReminder.v1.2.zip v1.0 – 09-14-2012 -Â New-ExpiringCertificatesReminder.v1.0.zip ScriptImages.zipÂ – these are the images specified in the emails # Changelog See the changelog for information on what’s changed/included in each version. Categories: PowerShell Tags: ## Script: Grant-CsPolicyByADGroup.ps1 – Assign Lync/Skype for Business Policies to Users According to AD Group September 10th, 2012 11 comments This idea is from a LinkedIn post that I responded to. The original poster wanted to know if there was a way to manage Lync external access policies based on AD group membership. Absolutely! This is a fairly simple script that uses a scheduled task that runs every 4 hours, looks at the members of a given AD security group, including nested groups, and applies a Lync policy to each member. The name of the AD security group and the type and name of the policy are all configurable. The ActiveDirectory and Lync PowerShell modules are used to complete this. The actual moving parts are pretty simple – really just two lines of code. But some extra error catching, installation code, and safeguards make it a tad bigger. Caveat – users get policies when they launch the Lync client. So even though a policy might be assigned to a user, they won’t see any change until the client is restarted. Caveat #2 – if you configure this script with several scheduled tasks to handle different policies and different AD groups, make sure users don’t end up in multiple groups, or you could have unintended results. Also removing a user from a group does NOT revert their policy back. The reason I didn’t add that is because moving a user from one group to another could cause problems if the script set them back to a default policy, yet another group needed to change it to a different policy. # Installation Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet. Download the script from the DOWNLOAD section below. Open it in your favorite text editor. Find the line that reads [string]$GroupDN = "",

and put the Distinguished Name of the group in between the quotes. For example

[string]$GroupDN = "CN=Lync Policy Group,DC=contoso,DC=com", Next, define the policy that will be granted to members of the group. Find the line that reads [string]$PolicyName = "",

and put the name of the Lync policy in between those quotes, such as

[string]$PolicyName = "Executives External Access Policy", The last thing we need to do in the script file is define what KIND of policy we’re going to grant. Find the line that reads [string]$PolicyType = "ExternalAccess",

And adjust accordingly. The allowed values are Archiving,Client,ClientVersion,Conferencing,ExternalAccess,HostedVoicemail,Location,Mobility,Pin,Presence,Voice to represent the various types of policies you can apply to a user. The default is ExternalAccess.

Next, ensure that the server where the script will run has both the ActiveDirectory and Lync PowerShell modules installed. Domain controllers typically have the ActiveDirectory module, and Lync servers have the Lync module. Install the appropriate ones using these steps.

To install the ActiveDirectory module, open PowerShell and type the following:

Import-Module ServerManager
Add-WindowsFeature -name AD-Domain-Services -IncludeManagementTools

To install the Lync Server Management Tools, which includes the PowerShell module, install the core components. See Install Lync Server Administrative Tools for details.

This will ensure that both modules are available. The ActiveDirectory module is used to get the members of the AD security group, and the Lync module is used to actually grant the policy.

The script must run as a member of the CsUserAdministrator or CsAdministrator groups, as those have the rights to assign policies.

Next, open PowerShell and run the script with the -install switch. The script will prompt for the password of the currently logged on user, and then create the scheduled task to run the script every 4 hours.

Grant-CsPolicyByADGroup.ps1 -install

The scheduled task will run every 4 hours, with a start time of when you ran the -install option. You can open the scheduled task in Task Manager and adjust as needed.

You can run the script manually as well. Just run

Grant-CsPolicyByADGroup.ps1

Note that it may take a while before the policy is visible on the user account due to AD replication.

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

# Changelog

See the changelog for this script for a description of changes with each release.

# Description

When cumulative updates are released from the Lync Product Group, they often contain firmware updates for Lync Phone Edition devices. The update process is somewhat arduous in that you have to download each update for each device model, extract it, then manually upload each firmware file, test it, then approve it for wide scale release. If you have multiple pools, the updates need to be uploaded to each one so that a copy exists in each Lync file share. And there is no way to select multiple files and upload them, and each file is named ucpdates.cab, so they need to be in separate folders. So, I made this little script to help deal with the upload process.

Create a parent folder called whatever you want. In my example, it is called “CU6 – June 2012”. Inside that folder, I have the Cumulative Update file, LyncServerUpdateInstall.exe, as well as child folders for the various devices. The child folders can be called anything.

Folder and file structure

Files in each child folder

Next, run the script using

.\New-CsFirmware.ps1

If the script was launched from a plain PowerShell console, the Lync module will be loaded automatically.

Next, you’ll be prompted for the parent folder.

Prompt for folder

Select the parent folder and click ok. The script will look through the parent folder and all child folders for update files called ucupdates.cab, and will upload them to all pools that it can find.

That’s all there is to it. You will still need to follow the rest of the upgrading process such as configuring test devices, testing, and then approving. Fellow MVP Jeff Schertz has a fabulous blog post, Updating Lync Phone Edition Devices that details the entire process.

You can also include the path to the parent folder when you run the script, such as

.\New-CsFirmware.ps1 -FilesPath "c:\users\lyncent.administrator\desktop\cu6-june 2012"

and the script will skip prompting for the folder.

.\New-CsFirmware.ps1 -Download

Will download the firmware for LPE devices, and automatically import them. It does NOT download firmware for SNOM or Polycom VVX devices (yet).

A special shout-out to fellow MVP and Lync MCM Kevin Peters, who gave me the idea to script it out and include all of the child folders and all of the pools.

If you’d like to target just a specific pool for the updated firmware, using the -PoolFqdn parameter with the desired pool FQDN.

Once you’ve deployed the firmware, you can easily see the firmware versions connecting to Lync by using my Get-CsConnections script and specifying the -ClientVersion parameter with a value of “CPE”.

.\Get-CsConnections.ps1 -PoolFqdn mypool.fabrikam.local -ClientVersion CPE

And look at the first table:

# Installation

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

No real installation required. The script can be run from any machine that has the Lync Core Components installed. As usual, you do need to set your Execution Policy to RemoteSigned or Unrestricted in order to run PowerShell scripts. The script will create a folder called .\Logs, and it will create the transcript file in there for future reference.

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

Question: Will this update Roundtable devices?

Answer: No, but fortunately, fellow Lync MVP Jeff Schertz has an excellent article on how to upgrade those devices at http://blog.schertz.name/2012/02/update-cx5000-rt-firmware/.

Answer: Could be this quirky issue. http://uclobby.com/2013/11/06/lync-phone-edition-test-device-wont-update-to-unapproved-version/

v2.1 – 02-08-2017 – New-CsFirmware.v2.1.zip

v1.9 – 03-31-2015 – New-CsFirmware.v1.9.zip

v1.8 – 02-08-2015 – New-CsFirmware.v1.8.zip

v1.7 – 05-20-2014 – New-CsFirmware.v1.7.zip

v1.6 – 02-08-2014 – New-CsFirmware.v1.6.zip

v1.5 – 09-09-2013Â – New-CsFirmware.v1.5.zip

v1.4 – 05-10-2013 – New-CsFirmware.v1.4.zip

v1.3 – 10-17-2012 – New-CsFirmware.v1.3.zip

v1.2 – 08-17-2012 – New-CsFirmware.v1.2.zip

v1.1 – 07-10-2012 – New-CsFirmware.v1.1.zip

v1.0 – 06-30-2012 – New-CsFirmware.v1.0.zip

# Changelog

See the changelog for this script for a list of what’s changed in each version

## Description

I had a need to see real-time call data. Lync MVP/MCM Tom Pacyk has a really cool script for logging concurrent calls to .csv over time by querying perfmon counters at regular intervals. That works great when you’re trying to determine concurrent for scale planning. But I wanted to see who was on the phone – not just the number of current calls.

This script will look at the LCSCDR database, which is installed when you install a Monitoring Server in your topology. The script gathers information about current calls in progress, and displays them in list style. It’s fairly basic.

Call between Lync users

As you can see, the list shows the two users in the call, their ID number, who initiated the call, when it was made, etc. In this screen shot, User 1 was connected from outside the environment (IsUser1Internal is false), while User2 was in a company office with WAN connectivity to the Lync infrastructure (IsUser2Internal is True).

If a user has initiated or received a call to/from a PSTN number, then User2Uri will read “PSTN call”.

Call to PSTN number

As mentioned above, a Monitoring Server does need to be installed in your topology so that the LCSCDR database is created and updated. But the script can be run from anywhere.

You could also wrap this into a function and toss it in your PowerShell profile to make easily accessible.

This script was more of a proof of concept into querying SQL from PowerShell, and the required query. If you have suggestions, let me know!

## Installation

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

Download the script from below to a server with PowerShell. Run the script in PowerShell using

Get-CsVoiceCalls.ps1 -server [SQL server]

If the lcscdr database is in a named instance, specify the instance

Get-CsVoiceCalls.ps1 -server [SQL server] -instance [instance]

Where [SQL server] is the FQDN of the database server containing your LCSCDR database.

You can also hard code the SQL server FQDN and the instance in the script. Look for

[string]$server, and change it to include the SQL server FQDN, such as [string]$server = "sqlserver.domain.local",

and look for

[string]$instance, and change it to include the instance name, such as [string]$instance = "Lync",

And then you can just call the script by name using

Get-CsVoiceCalls.ps1

There is also full comment based help, using

Get-Help Get-CsVoiceCalls.ps1

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

## Known Issues

1. The logic that looks for the database in named instances still needs more testing. If you run it in an environment where you have the lcscdr database in a named instance, please let me know your results.
2. I tried to adapt to correcting the time display. The data is apparently stored in SQL in GMT. So I’ve coded the script to display it according to the local time zone (according to Windows). Let me know if your results aren’t as expected.
3. If a user receives a call from a PSTN number, the SessionStartedById field is blank. Working around that has been problematic, but I’m still trying.

Get-CsVoiceCalls.v1.4.zip

Get-CsVoiceCalls.v1.2.zip

## Changelog

See the changelog for this script to see what has changed between versions.

## Script: New-HandBrakeConversion.ps1 – Convert Entire Folders of Files to .mp4 With HandBrake

I watch at LOT of movies. Since I’m generally away from home at least 200 days a year, I spend a lot of time in airports, on airplanes, in hotels, etc. When I work from home, I watch movies and TV shows as well. My iPad and my 5TB iTunes library keep me entertained.

Many of the videos I have start in something other than the .mp4/.m4vÂ format that iTunes requires. Either it’s something I’ve downloaded, something someone sent me, training (CBT) videos, or something pulled from my HD video camera’s hard drive. The files usually are either .avi or .mkv.

There are plenty of utilities out there that will convert video files from one format to another. Some of them are free, and some cost a few bucks. By far the best, most flexible utility I’ve found is the popular HandBrake. HandBrake has many options that let you get down “in the weeds” with every setting conceivable for converting videos. It has a popular queuing feature that lets you add several files to the queue, and HandBrake will process them, one at a time. Processing time depends on the source file size and format, as well as the destination format. And, it’s FREE.

Since I am away from my monster desktop machine so much, I put it’s i7 processor’s idle time to good use by having it process videos, saving them as .mp4 videos. But manually adding a bunch of videos to HandBrake’s queue can take a while. Plus, since I’m not around when the processing is taking place, I don’t need the fancy GUI from HandBrake. When HandBrake is installed, a CLI version is also automatically installed So I created a PowerShell script that will use the CLI version, take a source folder, and process every video in that directory that doesn’t have a corresponding .mp4 file of the same name. That way, if the script stops and you need to restart it, it won’t re-process video’s it’s already converted. It will only attempt to convert files with .avi, mkv, .ogm, and .wmv extensions, but only the first two, .avi, and .mkv, have been extensively tested.

The script will automatically detect if/where HandBrake is installed, so there is nothing really to configure. Run the script with no switches, and you’ll be prompted for the source folder that contains the videos to be converted:

.\New-HandBrakeConversion.ps1

Or, you can specify the source folder and avoid the prompt:

.\New-HandBrakeConversion.ps1 -dir "c:\path\to\files"

For those of you who are hardcore HandBrake users, the configuration settings I use are the following:

-e x264 -b 1500 -a 1 -E faac -B 160 -R Auto -6 dpl2 -f mp4 -m -2 -T -x ref=2:bframes=2:me=umh -n eng

Let me know if you have any questions or comments.

# Installation

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

There is no installation routine for this script. It’s meant to be manually run.

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

# Changelog

See the changelog for this script for all version information

Categories: PowerShell Tags:

## Script: New-DirectoryUpdateReminder.ps1 – Prompt Users to Update Their Active Directory Information

This script will look at all users in AD, and determine if they are missing key information such as office, address, title, and manager. If they are, it will send them an email requesting they update their information. It should be noted that this script is designed for environments that have a self-service solution in place for users to update their information. This can include Exchange 2010, where ECP allows the user to change many fields:

ECP options to change user info

In some of the environments that I build, where Exchange 2010 isn’t an option, or other fields need to be changed, I install Directory Update, a small footprint solution for IIS. Directory Update is a PHENOMENAL solution that’s inexpensive, yet feature packed. It’s fully configurable and features drop downs, check boxes, and logic to ensure that users are inputting the correct information in the correct format. It also allows you to specify what fields the user can update. I highly recommend it. Other environments might use some home-grown solution, or even SharePoint. Either way, a self-service solution takes the burden off the Help Desk. A perfect example is when a manager leaves the organization. When their AD account is deleted, the users who had that person listed as their manager will automatically start getting reminders from this script since the field is now empty.

Many orgs don’t worry as much about some of these fields. However, when the information is current and correct, the data can be pulled for other purposes, such as workflow applications, org charts, phone lists, etc. Some orgs use transport rules to create disclaimer or signature phrases such as how to contact a user’s manager. All of these are perfect reasons for using this script.

## Features

Runs as a scheduled task, and will remind users daily until their information is complete.

Can be run in DEMO mode to see which users would receive an email.

Can be run in PREVIEW mode to receive the formatted message to see what it looks like before rolling it out in production.

## Installation

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

This script requires a receive connector that will accept mail. See Creating a receive connector to use for sending email from PowerShell.

Once the receive connector is created, copy the script from the .zip file below to your server.  Open the script in any true text editor, and set the various parameters. See the highlighted lines in the script below. Each should be configured for your environment.

[parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$true, Mandatory=$false, HelpMessage="Please specify a company name.")] [ValidateNotNullOrEmpty()] [string]$Company = "Contoso Ltd",
[parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$true, Mandatory=$false, HelpMessage="Please specify an OWA URL")] [ValidateNotNullOrEmpty()] [string]$UpdateUrl = "https://directory.contoso.com/",
[parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$true, Mandatory=$false, HelpMessage="Please specify the IP address of your email server")] [ValidateNotNullOrEmpty()] [string]$EmailServer = "10.9.0.11",
[parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$true, Mandatory=$false, HelpMessage="Please specify a name and email address for the email 'from' field")] [ValidateNotNullOrEmpty()] [string]$EmailFrom = "Help Desk ",
[parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$true, Mandatory=$false)] [string]$HelpDeskPhone = "(586) 555-1010",
[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$false)] [ValidatePattern("^http")] [string]$HelpDeskURL = "https://intranet.contoso.com/",
[parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$true, Mandatory=$false)] [string]$TranscriptFilename = $MyInvocation.MyCommand.Name + " " + (hostname)+ " {0:yyyy-MM-dd hh-mmtt}.log" -f (Get-Date), [parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$false, Mandatory=$false, HelpMessage="This must be zero")]
[ValidateNotNullOrEmpty()]
[int]$UsersNotified = 0, [parameter(ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$true, Mandatory=$false)]
[string] \$ImagePath = "http://www.domain.com/images",

Save the script on your server.

Copy the images in the .zip file to the path you specified on line 102 above.

Run the script in demo mode to see a list of users that would receive the email messages:

.\New-DirectoryUpdateReminder.ps1 -demo

Test the script’s email functionality next by using preview mode. In preview mode,Â a single user will receive the email message. This will allow you to see what the users will see, as well as ensure that the formatting and wording is sufficient.

.\New-DirectoryUpdateReminder.ps1 -preview -previewuser [username]

After receiving and reviewing the message, adjust the HTML code as needed.

To configure the script to run as a scheduled task, run the script in install mode using

.\New-DirectoryUpdateReminder -install

This will create a Windows scheduled task that will run the script every day at 6:30am. Once the scheduled task is created, feel free to edit it to change the time.

That’s all it takes. Feel free to leave comments below, including any feature requests you’d like.

# Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.