If you ever had problems with corrupt databases in an Exchange 2010 DAG setup you might have encountered this error. Trying to activate the database on a server where it has this state will fail.
However there is a quite simple fix given that you have a healthy copy of the database on a different server:
Update-MailboxDatabaseCopy -Identity DB<server with failed content index state> -SourceServer <server with healty copy> -CatalogOnly
Run the command in the Exchange Management Shell and it should fix the Content index state and allow you to activate the database again.
After some exchange services failed on one of the nodes in our Exchange 2010 DAG we got some problems with one database. The database was mounted on server2 where it has an activation preference of 2.
Trying to manually activate the database on server1, where is has an activation preference of 1, resulted in the following error:
Activate Database Copy…
Failed
Error:
An Active Manager operation failed. Error: The database action failed. Error: Operation failed with message: MapiExceptionJetErrorAttachedDatabaseMismatch: Unable to mount database. (hr=0x80004005, ec=-1216)
. [Database: DB1, Server: server1]
An Active Manager operation failed. Error: Operation failed with message: MapiExceptionJetErrorAttachedDatabaseMismatch: Unable to mount database. (hr=0x80004005, ec=-1216)
. [Server: server1]
MapiExceptionJetErrorAttachedDatabaseMismatch: Unable to mount database. (hr=0x80004005, ec=-1216)
——————————————————–
OK
——————————————————–
The solution is actually quite simple:
Suspend the database copy on server1 and update the database copy. Then try to activate the database copy again.
More detailed steps:
Using the Exchange management shell:
Suspend-MailboxDatabaseCopy -Identity DB1Server1
Update-MailboxDatabaseCopy -Identity DB1Server1 -SourceServer Server2
Move-ActiveMailboxDatabase DB2 -ActivateOnServer MBX1
Using the Exchange Management Console:
Navigate to Server Configuration–>Mailbox and select Server1
Right click the database and click Suspend Database Copy
Right click the database and click Update Database Copy
In the wizard select server2 as the source server and click Update
When the job completes right click the database again and click Activate Database Copy
OpenService FAILED 5: Access is denied. — “Oh crap!”
If you ever see this error and need to reset the DACL on a Windows service, let’s say in case you (or someone else) accidentally deletes it, or configure it to something that prevents you from reading it’s security settings, this might do the trick:
First of all, get a cup of coffee.
Download PsExec (a tool in PsTools), which among other things allow you to run commands as the “local system” account.
Find out what the real name of the service is by looking in the following registry key:
HKLMSYSTEMCurrentControlSetServices
The real name (not the display name) of the service is the name of the key itself.
Start a Command Prompt (cmd) window as administrator.
Start a new cmd session as the system account:
PsExec.exe /s cmd
Now it’s time to set a new DACL, this is done by using the command “sc sdset” followed by the service name and the new security descriptor using SDDL-format (Security Descriptor Definition Language). If you are unsure what parameters to use here, you can either run “sc sdshow” on another service that most likely are configured the same way as the service you are changing were, or try the command in the example below.
The command below will give access to Local System (SY), Built-in administrators (BA), Interactively logged-on user (IU) and Service logon user (SU).
I don’t know how useful this will be for others, but in our case we had a need to check a few public dns records on some of our domains. Doing so by using a web portal will be time consuming and straight out boring. Luckily you can use Powershell for such things:
foreach ($element in $domains)
{
Resolve-DnsName -server 8.8.8.8 record.$($element)
}
You might notice that I use Google’s public dns servere here, but you can use whatever dns server you want, or just leave the -server part out.
The example above is pretty basic and only checks for an A record. In our case we needed to check several SRV records for each of the domains, so I had to extend the script a little. The cmdlet Resolve-DnsName is equivalent to the good ol’ nslookup so it’s quite powerful, given the right swithces.
Heres the script I ended up with for our case (10 points if you guess what the SRV records are for ):
A little while ago I posted a script for enabling users for Lync and settings some settings for that user. That script has been used here ever since I posted it and it has worked like a charm. However there’s always room for improvement, right?.
So I have made a function out of it and for the first time (I think) I have even implemented some error handling. The function is also improved quit a bit on the help section and the info that is shown to the user after the function completes.
As in the script, this function will enable the user for Lync and set some default settings like Dial Plan, Voice Policy, Conferencing Policy. It also gives you the option to specify a Line URI.
The difference is that this function will use the default settings only if nothing else is specified, so you can change the settings if you like, using parameters. Of course theres also the possibility to pipe input from a csv file.
Here’s the code:
function Enable-LyncUser {
[CmdletBinding()]
Param (
[parameter(Mandatory=$True)][string]$Identity,
[string]$Pool = 'lyncpool1.test.local',
[string]$DialPlan = 'DialPlanSIPtrunk',
[string]$Voice = 'SIP Trunk Service',
[string]$Conference = 'Conference',
[string]$LineURI
)
Write-Host "Enabling user..."
#Importing the Lync PowerShell module
Import-Module Lync
#Trying to enable the user for Lync
try {
Enable-CsUser -identity $Identity -RegistrarPool $Pool -SipAddressType emailaddress
}
#Catching errors, aborting if the user is not found
catch [Microsoft.Rtc.Management.AD.ManagementException] {
throw "User not found, check username"
}
#Sleeping, so that the next command doesn't fail
Write-Host "Sleeping... Please wait..."
Start-Sleep -s 4
Write-Host "Configuring user..."
#Setting the user as EnterpriseVoice enabled
Set-CsUser -identity $Identity -EnterpriseVoiceEnabled $True
#Setting dial plan
Grant-CsDialPlan –Identity $Identity -PolicyName $DialPlan
#Setting voice policy
Grant-CsVoicePolicy –Identity $Identity –PolicyName $Voice
#Setting conferenceing policy
Grant-CsConferencingPolicy -identity $Identity -PolicyName $Conference
#Trying to set the optional Line URI
try {
Set-CsUser -identity $Identity -LineUri $LineURI
}
#Cathing errors and continuing
catch [System.FormatException] {
Write-Error -Message "Wrong format on LineURI, it should be tel:+xxxxxxxx." -Category SyntaxError
}
Write-Host "Config finished"
#Grabbing the Lync login for the user and writing it to the host
$SipAddress = Get-CsUser -Identity $Identity | Select-Object SipAddress
Write-Host "The user may now log in to Lync as $($SipAddress.SipAddress.substring(4))" -ForegroundColor Green
<#
.Synopsis
Enables given user for Lync and sets config
.Description
The function will enable the user for Lync and add the given config, if no config is given the default values will be used.
.Parameter Identity
The user who you want to enable for Lync
.Parameter Pool
The Lync pool you want to assign a user to. Default is lyncpool1.test.local
.Parameter DialPlan
The dialplan you want to associate the user with. Default is DialPlanSIPtrunk
.Parameter Voice
The voice policy you want to associate the user with. Default is SIP Trunk Service
.Parameter Conference
The conference policy you want to associate the user with. Default is Conference
.Parameter LineURI
If you want to specify a Line URI, do so in the format of tel:
.Example
Enable-LyncUser user1
This will enable user1 with default settings
.Example
Enable-Lyncuser user2 -LineURI tel:+4712345678
This will enable user2 and set the lineuri to tel:+4712345678
.Link
http://cloud.kemta.net
#>
}
You may wonder why the Start-Sleep command is there. The reason is that my testing indicated that the function will work to fast for Active Directory if it isn’t there. During my testing I found that without the sleep the next command, Set-CsUser, will fail because the object cannot be found. Running the function again resultet in no errors.
Therefore I tested adding a few seconds of sleep to prevent the Set-CsUser command (and the following commands) from failing. Depending on you environment you can decrease the seconds or even remove the sleep, but I found that 3 seconds was just a bit to short (sometimes it would fail, sometimes not) so I ended up with 4.
I am kinda proud of the error handling in this function, given that I have never used error handling in Powershell before. But please let me know if there are improvements to be made or errors in my code.
Guess what? It’s time for something different than powershell
I finally got myself a server to play around with Hyper-V on. This has been sorely missed for a long time. I worked a lot with Hyper-V in my previous job, and even built a small data center running on Hyper-V. But at my current job we only use vmware, which is a great product but to expensive in my book. Especially when we are finally looking at a datacenter license from Microsoft and we already have the System Center suite. This means that we can save a ton of money on switching from vmware to Hyper-V.
Anyway…In this blogpost I want to show you a little about the HP Array Configuration Utility command-line interface.
I usually use the graphical interface for creating volumes and such, but for some reason I couldn’t get it working on my Hyper-V test server. So instead of looking on how to fix that I decided to give the cli a shot. What I want to achieve with this post is to show you how the steps you need after putting one or more new disks in the server.
The ACU cli can be launched by running Crogram Files (x86)CompaqHpacucliBinhpacucli.exe.
The first command you should know about is “controller all show”, this will show you all the controllers installed in the server. The output will look something like this:
=> controller all show
Smart Array P410i in Slot 0 (Embedded) (sn: 50014380124xxxxx)
This show that my controller is installed in slot 0, to get some more info on this controller I could run “controller slot=0 show”, the output should look something like this:
=> controller slot=0 show
Smart Array P410i in Slot 0 (Embedded)
Bus Interface: PCI
Slot: 0
Serial Number: 50014380124D5620
Cache Serial Number: PBCDF0CRHZU5D4
RAID 6 (ADG) Status: Disabled
Controller Status: OK
Hardware Revision: C
Firmware Version: 5.70
Rebuild Priority: Medium
Expand Priority: Medium
Surface Scan Delay: 15 secs
Surface Scan Mode: Idle
Queue Depth: Automatic
Monitor and Performance Delay: 60 min
Elevator Sort: Enabled
Degraded Performance Optimization: Disabled
Inconsistency Repair Policy: Disabled
Wait for Cache Room: Disabled
Surface Analysis Inconsistency Notification: Disabled
Post Prompt Timeout: 0 secs
Cache Board Present: True
Cache Status: OK
Cache Ratio: 25% Read / 75% Write
Drive Write Cache: Disabled
Total Cache Size: 1024 MB
Total Cache Memory Available: 912 MB
No-Battery Write Cache: Disabled
Cache Backup Power Source: Capacitors
Battery/Capacitor Count: 1
Battery/Capacitor Status: OK
SATA NCQ Supported: True
On my test server I have already created a mirrored volume on which I have installed Hyper-V. I have only one extra disk, so I cannot show you how to create a fancy raid configuration but nevertheless I will show you how to create an array and a logical disk.
The first thing we need to do is to find any unassigned disk connected to the controller. This is done by running the command “controller slot=0 physicaldrive allunassigned show” (replace slot=0 with the slot where your controller is connected). The output will look something like this:
So here we see that I have one unassigned disk that I can use. Given that I want to use all unassigned disks to create a new logical disk in a new array I can run the command “controller slot=0 create type=ld drives=allunassigned raid=0”
This will create a new array and a new logical drive that uses all unassigned drives, the raid level is 0 (striping)
Thats basically what you need to do from the acu. But before you can use the disk in Windows you need to initialize it, create a partition and so on, the required steps could be something like this:
DISKPART> list disk
DISKPART> select disk 1
DISKPART> attributes disk clear readonly
DISKPART> online disk
DISKPART> create partition primary
DISKPART> list volume
DISKPART> select volume 4
DISKPART> assign letter=e:
DISKPART> EXIT
C:UsersAdministrator> format E: /Q
I’m just gonna start by putting this out there: I have never been a fan of SuperOffice, and I probably never will be either.
Now that thats out there, heres the situation: We have one citrix farm, and three different SuperOffice instances. The goal with our citrix farm is to have each citrix server completely the same as the others. Because of that, only one of the SuperOffice instance have been accessible from the citrix farm. Until yesterday…
That didn’t work at all so we didn’t bother trying anymore as the other two instances isn’t that much used anyway.
But yesterday I did another attempt and it turns out that the documentation from SuperOffice is flawed, it clearly states that the inipath parameter should be used like this:
socrm.exe -inipath=c:superoffice.ini
But when in fact the correct way would be like this:
socrm.exe -inipath=c:
As far as I can see, SuperOffice is coded to look for superoffice.ini in the folder specified by the inipath parameter. It also will not recognize i.e. c:superoffice as a folder, you would need to specify c:superoffice
Another thing that is important, and that I have found no documentation on, is that superoffice.config needs to be in the same folder as superoffice.ini.
So to sum up: If you want to run a SuperOffice client and connect to different databases, you need to use the -inipath parameter. You should create a superoffice.ini and a superoffice.config file, store it somewhere (a network share works fine), and then start SuperOffice or SuperOffice Admin with the following switch: -inipath=\serversharefolder
A friend of mine asked me a couple of days ago if I knew a way to gather users who are members of given groups. I thought to myself “Hmm, challenge accepted!” and started writing a small powershell script.
After he confirmed that the script worked as planned I decided to make a function of it (Yes, I know it has been a lot of them on this blog lately).
The function accepts two parameters: GroupNames and Filelocation. In addition there is an optional switch called KeepCSV.
Rest of the function isn’t that interesting, if you want to use it you can always consult the help (get-help get-membersinadgroups) that I actually have created
Heres the code:
function Get-MembersInADGroups
{
Param
(
[parameter(Mandatory=$True)][string[]]$GroupNames,
[parameter(Mandatory=$True)][string[]]$Filelocation,
[switch]$KeepCSV
)
Get-ADGroup -LDAPFilter "(name=$GroupNames)" | export-csv $FileLocationtemp.csv -NoTypeInformation
$groups = Import-Csv $FileLocationtemp.csv
$groups | ForEach-Object {
$groupname = $_.SamAccountname
Get-ADGroupMember -Identity $_.SamAccountName | select-object name,samaccountname | Out-File $Filelocation$groupname.txt -Encoding utf8
}
if ($KeepCSV)
{
Write-Host "CSV file is now saved as $filelocationtemp.csv"
}
Else
{
Remove-Item $FileLocationtemp.csv
}
<#
.Synopsis
Gathers members in given group(s) and puts the result in txt files
.Description
This function will gather all users in the group(s) you specify and write a txt file for each group containing the users who are member of that group. The function accepts wildcards in group name
.Parameter Groupnames
This parameter defines what group(s) to look for
.Parameter FileLocation
This parameter defines where the output files should be saved
.Parameter KeepCSV
Defining this switch will not delete the temp.csv file containing the groups which are polled
.Example
Get-MembersInADGroups -GroupNames some_group -Filelocation c:test
This command will poll Active Directory for the members of some_group and write a file called some_group.txt in c:test
.Example
Get-MembersInADGroups -GroupNames some_group* -Filelocation c:test
This command will poll Active Directory for members of groups whose name begins with some_group and write a txt file for each of them in c:test
.Link
http://cloud.kemta.net
#>
}
PS: the function requires that you already have loaded the Active Directory module in powershell
If you are ever in need of some motivation, here is a very simple Powershell function for that:
function Motivate-Me
{
$motivator = Get-Random -Minimum 1 -Maximum 5
if ($motivator -eq 1)
{Write-Host "You are a Powershell God!"}
if ($motivator -eq 2)
{Write-Host "You rule dude!"}
if ($motivator -eq 3)
{Write-Host "I wish I could errorhandle like you"}
if ($motivator -eq 4)
{Write-Host "I am nothing compared to you"}
if ($motivator -eq 5)
{Write-Host "Are you sure you intirely human? 'cause you seem to cool to be real"}
<#
.Synopsis
Show som motivational words on the screen
.Description
This function will print some motivational words on the screen
.Example
Motivate-Me
Show som motivational words on the screen
.Link
http://cloud.kemta.net
#>
}
Now all you need to do is write Motivate-Me in the powershell window to receive some inspirational words
This is a function I created just because I wanted to toy around with Powershell and get-wmiobject. Also, this is my first function where I made it possible to use a switch parameter.
What the function does is gather some system information using get-wmiobject. The info is written to a temp file and then shown using out-gridview.
If the KeepTempFile parameter is used the temp file is saved in the users profile, if not it is deleted after the function finishes.
Heres the code:
function Show-Debug
{
Param(
[switch]$KeepTempFile
)
$tempfile = "$env:userprofilepstempfile.txt"
New-Item $tempfile -ItemType file -Force
Get-WmiObject -Class Win32_ComputerSystem |fl Manufacturer,Model,Name,Domain,PrimaryOwnerName | Out-File $tempfile -Append
Get-WmiObject -class "Win32_BIOS" -namespace "rootCIMV2" -computername localhost | fl BIOSVersion,Serialnumber,Status | Out-File $tempfile -Append
Get-WmiObject Win32_OperatingSystem | fl @{Expression={$_.Caption};Label="OS Name"},SerialNumber,OSArchitecture,Version | Out-File $tempfile -Append
Get-WmiObject Win32_PhysicalMemory | ft Tag,Capacity,Speed | Out-File $tempfile -Append
Get-WmiObject Win32_Processor | fl DeviceID,Manufacturer,Caption,Name,NumberOfCores,NumberOfLogicalProcessors,MaxClockSpeed,CurrentClockSpeed,L2CacheSize,L3CacheSize,Status | Out-File $tempfile -Append
Get-Content $tempfile | Out-GridView
if ($KeepTempFile){
Write-Host "Log file is now saved as $tempfile"
}
Else {
Remove-Item $tempfile
}
<#
.Synopsis
Show some information about your computer
.Description
This function will create a txt file which will be populated with some information from wmi. It will then show the info to the user and delete the file
.Parameter KeepTempFile
Setting this parameter will keep the txt file with all info
.Example
Show-Debug
Gathers info and show it on screen
.Link
http://cloud.kemta.net
#>
}