OnPrem Lync/Skype and Office 365

Had an issue with mailboxes migrated to Office 365 while using OnPrem Lync/Skype.

Lync showed a constant “Enter Credentials” dialog:

LyncEnterCredentials

The KB appears to have fixed it: Office 2013 and Lync 2013 periodically prompt for credentials to SharePoint Online, OneDrive, and Lync Online

A simple registry key that you can rollout with a GPO.

#Lync Integration with #BlackBerry

So I have a need to integrate Lync with BlackBerry.  So I followed this wicked guide http://talesfromc.blogspot.co.uk/2011/04/lync-bes-503-integration.html?m=1 and all was shweet.  I had to make a few tweeks to the certificate request inf file, as the SAN names just didn’t want to add themselves to the certificate request:

[Version]
Signature=”$Windows NT$”

[NewRequest]
Subject = “CN=LyncFEPool.domain”
Exportable = TRUE
KeyLength = 1024
KeySpec = 1
KeyUsage = 0xA0
MachineKeySet = True
FriendlyName = “OCSConnector”
ProviderName = “Microsoft RSA SChannel Cryptographic Provider”
ProviderType = 12
RequestType=pkcs10

[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1
OID=1.3.6.1.5.5.7.3.2

[Extensions]
2.5.29.17 = “{text}”
_continue_= “DNS=PrimaryBES.domain&”
_continue_= “DNS=StandbyBES.domain&”
_continue_= “DNS=LyncFEPool.domain”

Then run certreq -new c:\LyncRequest.inf c:\LyncCertNew.req and request the cert, then import it blah, blah.

However, I have an Active/Passive BlackBerry setup and when I failed over to the Passive node, Lync didn’t work from my device.

The BlackBerry Collaboration Service would start and then stop with 3 Error events in the application event log:

Source:        BlackBerry Collaboration Service
Event ID:      15000
Level:         Error
Description:
<2013-04-12 12:12:44.910 BST>:[126]:<BBIM_EMDC2BEM01_BBIM_1>:<ERROR>:<LAYER = BBIM, [OCSC] TlsFailureException: The operation failed due to issues with Tls. See the exception for more information., ErrorCode=-2146893042, FailureReason = Other, InnerExceptionCertificateInfoNative::AcquireCredentialsHandle() failed; HRESULT=-2146893042>

Source:        BlackBerry Collaboration Service
Event ID:      15000
Level:         Error
Description:
<2013-04-12 12:12:44.910 BST>:[127]:<BBIM_EMDC2BEM01_BBIM_1>:<ERROR>:<LAYER = BBIM, [OCSC] TlsFailureException: The operation failed due to issues with Tls. See the exception for more information., ErrorCode=-2146893042, FailureReason = Other, InnerExceptionCertificateInfoNative::AcquireCredentialsHandle() failed; HRESULT=-2146893042>

Source:        BlackBerry Collaboration Service
Event ID:      15000
Level:         Error
Description:
<2013-04-12 12:12:44.925 BST>:[130]:<BBIM_EMDC2BEM01_BBIM_1>:<ERROR>:<LAYER = BBIM, [OCSC] BlackBerry OCSConnector will terminate…>

Turns out that you can’t use the initial cert you created, you have to export it with the public key to a .pfx file.  Then import that on to the Standby BES.

Everyday is a school day!

 

Get-LyncServer v1.3

#Powershell, #Lync

Wow feedback .. thanks mike for the observation on the vertical text.  Have updated it to do it a different way, so let me know what you think.

You can download it here or cut and paste below

<#
  .NOTES
  NAME: Get-LyncServer.ps1
  AUTHOR: Paul Flaherty
  Last Edit: "v1.3 [28 February 2012]

  v1.0 08 Feb 2012 : A script it born
  v1.1 20 Feb 2012 : Change Services to *RTC* instead of RTC*
  v1.2 21 Feb 2012 : Added Lync Server version
  v1.3 28 Feb 2012 : Updated HTML TH style

  .LINK
  blogs.flaphead.com

  .SYNOPSIS
  This Script gets connectes to a Lync Server and enumerates a list
  of all OCS/Lync Servers and gathers additional information.
.DESCRIPTION
  This script will connect to a Lync Server using the /OcsPowershell URI.
  Once connected it will use Get-CsComputer to get a list of OCS/Lync related servers.
  Then it uses Get-CsService to get a list of Lync Services and the Lync related
  windows services.

  The script then creates a matrix of the data an output a CSV file and HTML web Page
.OUTPUTS
  Get-LyncServer.html
  Get-LyncServer.csv
.EXAMPLE
  Get-LyncServer.ps1
  This will prompt you for Credentials and search the AD for a lync server to use
.EXAMPLE
  Get-LyncServer.ps1 -LyncServer myLyncServer01
  This will prompt you for Credentials and use the specified lync server.
  it will also add the default ad domain to the server name is missing
.EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt
  This will search the AD for a lync server to use and use the current user account and
  credentials store in the CredentialsFile as the password
.EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt -LyncServer myLyncServer01
  This will use the specified lync server and use the current user account and
  credentials store in the CredentialsFile as the password
  .PARAMETER LyncServer
  Netbios or FQDN of a lync server to use.
  If the Netbios name is used, the AD Domain DNS name will be appended
  .PARAMETER CredentialsFile
  Credentials Password file for the current logged on user.
  To Create the credentials file run:
  $creds = Get-Credential
  $creds.Password  | ConvertFrom-SecureString | Set-Content creds.txt

#>
##########################################################################################
PARAM([String]$LyncServer="", [String]$CredentialsFile="")

$AppName                = "Get-LyncServer.ps1"
$AppVer                 = "v1.3 [28 February 2012]"
$errorPref              = $errorActionPreference
$errorActionPreference  = "SilentlyContinue"
$ServerName             = hostname
$Today                  = Get-Date
$Global:CurrentUser     = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Global:CurrentUserName = $Global:CurrentUser.Name
$xUser                  = $Global:CurrentUserName
$currentdom             = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$Forest                 = $currentdom.Forest.ToString()
$ForestDomain           = $Forest
$xHTMLoutFolder         = "E:PsMon.LyncHTML"

##########################################################################################
#Display script name and version
#########################################################################################
Write-host " " $AppName -NoNewLine -foregroundcolor Green
Write-Host ": " $AppVer -foregroundcolor Green
Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow
Write-Host "|——————————————————————-|`n"
##########################################################################################
#Load the Lync bits & bobs
#########################################################################################
If($CredentialsFile -eq "") {
  $creds = Get-Credential -Credential $xUser
}ELSE{
  Write-Host "Using Credentials for " -NoNewLine
  Write-Host $xUser -NoNewLine -ForeGroundColor Yellow
  Write-Host " and password from " -NoNewLine
  Write-Host $CredentialsFile -ForeGroundColor Yellow

  $password = Get-Content $CredentialsFile | ConvertTo-SecureString
  $creds = New-Object System.Management.Automation.PsCredential $xUser,$password
} #$CredentialsFile

If($LyncServer -eq ""){
  Write-Host "Looking in RTCHSUniversalServices for a Lync Server"
  $Forest              = $Forest.Replace(".", ",DC=")
  $Forest              = "DC=" + $Forest
  $Dom                 = "LDAP://"
  $Dom                += $Forest
  $Root                = New-Object DirectoryServices.DirectoryEntry $Dom
  $Filter              = "(&(ObjectCategory=group)(name=*RTCHSUniversalServices*))"
  $selector            =
New-Object DirectoryServices.DirectorySearcher $Filter
  $selector.PageSize   = 1000
  $selector.SearchRoot = $root
  $objs                = $selector.findall()
  $tmpGroup            = $objs | Select Path -First 1
  $Group               = [ADSI]$tmpGroup.Path
  $GrpMembers          = $Group.Member
  $grpCnt              = $GrpMembers.Count
  Write-Host "Found Group.  It has " -NoNewLine
  Write-Host  $GrpCnt -NoNewLine -ForeGroundColor Green
  Write-Host " Members"

  $LyncServerList = @()
  ForEach($tmpMember in $GrpMembers){
    $tmpADSI = "LDAP://" + $tmpMember
    $tmpA    = [ADSI]$tmpADSI
    If($tmpA.objectClass -contains "computer"){$LyncServerList += $tmpA.Name}
  }

  $LyncServerList = $LyncServerList | Sort
  $tmpNumber = Get-Random -Minimum 0 -Maximum $LyncServerList.Count
  $LyncServer = $LyncServerList[$tmpNumber]
  $LyncServer = $LyncServer + "." + $ForestDomain
  $LyncConnectionURI = "
https://" + $LyncServer + "/OcsPowershell" 

 

}ELSE{
  IF($LyncServer.Contains(".") -eq $False){$LyncServer = $LyncServer + "." + $ForestDomain}
  $LyncConnectionURI = "
https://" + $LyncServer + "/OcsPowershell"
}

Write-Host "`nConnecting to:"$LyncConnectionURI
$s=New-PSSession -ConnectionURI $LyncConnectionURI -Credential $creds
If ($s -eq $Null){
  Write-Host "Error connecting to Lync" -Foregroundcolor Red
  Write-Host "Exiting" -Foregroundcolor Yellow
  Exit
}
Import-PSSession $s

$arrObjects = @()
$LyncRoleLabels = @()
$LyncRoleLabels += "Computer", "Pool", "Site", "ProductVersion", "DeploymentType", "OS", "RAM","UpToDate"

Write-Host "`nGetting Lync Servers`t" -NoNewLine
$LyncServers  = Get-CsComputer | Sort Identity
Write-host $LyncServers.Count"`n" -ForeGroundColor Green

Write-Host "Get-CsService`t" -NoNewLine
$LyncService  = Get-CsService
Write-Host $LyncService.count "Services found" -ForeGroundColor Green

Write-Host "`nGetting Windows Services"
$LyncWindowsServices = @()
ForEach($item in $LyncServers){
  $n = $item.Identity
  Write-Host $n"`t" -NoNewLine
  $tmpLWS = @()
  $tmpLWS = Get-Service *RTC* -ComputerName $n #| select @{Expression={($_.DisplayName).Replace(" ","")};Label="DisplayName"}, Status
  Write-Host $tmpLWS.count -ForeGroundColor Green
  $LyncWindowsServices += $tmpLWS

 
}
Write-host "Total Services Found"$LyncWindowsServices.count

$LyncWindowsServicesByServer = $LyncWindowsServices | Group MachineName

#Get Available Roles
Write-host "`nGetting Lync Server Roles"

$LyncRoles = $LyncService | group Role | sort name
ForEach($tmpRole in $LyncRoles){$LyncRoleLabels += $tmpRole.Name}
$LyncServiceByPool = $LyncService | Group PoolFqdn | Sort Name

#Get Available Services
$grpLyncWindowsServices = $LyncWindowsServices | Group DisplayName
$grpLyncWindowsServices | ForEach{$n = $_.name; $LyncRoleLabels += $n}

Write-Host "`nMatrix Label Count" $LyncRoleLabels.count
Write-Debug $LyncRoleLabels

Write-Host "`nBuilding Matrix"
ForEach($tmpServer in $LyncServers){
  $tmpLyncServerId = $tmpServer.Identity
  Write-Host $tmpLyncServerId
  $objSite = Get-CsPool -Identity $tmpServer.pool | Select-Object Site
  $objReplication = $Null
  $objReplication = Get-CsManagementStoreReplicationStatus -ReplicaFqdn $tmpLyncServerId | Select-Object UpToDate
  $strReplication = $objSite.site -replace("Site:","")
  $tmpOS          = Get-WmiObject win32_operatingsystem -ComputerName $tmpLyncServerId

  $key="SOFTWAREMicrosoftReal-Time Communications"
  $type = [Microsoft.Win32.RegistryHive]::LocalMachine
  $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $tmpLyncServerId)
  $regKey = $regKey.OpenSubKey($key, $True)
  $tmpLabel = $regKey.GetValueNames()
  $tmpVC = "" | Select $tmpLabel
  ForEach($vc in $regKey.GetValueNames()){$tmpVC.$vc = $regkey.GetValue($vc)}

  $tmpLyncServer = "" | Select $LyncRoleLabels
  $tmpLyncServer.Computer = $tmpLyncServerId
  $tmpLyncServer.Pool     = $tmpServer.Pool
  $tmpLyncServer.Site     = $strReplication
  $tmpLyncServer.UpToDate = $objReplication.UpToDate
  $tmpLyncServer.OS       = $tmpOS.Caption + " " + $tmpOS.CSDVersion
  $tmpLyncServer.RAM      = "!AR!" + $tmpOS.FreePhysicalMemory
  $tmpLyncServer.ProductVersion = $tmpVC.ProductVersion
  $tmpLyncServer.DeploymentType = $tmpVC.DeploymentType

  $tmpLSbP = $LyncServiceByPool | Where {$_
.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpLSbP){
    $tmpG = $item.Group
    ForEach($itemG in $tmpG){
      $xRole = $itemG.Role
      $tmpLyncServer.$xRole = $True
    }
  }

  $tmpWinSvc = $LyncWindowsServicesByServer | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpWinSvc){
    $tmpG = $item.Group
    Write-Host $tmpG.count  
    ForEach($itemG in $tmpG){
      $xSvc = $itemG.DisplayName
      Write-Host $xSvc
      $tmpLyncServer.$xSvc = "svc"
    }
  }

  $arrObjects += $tmpLyncServer
}

$HtmlHeader = "
<Style>
  TABLE{border-width: 1px;
        padding: 1px;
        border-style: solid;
        border-color: black;
        border-collapse: collapse;}
  TD{border-width: 1px;
     padding: 1px;
     border-style: solid;
     border-color: black;}
  TH{font-family:’Arial’;
     font-size:12px;
     border-width: 1px;
     padding: 1px;
     border-style: solid;
     border-color: black;
     background-color:peachpuff;
     white-space: nowrap;
     writing-mode:tb-rl;
     filter: flipv fliph;
     Text-align:left}
  TR{font-family:’Arial’;
     font-size:10px}
  P{font-family:’Arial’;}
</Style>
<TITLE>LYNC SERVERS</TITLE>"

$z="<B><FONT size=’2′ face=’VERDANA’>Lync Servers</B></FONT><BR><FONT size=’1′ face=’VERDANA’>Last updated: $today</FONT></font><HR size=6 color=Green>"
$xHTML = $arrObjects | ConvertTo-Html -head $HtmlHeader -Title "Lync Server Info" -body $z

$txtYELLOW = @()
$txtAR     = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>True*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>True","<td bgcolor=ORANGE>True")}

$txtYELLOW = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>svc*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>svc","<td bgcolor=ORANGE>svc")}

$i=0; $xHTML | foreach{IF ($_ -like "*>!AR!*"){ $txtAR += $i;}; $i++}
$txtAR | ForEach{$xHTML[$_] = $xHTML[$_].Replace(">!AR!"," align=right>")}

$xEnd = get-Date
$xHTML += "
<HR size=6 color=Green>
<FONT size=’1′ face=’VERDANA’>Script Completed: $xEnd</FONT>
</FONT><BR></BODY>
</HTML>
"

$arrObjects | ForEach{$_.RAM = $_.RAM.Replace("!AR!","")}
$xHTML      | out-file $xHTMLoutFolderGet-LyncServer.html
$arrObjects | Export-csv Get-LyncServer.csv -NoTypeInformation

Get-PSSession | ForEach{Remove-PSSession -id $_.id}
$errorActionPreference = $errorPref
#End
##########################################################################################

Get-LyncServer v1.2

#Powershell, #Lync

Okay so made some updates to include Lync/OCS version, Lync Type, OS and Memory.  Also change the services from RTC* to *RTC*

Downloadable from here or cut and paste below .. enjoy

<#
  .NOTES
  NAME: Get-LyncServer.ps1
  AUTHOR: Paul Flaherty
  Last Edit: "v1.2 [21 February 2012]
  .LINK
  blogs.flaphead.com
  .SYNOPSIS
  This Script gets connectes to a Lync Server and enumerates a list
  of all OCS/Lync Servers and gathers additional information.
 .DESCRIPTION
  This script will connect to a Lync Server using the /OcsPowershell URI.
  Once connected it will use Get-CsComputer to get a list of OCS/Lync related servers.
  Then it uses Get-CsService to get a list of Lync Services and the Lync related
  windows services.

  The script then creates a matrix of the data an output a CSV file and HTML web Page
 .OUTPUTS
  Get-LyncServer.html
  Get-LyncServer.csv
 .EXAMPLE
  Get-LyncServer.ps1
  This will prompt you for Credentials and search the AD for a lync server to use
 .EXAMPLE
  Get-LyncServer.ps1 -LyncServer myLyncServer01
  This will prompt you for Credentials and use the specified lync server.
  it will also add the default ad domain to the server name is missing
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt
  This will search the AD for a lync server to use and use the current user account and
  credentials store in the CredentialsFile as the password
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt -LyncServer myLyncServer01
  This will use the specified lync server and use the current user account and
  credentials store in the CredentialsFile as the password
  .PARAMETER LyncServer
  Netbios or FQDN of a lync server to use.
  If the Netbios name is used, the AD Domain DNS name will be appended
  .PARAMETER CredentialsFile
  Credentials Password file for the current logged on user.
  To Create the credentials file run:
  $creds = Get-Credential
  $creds.Password  | ConvertFrom-SecureString | Set-Content creds.txt

#>

PARAM([String]$LyncServer="", [String]$CredentialsFile="")
##########################################################################################
$AppName = "Get-LyncServer.ps1"
$AppVer  = "v1.0 [13 February 2012]"
#v1.0 08 Feb 2012 : A script it born
#v1.1 20 Feb 2012 : Change Services to *RTC* instead of RTC*
#v1.2 21 Feb 2012 : Added Lync Server version
#
# This script gets a list of Lync Servers
#
#Written By Paul Flaherty
#blogs.flaphead.com
##########################################################################################
$errorPref = $errorActionPreference
$errorActionPreference = "SilentlyContinue"

$ServerName             = hostname
$Today                  = Get-Date
$Global:CurrentUser     = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Global:CurrentUserName	= $Global:CurrentUser.Name
$xUser                  = $Global:CurrentUserName
$currentdom             = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$Forest                 = $currentdom.Forest.ToString()
$ForestDomain           = $Forest

$xHTMLoutFolder         = "E:PsMon.LyncHTML"

##########################################################################################
#Display script name and version
#########################################################################################
Write-host " " $AppName -NoNewLine -foregroundcolor Green
Write-Host ": " $AppVer -foregroundcolor Green
Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow
Write-Host "|-------------------------------------------------------------------|`n"
##########################################################################################
#Load the Lync bits & bobs
#########################################################################################
If($CredentialsFile -eq "") {
  $creds = Get-Credential -Credential $xUser
}ELSE{
  Write-Host "Using Credentials for " -NoNewLine
  Write-Host $xUser -NoNewLine -ForeGroundColor Yellow
  Write-Host " and password from " -NoNewLine
  Write-Host $CredentialsFile -ForeGroundColor Yellow

  $password = Get-Content $CredentialsFile | ConvertTo-SecureString
  $creds = New-Object System.Management.Automation.PsCredential $xUser,$password
} #$CredentialsFile

If($LyncServer -eq ""){
  Write-Host "Looking in RTCHSUniversalServices for a Lync Server"
  $Forest              = $Forest.Replace(".", ",DC=")
  $Forest              = "DC=" + $Forest
  $Dom                 = "LDAP://"
  $Dom                += $Forest
  $Root                = New-Object DirectoryServices.DirectoryEntry $Dom
  $Filter              = "(&(ObjectCategory=group)(name=*RTCHSUniversalServices*))"
  $selector            = New-Object DirectoryServices.DirectorySearcher $Filter
  $selector.PageSize   = 1000
  $selector.SearchRoot = $root
  $objs                = $selector.findall()
  $tmpGroup            = $objs | Select Path -First 1
  $Group               = [ADSI]$tmpGroup.Path
  $GrpMembers          = $Group.Member
  $grpCnt              = $GrpMembers.Count
  Write-Host "Found Group.  It has " -NoNewLine
  Write-Host  $GrpCnt -NoNewLine -ForeGroundColor Green
  Write-Host " Members"

  $LyncServerList = @()
  ForEach($tmpMember in $GrpMembers){
    $tmpADSI = "LDAP://" + $tmpMember
    $tmpA    = [ADSI]$tmpADSI
    If($tmpA.objectClass -contains "computer"){$LyncServerList += $tmpA.Name}
  }

  $LyncServerList = $LyncServerList | Sort
  $tmpNumber = Get-Random -Minimum 0 -Maximum $LyncServerList.Count
  $LyncServer = $LyncServerList[$tmpNumber]
  $LyncServer = $LyncServer + "." + $ForestDomain
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"



}ELSE{
  IF($LyncServer.Contains(".") -eq $False){$LyncServer = $LyncServer + "." + $ForestDomain}
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"
}

Write-Host "`nConnecting to:"$LyncConnectionURI
$s=New-PSSession -ConnectionURI $LyncConnectionURI -Credential $creds
If ($s -eq $Null){
  Write-Host "Error connecting to Lync" -Foregroundcolor Red
  Write-Host "Exiting" -Foregroundcolor Yellow
  Exit
}
Import-PSSession $s

$arrObjects = @()
$LyncRoleLabels = @()
$LyncRoleLabels += "Computer", "Pool", "Site", "ProductVersion", "DeploymentType", "OS", "RAM","UpToDate"

Write-Host "`nGetting Lync Servers`t" -NoNewLine
$LyncServers  = Get-CsComputer | Sort Identity
Write-host $LyncServers.Count"`n" -ForeGroundColor Green

Write-Host "Get-CsService`t" -NoNewLine
$LyncService  = Get-CsService
Write-Host $LyncService.count "Services found" -ForeGroundColor Green

Write-Host "`nGetting Windows Services"
$LyncWindowsServices = @()
ForEach($item in $LyncServers){
  $n = $item.Identity
  Write-Host $n"`t" -NoNewLine
  $tmpLWS = @()
  $tmpLWS = Get-Service *RTC* -ComputerName $n #| select @{Expression={($_.DisplayName).Replace(" ","")};Label="DisplayName"}, Status
  Write-Host $tmpLWS.count -ForeGroundColor Green
  $LyncWindowsServices += $tmpLWS


}
Write-host "Total Services Found"$LyncWindowsServices.count

$LyncWindowsServicesByServer = $LyncWindowsServices | Group MachineName

#Get Available Roles
Write-host "`nGetting Lync Server Roles"

$LyncRoles = $LyncService | group Role | sort name
ForEach($tmpRole in $LyncRoles){$LyncRoleLabels += $tmpRole.Name}
$LyncServiceByPool = $LyncService | Group PoolFqdn | Sort Name

#Get Available Services
$grpLyncWindowsServices = $LyncWindowsServices | Group DisplayName
$grpLyncWindowsServices | ForEach{$n = $_.name; $LyncRoleLabels += $n}

Write-Host "`nMatrix Label Count" $LyncRoleLabels.count
Write-Debug $LyncRoleLabels

Write-Host "`nBuilding Matrix"
ForEach($tmpServer in $LyncServers){
  $tmpLyncServerId = $tmpServer.Identity
  Write-Host $tmpLyncServerId
  $objSite = Get-CsPool -Identity $tmpServer.pool | Select-Object Site
  $objReplication = $Null
  $objReplication = Get-CsManagementStoreReplicationStatus -ReplicaFqdn $tmpLyncServerId | Select-Object UpToDate
  $strReplication = $objSite.site -replace("Site:","")
  $tmpOS          = Get-WmiObject win32_operatingsystem -ComputerName $tmpLyncServerId

  $key="SOFTWAREMicrosoftReal-Time Communications"
  $type = [Microsoft.Win32.RegistryHive]::LocalMachine
  $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $tmpLyncServerId)
  $regKey = $regKey.OpenSubKey($key, $True)
  $tmpLabel = $regKey.GetValueNames()
  $tmpVC = "" | Select $tmpLabel
  ForEach($vc in $regKey.GetValueNames()){$tmpVC.$vc = $regkey.GetValue($vc)}


  $tmpLyncServer = "" | Select $LyncRoleLabels
  $tmpLyncServer.Computer = $tmpLyncServerId
  $tmpLyncServer.Pool     = $tmpServer.Pool
  $tmpLyncServer.Site     = $strReplication
  $tmpLyncServer.UpToDate = $objReplication.UpToDate
  $tmpLyncServer.OS       = $tmpOS.Caption + " " + $tmpOS.CSDVersion
  $tmpLyncServer.RAM      = "!AR!" + $tmpOS.FreePhysicalMemory
  $tmpLyncServer.ProductVersion = $tmpVC.ProductVersion
  $tmpLyncServer.DeploymentType = $tmpVC.DeploymentType

  $tmpLSbP = $LyncServiceByPool | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpLSbP){
    $tmpG = $item.Group
    ForEach($itemG in $tmpG){
      $xRole = $itemG.Role
      $tmpLyncServer.$xRole = $True
    }
  }

  $tmpWinSvc = $LyncWindowsServicesByServer | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpWinSvc){
    $tmpG = $item.Group
    Write-Host $tmpG.count
    ForEach($itemG in $tmpG){
      $xSvc = $itemG.DisplayName
      Write-Host $xSvc
      $tmpLyncServer.$xSvc = $True
    }
  }

  $arrObjects += $tmpLyncServer
}


$HtmlHeader = "
<Style>
  TABLE{border-width: 1px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
  TD{border-width: 1px;padding: 1px;border-style: solid;border-color: black;}
  TH{font-family:'Arial';font-size:12px;border-width: 1px;padding: 1px;border-style: solid;border-color: black;background-color:peachpuff;layout-flow:vertical-ideographic;Text-align:left}
  TR{font-family:'Arial';font-size:10px}
  P{font-family:'Arial';}
</Style>
<TITLE>LYNC SERVERS</TITLE>"

$z="<B><FONT size='2' face='VERDANA'>Lync Servers</B></FONT><BR><FONT size='1' face='VERDANA'>Last updated: $today</FONT></font><HR size=6 color=Green>"
$xHTML = $arrObjects | ConvertTo-Html -head $HtmlHeader -Title "Lync Server Info" -body $z

$txtYELLOW = @()
$txtAR     = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>True*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>True","<td bgcolor=ORANGE>True")}

$i=0; $xHTML | foreach{IF ($_ -like "*>!AR!*"){ $txtAR += $i;}; $i++}
$txtAR | ForEach{$xHTML[$_] = $xHTML[$_].Replace(">!AR!"," align=right>")}


$xEnd = get-Date
$xHTML += "
<HR size=6 color=Green>
<FONT size='1' face='VERDANA'>Script Completed: $xEnd</FONT>
</FONT><BR></BODY>
</HTML>
"

$xHTML      | out-file $xHTMLoutFolderGet-LyncServer.html
$arrObjects | Export-csv Get-LyncServer.csv -NoTypeInformation

Get-PSSession | ForEach{Remove-PSSession -id $_.id}
$errorActionPreference = $errorPref
#End
##########################################################################################

Get-LyncServer v1

#Powershell, #Lync

So I just love Exchange 2010 and PowerShell, and a cmdlet that rocks is Get-ExchangeServer which is a cmdlet that get the attributes of some or all the servers in the Exchange organization.

Lync however doesn’t have a similar cmdlet and that annoyed the hell out of me.  All I want is a list of Lync Servers and what they do .. simple you would think! Think again Disappointed smile

So I knocked this up.  It has some help text too that will help with the usage.  You can run get-help ./get-lyncserver –full

The basic output is a HTML summary matrix and a csv file that I use as input to other scripts.  Essentially I run this script once a day and then the other scripts when needed.

Oh another thing, the connectionuri needs credentials .. help explains how to set them or you get a prompt.

Let me know what you think!  this is v1 to enjoy

You can download the script from here or copy and paste from here:

<#
  .NOTES
  NAME: Get-LyncServer.ps1
  AUTHOR: Paul Flaherty
  Last Edit: "v1.0 [13 February 2012]
  .LINK
  blogs.flaphead.com
  .SYNOPSIS
  This Script gets connects to a Lync Server and enumerates a list
  of all OCS/Lync Servers and gathers additional information.
 .DESCRIPTION
  This script will connect to a Lync Server using the /OcsPowershell URI.
  Once connected it will use Get-CsComputer to get a list of OCS/Lync related servers.
  Then it uses Get-CsService to get a list of Lync Services and the Lync related
  windows services.

  The script then creates a matrix of the data an output a CSV file and HTML web Page
 .OUTPUTS
  Get-LyncServer.html
  Get-LyncServer.csv
 .EXAMPLE
  Get-LyncServer.ps1
  This will prompt you for Credentials and search the AD for a lync server to use
 .EXAMPLE
  Get-LyncServer.ps1 -LyncServer myLyncServer01
  This will prompt you for Credentials and use the specified lync server.
  it will also add the default ad domain to the server name is missing
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt
  This will search the AD for a lync server to use and use the current user account and
  credentials store in the CredentialsFile as the password
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt -LyncServer myLyncServer01
  This will use the specified lync server and use the current user account and
  credentials store in the CredentialsFile as the password
  .PARAMETER LyncServer
  Netbios or FQDN of a lync server to use.
  If the Netbios name is used, the AD Domain DNS name will be appended
  .PARAMETER CredentialsFile
  Credentials Password file for the current logged on user.
  To Create the credentials file run:
  $creds = Get-Credential
  $creds.Password  | ConvertFrom-SecureString | Set-Content creds.txt

#>

PARAM([String]$LyncServer="", [String]$CredentialsFile="")
##########################################################################################
$AppName = "Get-LyncServer.ps1"
$AppVer  = "v1.0 [13 February 2012]"
#v1.0 08 Feb 2012 : A script it born
#
# This script gets a list of Lync Servers
#
#Written By Paul Flaherty
#blogs.flaphead.com
##########################################################################################
$errorPref = $errorActionPreference
$errorActionPreference = "SilentlyContinue"

$ServerName             = hostname
$Today                  = Get-Date
$Global:CurrentUser     = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Global:CurrentUserName	= $Global:CurrentUser.Name
$xUser                  = $Global:CurrentUserName
$currentdom             = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$Forest                 = $currentdom.Forest.ToString()
$ForestDomain           = $Forest

$xHTMLoutFolder         = $pwd

##########################################################################################
#Display script name and version
#########################################################################################
Write-host " " $AppName -NoNewLine -foregroundcolor Green
Write-Host ": " $AppVer -foregroundcolor Green
Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow
Write-Host "|-------------------------------------------------------------------|`n"
##########################################################################################
#Load the Lync bits & bobs
#########################################################################################
If($CredentialsFile -eq "") {
  $creds = Get-Credential -Credential $xUser
}ELSE{
  Write-Host "Using Credentials for " -NoNewLine
  Write-Host $xUser -NoNewLine -ForeGroundColor Yellow
  Write-Host " and password from " -NoNewLine
  Write-Host $CredentialsFile -ForeGroundColor Yellow

  $password = Get-Content $CredentialsFile | ConvertTo-SecureString
  $creds = New-Object System.Management.Automation.PsCredential $xUser,$password
} #$CredentialsFile

If($LyncServer -eq ""){
  Write-Host "Looking in RTCHSUniversalServices for a Lync Server"
  $Forest              = $Forest.Replace(".", ",DC=")
  $Forest              = "DC=" + $Forest
  $Dom                 = "LDAP://"
  $Dom                += $Forest
  $Root                = New-Object DirectoryServices.DirectoryEntry $Dom
  $Filter              = "(&(ObjectCategory=group)(name=*RTCHSUniversalServices*))"
  $selector            = New-Object DirectoryServices.DirectorySearcher $Filter
  $selector.PageSize   = 1000
  $selector.SearchRoot = $root
  $objs                = $selector.findall()
  $tmpGroup            = $objs | Select Path -First 1
  $Group               = [ADSI]$tmpGroup.Path
  $GrpMembers          = $Group.Member
  $grpCnt              = $GrpMembers.Count
  Write-Host "Found Group.  It has " -NoNewLine
  Write-Host  $GrpCnt -NoNewLine -ForeGroundColor Green
  Write-Host " Members"

  $LyncServerList = @()
  ForEach($tmpMember in $GrpMembers){
    $tmpADSI = "LDAP://" + $tmpMember
    $tmpA    = [ADSI]$tmpADSI
    If($tmpA.objectClass -contains "computer"){$LyncServerList += $tmpA.Name}
  }

  $LyncServerList = $LyncServerList | Sort
  $tmpNumber = Get-Random -Minimum 0 -Maximum $LyncServerList.Count
  $LyncServer = $LyncServerList[$tmpNumber]
  $LyncServer = $LyncServer + "." + $ForestDomain
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"



}ELSE{
  IF($LyncServer.Contains(".") -eq $False){$LyncServer = $LyncServer + "." + $ForestDomain}
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"
}

Write-Host "`nConnecting to:"$LyncConnectionURI
$s=New-PSSession -ConnectionURI $LyncConnectionURI -Credential $creds
If ($s -eq $Null){
  Write-Host "Error connecting to Lync" -Foregroundcolor Red
  Write-Host "Exiting" -Foregroundcolor Yellow
  Exit
}
Import-PSSession $s

$arrObjects = @()
$LyncRoleLabels = @()
$LyncRoleLabels += "Computer", "Pool", "Site", "UpToDate"

Write-Host "`nGetting Lync Servers`t" -NoNewLine
$LyncServers  = Get-CsComputer | Sort Identity
Write-host $LyncServers.Count"`n" -ForeGroundColor Green

Write-Host "Get-CsService`t" -NoNewLine
$LyncService  = Get-CsService
Write-Host $LyncService.count "Services found" -ForeGroundColor Green

Write-Host "`nGetting Windows Services"
$LyncWindowsServices = @()
ForEach($item in $LyncServers){
  $n = $item.Identity
  Write-Host $n"`t" -NoNewLine
  $tmpLWS = @()
  $tmpLWS = Get-Service RTC* -ComputerName $n #| select @{Expression={($_.DisplayName).Replace(" ","")};Label="DisplayName"}, Status
  Write-Host $tmpLWS.count -ForeGroundColor Green
  $LyncWindowsServices += $tmpLWS
}
Write-host "Total Services Found"$LyncWindowsServices.count

$LyncWindowsServicesByServer = $LyncWindowsServices | Group MachineName

#Get Available Roles
Write-host "`nGetting Lync Server Roles"

$LyncRoles = $LyncService | group Role | sort name
ForEach($tmpRole in $LyncRoles){$LyncRoleLabels += $tmpRole.Name}
$LyncServiceByPool = $LyncService | Group PoolFqdn | Sort Name

#Get Available Services
$grpLyncWindowsServices = $LyncWindowsServices | Group DisplayName
$grpLyncWindowsServices | ForEach{$n = $_.name; $LyncRoleLabels += $n}

Write-Host "`nMatrix Label Count" $LyncRoleLabels.count
Write-Debug $LyncRoleLabels

Write-Host "`nBuilding Matrix"
ForEach($tmpServer in $LyncServers){
  $tmpLyncServerId = $tmpServer.Identity
  Write-Host $tmpLyncServerId
  $objSite = Get-CsPool -Identity $tmpServer.pool | Select-Object Site
  $objReplication = $Null
  $objReplication = Get-CsManagementStoreReplicationStatus -ReplicaFqdn $tmpLyncServerId | Select-Object UpToDate
  $strReplication = $objSite.site -replace("Site:","")

  $tmpLyncServer = "" | Select $LyncRoleLabels
  $tmpLyncServer.Computer = $tmpLyncServerId
  $tmpLyncServer.Pool     = $tmpServer.Pool
  $tmpLyncServer.Site     = $strReplication
  $tmpLyncServer.UpToDate = $objReplication.UpToDate

  $tmpLSbP = $LyncServiceByPool | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpLSbP){
    $tmpG = $item.Group
    ForEach($itemG in $tmpG){
      $xRole = $itemG.Role
      $tmpLyncServer.$xRole = $True
    }
  }

  $tmpWinSvc = $LyncWindowsServicesByServer | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpWinSvc){
    $tmpG = $item.Group
    Write-Host $tmpG.count
    ForEach($itemG in $tmpG){
      $xSvc = $itemG.DisplayName
      Write-Host $xSvc
      $tmpLyncServer.$xSvc = $True
    }
  }

  $arrObjects += $tmpLyncServer
}


$HtmlHeader = "
<Style>
  TABLE{border-width: 1px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
  TD{border-width: 1px;padding: 1px;border-style: solid;border-color: black;}
  TH{font-family:'Arial';font-size:12px;border-width: 1px;padding: 1px;border-style: solid;border-color: black;background-color:peachpuff;layout-flow:vertical-ideographic;Text-align:left}
  TR{font-family:'Arial';font-size:10px}
  P{font-family:'Arial';}
</Style>
<TITLE>LYNC SERVERS</TITLE>"

$z="<B><FONT size='2' face='VERDANA'>Lync Servers</B></FONT><BR><FONT size='1' face='VERDANA'>Last updated: $today</FONT></font><HR size=6 color=Green>"
$xHTML = $arrObjects | ConvertTo-Html -head $HtmlHeader -Title "Lync Server Info" -body $z

$txtYELLOW = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>True*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>True","<td bgcolor=ORANGE>True")}


$xEnd = get-Date
$xHTML += "
<HR size=6 color=Green>
<FONT size='1' face='VERDANA'>Script Completed: $xEnd</FONT>
</FONT><BR></BODY>
</HTML>
"

$xHTML      | out-file $xHTMLoutFolderGet-LyncServer.html
$arrObjects | Export-csv Get-LyncServer.csv -NoTypeInformation

Get-PSSession | ForEach{Remove-PSSession -id $_.id}
$errorActionPreference = $errorPref
#End
##########################################################################################

Prognosis Webinar – Top 5 ways to Microsoft Lync success

#Lync

Could be interesting

If you haven’t already registered to attend next week’s Prognosis for Microsoft Lync Webinar, please REGISTER NOW by clicking on the date below for your region. 
In this 60-minute webinar you can learn how Prognosis bridges the gap between server infrastructure management and UC management teams and build the new management skills you need to integrate Microsoft Lync server and voice quality performance management. Accelerate the transition from server and application expertise to real-time Unified Communications management!

Webinar:

Top 5 ways to ensure success in your Microsoft Lync deployment

Dates:

Australia: Tuesday, 17 January 2012, 1pm – 2pm AEDT
Americas: Wednesday, 18 January 2012, 2:00pm – 3:00pm EST
Europe: Wednesday, 18 January 2012, 1:00pm – 2:00pm GMT

A Month in #Exchange and #OCS: September 2011: Events

#Exchange2010 #Lync #MMMUG

#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#* New On-Demand Web Content from August 2011

Business Insights Webcast: Office 365 Essentials- Guide to the best online productivity experience in the industry (Level 100)
Office 365 is on the market and thousands of customers have been experiencing the potential of Office 365. Learn about how Office 365 can revolutionize your workplace productivity experience from Jeff Medford, Tech Product Mgr at Microsoft. Jeff is one of the most respected Office 365 resources at Microsoft and has been helping customers & partners realize the potential of Office 365.
https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032491168&EventCategory=5&culture=en-US&CountryCode=US

#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#* Webcasts of interest showing at a desktop near you in September 2011

Friday, September 09, 2011
TechNet Webcast: Talk TechNet with Keith Combs and Matt Hester – Episode 58: PowerShell with Sarah Dutkiewicz (Level 200)
https://msevents.microsoft.com/CUI/EventDetail.aspx?culture=en-US&EventId=1032493305

Friday, September 16, 2011
TechNet Webcast: Deep Dive: Lync Server 2010 Edge Servers (Level 300)
Understanding the details about how to set up and deploy edge servers is a key feature to allow the customer investment to include users–domain members, partners in a federated infrastructure, and customers–outside of the internal network in the Microsoft Lync Server 2010 experience. Edge servers provide external user connections to the Lync Server platform using the Lync 2010 client not leveraging a VPN connection. In this webcast, we discuss edge server deployment topologies, the Lync Server Planning Tool, and best practices for configuring edge servers. At the end of this webcast, you will be better prepared to answer customer questions and to plan and implement an edge server infrastructure for Lync Server 2010.
https://msevents.microsoft.com/CUI/EventDetail.aspx?culture=en-US&EventId=1032492168

Friday, September 23, 2011
TechNet Webcast: Microsoft Lync 2010 High Availability and Resiliency (Level 300)
In this webcast, we explore the new high availability and resiliency offerings from Microsoft Lync Server 2010. These offerings include branch office resiliency, data center resiliency, intrasite high availability architecture, and capabilities for instant messaging, conferencing, and voice workloads. Quadrantechnologies is dedicated to delivering the most advanced innovation and technology to clients. We design and support the deployment of Microsoft Unified Communications, including Microsoft Lync Server 2010 and Microsoft Exchange Server 2010. Our vision as a business solutions company is to provide software support, technical guidance, and system training while ensuring precision, commitment, and effectiveness. 
https://msevents.microsoft.com/CUI/EventDetail.aspx?culture=en-US&EventId=1032492171

Tuesday, September 27, 2011
TechNet Webcast: How Microsoft IT Implemented Key Support and Monitoring Requirements (Level 300)
Learn how the Microsoft IT Volume Licensing team reviewed and implemented key support and monitoring requirements for a business-critical application migrated to Windows Azure and Microsoft SQL Azure.
https://msevents.microsoft.com/CUI/EventDetail.aspx?culture=en-US&EventId=1032491417