Archive

Posts Tagged ‘PowerShell’

New-MtrWallpaper – Automatically Change Wallpaper on Teams Room System Every Day

January 19th, 2020 5 comments

Description

In playing with setting a custom wallpaper on some Microsoft Teams Room (MTR) systems, I wondered how hard it would be to have a new wallpaper everyday. I looked up the official documentation, as well as chatted with Eric Marsi (@EricMarsi) about how custom wallpaper is handled on MTRs. Eric has written an article, Configuring Custom Themes for Microsoft Teams/Skype Room Systems, on the basics of how to set a custom theme for an MTR, which includes a custom wallpaper. Check out his article. My article focuses on using the same core process, but automating it and having it run daily, randomly picking a new wallpaper each day.

My first theory was to just copy a wallpaper and generic SkypeSettings.xml file to the folder each day, then send a reboot command to the computer to implement the change. I had it all figured out, but then a coincidence made life easier. I was working at my PC on an unrelated project late one night (about 2:30am), when I heard the Rally camera behind me start it’s initialization process. When I checked, the Intel Nuc that serves as the compute for my Logitech Tap, was rebooting. I added “figure out what’s wrong with the Tap” to my task list. Anyways, next night, not having gotten that far down my task list yet, same thing happened, and I noticed it was at the exact same time. Time to roll up my sleeves. What I determined was there was a scheduled task called ‘NightlyReboot’ that runs at 2:00AM daily on MTRs. Drilling down, I discovered that a BUNCH of PowerShell scripts run as a result, including some that do Windows Updates, and some routine cleanup. At the end of this ~30 minute process was a Restart-Computer -Force command. I figured that makes life easier for my wallpaper idea. So, I came up with a function that looks into a folder full of wallpaper .jpg files, randomly selects one, and copies it to the appropriate folder. Next, the script writes a new XML file that includes ONLY the elements required for a custom theme. That’s all that’s done. I thought about just adding my function to one of these existing PowerShell scripts, but then opted not to do that to ensure it survives any upgrades and updates to the MTR software. The script is executed daily with a dedicated scheduled task. We then leverage the daily reboot that’s already in place to implement the changes. Presto – daily wallpaper change. I think I spent more time looking for cool wallpaper images than writing the code. One of my favorites is the Spy vs. Spy image shown above on one of the MTRs in my home office.

There is nothing fancy about my method, and it could easily be customized to use, say, an XML file full of dates and wallpaper names to use specific wallpaper images on certain days, such as holidays or company events and announcements.

Installation

Log onto the MTR as admin

Life is much easier if you use RDP to do all of this. RDP isn’t enabled by default on MTRs, but just enabling it Windows 10 is straight forward. Click ‘Settings’ on the touch screen, enter the password, then go to Windows settings. Enter the admin password and you’re in Windows 10. A quick search for ‘remote desktop’ gets you there. Everything configured here is done so while logged in as Admin.

Create folder

  • Open Windows Explorer and navigate to ‘C:\Users\Skype\AppData\Local\Packages\Microsoft.SkypeRoomSystem_8wekyb3d8bbwe\LocalState’. Create a folder there called ‘Wallpapers’.

Copy script to the Wallpapers folder.

  • Download the New-MtrWallpaper.ps1 script file from the link below, and copy it to the folder created above.

Upload wallpaper images

  • Copy all of your wallpaper files to that same folder. The script is written for .jpg files. You should now have a folder with the script and wallpapers in it.

Create scheduled task

Open Task Scheduler

  • Navigate to Task Scheduler Library>Microsoft>Skype
  • Create a new Basic Task called ‘Rotate Wallpaper’

On the ‘General’ tab:

  • Ensure that the admin account is specified under ‘When running the task, use the following user account’.
  • Select ‘Run whether user is logged on or not’
  • Select ‘Run with highest privileges’

On the ‘Triggers’ tab, create a trigger:

  • ‘Begin the task’ set to ‘On a schedule’
  • Set the ‘Settings’ to ‘Daily’
  • Set the time to any time before 2:00am. I use 10:15:00 PM. Set the recurrence to every 1 days (or whatever schedule you’d like, keeping in mind that the scheduled reboot only happens once a day).
  • All other check boxes except ‘Enabled’ should NOT be checked.

On the ‘Actions’ tab:

  • Set ‘Action’ to ‘Start a program’.
  • For Program/script, use ‘Powershell’.
  • For ‘Add arguments (optional)’, paste the following single line:

-NoProfile -ExecutionPolicy bypass -file C:\Users\Skype\AppData\Local\Packages\Microsoft.SkypeRoomSystem_8wekyb3d8bbwe\LocalState\Wallpapers\New-MtrWallpaper.ps1

  • For ‘Start in (optional), paste the following single line:

C:\Users\Skype\AppData\Local\Packages\Microsoft.SkypeRoomSystem_8wekyb3d8bbwe\LocalState\Wallpapers

On the ‘Conditions’ tab

  • Leave all blank except the first two under ‘Power’.

On the ‘Settings’ tab:

  • Select ‘Allow task to be run on demand’
  • Select ‘Stop the task if it runs longer than 1 hour’
  • Select ‘If the running task does not end when requested, force it to stop’.

Save the task, entering the password for the admin account when prompted. Now, right-click the task in the list, and select ‘Run’. Wait a few seconds and refresh, and the ‘Last Run Result’ field should say ‘The operation completed successfully. (0x0)’. Verify that both the SkypeSettings.xml and wallpaper.jpg now exist in the ‘C:\Users\Skype\AppData\Local\Packages\Microsoft.SkypeRoomSystem_8wekyb3d8bbwe\LocalState’ folder. Restart Windows. The MTR will boot accordingly, and you’ll have a new wallpaper. If you look into that folder now, the XML and wallpaper files will no longer be there.

Known Issues

There is a strange occurrence where I’ve manually run the script, then manually rebooted one of my MTRs and the new wallpaper wasn’t incorporated. However, every time the schedule task runs, and the MTR restarts as part of its nightly maintenance, it’s worked fine.

Frequently Asked Questions

Q. What resolution do my wallpaper files need to be?

A. They need to be exactly 3840×1080, regardless of whether you have a single or dual screen Teams Room System.

Q. How many wallpaper images can I have?

A. As many as you like, keeping in mind that the more you have, the less likely you’ll have consecutive days with the same image.

Q. Does this impact performance?

A. This script does NOT impact performance in any way. It can easily run while the MTR is connected to a meeting. The reboot occurs regardless, so no added impact there.

Download

This script is available in my GitHub repo at https://github.com/patrichard/New-MtrWallpaper. Feel free to grab it from there, and contribute any updates or improvements.

If you’re looking for wallpaper, Bing search yields a ton of them.

Changelog

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

Set-CsFeatures.ps1 – Now With Support for Skype for Business Server 2019 and Windows Server 2019!

September 17th, 2018 7 comments

Description

I’m happy to reach another major milestone for the Set-CsFeatures.ps1 script today, after many weeks of work. This PowerShell script, which installs prerequisites and post installation configuration and tools for Lync Server and Skype for Business Server, now adds support for a few new things. This includes a new version of Skype for Business Server, as well as another operating system. The major changes are listed below. See the full list of changes in the changelog (link at the bottom of this article). Having said all of that, let’s look at all the exciting stuff…

Support for Skype for Business 2019

The script will now install the prerequisites for Skype for Business Server 2019 roles, including front-end, mediation, and edge. “But Pat”, you say – “Skype for Business 2019 isn’t even out yet”. This is true. This script adds the support so that you can hit the ground running when the RTM version is released. If you’re already playing with the Preview version in your lab, this will work there as well. Since Skype for Business Server 2019 has more features related to Office 365, including Skype for Business hybrid and online, and Microsoft Teams, rest assured that I’ll be adding more options and features to support and utilize those.

Support for Windows Server 2019

Now supported by this script are the prerequisites for Windows Server 2019 when installing Skype for Business Server 2019. What what what? That’s right, I support a not-yet released version of Skype for Business on a not-yet released operating system. Crazy? Yep. But some individuals and organizations are already working with this combination, and I wanted to provide a solution that makes life easier for them. Rest assured that as the SfB 2019 and WS2019 solutions evolve, so will this script. Version 5.0 of this script was tested against build 17744.r5 of Windows Server 2019.

Optimized code

As I’ve said before, I don’t consider myself a developer. I’m merely a coder that manages to make things work. As my skills increase, I always try to revisit existing scripts and enhance them with better ways of accomplishing tasks. Some of that is from methods available in newer versions of PowerShell, and some are just in the discovery of better avenues of approach to tasks. There are a LOT of changes in the script to reflect that. If I had to guess, I’d say at least 1000 lines of code have been touched just in the past few weeks.

Skype for Business 2019 Control Panel. Click to view full size.

Enhanced logging

While I realize most people probably never look at the resulting log files generated from this script, they can be key in knowing what’s happened on a server as well as being able to review for troubleshooting in the event of an issue. I think I’ve built and provisioned more servers in my lab to test changes in logging than anything else. There is also the built-in ‘tail’ function that allows you to watch the log file in real-time to see what’s going on ‘under the hood’.

Set-CsFeatures.ps1 log file. Click to view full size.

Latest updates for key components

There are updates for some components that have been released recently. This includes the latest cumulative update for Office Online Server, and an update for Windows Server 2012 R2 that replaces a previously required hotfix for Skype for Business Server 2015.

Feature requests

Sometimes, someone suggests a feature or alternative option to something. This version is no different, incorporating some ideas presented by the community. A few are “why didn’t I think of that” type features. An example is popping up a folder browse dialog box if the script can’t find the Windows source files, instead of just throwing an error. Please continue to send feature requests!

Bugfixes

Yeah, bugs happen. As much as I test, some people still find things, although most are just minor things like typos, or features that work differently than what someone expected or wanted. And some are ones I notice that haven’t been reported by anyone else. These pop up either in my lab testing or when I’m working on an unrelated part of the code and just notice it.

More than 8500 lines of PowerShell code mean that the script is fairly complex. Perfect? Hell no. As I mentioned above, I’m a coder. I will say that I ferociously attack known/reported issues and feature requests, and strive to make this tool as best as it can be. While I can’t test every possible combination of environments, I think I’ve accounted for a lot of possibilities.

I sincerely appreciate when people notify me of issues. Seriously. There is an option, 96, in the script that shows you how to report a bug, including what log file to send me. That really helps me address problems quicker.

Finally…

Future additions currently under consideration include at least the following:

  1. Automatically add Windows Defender exceptions (auto discovery). This feature will discover an existing Skype for Business Server 2015/2019 installation, and automatically add the required anti-virus exceptions required for Windows Defender for a healthy operating Skype for Business deployment. Since both Windows Server 2016 and 2019 include Defender components, it makes sense to include this. These exceptions are based on the official exclusion list provided by Microsoft.
  2. Debugging tools, resource kit, etc. If/when these are added for Skype for Business Server 2019, the script will be updated to support the automated installation of them.
  3. Visual C++ 2017

So, with all of this newfound goodness baked into the script, where can one download this pot of gold? Head over to the home page for the script to grab this, or any version of it. The script fully supports using Get-Help for related information. All versions including this new v5.0, are signed with my Digicert code-signing certificate to verify authenticity. Digicert really makes it easy to use certificates, and they have stellar support, too. Also, any recent version of this script will notify you of an updated version when you run it (assuming it’s run on an Internet connected machine).

The changelog for the script shows all of the changes for each new version. Any bug fixes, feature additions & updates are reflected here.

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.

Prereq/provisioning script being updated to include Skype for Business Server 2019

March 27th, 2018 No comments

The biggest and most popular public script I’ve ever done is Set-CsFeatures.ps1. It performs tasks such as installation and configuration of all prerequisites for any desired Lync Server 2013/Skype for Business 2015 role, as well as many post installation tasks such as installation of many tools, and configuration of many parameters. What started out as a script to make MY life easier (as are most of my scripts), I’m glad to see the adoption by others. I’m ecstatic that enough people have reported their success and details to say that literally millions of seats have been deployed with this script.

As you can imagine, it’s a substantial effort, with the latest version weighing in at around 8000 lines of PowerShell code. And it’s constantly evolving to include more than 100 options, such as the latest version of tools and applications, features requests, and bug fixes, as the changelog clearly indicates. It’s also tweaked as my own development skills evolve. It’s a true labor of love, and I’m very grateful for all of the feedback, both good and bad. Please, keep it coming! With that being said, I’m happy to report that I’m already well into adding support for Skype for Business Server 2019.

For those of you who are fortunate enough to be involved in TAP/MVP/Elite groups that give you access to the bits, I’m hoping that you’ll use this script in your labs and provide any feedback (my email address is in the header of every script I release). For everyone else, don’t expect a lot of details about things with regards to Skype for Business Server 2019 other than what’s public. TAP/MVP/Elite groups are under strict NDAs. The changes I’m adding to Set-CsFeatures.ps1 don’t reveal anything that hasn’t been announced previously.

For those who continue to use the script to deploy Skype for Business 2015, again, please continue to provide feedback. While I can’t always accommodate every request, I do what I can to implement them. And I’m extremely grateful for bug reports. Seriously. I can’t test every possible scenario, so I’m glad that you take the time to send me info so I can correct it.

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.

Function: Get-CsMaliciousCalls – Retrieve Records for User Reported Malicious Calls in Skype for Business

January 25th, 2018 No comments

Description

A little known feature in Skype for Business is the ability for a user to report a malicious call that they’ve received. This can be done by going to Settings>Tools>Report a Call…, as shown below.

At that point, the user is presented a dialog that allows them to report the just completed call:

If you don’t see the ‘Report a Call…’ option in your client, ensure that the option is enabled in the appropriate voice policy. It can be enabled by setting EnableMaliciousCallTracing to $true, such as

Set-CsVoicePolicy -Identity Global -EnableMaliciousCallTracing $true

Clients will pick up that setting at the next policy refresh.

When the call is reported, info is inserted into the ErrorReportView table of the LcsCDR database. However, unless you’re querying for it, you don’t see it, and many don’t even know where it is, or that it’s even there. It doesn’t do much good if your users are reporting the calls, but you have no way to view the data.

There are a couple of ways you can retrieve the data. The first is some custom reports in your Monitoring Server’s reports. Next is a simple SQL query in SQL Server Management Studio against the LcsCDR database for records with a diagnostics ID of 51017. Just use the following:

SELECT * FROM [LcsCDR].[dbo].[ErrorReportView] WHERE [MsDiagId] = '51017'

The last option is to use PowerShell to make the query against the SQL server for the same info. SQL queries in PowerShell are nothing new. They’re relatively fast, and you end up with an array that can be handled like any other object in PowerShell. If you’re using the default instance of SQL server for the LcsCDR database, use the function like this:

Get-CsMaliciousCalls -Server [server name]

If you’re using a named instance, you can just add the instance name to the command, such as this:

Get-CsMaliciousCalls -Server [server name] -Instance [instance name]

As you can see from the screenshot below, the function will return objects with plenty of info. Note that the FromUri field is the user reporting the malicious call (callee), and the ToUri is the caller. We see the MsDiagHeader notes the reason as “Call Identified as malicious by user”.

Obviously, what you do with the information is up to you. You could use PowerShell to further filter the ToUri into an e.164 number and use that to block numbers at your gateways. Or, use an MSPL script on the front end/mediation servers to drop calls with that number. Quite a few possibilities. If you come up with more ways to use the data, drop me a line or post a comment below. For now, toss the function in your PowerShell profile and enjoy your new data view.

Download

This script is available in my GitHub repo at https://github.com/patrichard/Get-CsMaliciousCalls. Feel free to grab it from there, and contribute any updates or improvements.

Function: Get-CsPhoneNumberAssignment – Find Where a Number is Assigned in Skype for Business

January 22nd, 2018 1 comment

Description

One of the problems that can be truly maddening when troubleshooting issues is a 485 ‘ambiguous’ error in Snooper. This is when Skype for Business doesn’t know what to do with an inbound call because the number being called is configured in more than one place. Skype for Business will complain if you try to configure a number more that once in SOME areas, such as several users, but not in all areas. So you’re left with hunting around for a while to figure out where else the number is defined. Meanwhile, users are complaining that calls aren’t working. So I came up with a quick function that will look through all of the areas that a number can be defined, and will list all matches. Additionally, you can use the script to verify that a number is NOT assigned somewhere before assigning it to a resource.

Yes, I know that others have done similar things, notably Tom Arbuthnot’s Get-LyncNumberAssignment :Find #Lync Users/Objects by Phone Number/LineURI #PowerShell and Amanda Debler’s Is that Skype for Business (Lync) Number Free?, as well as other phone number management solutions such as those by Stale Hansen and Lasse Nordvik Wedø. I’ve had a previous version of my script in my profile for a long time and decided to clean it up and make it available.

Is that Skype for Business (Lync) Number Free?

This PowerShell function will look for a full or partial number to see where it is allocated. It looks at the following:

  • User LineUri
  • User PrivateLine
  • Meeting Room LineUri
  • Meeting Room PrivateLine
  • Analog Devices
  • Common Area Phones
  • Unified Messaging (UM) Contacts
  • Dial-In Conferencing Access Numbers
  • Trusted Application Numbers
  • Response Group Numbers

The function accepts input via the named LineUri parameter, or via pipeline. It returns a typical PowerShell object. Here is an example of specifying a full e.164 number.

Get-CsPhoneNumberAssignment -LineUri 12145551212

Example: Specifying a full e.164 number results in a single match. In this case, a user. Click image for larger view.

Specifying a partial number will likely show more matches.

Get-CsPhoneNumberAssignment -LineUri 1214

Example: Specifying a partial number results in several matches. In this case, some users and a dial-in access number. Click image for larger view.

Note that since it must look at all of the related objects in order to build the object, it can take a minute or so to complete. But at least now there is a single command you can run to look in all areas.

Download

This script is available in my GitHub repo at https://github.com/patrichard/Get-CsPhoneNumberAssignment. Feel free to grab it from there, and contribute any updates or improvements.

One-Liner: Get Your Office 365 Tenant ID

November 8th, 2017 No comments

Office 365 logoThere are occasions that you’ll need your Office 365 tenant ID. The tenant ID is just a GUID assigned to your tenant. You can look it up in the Office 365 admin portal by peeking under Admin>Admin Centers>Azure AD>Azure Active Directory>Properties, and you’ll see the tenant ID in the ‘Directory ID’ field. That’s quite a few clicks, AND you have to log in to the Office 365 portal. Over time, there have been other places in the Office 365 portal where you can find it as well. All of them requiring a handful of clicks.

If you’re logged into your tenant via the SkypeOnlineConnector PowerShell module, you can use the following to get your tenant ID:

Get-CsTenant | Select-Object DisplayName, TenantID

Note, if you’re not logged in via the SkypeOnlineConnector, you can run the following first after installing the SkypeOnlineConnector:

Import-Module -Name SkypeOnlineConnector
$session = New-CsOnlineSession -Credential $(Get-Credential)
Import-PSSession -Session $session

Just like the portal method, this requires you to be logged in. There’s a similar method if you’re connected to Microsoft Azure Active Directory Module for Windows PowerShell using Get-MsolPartnerContract, but with the same limitations. You get the idea. But sometimes you just need the tenant ID without having to login to anything. Well, a PowerShell one-liner to the rescue! Just change the ‘mycompany.onmicrosoft.com’ to your Office 365 domain name in the line below and run it in PowerShell:

(Invoke-WebRequest -Uri 'https://login.windows.net/mycompany.onmicrosoft.com/.well-known/openid-configuration' | ConvertFrom-Json).authorization_endpoint.Split('/')[3]

If you look at that one-liner, you see that we’re merely invoking a web request to a specific URI, converting the Json format that it returns, and then grabbing a bit of the resulting Uri.

If you want it to be a little more flexible, we can adjust the code to prompt for a domain name, in case you want to use it in various scripts, as well as suppress the verbose output:

(Invoke-WebRequest -Uri "https://login.windows.net/$(Read-Host -Prompt 'enter domain name')/.well-known/openid-configuration" -Verbose:$false | ConvertFrom-Json).authorization_endpoint.Split('/')[3]

Of course, us consultant types can turn that into a function and toss it into our PowerShell profiles so that it’s always available. This method works with either your default onmicrosoft.com or your primary vanity domain name. I don’t have a tenant with multiple domain names to test with, but I surmise that it works the same.

While I had this post in draft, my buddy Tony Redmond (@12knocksinna) tweeted a link to an article that shows you how to retrieve the tenant ID using a web browser. From a web browser, you can also get the information by going to the same URL as determined above:

https://login.windows.net/mycompany.onmicrosoft.com/.well-known/openid-configuration

In the results, look for a line that begins with ‘authorization_endpoint’ (usually the first line), and you’ll see your tenant ID GUID in the URL on that line.

As you can see, there are multiple ways to get the tenant ID. Some require PowerShell, some don’t. Some require you to login, some don’t.

 

PowerShell Default Parameter Values – Time to Tweak Your Profile Again!

January 18th, 2017 No comments

One of the great things about a PowerShell profile is you get to customize the environment. One nice feature to accomplish this is the ability to set default parameter values for cmdlets. A great write-up about this is available at About Parameters Default Values. You can see similar info by running get-help about_Parameters_Default_Values. I’m not going to go into great detail about the feature, as those two resources are more than sufficient. What I am going to list here are some great examples that I’ve come to love. They are all in my profile.

This first example if my favorite. When you use the Get-Help cmdlet, the resulting info is shown in a popup window. This is great as I can keep it open while I work on my code in the main console window.

$PsDefaultParameterValues.add("Get-Help:ShowWindow",$True)

If you’re an OCD type like me, you want output of commands to be formatted and everything to line up. This example defaults the Format-Table cmdlet to autosize its output.

$PsDefaultParameterValues.add("Format-Table:AutoSize",$True)

We can actually set this behavior for both Format-Wide and Format-Table at the same time (courtesy of TechNet):

$PSDefaultParameterValues.add("Format-[wt]*:Autosize",$True)

How about we capture the output of the last PowerShell command into a variable, such as $0 (courtesy of TechNet):

$PSDefaultParameterValues.add("Out-Default:OutVariable",“0”)

If you can’t tell by my other articles and scripts here, I spend a lot of time writing scripts to help in deployments, migrations, etc. When you’re getting or setting data in Active Directory, the last thing you want is for replication (intersite or intrasite) to be an issue. So, when possible, you specify a specific domain controller to send all of your commands together. This example comes from serverfault:

$PSDefaultParameterValues = @{"*-AD*:Server"='YOUR-CHOSEN-DC'}

Now that’s not completely perfect, as it would have a hard coded DC name. And just our luck, it will be migrated out of existence and then our stuff breaks. So, let’s set a default parameter value with the result of a PowerShell query. In this case, a DC in the same site for each of our Lync/Skype for Business cmdlets that support the Server parameter:

$PSDefaultParameterValues.add("*-Cs*:Server",(Get-ADDomainController -Discover -NextClosestSite))

Or maybe you want to specify the PDC emulator instead? (courtesy Tommy Maynard)

$PSDefaultParameterValues.Add("Get-ADPrincipalGroupMembership:Server",$((Get-ADDomain).PDCEmulator))

Or, we can use a variable. Let’s say we assign $DC to a DC in the same site, and then use that going forward:

$dc = Get-ADDomainController -Discover -NextClosestSite
$PSDefaultParameterValues.add("*-AD*:Server","$dc")
$PSDefaultParameterValues.add("*-Cs*:Server","$dc")

Now, how many times do you get the “Are you sure” prompt? Force the command instead of getting prompted!

$PSDefaultParameterValues['*:Force']= $true

Fellow MVP Boe Prox also has a great list of examples on his post Using $PSDefaultParameterValues in PowerShell. Check it out!

Now, you can list each of these, or any combination, in your profile, each on a separate line. Or, we can use an array to set all at one time:

$PSDefaultParameterValues=@{
'Format-Table:AutoSize'=$True;
'Get-Help:ShowWindow'=$True;
'Send-MailMessage:SmtpServer'=$smtpserver
}

Something to keep an eye on here. In previous examples, I was using the $PSDefaultParameterValues.add method which ADDS the value to the existing list. If you omit the “.add” and instead use “=” or “=@{}”, you are replacing all existing values with what you specify. Additionally, you can use the $PSDefaultParameterValues.remove method to remove specific parameter values and keep any remaining values. An example of removing a single default parameter value:

$PsDefaultParameterValues.remove("Get-Help:ShowWindow",$True)

Are all of these changes permanent? No. They are valid for the life of the PowerShell session. If you need to remove them mid-session, you can clear them using:

$PsDefaultParameterValues.clear()

Defining default parameter values can also be defined at various scopes, as well, including Global, Script, etc. See Get-Help about_Scope for more info.

I mentioned at the beginning that these are great in your profile. Well, they’re great in your scripts as well. They allow for global changes instead of going through a script and updating each call to a cmdlet. By all means, send me your favorites. We’ll build a big list!

Categories: PowerShell Tags: ,

All Skype for Business 2015 Cmdlets and the Default RBAC Roles That Can Use Them

December 23rd, 2016 2 comments

Description

In All Lync 2013 Cmdlets and the Default RBAC Roles That Can Use Them and the corresponding 2010 version, I show a table that lists every cmdlet available in a fully patched Lync server environment, and the default permissions for each of the default RBAC roles. Doing one for Skype for Business was always on my list, but I never really got around to it until a visitor recently noted that some of the RBAC permissions changed for existing cmdlets when compared to the Lync Server 2013 list. So I figured it was time to do a new one. The previous versions were all manually created – every row. That was extremely laborious, taking many hours. This time around I automated the info gathering using (what else), PowerShell. This gave me all of the data in a .csv file, and three minutes of styling in Excel, and presto!

One thing I did notice is that there is a small group of cmdlets that don’t yet have a description, synopsis, uri, etc. So you’ll see those blank cells highlighted in bright red for now. I’ve reached out to the Product Group for info on when that info will be available. As soon as I have an answer, I’ll get it posted here.

So the spreadsheet is available below, but what good would a blog article be without some PowerShell code? So here’s the code I came up with to create the spreadsheet.

$objectCollection = @()
foreach ($cmdlet in (Get-Command -Module SkypeForBusiness | Sort-Object -Property Name)){
  Write-Output -InputObject $cmdlet
  $cmdletHelp = $(Get-Help -Name $cmdlet)
  [string] $Synopsis = $cmdletHelp.Synopsis
  [string] $URI = (($cmdletHelp.relatedLinks.navigationLink | Where-Object {$_.linkText -match 'Online Version'}).uri) -replace 'EN-US/',''
  [string] $RBAC = "Get-CsAdminRole | Where-Object {`$`_.Cmdlets `-imatch `"$cmdlet`"}"
  $rbacroles = Get-CsAdminRole | Where-Object {$_.Cmdlets -imatch "$cmdlet"}

  [bool] $RbacCSAdministrator = $rbacroles.identity -icontains 'CSAdministrator'
  [bool] $RbacCSVoiceAdministrator = $rbacroles.identity -icontains 'CSVoiceAdministrator'
  [bool] $RbacCSUserAdministrator = $rbacroles.identity -icontains 'CSUserAdministrator'
  [bool] $RbacCSResponseGroupAdministrator = $rbacroles.identity -icontains 'CSResponseGroupAdministrator'
  [bool] $RbacCSLocationAdministrator = $rbacroles.identity -icontains 'CSLocationAdministrator'
  [bool] $RbacCSArchivingAdministrator = $rbacroles.identity -icontains 'CSArchivingAdministrator'
  [bool] $RbacCSViewOnlyAdministrator = $rbacroles.identity -icontains 'CSViewOnlyAdministrator'
  [bool] $RbacCSServerAdministrator = $rbacroles.identity -icontains 'CSServerAdministrator'
  [bool] $RbacCSHelpDesk = $rbacroles.identity -icontains 'CSHelpDesk'
  [bool] $RbacCSResponseGroupManager = $rbacroles.identity -icontains 'CSResponseGroupManager'
  [bool] $RbacCSPersistentChatAdministrator = $rbacroles.identity -icontains 'CSPersistentChatAdministrator'

  $object = [PSCustomObject]@{
    'Cmdlet' = $cmdlet
    'Description' = $Synopsis
    'Uri' = $Uri
    'Validate' = $rbac
    'CSAdministrator' = $RbacCSAdministrator
    'CSArchivingAdministrator' = $RbacCSArchivingAdministrator
    'CSHelpDesk' = $RbacCSHelpDesk
    'CSLocationAdministrator' = $RbacCSLocationAdministrator
    'CSPersistentChatAdministrator' = $RbacCSPersistentChatAdministrator
    'CSResponseGroupAdministrator' = $RbacCSResponseGroupAdministrator
    'CsResponseGroupManager' = $RbacCSResponseGroupManager
    'CSServerAdministrator' = $RbacCSServerAdministrator
    'CSUserAdministrator' = $RbacCSUserAdministrator
    'CSViewOnlyAdministrator' = $RbacCSViewOnlyAdministrator
    'CSVoiceAdministrator' = $RbacCSVoiceAdministrator
  } 
  $objectCollection += $object 
}
$objectCollection | Export-Csv -Path $env:UserProfile\desktop\SfB2015cmdlets.csv -NoTypeInformation -Encoding UTF8

 

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.1 – 03-01-2018 (through CU5) – SfB2015cmdletsCU5.xlsx

v1.0 – 12-23-2016 – SkypeForBusiness2015cmdlets.xlsx

Function: Remove-IisLogFile – Purging Old IIS Log Files with PowerShell

November 21st, 2016 1 comment

PowerShell-logo-128x84If you’re not careful, your server running IIS can create a LOT of logs. The default location for logs is in a sub-folder for the specific web site in c:\inetpub\logs\logfiles\. You can imagine the problems that will happen when your OS drive fills up with logs… things tend to not go so well, and the phone starts to ring. We can’t really just disable logging, as log files are an invaluable resource used in troubleshooting, planning, and maintenance.

Ryan over at Ryadel wrote a great article on adjusting the logging for IIS to be a little more helpful, and to minimize bloat. But we still need to watch for the accumulation of logs and the disk space they take. Ryan includes a two-line method of cleaning up the files in a single IIS site. But some servers, such as Lync and Skype for Business front end servers, have multiple web sites defined. I’ve taken Ryan’s method a bit further by incorporating an idea presented in a Stack Overflow thread, tweaked it a bit, and now we have some code that will clean up all log files that are older than 180 days for all websites on a server. Obviously, that time frame can be adjusted. Here it is the simple method:

Import-Module WebAdministration
$start = (Get-Date).AddDays(-180) 
foreach($WebSite in $(Get-WebSite)) {
  $logFile = "$($Website.logFile.directory)\w3svc$($website.id)".replace("%SystemDrive%",$env:SystemDrive)
  if (Test-Path $logfile){
    Get-ChildItem -Path "$logFile\*.log" | Where-Object {$PSItem.LastWriteTime -lt $start} | Remove-Item -Force
    # Write-Output "$($WebSite.name) [$logfile]"
  }
}

By adjusting the number at the end of the second line, we tailor the maximum age of the logs. In the above example, we’re keeping 180 days of them. We could put that code into a script and call it with a scheduled task to automate the cleanup, essentially creating a self-cleaning server. We can also wrap that code into a function and toss it into the PowerShell profile on the web server, allowing us to run it whenever we need to:

function Remove-IisLogFile{
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [int] $age = 180
    )
    Import-Module WebAdministration
    $start = (Get-Date).AddDays(-$age) 
    foreach($WebSite in $(Get-WebSite)) {
      $logFile = "$($Website.logFile.directory)\w3svc$($website.id)".replace("%SystemDrive%",$env:SystemDrive)
      if (Test-Path $logfile){
        Get-ChildItem -Path "$logFile\*.log" | Where-Object {$PSItem.LastWriteTime -lt $start} | Remove-Item
        # Get-ChildItem -Path "$logFile\*.log" | Where-Object {$PSItem.LastWriteTime -lt $start}
        Write-host "$($WebSite.name) [$logfile]"
      }
    }
}

Then we can call it, optionally specifying the age of the log files we want to purge using the -age parameter. I incorporate the Test-Path code to ensure we’re not throwing an error for a website that is stopped and has never run. This is often the case in the aforementioned Lync/Skype for Business servers, where the default web site is disabled.

As you can see, PowerShell can be great at making sure your servers don’t get packed full of log files, while still maintaining enough logs to be helpful.

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.

Script: Set-CsFeatures.ps1 – Easily Install Prerequisites and Tools for Lync Server 2013 and Skype for Business Server 2015/2019

October 24th, 2016 52 comments

Skype for Business PowerShell logoDescription

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 and 2019. 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.

When calling the script, one only needs to specify the –Skype4b switch to put the script into “Skype for Business 2015 mode” or -Skype4b2019 for “Skype for Business 2019 mode”. Not specifying that switch cause a pop-up to appear, asking what mode you’d like. The menus don’t change based on what mode the script is in. Options for only one platform are clearly noted. Otherwise, the options automatically adjust for the platform you’ve chosen. The menu starts out with core prerequisite options for common Lync/SfB roles, followed by Microsoft tools and resources, some third-party tools and options, and then some sub-menus. Sub-menus are broken down by Misc server config, Desktop shortcuts, Taskbar shortcuts, Downloads, Security options, and Misc reports. As you can see, there are TONS of options. I’m not going to list every menu and option here, as the nature of the script means I’ll be adding/updating things as people request them, or as vendors update/alter their offerings. Just note that the options from the 2013 script have been moved around a little bit as I try to keep things organized.

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. This script has more than 100 options for prereqs, post install config, third party tools, and reports.

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 ] [-Skype4b2019 ] [-SkipUpdateCheck ] [-DisableAutoUpdates ] [-IncludeLanguagePack ] [-SkipEdgeNicConfig ] [-DisableWac] [-WhatIf ] [-Confirm ] [-IncludeTotalCount ] [-Skip <UInt64>] [-First <UInt64>] [<CommonParameters>]

C:\Set-CsFeatures.ps1 [-TargetFolder <String>] [-GetInfoFromRegistry ] [-DownloadAll ] [-SkipCoreCheck ] [-Tail ] [-Skype4b ] [-Skype4b2019 ] [-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 ] [-Skype4b2019 ] [-WhatIf ] [-Confirm ] [-IncludeTotalCount ] [-Skip <UInt64>] [-First <UInt64>] [<CommonParameters>]

Examples

.\Set-CsFeatures.ps1 -Skype4b2019

Runs script in Skype for Business Server 2019 mode. Options chosen while running in this mode are tailored to Skype for Business Server 2019. 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 -Skype4b

Runs script in Skype for Business Server 2015 mode. Options chosen while running in this mode are tailored to Skype for Business Server 2015. 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. The script will prompt for which platform (Lync Server 2013/Skype for Business Server 2015/Skype for Business Server 2019) is being installed.

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

Runs script with the location defined for the Windows Server 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, similar to a Unix tail function. Please note that running this option may result in some popup alerts or prompts being behind the log (tail) window.

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.

-IncludeOnlineAdminTools

If specified, tells the script to automatically include the Skype for Business Online admin tools when installing prerequisites for front-end servers.

-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.

-DownloadOnly

Tells this script to not install or configure anything – just download 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. The big difference between this option and -DownloadAll, is that this option presents the normal menus, and allows you to download files for the options you pick. The -DownloadAll option downloads ALL files needed for ALL options.

-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 or -Skype4b2019 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, or Skype for Business Server 2019.

-Skype4b2019

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

-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.

-DisableWac

When specified, will automatically disable the Windows Action Center prompt when Server Manager is launched on Windows Server 2019. This can be crucial, as installing Windows Admin Center can cause some conflicts with some of the IIS settings for Skype for Business Server 2019. If this is not specified, and the script is running on Windows Server 2019, a prompt will appear.

-DomainSuffix

When specified, is used for the domain suffix configured on edge servers. If not specified, a prompt will appear to enter a domain suffix.

-DisableFPSharing

When specified, will disable Microsoft File and Printer Sharing. This is useful when building edge servers. If not specified, a prompt will appear at the appropriate time in the build process.

-DisableLmHosts

When specified, will disable LMHosts file lookup. This is useful when building edge servers. If not specified, a prompt will appear at the appropriate time in the build process.

-DisableNetBios

When specified, will disable NetBIOS. This is useful when building edge servers. If not specified, a prompt will appear at the appropriate time in the build process.

-IncludeTrustedCerts

Automatically adds trusted certificates to edge servers. This includes comodo, digicert, entrust, geotrust, globalsign, godaddy, letsencrypt, networksolutions, ssl, swisssign, symantec, thawte, and wisekey.

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, and doesn’t work at all in Windows Server 2019. 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 (including where the log file is).

Frequently Asked Questions

Question: Does the script support Windows Server 2019?

Answer: Yes – starting with version 5.0, prerequisites for Windows Server 2019 are included for Skype for Business Server 2019.


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 used to 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.x.

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, Server 2012 R2, Server 2016, and Server 2019 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 four 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 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?

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. If the script will start, select option 96, “Report a bug/problem with this script”. If you’re not using the latest version of the script, please download it from the Downloads section below 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. An exception to this is the latest cumulative update, which is always downloaded, since the URL and file name don’t change, even when the version does.


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

Answer: This is because the script didn’t exit gracefully previously. 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.


Question: Can I run the script more than once?

Answer: Absolutely. The script was designed to not only support running more than once, but also to be safe if run on a working Lync/Skype for Business server. HOWEVER, I wouldn’t recommend running the script in a different mode (Lync/SfB 2015/Sfb 2019) than what was run previously. That could be problematic.


Question: Why do I get prompted for some things? Can’t I run the script without all of those prompts?

Answer: The prompts are for things that are not explicitly required for the installation of the role you’ve chosen (according to official Microsoft documentation), but are recommended. The telnet client is a perfect example. It’s not required for any role, but I’ve found a lot of people install it to help with functionality testing and troubleshooting. So, optional items involve a prompt. Can you run without the prompts? Yep. Plenty of options when calling the script to accept some optional features. In the example of telnet, -IncludeTelnet will install the telnet client without prompting. For a complete list of command line options, see the parameter section above, or run ‘Get-Help Set-CsFeatures.ps1’


Download

v5.5 – 08-12-2019 – Set-CsFeatures.v5.5.zip Code signed with Digicert Code Signing certificate

v5.4 – 12-26-2018 – Set-CsFeatures.v5.4.zipCode signed with Digicert Code Signing certificate

v5.3 – 11-21-2018 – Set-CsFeatures.v5.3.zipCode signed with Digicert Code Signing certificate

v5.2 – 11-11-2018 – Set-CsFeatures.v5.2.zip Code signed with Digicert Code Signing certificate

v5.1 – 10-05-2018 – Set-CsFeatures.v5.1.zip Code signed with Digicert Code Signing certificate

v5.0 – 09-17-2018 – Set-CsFeatures.v5.0.zip Code signed with Digicert Code Signing certificate

v4.9 – 08-31-2018 – Set-CsFeatures.v4.9.zip Code signed with Digicert Code Signing certificate

v4.8 – 03-10-2018 – Set-CsFeatures.v4.8.zip Code signed with Digicert Code Signing certificate

v4.7 – 02-23-2018 – Set-CsFeatures.v4.7.zip Code signed with Digicert Code Signing certificate

v4.6 – 01-19-2018 – Set-CsFeatures.v4.6.zip Code signed with Digicert Code Signing certificate

v4.5 – 12-21-2017 – Set-CsFeatures.v4.5.zip Code signed with Digicert Code Signing certificate

v4.4 – 11-12-2017 – Set-CsFeatures.v4.40.zip Code signed with Digicert Code Signing certificate

v4.30 – 10-11-2017 – Set-CsFeatures.v4.30.zip Code signed with Digicert Code Signing certificate

v4.20 – 09-04-2017 – Set-CsFeatures.v4.20.zip Code signed with Digicert Code Signing certificate

v4.10 – 05-15-2017 – Set-CsFeatures.v4.10.zip Code signed with Digicert Code Signing certificate

v4.09 – 05-13-2017 – Set-CsFeatures.v4.09.zip Code signed with Digicert Code Signing certificate

v4.08 – 04-19-2017 – Set-CsFeatures.v4.08.zip Code signed with Digicert Code Signing certificate

v4.07 – 04-14-2017 – Set-CsFeatures.v4.07.zip Code signed with Digicert Code Signing certificate

v4.06 – 02-05-2017 – Set-CsFeatures.v4.06.zip Code signed with Digicert Code Signing certificate

v4.05 – 11-04-2016 – Set-CsFeatures.v4.05.zip Code signed with Digicert Code Signing certificate

v4.04 – 11-02-2016 – Set-CsFeatures.v4.04.zip Code signed with Digicert Code Signing certificate

v4.03 – 11-01-2016 – Set-CsFeatures.v4.03.zip Code signed with Digicert Code Signing certificate

v4.02 – 10-28-2016 – Set-CsFeatures.v4.02.zip Code signed with Digicert Code Signing certificate

v4.01 – 10-25-2016 – Set-CsFeatures.v4.01.zip Code signed with Digicert Code Signing certificate

v4.0 – 10-24-2016 – Set-CsFeatures.v4.0.zip Code signed with Digicert Code Signing certificate

Changelog

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