Archive

Posts Tagged ‘Skype for Business Server 2015’

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

December 23rd, 2016 No 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 Name)){
    Write-Output $cmdlet
    $cmdletHelp = $(Get-Help $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 = New-Object –Type PSObject
    $object | Add-Member –Type NoteProperty –Name Cmdlet -Value $cmdlet
    $object | Add-Member –Type NoteProperty –Name Description -Value $Synopsis
    $object | Add-Member –Type NoteProperty –Name Uri -Value $URI
    $object | Add-Member –Type NoteProperty –Name Validate -Value $rbac
    $object | Add-Member –Type NoteProperty –Name CSAdministrator -Value $RbacCSAdministrator
    $object | Add-Member –Type NoteProperty –Name CSArchivingAdministrator -Value $RbacCSArchivingAdministrator
    $object | Add-Member –Type NoteProperty –Name CSHelpDesk -Value $RbacCSHelpDesk
    $object | Add-Member –Type NoteProperty –Name CSLocationAdministrator -Value $RbacCSLocationAdministrator
    $object | Add-Member –Type NoteProperty –Name CSPersistentChatAdministrator -Value $RbacCSPersistentChatAdministrator
    $object | Add-Member –Type NoteProperty –Name CSResponseGroupAdministrator -Value $RbacCSResponseGroupAdministrator
    $object | Add-Member –Type NoteProperty –Name CSResponseGroupManager -Value $RbacCSResponseGroupManager
    $object | Add-Member –Type NoteProperty –Name CSServerAdministrator -Value $RbacCSServerAdministrator
    $object | Add-Member –Type NoteProperty –Name CSUserAdministrator -Value $RbacCSUserAdministrator
    $object | Add-Member –Type NoteProperty –Name CSViewOnlyAdministrator -Value $RbacCSViewOnlyAdministrator
    $object | Add-Member –Type NoteProperty –Name CSVoiceAdministrator -Value $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.0 – 12-23-2016 – SkypeForBusiness2015cmdlets.xlsx

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

October 24th, 2016 12 comments

skype_for_business_secondary_blue_rgbDescription

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 SfB 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 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, and Security options. 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.

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] [-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 prereqs 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 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. 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

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

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.

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

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


Download

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.

Automatically Installing and Configuring WireShark for Skype for Business

October 7th, 2016 2 comments

wiresharkDescription

I mention in the blog article Script: Set-Cs2013Features.ps1 – Easily Install Prerequisites and Tools for Microsoft Lync Server 2013 that one of the options in the menu, #30, is download, install, and configure WireShark. The configuration settings are based on those mentioned by Jeff Schertz (Wireshark Capture Tips) and Matt Landis (Getting Started With Lync and Wireshark: Tips & Quirks) , as well as those I’ve found useful. Most of these settings REALLY help when you’re looking at traces (and who doesn’t love an afternoon of doing that?). Among some of the configuration settings are:

  1. adds Source Port (resolved) column
  2. adds Destination Port (resolved) column
  3. adds DSCP 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

Why manually configure these on your server (or worse, many servers), if we can automate it? Let’s make our deployment life easier. Getting WireShark installed programmatically isn’t like other programs. There is no .msi file, or silent install switches. Methods I’ve used in other scripts just didn’t work. And believe me, I tried. And tried. And tried. So, I went medieval on it, and used AutoIt to create a macro that steps through the installer, clicking the right buttons. This works exceptionally well, and is fairly fast. But I wanted to also include the configuration steps mentioned above. And this is where it got interesting. WireShark’s config file seems to change formats and details often. So writing something that would change the config file directly seemed like it would be a losing battle. So, back to AutoIt. For 95% of the config, it worked great. But there seemed to be a need to click on the custom columns in order to set their name. AutoIt allows for moving the mouse to a certain vector, then clicking. But even with maximizing everything, the coordinates were never the same on different servers with different resolutions or RDP sessions. So that part of it would often not work. You’d get the columns, but they’d be named “New Column”. Not ideal. Finally, after taking a break from trying to figure that out, I rethought about it, and was able to figure out the right keyboard combination to accomplish the same thing. Success! There is one section right after that where the mouse is required to move the new columns into the desired order, but that seems to always work, and there’s no keyboard control for that. A remaining issue has been there since I first started this task. And that is the fact that AutoIt is written to take action based on app windows with certain titles. Usually not an issue at all, except that WireShark has always included the version number in the title bar. So every time there is a new version released, I’d have to open the source file, change the version number, re-compile to an .exe file, test, upload to my server, and update the prereq script. All in all, it is like 10 minutes of work, but I’ll need to continue to do that. As a result, I’m releasing the macros bundled the appropriate version of WireShark. Not sure if that violates some license with WireShark, but since they seem uninterested in making a silent installer method… Download the file from the link below. Unzip anywhere, as long all of the files are in the same folder. You’ll see there are three files:

  1. The WireShark bits, which are named with the version number, such as Wireshark-win64-2.2.1.exe for version 2.2.1. This is the file as it comes from WireShark.
  2. The installer macro, which is also named according to the WireShark version it applies to, such as WireShark_2.2.1-install.exe
  3. The config macro, which is also named according to the WireShark version it applies to, such as WireShark_2.2.1-config.exe

Run the installer macro first by double clicking on it. You’ll see it zip through the WireShark install routine. Once that closes, you can run the config macro. You’ll see it walk though the config. I do NOT recommend running the config macro more than once – lest you end up with a completely mangled config. It takes a minute or so to run. Once it’s done, you can open WireShark Legacy and use it. Once you start a trace, you should immediately be able to see the added columns:

ports

Added columns in WireShark. Click for a larger version.

If you wander through the config menus, you’ll see the other settings as well. The v2.x WireShark application that is also installed when you install WireShark is configured somewhat differently, and I’ll address that in the future. Right now, I’m not aware that it provides any added benefit for Skype for Business/Lync admins anyways. But really, WireShark, would it kill you to use an XML file for your config?! Or registry values? If you have some specific config settings you use for WireShark, pass them along!

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.

Downloads

WireShark v2.2.4 – 01-31-2017 – Wireshark_2.2.4-install.zip

WireShark v2.2.3 – 12-23-2016 – Wireshark_2.2.3-install.zip

WireShark v2.2.2. – 11-24-2016 – WireShark_2.2.2-install.zip

WireShark v2.2.1 – 10-07-2016 – WireShark_2.2.1-install.zip

Changelog

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

Writing a Book – A Labor of Love

October 5th, 2016 1 comment

book-coverAny tech types who’ve written tech books can attest to the fact that it’s a LOT of work. And this one was no different. Skype for Business is a very dynamic product, with features being added and updated on a continuing basis. Fortunately, I had the chance to work with some great tech luminaries – people far smarter than me, for Skype for Business Unleashed. That includes Phil Sharp, Rui Maximo, and Alex Lewis. But don’t let the fact that there are four names on the cover fool you. Plenty of others work behind the scenes, including contributing authors, editors, and publisher staff. I can’t possibly name them all, but I would like to point out a few. Stale Hansen stepped up and wrote a killer chapter on the VDI components of Skype for Business, while John Cook handled, what else, the Mac client chapter. Tom Morgan, one of Modality Systems’ ace developers, wrote on Developing Skype for Business Solutions. Former colleagues Tom Arbuthnot and Iain Smith also contributed. Even ‘The Hoff’ himself, Ken Lasko, added some great info. And to keep us all true to the product, Tim Harrington served as the tech editor. Jamie Stark, a beloved Program Manager in the Skype product group at Microsoft, wrote a killer forward.

During the project, several events occurred that seemed to derail the project. The publisher, Pearson, eliminated 4000 staff in a corporate downsizing. This was also around the time that Microsoft Press also underwent a significant restructuring. The project was in doubt for a while, but Pearson came back, committed to getting the book on to the shelves. Our normal full time gigs, family lives, and other interests also came into play. And unfortunately, someone involved in the book suffered a tragic loss. All of these caused the project timeline to slip. And during this time, the product group kept working on the product. Each time a Cumulative Update was released, we would have to review what had already been written to verify it still was valid, including details, screen shots, PowerShell commands, and more.

So why write this book? We certainly aren’t getting rich doing it. In fact, we’d all likely agree that you can’t survive on writing books at this pace. And time spent away from family and friends, and other interests can be tough. But seeing it on the shelf is rewarding on so many levels. It’s great to add the publication to your resume, LinkedIn profile, and more. Name recognition is always nice. But more importantly, getting the knowledge and experience into a format that can be beneficial to others is extremely personally rewarding to me. Is every little tidbit in there? Of course not. The book is 1100 pages. Decisions were made on how much space we could to allocate to each topic. Some chapters could be exponentially larger. But we tried to touch on the important stuff. Enough to get an environment properly designed, build, configured, and administered. And I think we did pretty well in that regard. And of course, as soon as we turned in the final edits, new features were released by the product group.

Books don’t sell unless people know about them. So we don our marketing hats and get on LinkedIn, Twitter, Facebook, blogs, and other online resources and let the world know it’s out there. Modality Systems was generous enough to put together a book signing event at Microsoft Ignite, and gave away some signed copies, as well. Twitter followers even started sending in pictures of where the book had been sighted, including the Microsoft Conference Store, MIT, and more. A signed copy even made its way to Gurdeep Pall‘s desk. Gurdeep is the Corporate Vice President of the Skype business unit at Microsoft, and he tweeted a selfie of himself holding the book. As I write this article, the book is the highest ranked Skype for Business book on Amazon. And that’s no easy task, as the other books were also written by some other top notch nerds like us.

cth_vttw8aij5ka-jpg-large

Book signing event at Microsoft Ignite 2016. From left to right: Stale Hansen, Phil Sharp, me, Rui Maximo, and Tom Morgan.

I again want to thank everyone involved. It would not have been possible without them. I’d also like to thank the entire Product Group, as well as the Skype for Business MVPs. Both of these groups were instrumental in answering questions that popped up throughout this process.

I hope you enjoy the book, and welcome any comments or concerns.

One liner: Find Lync/Skype for Business Users Whose Extension Doesn’t Match Part of Their DID

September 18th, 2015 2 comments

Description

 

Get-CsUser -Filter {LineURI -ne $null} | Where-Object {$_.LineURI.Split("=")[1] -NotMatch $_.LineURI.Substring($_.LineURI.Split(";")[0].Length -4,4)} | Select-Object DisplayName,LineURI | Sort-Object DisplayName