Sunday, March 19, 2017

Reset Skype for Business Statistics Manager (StatsMan) history

Scenario

You have a brand new or existing deployment of Skype for Business Statistics Manager. Your graph shows some very old statistics (few days/weeks ago) as well as recent statistics (by default: 24 hours old) in a single chart.



Cause
Don't know yet. Maybe related to Open Source of Redis in-memory caching system :-P

Solution

Reset statistics completely (--age:0) or to 24 hours old (by default).
1. Run as Administrator "cmd" on server where SfB Statistics Manager Listener is installed:
2. Run either:

C:\>"C:\Program Files\Skype for Business Server StatsMan Listener\PerfAgentStorageManager.exe" --redis:localhost --action:cleanup --age:0

or

C:\>"C:\Program Files\Skype for Business Server StatsMan Listener\PerfAgentStorageManager.exe" --redis:localhost --action:cleanup

Using age: 1.00:00:00
FillNameCacheAsync of 6,889 counters took 180ms
GetLastWriteTimesAsync of 6,889 counters took 56ms
Scanned through 7,389 redis keys in 79ms and found 36 that should be deleted.
36 counters, 0 hosts, 36 storage keys, haven't been written to in 6.00:00:00
Do you want to remove the above hosts,36 counters and 36 storage keys? Y|[N]:y
Removed: 36 keys in 29ms
BulkDereferenceCounters: Attempting to dereference 36 storage keys
BulkDereferenceCounters: Deleted 36 last write time entries in 10ms
BulkDereferenceCounters: Removed 36 storage key entries from set in 1ms

Deleted 0 server infos.

I got normal graph after clearing history.



More information 
about PerfAgentStorageManager.exe /?

  --action<:action>

    updateServerInfo : Need --redis : Must provide --file or (--hostname and one or more --population options), --file should be in the format of getServerInfo output
                     : optional --noPrompt (will automatically do it without asking)
                     : optional --disableUpdate (will do adds only)
                     : optional --debug will show extra output
                     : The following shard scheme docs are only for multi-azure storage account setups:
                     : optional --shardScheme=none (to disable updating shard assignement for new servers)
                     : optional --shardScheme=<scheme>
                     :          <scheme> is one or more population matches separated by comma.
                     :          The default is Pool_,Site_ and it is recommended to not change this.
                     :          This will look at each new server's populations and try to match (start with) with a
                     :          scheme component then it will assign to that populations shard if it exists.
                     :          So for the default scheme it will look for the servers Pool shard, if that doesn't exist
                     :          then it will look for the servers Site shard, if that doesn't exist it will just stay as
 default

    getServerInfo : Need --redis : optional --uri for the location to upload to, Default is redishash:///_ServerInfo
                  : optional --file will output the xml for edit
                  : optional --mode=command will output the information with the command line options for PerfAgentStorageManager
                  : optional one or more --population will get only the servers in one of those populations

    getRedirectCandidates : Need --redis, default is to find populations with a single server where the name of the server is the last part of the population
                  : optional --mode=<current>, current will retrieve the current list of configured redirected populations
                  : optional --file=filename.csv will output a file that can be used with --action=updateRedirectCandidates
                  : example: Pool_mySEserverFE01 server=mySEServerFE01

    updateRedirectCandidates : Need --redis --file is a csv with Population,Server

    getShardInfo : Need --redis.
                : Optional: One or more modes
                : --mode=verbose to output every assignment
                : --mode=password to see the configured password (careful!)
                : --mode=history to see the history of all shard assignments (assumes --mode=verbose)

    updateShardAssignments : Need --redis and one or more --population or a single --hostname and --mode=specific or --mode=population and --value
                : --value=# the number of the shard to assign them to
                : mode=specific means assign that population or host to the shard
                : mode=population means assign the population(s) to the shard and all of the servers in all populations given
                : mode=correction (be careful with this) means update any shard assignement that matches -value=shardid and -match=tableID (see -a=getshardinfo -verbose)
                : this is used when a mistake in timing was made and the shard assignement hasn't been used yet and this will update to the next
                :if you get this wrong and use it on something that is in use, the data will be missing
and not easily recovered
                : The assignment won't switch until the next 12 hour period. Be careful that you assign far enough from daily 12 hour boundaries
                : Optional: if in --mode=population you can also add a --match=<population match> to also add any population to the shard for servers
                : in the given population. For example: --mode=population --population=Site_Blah --match=Pool_ this will add any Pool in has servers in that
                : site. It will ask you for each one unless you have --noPrompt

    updateAzureShard : Need --redis and --value=<shard ID> --azure=<accountName> --azurePassword=<azure key> --thumbprint=<password decryption certificate thumbprint>
                 : Optional --noPrompt to not prompt, you can add a --new to fail if expect it to be a new account (it will fail if the account or shard ID exists)

    validateSharding : Need --redis and --azure=<accountName> --azurePassword=<azure key> (for the default account)
                 : Optional --noPrompt will not prompt for keys to check but you'll need to provide --value=<hostname or population name or all>

    getRedirectedCounters : Need --redis

    deleteServerInfo : Need --redis and --file or one or more --hostname entries : File contains names of servers (one p
er line). optional --uri for the key to upload to, Default is redishash:///_ServerInfo (only redishash uri supported)

    checkServerInfo : Need --redis and --file or one or more --hostname entries : File contains names of servers (one pe
r line).

    cleanup : Need --redis, this will cleanup all hosts, populations and counters that haven't been written to in the given age time
            : Optional --age=<hours> (default 24)
            : Optional --match=<regex> to only match certain hosts/populations
            : Optional --notmatch=<regex> to exclude certain hosts/populations

    listKeys : Need --redis optional --file and --match and --key (key will make this a hash key list) --includeValues will show the value of the hash keys as well

    deleteKeys : Need --redis and --match  optional --notMatch, optional: --count=<batchSize> default=1000

    listHostIds : Need --redis and --match  optional --notMatch

    backupIdentifiers : Need --redis and --file, optional: --mode=overwrite

    subscribe : Need --redis and --counter

    listCounterStorageNames : Need --redis optional --file and --match and --notMatch

    listBuckets : Need --redis optional --match and --notMatch, optional --mode=<counters>, counters mode will try to distill down to the list of perf counters polled

    readListValues : Need --redis and --key optional --count

    deleteHashKeys : Need --redis and --key optional --match and --count (this will decide batch size), you will be prompted

    lookupStorageName: Need --redis and one or more --counter and/or --bucket this will lookup the counter or bucket storage names, optional: --mode=redirected

    findBadServers: Need --redis and optional --bucket (it will by default use \\*\Memory\% Memory Free_Maximum\@ bucket)

    getCounterValues : Need --redis and --counter : Optional --file=<csv output file path>

    getCounterValuesRange : Need --redis and --azure. Optionally need --counter (default is memory max) --startTime and --endTime (both in local time), defaults 24 hours ago and now

    counterLastWriteTimes: Need --redis optional --age=<seconds> will only print counters older than this, optional --count will limit the output, optional --mode=host will output the hosts and their youngest value age

    getBucketValues : Need --redis and optional --bucket (default will be \\*\Memory\% Memory Free_Maximum\@), optional --count will limit the output

    getBucketDueTimes: Need --redis optional --key default is _BucketDueTime

    getStats: Shows info about number of counters/buckets/etc. Need --redis

    listAggLocks: Need --redis. Shows which server owns which agg lock for buckets.

    setting: Need --redis and --setting=SettingName and --value=[true|false|int32#]. Updates/gets.

  --setting<:setting>
    all: retrieves all of the current values
    aggregation: optional --value=[true|false] (if not given it gets the current value)
    redirectedAggregations: optional --value=[true|false] (if not given it gets the current value)
    persistentStore: optional --value=[true|false] (if not given it gets the current value)
    rediscounterStore: optional --value=[true|false] (if not given it gets the current value)
    bucketManagerMaxConcurrency: optional --value=int32# (if not given it gets the current value)

  --value<:value>  Some actions require a 'value' parameter.
  --redis<:redis>  Set the redis server configuration
  --redisDatabase<:redisDatabase>  Set the redis database number. Default: 0
  --redisPassword<:redisPassword>  Optional redis password. Otherwise it will be looked up from the config.
  --azure<:azure>  Set the azure storage account name
  --azurePassword<:azurePassword>  Optional azure storage password. Otherwise it will be looked up from the config.
  --startTime<:startTime>  Some actions take a startTime arg.
  --endTime<:endTime>  Some actions take a endTime arg.
  --file<:file>  Some actions take a file arg.
  --hostname<:hostname>  Some actions take a hostname arg.
  --population<:population>  Some actions take a population arg.
  --match<:match>  Some actions uses a pattern or match.
  --notMatch<:notMatch>  Some actions uses a pattern or match to exclude.
  --new  Some actions are being tested with a 'new' mode.
  --disableUpdate  Some actions need a way to disable updates (and do adds only).
  --counter<:counter>  Some actions take a counter arg.
  --bucket<:bucket>  Some actions take a bucket arg.
  --shardScheme<:shardScheme>  Some actions take a shard scheme.
  --age<:age>  Some actions take an age arg. In seconds.
  --noPrompt  Some actions prompt to continue, this will answer affirmative to any prompt.
  --count<:count>  Some actions can take a count
  --includeValues  Some actions have an option to show the values.
  --key<:key>  Some actions need a key arg.
  --mode<:mode>  Some actions take a mode arg (often optional).
  --thumbprint<:thumbprint>  Some actions need a certificate thumbprint arg.
  --debug[:debug]  This will enable debugging output.
  --uri<:uri>  Some actions need a uri arg.
  --help  Print this help and exit.

Sunday, March 12, 2017

Configure static IP address in Windows PE environment

Scenario

You've made backup image of your Windows OS and put it on the network share. 
At some point you need this backup image for system recovery purposes. You boot from Windows PE disk to recover system image backup in non-DHCP enabled network. You can't access to your backup image file via network. You must setup static IP on the network interface prior to network discovery and image recovery.

Quick notes

Enter to command prompt:

netsh interface ip show addresses
netcfg -winpe
wpeutil InitializeNetwork

or simply

wpeinit

NOTE: The default connection names are "Local Area Connection" or "Ethernet" for wired adapters and "Wireless Network Connection" for Wi-Fi adapters. You can check network connection name by entering "ipconfig" command.

The IP address order: client IP, subnet mask, and gateway IP.

netsh interface ipv4 set address "Local Area Connection" static 192.168.0.101 255.255.255.0 192.168.0.1
netsh interface ipv4 add dns "Local Area Connection" 192.168.0.10 index=1
netsh interface ipv4 add dns "Local Area Connection" 192.168.0.11 index=2

The service has not been started

Friday, March 10, 2017

Cannot grant AccessRights for RTCUniversalServerAdmins/RTCComponentUniversalServices of SfB to read Exchange UM AD objects using ExchUCUtil.ps1

Scenario


Per Microsoft guide you try to integrate Exchange Server (2013/2016) with Skype for Business (or Lync Server 2013) for UM. You run ExchUCUtil.ps1 integration script with required permissions (Exchange Organization administrator, Exchange Recipient administrator)

C:\Program Files\Microsoft\Exchange Server\V15\Scripts> .\ExchUCUtil.ps1

at the end you get something like:


Grants Skype for Business Server 2015 permission to read Exchange UM Active Directory Domain Services objects

Configuring UM IP Gateway objects...
Pool: pool.domain.com
A UMIPGateway already exists in Active Directory for the Lync Server pool. A new UM IP gateway wasn't created for the po
ol.
IsBranchRegistrar: False
MessageWaitingIndicatorAllowed: True
OutcallsAllowed: True
WARNING: The command completed successfully but no settings of 'pool' have been modified.
Dial plans: Contoso Dial Plan

Permissions for group domain.com\RTCUniversalServerAdmins

ObjectName                              AccessRights                            Configured
----------                              ------------                            ----------
First Organization                      ListChildren                            True
UM DialPlan Container                   ListChildren, ReadProperty              True
UM AutoAttendant Container              ListChildren, ReadProperty              True
Administrative Groups                   ListChildren, ReadProperty              False

Permissions for group domain.com\RTCComponentUniversalServices

ObjectName                              AccessRights                            Configured
----------                              ------------                            ----------
First Organization                      ListChildren                            True
UM DialPlan Container                   ListChildren, ReadProperty              True
UM AutoAttendant Container              ListChildren, ReadProperty              True
Administrative Groups                   ListChildren, ReadProperty              False

PoolFqdn                                UMIPGateway                             DialPlans
--------                                -----------                             ---------
pool.domain.com                         pool                                    {Contoso Dial Plan}

You may notice that some ObjectNames have "Configured" status as "False".
In the event log "MSExchange Management" (Applications and Service Logs) following event maybe registered after running this script:

Log Name:      MSExchange Management
Source:        MSExchange CmdletLogs
Date:          10/03/2017 10:38:07
Event ID:      6
Task Category: (1)
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      computer1.domain.com


The following information was included with the event:


Add-ADPermission -InheritanceType "All" -AccessRights ("ListChildren, ReadProperty") -Identity "Administrative Groups" -Debug "True" -User "domain.com\RTCUniversalServerAdmins" -ErrorVariable "ErrorList"
domain.com/UMAdmin
Local-ConsoleHost-Unknown
12164 powershell.exe
00:00:53.5386187
View Entire Forest: 'True',
Microsoft.Exchange.Configuration.Tasks.ManagementObjectAmbiguousException: There are multiple objects matching the identity "Administrative Groups". Please specify a unique value.

The same error occurs if to run script commands manually (obviously):

Add-ADPermission -InheritanceType "All" -AccessRights ("ListChildren, ReadProperty") -Identity "Administrative Groups" -User "domain.com\RTCUniversalServerAdmins"  

Add-ADPermission -InheritanceType "All" -AccessRights ("ListChildren, ReadProperty") -Identity "Administrative Groups" -User "domain.com\RTCComponentUniversalServices"  

Cause


In my case my domain.com forest had Organization Unit (OU) named like "Administrative Groups" and created manually by helpdesk group.  As you probably know "Administrative Groups" AD container with the same exact name is used for Exchange AD objects by Microsoft design. But I'm sure the same issue occurs if you have OU named like: "First Organization", "UM DialPlan Container", "UM AutoAttendant Container". Don't name OUs with such system names and you'll never get this problem.

Solution


Rename OU "Administrative Groups" created by helpdesk to something else (ex. "Admin Groups") and run ExchUCUtil.ps1 script again.
How to determine where this "smart" OU is located?

Get-ADPermission -Identity "Administrative Groups" | Select-Object Identity | Sort-Object Identity | Get-Unique -AsString

I my case I got something like:

Identity
--------
Administrative Groups
contoso.com/HelpDesk Groups/Administrative groups

where "contoso.com/HelpDesk Groups/" is a path to the OU with a source of problems

Thursday, December 15, 2016

Unable to delete contacts from Outlook Contacts folder (Skype for Business or Lync)

Scenario:

You want to delete contacts from Office 365 Outlook folder: "Skype for Business Contacts" or "Lync Contacts". You get error:
"You cannot make changes to contents of this read-only folder"

Solution:

Go to the "light" Exchange Online mode: https://outlook.office365.com/owa/?exsvurl=1&layout=light and delete contacts.


Wednesday, December 14, 2016

Easy way to determine UEFI or Legacy BIOS from PowerShell

PowerShell script which determines the underlying system firmware (BIOS) type - either UEFI or Legacy BIOS:

if (Test-Path $env:windir\Panther\setupact.log) {(Select-String 'Detected boot environment' -Path "$env:windir\Panther\setupact.log"  -AllMatches).line -replace '.*:\s+'else {if (Test-Path HKLM:\System\CurrentControlSet\control\SecureBoot\State) {"UEFI"} else {"BIOS"}}

PowerShell script which determines EFI partition:

Get-WmiObject  -query 'Select * from Win32_DiskPartition Where Type = "GPT: System"' | select Name, Index, Bootable, BootPartition,PrimaryPartition, @{n="SizeInMB";e={$_.Size/1MB}}

You may need this information for VMware/Physical machines to Azure with Azure Site Recovery scenario (or even Hyper-V Gen 2 VMs where you don't have actual access to Hyper-V itself, ex. 3rd party IaaS provider). As of today UEFI partitions are not supported in these scenarios and you will end with
ERROR ID 78006
ERROR MESSAGE
The requested operation did not complete. 
PROVIDER ERROR
Provider error code: 95185 Provider error message: Protection could not be enabled. Provider error possible causes: Enable protection failed for the source disks {GUID} on the source machine <Hostname> (IP Address). UEFI partitions are not supported. Provider error recommended action: UEFI partitions are not supported. See http://go.microsoft.com/fwlink/?LinkId=613318 for the pre-requisites.
POSSIBLE CAUSES
Check the provider error for more details.
RECOMMENDATION
Resolve the issue as recommended in the provider error details.

Saturday, November 5, 2016

Cert Exam Prep Materials: 70-740, 70-741, 70-742, 70-743: MCSA: Windows Server 2016

These exams are required for the new MCSA: Windows Server 2016 certification: 70-740, 70-741, 70-742 (or just 70-743 for upgrade from MCSA: Windows Server 2008 or MCSA: Windows Server 2012 R2)


Cert Exam Prep: Exam 70-740: Installation, Storage, and Compute

This Certification Exam Prep session is designed for people experienced with Microsoft Windows Server who are interested in taking the 70-740 exam or the 70-743 exam.

VideoPowerPoint

Cert Exam Prep: Exam 70-741: Networking with Windows Server 2016

This Certification Exam Prep session is designed for people experienced with Microsoft Windows Server who are interested in taking the 70-741 exam or the 70-743 exam.

VideoPowerPoint 

Cert Exam Prep: Exam 70-742: Identity with Windows Server 2016

This Certification Exam Prep session is designed for people experienced with Microsoft Windows Server who are interested in taking the 70-742 exam or the 70-743 exam.

VideoPowerPoint

References

Friday, November 4, 2016

"Office 365 mailbox" button is missing in Exchange Admin Center (EAC) UI

Scenario

You install Microsoft Exchange Server for "Synchronized Identity" management only.
Example: after 3rd party mail server migration (Kerio Mailserver, Lotus Notes, CommunigatePro, etc.) and you have existing Active Directory configured with AAD Connect. Microsoft Exchange Server (EAC or EMS) is the only supported way for "Synchronized Identity" management and configured AAD Connect.
You try to create new "Office 365 mailbox" via EAC UI and with "Organization Management" permissions but no "Office 365 mailbox" button appears.


Notwithstanding this fact, you can create Office 365 mailbox via Exchange Management Shell (New-RemoteMailbox)

Solution

You need to install the Hybrid license key (free for Office 365 customers) on the Exchange Server (there is no need to configure full Exchange Server Hybrid however)

To obtain a Hybrid Edition product key for your Exchange 2010 SP3 or 2013 or 2016 server, go to the Exchange hybrid product key distribution wizard using Office 365 Global Admin credentials.

Apply obtained key to your Hybrid Exchange Server:

Set-ExchangeServer -Identity HybServer01 -ProductKey XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
Get-Service -Name MSExchangeIS -ComputerName HybServer01 | Restart-Service

New-RemoteDomain -Name "Online Domain" -DomainName "tenant.mail.onmicrosoft.com"
Set-RemoteDomain -Identity "Online Domain" -TargetDeliveryDomain $true

Refresh browser session and "Office 365 mailbox" UI button will appear in EAC UI. If not then restart Hybrid server



References: