commit d6a8bce79e491a8a245a37a9e20e6a6bec4d325b Merge: 0ab4e4e1 a7c70ad4 Author: jdeckerMS <jdecker@microsoft.com> Date: Thu Mar 23 10:35:16 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 0ab4e4e119590e0e8cef691eee2b87180b07c5b3 Author: jdeckerMS <jdecker@microsoft.com> Date: Thu Mar 23 10:29:48 2017 -0700 Jordan feedback commit 4454eeadbebb5fccdbfb3b1d07e87d708fefbe87 Merge: 03444e15 ef670cb5 Author: jdeckerMS <jdecker@microsoft.com> Date: Thu Mar 23 09:26:54 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 03444e15f5b51bd1bdf1e76745f62cbbed3b529d Merge: 603408f3 660a6984 Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 22 11:00:46 2017 -0700 Merge branch 'rs2' into jdrs2sh commit 603408f38ecd99e6f7fce1f61a4f199918fd67c4 Merge: 6821f22f b96e1555 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 21 13:54:33 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 6821f22f07f1864bb0a5c8eda33f7daf4f9531bc Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 21 13:41:44 2017 -0700 change ICD references commit 5804bc18db376fba16e8c863f5af8ffdd965359a Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 21 13:39:55 2017 -0700 rename file commit 9268142c9b881b0e0ad4fc2a0d4dcfddc180a1b3 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 21 13:32:31 2017 -0700 update what's new commit 503be68ec3a731434ca789df2da1f1c4783fdca7 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 21 13:30:48 2017 -0700 art commit 93914a2cf2aef9622b172c8ea97a3c1d72544c6a Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 21 13:30:43 2017 -0700 Jordan updates commit 27b1445ba4149fa78b7ec628870b19933307ba38 Merge: 9578dffe 6f0a1f7f Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 21 08:19:27 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 9578dffee198b0be16992368f571eed81f261818 Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Mar 20 09:09:56 2017 -0700 new oobe image commit 616c10e4e404574ecce7726fc76d7582c56b318e Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Mar 20 08:23:53 2017 -0700 get bulk token warning commit 5600a6c7b320c4968686c07df90c62d8110764c9 Merge: cf29bb53 4b34636b Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Mar 20 08:22:02 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit cf29bb53ec1c6e45e068219a796b2a5b04347b15 Merge: 695ec39f a5ec4c4d Author: jdeckerMS <jdecker@microsoft.com> Date: Fri Mar 17 09:42:51 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 695ec39f81b6da46b442ce8e52c9d9b28d65434a Author: jdeckerMS <jdecker@microsoft.com> Date: Thu Mar 16 12:25:06 2017 -0700 delete # Conflicts: # devices/surface-hub/TOC.md # devices/surface-hub/intro-to-surface-hub.md # devices/surface-hub/surface-hub-administrators-guide.md commit cc123f7aa0718efaa7cd355df4e3693afb073b9c Merge: 6b7ddf3e 3c12e864 Author: jdeckerMS <jdecker@microsoft.com> Date: Thu Mar 16 12:23:40 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 6b7ddf3e498d541c2dbb531dd132e7ec0f45eb9d Merge: 278d14c4 032c25d4 Author: jdeckerMS <jdecker@microsoft.com> Date: Thu Mar 16 11:34:53 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 278d14c462fa386e8979c4e998c464f2cdbf6a6c Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 15 10:26:22 2017 -0700 get bulk token commit 005f12e3939f8134143314e95e6bc9f76db8c3de Merge: 410e7508 1bff6ddd Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 15 10:25:19 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 410e750850a5037d843fe9d9c64a477d252ff10e Merge: d2f94c8f 8eed0956 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 13:51:32 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit d2f94c8f9d73868dec86e472fe5ace87b7370ac3 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 13:27:23 2017 -0700 tweak commit f629b4f1fd27fad24c258a7de903e6c18e85ec8c Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 12:44:21 2017 -0700 fix mdm enrollment commit 1dd74f9e7e353ba9ce5e71c8797cfa8cd02342a7 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 12:33:24 2017 -0700 add proxy commit c71e5af71bc866f1a5fe9abefb82b5124fb957fd Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 12:03:09 2017 -0700 add install link commit 0344deee4c68ae3c81529dc9cb602eec2af0b5c3 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 11:57:43 2017 -0700 stick commit be7ed51e1fb7b1a578c8e843b56e701bcf90be9d Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 11:56:52 2017 -0700 resize art commit 857be3cdfca07da3c5dfb470b3a3a3aee290a07c Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 11:55:09 2017 -0700 moved note to correct cell commit a91ca3943b8c0454549a1c0c5455b919ed46de8c Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 11:52:21 2017 -0700 sync commit 5bcf3c1db3c97d87ca60bfd4d688b908d4d9e518 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 11:43:25 2017 -0700 fix link commit de7d60524a2e1ba0d5e1bc1074da9bf887fa6457 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 11:42:46 2017 -0700 add apps to provisioning commit 67e14be35b30f4bfa45fb79815c25ef2317a171c Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 11:37:27 2017 -0700 sync to switch branches commit c6b9d8dae5d29f441ea262323baaad5e41b2bc9f Merge: 3260248b 4b13310a Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Mar 14 08:35:04 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 3260248b8a0511c081a5547419109f9380ea9b26 Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Mar 13 08:56:25 2017 -0700 fix table for non-IE browsers # Conflicts: # windows/whats-new/images/wcd-options.png commit a3ece5c8d4a6c37645f4aa5b39b582be855b98b9 Merge: 4ed80574 759b4a41 Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Mar 13 08:53:34 2017 -0700 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 4ed80574020c1291ba4e853553330a7b84f21657 Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 12:00:27 2017 -0800 fix typo commit 7541a4507508822dcd51da773536b89a5a49f305 Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:53:38 2017 -0800 fix table commit 37254f098396342dd23115ea10885f121f5b9371 Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:51:48 2017 -0800 resize art commit a936a6c4768729fec66775528a31c64132fa4f8e Merge: a217a9ae 9786c53a Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:50:43 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit a217a9ae8e48af3b533eb421a716b5a580daecba Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:45:55 2017 -0800 sync commit f09e8ae9e87db16b7ee6982864a1c4c2fc8ebcdc Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:39:34 2017 -0800 add image to index commit 80a133370000b2b7ff8c9e1383aca7eb1769258a Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:30:34 2017 -0800 fix link commit d8aa55211a62fecf56e6404146917b8e84b3c296 Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:25:33 2017 -0800 tweak TOC, get rid of intro commit 6415e3739e13f47f2d3a6355066015d0bcd4cc7a Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 11:16:33 2017 -0800 remove admin guide level from toc commit 0d016720488e8aa1e3e0621b50596a66db8d232f Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 07:53:03 2017 -0800 release in change history commit 67a8f585dd788db1a18247827b1f9d22378d5b9f Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 07:50:20 2017 -0800 add what's new commit be5e195fc41d9ce94cd1b6189f0da25e9e50b9f2 Merge: e3e75663 8e80f0e1 Author: jdeckerMS <jdecker@microsoft.com> Date: Wed Mar 8 07:40:34 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit e3e756632b462d8a110b0538782bc22487e96d4b Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 28 13:46:55 2017 -0800 end session # Conflicts: # windows/configure/windows-10-start-layout-options-and-policies.md commit 0a9b86a2f6b69e5883fcdab48bb22f19cf1e6c32 Merge: 13e94977 4530d39f Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 28 13:42:38 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 13e9497711b34daab936735edcfa87f13c89d006 Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 11:29:01 2017 -0800 resize art commit 17d830dfde1174c95cb2bde7018fa1c85b8dcacc Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 10:59:56 2017 -0800 delete file from images commit 395946c6c9b54516461e79a232525e965632686d Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 10:50:39 2017 -0800 fix link commit c328942818f6e4b5d2bd2062724a90687b85926e Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 10:40:29 2017 -0800 set up wizard table commit 942af3c56e6e6f7736e1ea03d6801633237a9311 Merge: 6ce5c31d 819ba842 Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 10:03:16 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 6ce5c31d127662010841791aa6498cd1606ed31e Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 09:55:32 2017 -0800 change branches commit a3c28ae9e83bde3c97dd2d9232ad430e08ae972b Merge: b794a681 0a914cf9 Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 08:31:41 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/jdrs2icd' into jdrs2sh commit b794a6819b1a3ad9deb834986a184f6b488497fa Merge: af38dabf 2d1267b5 Author: jdeckerMS <jdecker@microsoft.com> Date: Mon Feb 27 07:37:48 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit af38dabf79f6b51971fbf3891d72be73f0f9035a Author: jdeckerMS <jdecker@microsoft.com> Date: Fri Feb 24 11:25:09 2017 -0800 changed all to End Session # Conflicts: # devices/surface-hub/index.md commit 4e124566f0a01017232d6c2c6be95db15abf5db3 Merge: d07431ae 4b1663d8 Author: jdeckerMS <jdecker@microsoft.com> Date: Fri Feb 24 11:18:06 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit d07431ae706af0af4c6c44909c4e08b16b904ccc Merge: 237cb29c 8bfa038e Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 14 13:48:31 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh commit 237cb29ce337e73ab6d707c1c06eaa89f5b49f3b Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 15:06:27 2017 -0800 undo all commit 5461ccb226a5ee079f07c59d719c52f3fefe2343 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 07:53:02 2017 -0800 sync commit 1e56393ac1a33ff3d1b5eb2183e1ece4e776a9a6 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 07:41:45 2017 -0800 sync commit 25ad8424a8f0dff551367cebedad18563e9d1081 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 07:32:18 2017 -0800 iframe commit 114cccfb75b3f27f46b67b5577d05a5de55662c1 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 07:22:49 2017 -0800 try span commit 03c4b1bb5aad5871b6808c2b7c48e0e71b6c10c7 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 07:10:29 2017 -0800 remove test commit 8a55ced11b6e8d4117d940ec73e2b045a0d7cf24 Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 06:59:19 2017 -0800 test compass video commit f4ae742993fa9892f4d7c411fa87683697849cf7 Merge: dd9a3df0 94b855cd Author: jdeckerMS <jdecker@microsoft.com> Date: Tue Feb 7 06:55:10 2017 -0800 Merge remote-tracking branch 'refs/remotes/origin/rs2' into jdrs2sh
55 KiB
title, description, ms.assetid, keywords, ms.prod, ms.mktglfcycl, ms.sitesec, ms.pagetype, author, localizationpriority
title | description | ms.assetid | keywords | ms.prod | ms.mktglfcycl | ms.sitesec | ms.pagetype | author | localizationpriority |
---|---|---|---|---|---|---|---|---|---|
PowerShell for Surface Hub (Surface Hub) | PowerShell scripts to help set up and manage your Microsoft Surface Hub . | 3EF48F63-8E4C-4D74-ACD5-461F1C653784 | PowerShell, set up Surface Hub, manage Surface Hub | w10 | manage | library | surfacehub | jdeckerMS | medium |
PowerShell for Surface Hub
PowerShell scripts to help set up and manage your Microsoft Surface Hub.
You can check online for updated versions at Surface Hub device account scripts.
PowerShell scripts for Surface Hub administrators
What do the scripts do?
- Create device accounts for setups using pure single-forest on-premises (Microsoft Exchange and Skype 2013 and later only) or online (Microsoft Office 365), that are configured correctly for your Surface Hub.
- Validate existing device accounts for any setup (on-premises or online) to make sure they're compatible with Surface Hub.
- Provide a base template for anyone wanting to create their own device account creation or validation scripts.
What do you need in order to run the scripts?
- Remote PowerShell access to your organization's domain or tenant, Exchange servers, and Skype for Business servers.
- Admin credentials for your organization's domain or tenant, Exchange servers, and Skype for Business servers.
Note
Whether you’re creating a new account or modifying an already-existing account, the validation script will verify that your device account is configured correctly. You should always run the validation script before adding a device account to Surface Hub.
Running the scripts
The account creation scripts will:
- Ask for administrator credentials
- Create device accounts in your domain/tenant
- Create or assign a Surface Hub-compatible ActiveSync policy to the device account(s)
- Set various attributes for the created account(s) in Exchange and Skype for Business.
- Assign licenses and permissions to the created account(s)
These are the attributes that are set by the scripts:
Cmdlet | Attribute | Value |
---|---|---|
Set-Mailbox |
RoomMailboxPassword |
User-provided |
EnableRoomMailboxAccount |
True |
|
Type |
Room |
|
Set-CalendarProcessing |
AutomateProcessing |
AutoAccept |
RemovePrivateProperty |
False |
|
DeleteSubject |
False |
|
DeleteComments |
False |
|
AddOrganizerToSubject |
False |
|
AddAdditionalResponse |
True |
|
AdditionalResponse |
"This is a Surface Hub room!" |
|
New-MobileDeviceMailboxPolicy |
PasswordEnabled |
False |
AllowNonProvisionableDevices |
True |
|
Enable-CSMeetingRoom |
RegistrarPool |
User-provided |
SipAddress |
Set to the User Principal Name (UPN) of the device account |
|
Set-MsolUserLicense (O365 only) |
AddLicenses |
User-provided |
Set-MsolUser (O365 only) |
PasswordNeverExpires |
True |
Set-AdUser (On-prem only) |
Enabled |
True |
Set-AdUser (On-prem only) |
PasswordNeverExpires |
True |
Account creation scripts
These scripts will create a device account for you. You can use the Account verification script to make sure they ran correctly.
The account creation scripts cannot modify an already existing account, but can be used to help you understand which cmdlets need to be run to configure the existing account correctly.
Create an on-premise account
Creates an account as described in On-premises deployment.
# SHAccountCreateOnPrem.ps1
$Error.Clear()
$ErrorActionPreference = "Stop"
$status = @{}
# Cleans up set state such as remote powershell sessions
function Cleanup()
{
if ($sessExchange)
{
Remove-PSSession $sessExchange
}
if ($sessCS)
{
Remove-PSSession $sessCS
}
}
function PrintError($strMsg)
{
Write-Host $strMsg -foregroundcolor Red
}
function PrintSuccess($strMsg)
{
Write-Host $strMsg -foregroundcolor Green
}
function PrintAction($strMsg)
{
Write-Host $strMsg -ForegroundColor Cyan
}
# Cleans up and prints an error message
function CleanupAndFail($strMsg)
{
if ($strMsg)
{
PrintError($strMsg);
}
Cleanup
exit 1
}
# Exits if there is an error set and prints the given message
function ExitIfError($strMsg)
{
if ($Error)
{
CleanupAndFail($strMsg);
}
}
## Collect account data ##
$credNewAccount = (Get-Credential -Message "Enter the desired UPN and password for this new account")
$strUpn = $credNewAccount.UserName
$strDisplayName = Read-Host "Please enter the display name you would like to use for $strUpn"
if (!$credNewAccount -Or [System.String]::IsNullOrEmpty($strDisplayName) -Or [System.String]::IsNullOrEmpty($credNewAccount.UserName) -Or $credNewAccount.Password.Length -le 0)
{
CleanupAndFail "Please enter all of the requested data to continue."
exit 1
}
## Sign in to remote powershell for exchange and lync online ##
$credExchange = $null
$credExchange=Get-Credential -Message "Enter credentials of an Exchange user with mailbox creation rights"
if (!$credExchange)
{
CleanupAndFail("Valid credentials are required to create and prepare the account.");
}
$strExchangeServer = Read-Host "Please enter the FQDN of your exchange server (e.g. exch.contoso.com)"
# Lync info
$credLync = Get-Credential -Message "Enter credentials of a Skype for Business admin (or cancel if they are the same as Exchange)"
if (!$credLync)
{
$credLync = $credExchange
}
$strLyncFQDN = Read-Host "Please enter the FQDN of your Lync server (e.g. lync.contoso.com) or enter to use [$strExchangeServer]"
if ([System.String]::IsNullOrEmpty($strLyncFQDN))
{
$strLyncFQDN = $strExchangeServer
}
PrintAction "Connecting to remote sessions. This can occasionally take a while - please do not enter input..."
try
{
$sessExchange = New-PSSession -ConfigurationName microsoft.exchange -Credential $credExchange -AllowRedirection -Authentication Kerberos -ConnectionUri "http://$strExchangeServer/powershell" -WarningAction SilentlyContinue
}
catch
{
CleanupAndFail("Failed to connect to exchange. Please check your credentials and try again. If this continues to fail, you may not have permission for remote powershell - if not, please perform the setup manually. Error message: $_")
}
PrintSuccess "Connected to Remote Exchange Shell"
try
{
$sessLync = New-PSSession -Credential $credLync -ConnectionURI "https://$strLyncFQDN/OcsPowershell" -AllowRedirection -WarningAction SilentlyContinue
}
catch
{
CleanupAndFail("Failed to connect to Lync. Please check your credentials and try again. Error message: $_")
}
PrintSuccess "Connected to Lync Server Remote PowerShell"
Import-PSSession $sessExchange -AllowClobber -WarningAction SilentlyContinue
Import-PSSession $sessLync -AllowClobber -WarningAction SilentlyContinue
# In case there was any uncaught errors
ExitIfError("Remote connections failed. Please check your credentials and try again.")
## Create the Exchange mailbox ##
# Note: These exchange commandlets do not always throw their errors as exceptions
# Because Get-Mailbox will throw an error if the mailbox is not found
$Error.Clear()
PrintAction "Creating a new account..."
try
{
$mailbox = $null
$mailbox = (New-Mailbox -UserPrincipalName $credNewAccount.UserName -Alias $credNewAccount.UserName.substring(0,$credNewAccount.UserName.indexOf('@')) -room -Name $strDisplayName -RoomMailboxPassword $credNewAccount.Password -EnableRoomMailboxAccount $true)
} catch { }
ExitIfError "Failed to create a new mailbox on exchange.";
$status["Mailbox Setup"] = "Successfully created a mailbox for the new account"
$strEmail = $mailbox.WindowsEmailAddress
PrintSuccess "The following mailbox has been created for this room: $strEmail"
## Create or retrieve a policy that will be applied to surface hub devices ##
# The policy disables requiring a device password so that the SurfaceHub does not need to be lockable to use Active Sync
$strPolicy = Read-Host 'Please enter the name for a new Surface Hub ActiveSync policy that will be created and applied to this account.
We will configure that policy to be compatible with Surface Hub devices.
If this script has been used before, please enter the name of the existing policy.'
$easpolicy = $null
try {
$easpolicy = Get-MobileDeviceMailboxPolicy $strPolicy
}
catch {}
if ($easpolicy)
{
if (!$easpolicy.PasswordEnabled -and ($easpolicy.AllowNonProvisionableDevices -eq $null -or $easpolicy.AllowNonProvisionableDevices ))
{
PrintSuccess "An existing policy has been found and will be applied to this account."
}
else
{
PrintError "The policy you provided is incompatible with the surface hub."
$easpolicy = $null
$status["Device Password Policy"] = "Failed to apply the EAS policy to the account because the policy was invalid."
}
}
else
{
$Error.Clear()
PrintAction "Creating policy..."
$easpolicy = New-MobileDeviceMailboxPolicy -Name $strPolicy -PasswordEnabled $false -AllowNonProvisionableDevices $true
if ($easpolicy)
{
PrintSuccess "A new device policy has been created; you can use this same policy for all future Surface Hub device accounts."
}
else
{
PrintError "Could not create $strPolicy"
}
}
if ($easpolicy)
{
# Convert mailbox to user type so we can apply the policy (necessary)
# Sometimes it takes a while for this change to take affect so we have some nasty retry loops
$Error.Clear();
try
{
Set-Mailbox $credNewAccount.UserName -Type Regular
} catch {}
if ($Error)
{
$Error.Clear()
$status["Device Password Policy"] = "Failed to apply the EAS policy to the account."
}
else
{
# Loop until resource type goes away, up to 5 times
for ($i = 0; $i -lt 5 -And (Get-Mailbox $credNewAccount.UserName).ResourceType; $i++)
{
Start-Sleep -s 5
}
# If the mailbox is still a Room we cannot apply the policy
if (!((Get-Mailbox $credNewAccount.UserName).ResourceType))
{
$Error.Clear()
# Set policy for account
Set-CASMailbox $credNewAccount.UserName -ActiveSyncMailboxPolicy $strPolicy
if (!$Error)
{
$status["ActiveSync Policy"] = "Successfully applied $strPolicy to the account"
}
else
{
$status["ActiveSync Policy"] = "Failed to apply the EAS policy to the account."
}
$Error.Clear()
# Convert back to room mailbox
Set-Mailbox $credNewAccount.UserName -Type Room
# Loop until resource type goes back to room
for ($i = 0; ($i -lt 5) -And ((Get-Mailbox $credNewAccount.UserName).ResourceType -ne "Room"); $i++)
{
Start-Sleep -s 5
}
if ((Get-Mailbox $credNewAccount.UserName).ResourceType -ne "Room")
{
# A failure to convert the mailbox back to a room is unfortunate but means the mailbox is unusable.
$status["Mailbox Setup"] = "A mailbox was created but we could not set it to a room resource type."
}
else
{
try
{
Set-Mailbox $credNewAccount.UserName -RoomMailboxPassword $credNewAccount.Password -EnableRoomMailboxAccount $true
} catch { }
if ($Error)
{
$status["Mailbox Setup"] = "A room mailbox was created but we could not set its password."
}
$Error.Clear()
}
}
}
}
PrintSuccess "Account creation completed."
PrintAction "Setting calendar processing rules..."
$Error.Clear();
## Prepare the calendar for automatic meeting responses ##
try {
Set-CalendarProcessing -Identity $credNewAccount.UserName -AutomateProcessing AutoAccept
} catch { }
if ($Error)
{
$status["Calendar Acceptance"] = "Failed to configure the account to automatically accept/decline meeting requests"
}
else
{
$status["Calendar Acceptance"] = "Successfully configured the account to automatically accept/decline meeting requests"
}
$Error.Clear()
try {
Set-CalendarProcessing -Identity $credNewAccount.UserName -RemovePrivateProperty $false -AddOrganizerToSubject $false -AddAdditionalResponse $true -DeleteSubject $false -DeleteComments $false -AdditionalResponse "This is a Surface Hub room!"
} catch { }
if ($Error)
{
$status["Calendar Response Configuration"] = "Failed to configure the account's response properties"
}
else
{
$status["Calendar Response Configuration"] = "Successfully configured the account's response properties"
}
$Error.Clear()
## Configure the Account to not expire ##
PrintAction "Configuring password not to expire..."
Start-Sleep -s 20
try
{
Set-AdUser $mailbox.Alias -PasswordNeverExpires $true -Enabled $true
}
catch
{
}
if ($Error)
{
$status["Password Expiration Policy"] = "Failed to set the password to never expire"
}
else
{
$status["Password Expiration Policy"] = "Successfully set the password to never expire"
}
PrintSuccess "Completed Exchange configuration"
## Setup Skype for Business. This is somewhat optional and if it fails we SfbEnable can be used later ##
PrintAction "Configuring account for Skype for Business."
# Getting registrar pool
$strRegPool = $strLyncFQDN
$Error.Clear()
$strRegPoolEntry = Read-Host "Enter a Skype for Business Registrar Pool, or leave blank to use [$strRegPool]"
if (![System.String]::IsNullOrEmpty($strRegPoolEntry))
{
$strRegPool = $strRegPoolEntry
}
# Try to SfB-enable the account. Note that it may not work right away as the account needs to propogate to active directory
PrintAction "Enabling Skype for Business..."
Start-Sleep -s 10
$Error.Clear()
try {
Enable-CsMeetingRoom -Identity $credNewAccount.UserName -RegistrarPool $strRegPool -SipAddressType EmailAddress
}
catch { }
if ($Error)
{
$status["Skype for Business Account Setup"] = "Failed to setup the Skype for Business meeting room - you can run EnableSfb.ps1 to try again."
$Error.Clear();
}
else
{
$status["Skype for Business Account Setup"] = "Successfully enabled account as a Skype for Business meeting room"
}
Write-Host
## Cleanup and print results ##
Cleanup
$strDisplay = $mailbox.DisplayName
$strUsr = $credNewAccount.UserName
PrintAction "Summary for creation of $strUsr ($strDisplay)"
if ($status.Count -gt 0)
{
ForEach($k in $status.Keys)
{
$v = $status[$k]
$color = "yellow"
if ($v[0] -eq "S") { $color = "green" }
elseif ($v[0] -eq "F")
{
$color = "red"
$v += " Go to http://aka.ms/shubtshoot"
}
Write-Host -NoNewline $k -ForegroundColor $color
Write-Host -NoNewline ": "
Write-Host $v
}
}
else
{
PrintError "The account could not be created"
}
Create a device account using Office 365
Creates an account as described in Create a device account using Office 365
# SHAccountCreateO365.ps1
$Error.Clear()
$ErrorActionPreference = "Stop"
$status = @{}
# Cleans up set state such as remote powershell sessions
function Cleanup()
{
if ($sessExchange)
{
Remove-PSSession $sessExchange
}
if ($sessCS)
{
Remove-PSSession $sessCS
}
}
function PrintError($strMsg)
{
Write-Host $strMsg -foregroundcolor Red
}
function PrintSuccess($strMsg)
{
Write-Host $strMsg -foregroundcolor Green
}
function PrintAction($strMsg)
{
Write-Host $strMsg -ForegroundColor Cyan
}
# Cleans up and prints an error message
function CleanupAndFail($strMsg)
{
if ($strMsg)
{
PrintError($strMsg);
}
Cleanup
exit 1
}
# Exits if there is an error set and prints the given message
function ExitIfError($strMsg)
{
if ($Error)
{
CleanupAndFail($strMsg);
}
}
## Check dependencies ##
try {
Import-Module LyncOnlineConnector
Import-Module MSOnline
}
catch
{
PrintError "Some dependencies are missing"
PrintError "Please install the Windows PowerShell Module for Lync Online. For more information go to http://www.microsoft.com/download/details.aspx?id=39366"
PrintError "Please install the Azure Active Directory module for PowerShell from https://go.microsoft.com/fwlink/p/?linkid=236297"
CleanupAndFail
}
## Collect account data ##
$credNewAccount = (Get-Credential -Message "Enter the desired UPN and password for this new account")
$strUpn = $credNewAccount.UserName
$strDisplayName = Read-Host "Please enter the display name you would like to use for $strUpn"
if (!$credNewAccount -Or [System.String]::IsNullOrEmpty($strDisplayName) -Or [System.String]::IsNullOrEmpty($credNewAccount.UserName) -Or $credNewAccount.Password.Length -le 0)
{
CleanupAndFail "Please enter all of the requested data to continue."
exit 1
}
## Sign in to remote powershell for exchange and lync online ##
$credAdmin = $null
$credAdmin=Get-Credential -Message "Enter credentials of an Exchange and Skype for Business admin"
if (!$credadmin)
{
CleanupAndFail "Valid admin credentials are required to create and prepare the account."
}
PrintAction "Connecting to remote sessions. This can occasionally take a while - please do not enter input..."
try
{
$sessExchange = New-PSSession -ConfigurationName microsoft.exchange -Credential $credAdmin -AllowRedirection -Authentication basic -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -WarningAction SilentlyContinue
}
catch
{
CleanupAndFail "Failed to connect to exchange. Please check your credentials and try again. Error message: $_"
}
try
{
$sessCS = New-CsOnlineSession -Credential $credAdmin
}
catch
{
CleanupAndFail "Failed to connect to Skype for Business Online Datacenter. Please check your credentials and try again. Error message: $_"
}
try
{
Connect-MsolService -Credential $credAdmin
}
catch
{
CleanupAndFail "Failed to connect to Azure Active Directory. Please check your credentials and try again. Error message: $_"
}
Import-PSSession $sessExchange -AllowClobber -WarningAction SilentlyContinue
Import-PSSession $sessCS -AllowClobber -WarningAction SilentlyContinue
# In case there was any uncaught errors
ExitIfError "Remote connection failed. Please check your credentials and try again."
## Create the Exchange mailbox ##
# Note: These exchange commandlets do not always throw their errors as exceptions
# Because Get-Mailbox will throw an error if the mailbox is not found
$Error.Clear()
PrintAction "Creating a new account..."
try
{
$mailbox = $null
$mailbox = (New-Mailbox -MicrosoftOnlineServicesID $credNewAccount.UserName -room -Name $strDisplayName -RoomMailboxPassword $credNewAccount.Password -EnableRoomMailboxAccount $true)
} catch { }
ExitIfError "Failed to create a new mailbox on exchange.";
$status["Mailbox Setup"] = "Successfully created a mailbox for the new account"
$strEmail = $mailbox.WindowsEmailAddress
PrintSuccess "The following mailbox has been created for this room: $strEmail"
## Create or retrieve a policy that will be applied to surface hub devices ##
# The policy disables requiring a device password so that the SurfaceHub does not need to be lockable to use Active Sync
$strPolicy = Read-Host 'Please enter the name for a new Surface Hub ActiveSync policy that will be created and applied to this account.
We will configure that policy to be compatible with Surface Hub devices.
If this script has been used before, please enter the name of the existing policy.'
$easpolicy = $null
try {
$easpolicy = Get-MobileDeviceMailboxPolicy $strPolicy
}
catch {}
if ($easpolicy)
{
if (!$easpolicy.PasswordEnabled -and ($easpolicy.AllowNonProvisionableDevices -eq $null -or $easpolicy.AllowNonProvisionableDevices ))
{
PrintSuccess "An existing policy has been found and will be applied to this account."
}
else
{
PrintError "The policy you provided is incompatible with the surface hub."
$easpolicy = $null
$status["ActiveSync Policy"] = "Failed to apply the EAS policy to the account because the policy was invalid."
}
}
else
{
$Error.Clear()
PrintAction "Creating policy..."
$easpolicy = New-MobileDeviceMailboxPolicy -Name $strPolicy -PasswordEnabled $false -AllowNonProvisionableDevices $true
if ($easpolicy)
{
PrintSuccess "A new device policy has been created; you can use this same policy for all future Surface Hub device accounts."
}
else
{
PrintError "Could not create $strPolicy"
}
}
if ($easpolicy)
{
# Convert mailbox to user type so we can apply the policy (necessary)
# Sometimes it takes a while for this change to take affect so we have some nasty retry loops
$Error.Clear();
try
{
Set-Mailbox $credNewAccount.UserName -Type Regular
} catch {}
if ($Error)
{
$Error.Clear()
$status["Device Password Policy"] = "Failed to apply the EAS policy to the account."
PrintError "Failed to convert to regular account"
}
else
{
# Loop until resource type goes away, up to 5 times
for ($i = 0; $i -lt 5 -And (Get-Mailbox $credNewAccount.UserName).ResourceType; $i++)
{
Start-Sleep -s 5
}
# If the mailbox is still a Room we cannot apply the policy
if (!((Get-Mailbox $credNewAccount.UserName).ResourceType))
{
$Error.Clear()
# Set policy for account
Set-CASMailbox $credNewAccount.UserName -ActiveSyncMailboxPolicy $strPolicy
if (!$Error)
{
$status["Device Password Policy"] = "Successfully applied $strPolicy to the account"
}
else
{
$status["Device Password Policy"] = "Failed to apply the EAS policy to the account."
PrintError "Failed to apply policy"
}
$Error.Clear()
# Convert back to room mailbox
Set-Mailbox $credNewAccount.UserName -Type Room
# Loop until resource type goes back to room
for ($i = 0; ($i -lt 5) -And ((Get-Mailbox $credNewAccount.UserName).ResourceType -ne "Room"); $i++)
{
Start-Sleep -s 5
}
if ((Get-Mailbox $credNewAccount.UserName).ResourceType -ne "Room")
{
# A failure to convert the mailbox back to a room is unfortunate but means the mailbox is unusable.
$status["Mailbox Setup"] = "A mailbox was created but we could not set it to a room resource type."
}
else
{
Set-Mailbox $credNewAccount.UserName -RoomMailboxPassword $credNewAccount.Password -EnableRoomMailboxAccount $true
if ($Error)
{
$status["Mailbox Setup"] = "A room mailbox was created but we could not set its password."
}
$Error.Clear()
}
}
}
}
else
{
$status["Device Password Policy"] = "Failed to apply the EAS policy to the account."
PrintError "Failed to obtain policy"
}
PrintSuccess "Account creation completed."
PrintAction "Setting calendar processing rules..."
$Error.Clear();
## Prepare the calendar for automatic meeting responses ##
try {
Set-CalendarProcessing -Identity $credNewAccount.UserName -AutomateProcessing AutoAccept
} catch { }
if ($Error)
{
$status["Calendar Acceptance"] = "Failed to configure the account to automatically accept/decline meeting requests"
}
else
{
$status["Calendar Acceptance"] = "Successfully configured the account to automatically accept/decline meeting requests"
}
$Error.Clear()
try {
Set-CalendarProcessing -Identity $credNewAccount.UserName -RemovePrivateProperty $false -AddOrganizerToSubject $false -AddAdditionalResponse $true -DeleteSubject $false -DeleteComments $false -AdditionalResponse "This is a Surface Hub room!"
} catch { }
if ($Error)
{
$status["Calendar Response Configuration"] = "Failed to configure the account's response properties"
}
else
{
$status["Calendar Response Configuration"] = "Successfully configured the account's response properties"
}
$Error.Clear()
## Configure the Account to not expire ##
PrintAction "Configuring password not to expire..."
try
{
Set-MsolUser -UserPrincipalName $credNewAccount.UserName -PasswordNeverExpires $true
}
catch
{
}
if ($Error)
{
$status["Password Expiration Policy"] = "Failed to set the password to never expire"
}
else
{
$status["Password Expiration Policy"] = "Successfully set the password to never expire"
}
PrintSuccess "Completed Exchange configuration"
## Setup Skype for Business. This is somewhat optional and if it fails we SfbEnable can be used later ##
PrintAction "Configuring account for Skype for Business."
# Getting registrar pool
$strRegPool = $null
try {
$strRegPool = (Get-CsTenant).TenantPoolExtension
}
catch {}
$Error.Clear()
if (![System.String]::IsNullOrEmpty($strRegPool))
{
$strRegPool = $strRegPool.Substring($strRegPool[0].IndexOf(':') + 1)
}
<#
$strRegPoolEntry = Read-Host "Enter a Skype for Business Registrar Pool, or leave blank to use [$strRegPool]"
if (![System.String]::IsNullOrEmpty($strRegPoolEntry))
{
$strRegPool = $strRegPoolEntry
}
#>
# Try to SfB-enable the account. Note that it may not work right away as the account needs to propogate to active directory
PrintAction "Enabling Skype for Business on $strRegPool"
Start-Sleep -s 10
$Error.Clear()
try {
Enable-CsMeetingRoom -Identity $credNewAccount.UserName -RegistrarPool $strRegPool -SipAddressType EmailAddress
}
catch { }
if ($Error)
{
$status["Skype for Business Account Setup"] = "Failed to setup the Skype for Business meeting room - you can run EnableSfb.ps1 to try again."
$Error.Clear();
}
else
{
$status["Skype for Business Account Setup"] = "Successfully enabled account as a Skype for Business meeting room"
}
## Now we need to assign a Skype for Business license to the account ##
# Assign a license to thes
$countryCode = (Get-CsTenant).CountryAbbreviation
$loc = Read-Host "Please enter the usage location for this device account (where the account is being used). This is a 2-character code that is used to assign licenses (e.g. $countryCode)"
try {
$Error.Clear()
Set-MsolUser -UserPrincipalName $credNewAccount.UserName -UsageLocation $loc
}
catch{}
if ($Error)
{
$status["Office 365 License"] = "Failed to assign an Office 365 license to the account"
$Error.Clear()
}
else
{
PrintAction "We found the following licenses available for your tenant:"
$skus = (Get-MsolAccountSku | Where-Object { !$_.AccountSkuID.Contains("INTUNE"); })
$i = 1
$skus | % {
Write-Host -NoNewline $i
Write-Host -NoNewLine ": AccountSKUID: "
Write-Host -NoNewLine $_.AccountSkuid
Write-Host -NoNewLine " Active Units: "
Write-Host -NoNewLine $_.ActiveUnits
Write-Host -NoNewLine " Consumed Units: "
Write-Host $_.ConsumedUnits
$i++
}
$iLicenseIndex = 0;
do
{
$iLicenseIndex = Read-Host 'Choose the number for the SKU you want to pick'
} while ($iLicenseIndex -lt 1 -or $iLicenseIndex -gt $skus.Length)
$strLicenses = $skus[$iLicenseIndex - 1].AccountSkuId
if (![System.String]::IsNullOrEmpty($strLicenses))
{
try
{
$Error.Clear()
Set-MsolUserLicense -UserPrincipalName $credNewAccount.UserName -AddLicenses $strLicenses
}
catch
{
}
if ($Error)
{
$Error.Clear()
$status["Office 365 License"] = "Failed to add a license to the account. Make sure you have remaining licenses."
}
else
{
$status["Office 365 License"] = "Successfully added license to the account"
}
}
else
{
$status["Office 365 License"] = "You opted not to install a license on this account"
}
}
Write-Host
## Cleanup and print results ##
Cleanup
$strDisplay = $mailbox.DisplayName
$strUsr = $credNewAccount.UserName
PrintAction "Summary for creation of $strUsr ($strDisplay)"
if ($status.Count -gt 0)
{
ForEach($k in $status.Keys)
{
$v = $status[$k]
$color = "yellow"
if ($v[0] -eq "S") { $color = "green" }
elseif ($v[0] -eq "F")
{
$color = "red"
$v += " Go to http://aka.ms/shubtshoot for help"
}
Write-Host -NoNewline $k -ForegroundColor $color
Write-Host -NoNewline ": "
Write-Host $v
}
}
else
{
PrintError "The account could not be created"
}
Account verification script
This script will validate the previously-created device account on a Surface Hub, no matter which method was used to create it. This script is basically pass/fail. If one of the test errors out, it will show a detailed error message, but if all tests pass, the end result will be a summary report. For example, you might see:
15 tests executed
0 failures
2 warnings
15 passed
Details of specific settings will not be shown.
# SHAccountValidate.ps1
$Error.Clear()
$ErrorActionPreference = "Stop"
# Cleans up set state such as remote powershell sessions
function Cleanup()
{
if ($sessEx)
{
Remove-PSSession $sessEx
}
if ($sessSfb)
{
Remove-PSSession $sessSfb
}
}
function PrintError($strMsg)
{
Write-Host $strMsg -foregroundcolor "red"
}
function PrintSuccess($strMsg)
{
Write-Host $strMsg -foregroundcolor "green"
}
function PrintAction($strMsg)
{
Write-Host $strMsg -ForegroundColor Cyan
}
# Cleans up and prints an error message
function CleanupAndFail($strMsg)
{
if ($strMsg)
{
PrintError($strMsg);
}
Cleanup
exit 1
}
# Exits if there is an error set and prints the given message
function ExitIfError($strMsg)
{
if ($Error)
{
CleanupAndFail($strMsg);
}
}
$strUpn = Read-Host "What is the email address of the account you wish to validate?"
if (!$strUpn.Contains('@'))
{
CleanupAndFail "$strUpn is not a valid email address"
}
$strExServer = Read-Host "What is your exchange server? (leave blank for online tenants)"
if ($strExServer.Equals(""))
{
$fExIsOnline = $true
}
else
{
$fExIsOnline = $false
}
$credEx = Get-Credential -Message "Please provide exchange user credentials"
$strRegistrarPool = Read-Host ("What is the Skype for Business registrar pool for $strUpn" + "? (leave blank for online tenants)")
$fSfbIsOnline = $strRegistrarPool.Equals("")
$fHasOnPrem = $true
if ($fSfbIsOnline -and $fExIsOnline)
{
do
{
$strHasOnPrem = (Read-Host "Do you have an on-premises Active Directory (Y/N) (No if your domain services are hosted entirely online)").ToUpper()
} while ($strHasOnPrem -ne "Y" -and $strHasOnPrem -ne "N")
$fHasOnPrem = $strHasOnPrem.Equals("Y")
}
$fHasOnline = $false
if ($fSfbIsOnline -or $fExIsOnline)
{
$fHasOnline = $true
}
if ($fSfbIsOnline)
{
try {
Import-Module LyncOnlineConnector
}
catch
{
CleanupAndFail "To verify Skype for Business in online tenants you need the Lync Online Connector module from http://www.microsoft.com/download/details.aspx?id=39366"
}
}
else
{
$credSfb = (Get-Credential -Message "Please enter Skype for Business admin credentials")
}
if ($fHasOnline)
{
$credSfb = $credEx
try {
Import-Module MSOnline
}
catch
{
CleanupAndFail "To verify accounts in online tenants you need the Azure Active Directory module for PowerShell from https://go.microsoft.com/fwlink/p/?linkid=236297"
}
}
PrintAction "Connecting to Exchange Powershell Session..."
[System.Management.Automation.Runspaces.AuthenticationMechanism] $authType = [System.Management.Automation.Runspaces.AuthenticationMechanism]::Kerberos
if ($fExIsOnline)
{
$authType = [System.Management.Automation.Runspaces.AuthenticationMechanism]::Basic
}
try
{
$sessEx = $null
if ($fExIsOnline)
{
$sessEx = New-PSSession -ConfigurationName microsoft.exchange -Credential $credEx -AllowRedirection -Authentication $authType -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -WarningAction SilentlyContinue
}
else
{
$sessEx = New-PSSession -ConfigurationName microsoft.exchange -Credential $credEx -AllowRedirection -Authentication $authType -ConnectionUri https://$strExServer/powershell -WarningAction SilentlyContinue
}
}
catch
{
}
if (!$sessEx)
{
CleanupAndFail "Connecting to Exchange Powershell failed, please validate your server is accessible and credentials are correct"
}
PrintSuccess "Connected to Exchange Powershell Session"
PrintAction "Connecting to Skype for Business Powershell Session..."
if ($fSfbIsOnline)
{
$sessSfb = New-CsOnlineSession -Credential $credSfb
}
else
{
$sessSfb = New-PSSession -Credential $credSfb -ConnectionURI "https://$strRegistrarPool/OcsPowershell" -AllowRedirection -WarningAction SilentlyContinue
}
if (!$sessSfb)
{
CleanupAndFail "Connecting to Skype for Business Powershell failed, please validate your server is accessible and credentials are correct"
}
PrintSuccess "Connected to Skype for Business Powershell"
if ($fHasOnline)
{
$credMsol = $null
if ($fExIsOnline)
{
$credMsol = $credEx
}
elseif ($fSfbIsOnline)
{
$credMsol = $credSfb
}
else
{
CleanupAndFail "Internal error - could not determine MS Online credentials"
}
try
{
PrintAction "Connecting to Azure Active Directory Services..."
Connect-MsolService -Credential $credMsol
PrintSuccess "Connected to Azure Active Directory Services"
}
catch
{
# This really shouldn't happen unless there is a network error
CleanupAndFail "Failed to connect to MSOnline"
}
}
PrintAction "Importing remote sessions into the local session..."
try
{
$importEx = Import-PSSession $sessEx -AllowClobber -WarningAction SilentlyContinue -DisableNameChecking
$importSfb = Import-PSSession $sessSfb -AllowClobber -WarningAction SilentlyContinue -DisableNameChecking
}
catch
{
}
if (!$importEx -or !$importSfb)
{
CleanupAndFail "Import failed"
}
PrintSuccess "Import successful"
$mailbox = $null
try
{
$mailbox = Get-Mailbox -Identity $strUpn
}
catch
{
}
if (!$mailbox)
{
CleanupAndFail "Account exists check failed. Unable to find the mailbox for $strUpn - please make sure the Exchange account exists on $strExServer"
}
$exchange = $null
if (!$fExIsOnline)
{
$exchange = Get-ExchangeServer
if (!$exchange -or !$exchange.IsE14OrLater)
{
CleanupAndFail "A compatible exchange server version was not found. Please use at least exchange 2010."
}
}
$strAlias = $mailbox.Alias
$strDisplayName = $mailbox.DisplayName
$strLinkedAccount = $strLinkedDomain = $strLinkedUser = $strLinkedServer = $null
$credLinkedDomain = $Null
if (!$fExIsOnline -and ![System.String]::IsNullOrEmpty($mailbox.LinkedMasterAccount) -and !$mailbox.LinkedMasterAccount.EndsWith("\SELF"))
{
$strLinkedAccount = $mailbox.LinkedMasterAccount
$strLinkedDomain = $strLinkedAccount.substring(0,$strLinkedAccount.IndexOf('\'))
$strLinkedUser = $strLinkedAccount.substring($strLinkedAccount.IndexOf('\') + 1)
$strLinkedServer = Read-Host "What is the domain controller for the $strLinkedDomain"
$credLinkedDomain = (Get-Credential -Message "Please provide credentials for $strLinkedDomain")
}
Write-Host
Write-Host
Write-Host
PrintAction "Performing verification checks on $strDisplayName..."
$Global:iTotalFailures = 0
$global:iTotalWarnings = 0
$Global:iTotalPasses = 0
function Validate()
{
Param(
[string]$Test,
[bool] $Condition,
[string]$FailureMsg,
[switch]$WarningOnly
)
Write-Host -NoNewline -ForegroundColor White $Test.PadRight(100,'.')
if ($Condition)
{
Write-Host -ForegroundColor Green "Passed"
$global:iTotalPasses++
}
else
{
if ($WarningOnly)
{
Write-Host -ForegroundColor Yellow ("Warning: "+$FailureMsg)
$global:iTotalWarnings++
}
else
{
Write-Host -ForegroundColor Red ("Failed: "+$FailureMsg)
$global:iTotalFailures++
}
}
}
## Exchange ##
Validate -WarningOnly -Test "The mailbox $strUpn is enabled as a room account" -Condition ($mailbox.RoomMailboxAccountEnabled -eq $True) -FailureMsg "RoomMailboxEnabled - without a device account, the Surface Hub will not be able to use various key features."
$calendarProcessing = Get-CalendarProcessing -Identity $strUpn -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
Validate -Test "The mailbox $strUpn is configured to accept meeting requests" -Condition ($calendarProcessing -ne $null -and $calendarProcessing.AutomateProcessing -eq 'AutoAccept') -FailureMsg "AutomateProcessing - the Surface Hub will not be able to send mail or sync its calendar."
Validate -WarningOnly -Test "The mailbox $strUpn will not delete meeting comments" -Condition ($calendarProcessing -ne $null -and !$calendarProcessing.DeleteComments) -FailureMsg "DeleteComments - the Surface Hub may be missing some meeting information on the welcome screen and Skype."
Validate -WarningOnly -Test "The mailbox $strUpn keeps private meetings private" -Condition ($calendarProcessing -ne $null -and !$calendarProcessing.RemovePrivateProperty) -FailureMsg "RemovePrivateProperty - the Surface Hub will make show private meetings."
Validate -Test "The mailbox $strUpn keeps meeting subjects" -Condition ($calendarProcessing -ne $null -and !$calendarProcessing.DeleteSubject) -FailureMsg "DeleteSubject - the Surface Hub will not keep meeting subject information."
Validate -WarningOnly -Test "The mailbox $strUpn does not prepend meeting organizers to subjects" -Condition ($calendarProcessing -ne $null -and !$calendarProcessing.AddOrganizerToSubject) -FailureMsg "AddOrganizerToSubject - the Surface Hub will not display meeting subjects as intended."
if ($fExIsOnline)
{
#No online specifics
}
else
{
#No onprem specifics
}
#ActiveSync
$casMailbox = Get-Casmailbox $strUpn -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
Validate -Test "The mailbox $strUpn has a mailbox policy" -Condition ($casMailbox -ne $null) -FailureMsg "PasswordEnabled - unable to find policy - the Surface Hub will not be able to send mail or sync its calendar."
if ($casMailbox)
{
$policy = $null
if ($fExIsOnline -or $exchange.IsE15OrLater)
{
$strPolicy = $casMailbox.ActiveSyncMailboxPolicy
$policy = Get-MobileDeviceMailboxPolicy -Identity $strPolicy -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
Validate -Test "The policy $strPolicy does not require a device password" -Condition ($policy.PasswordEnabled -ne $True) -FailureMsg "PasswordEnabled - policy requires a device password - the Surface Hub will not be able to send mail or sync its calendar."
}
else
{
$strPolicy = $casMailbox.ActiveSyncMailboxPolicy
$policy = Get-ActiveSyncMailboxPolicy -Identity $strPolicy -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
Validate -Test "The policy $strPolicy does not require a device password" -Condition ($policy.PasswordEnabled -ne $True) -FailureMsg "PasswordEnabled - policy requires a device password - the Surface Hub will not be able to send mail or sync its calendar."
}
if ($policy -ne $null)
{
Validate -Test "The policy $strPolicy allows non-provisionable devices" -Condition ($policy.AllowNonProvisionableDevices -eq $null -or $policy.AllowNonProvisionableDevices -eq $true) -FailureMsg "AllowNonProvisionableDevices - policy will not allow the SurfaceHub to sync"
}
}
# Check the default access level
$orgSettings = Get-ActiveSyncOrganizationSettings
$strDefaultAccessLevel = $orgSettings.DefaultAccessLevel
Validate -Test "ActiveSync devices are allowed" -Condition ($strDefaultAccessLevel -eq 'Allow') -FailureMsg "DeviceType Windows Mail is accessible - devices are not allowed by default - the surface hub will not be able to send mail or sync its calendar."
# Check if there exists a device access rule that bans the device type Windows Mail
$blockingRules = Get-ActiveSyncDeviceAccessRule | where {($_.AccessLevel -eq 'Block' -or $_.AccessLevel -eq 'Quarantine') -and $_.Characteristic -eq 'DeviceType'-and $_.QueryString -eq 'WindowsMail'}
Validate -Test "Windows mail devices are not blocked or quarantined" -Condition ($blockingRules -eq $null -or $blockingRules.Length -eq 0) -FailureMsg "DeviceType Windows Mail is accessible - devices are blocked or quaratined - the surface hub will not be able to send mail or sync its calendar."
## End Exchange ##
## SfB ##
$strLyncIdentity = $null
if ($fSfbIsOnline)
{
$strLyncIdentity = $strUpn
}
else
{
$strLyncIdentity = $strAlias
}
$lyncAccount = $null
try {
$lyncAccount = Get-CsMeetingRoom -Identity $strLyncIdentity -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
} catch {
try {
$lyncAccount = Get-CsUser -Identity $strLyncIdentity -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
} catch { }
}
Validate -Test "There is a Lync or Skype for Business account for $strLyncIdentity" -Condition ($lyncAccount -ne $null -and $lyncAccount.Enabled) -FailureMsg "SfB Enabled - there is no Skype for Business account - meetings will not support Skype for Business"
if ($lyncAccount)
{
Validate -Test "The meeting room has a SIP address" -Condition (![System.String]::IsNullOrEmpty($lyncAccount.SipAddress)) -FailureMsg "SfB Enabled - there is no SIP Address - the device account cannot be used to sign into Skype for Business."
}
## End SFB ##
if ($fHasOnline)
{
#License validation and password expiry
$accountOnline = Get-MsolUser -UserPrincipalName $strUpn -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
Validate -Test "There is an online user account for $strUpn" -Condition ($accountOnline -ne $null) -FailureMsg "Could not find a Microsoft Online account for this user even though some services are online"
if ($accountOnline)
{
Validate -Test "The password for $strUpn will not expire" -Condition ($accountOnline.PasswordNeverExpires -eq $True) -FailureMsg "PasswordNeverExpires - the admin will need to update the device account's password on the Surface Hub when it expires."
if ($fIsSfbOnline -and !$fIsExOnline)
{
$strLicenseFailureMsg = "Has O365 license - The devices will not be able to use Skype for Business services."
}
elseif ($fIsExOnline -and !$fIsSfbOnline)
{
$strLicenseFailureMsg = "Has O365 license - The devices will not be able to use Exchange Online services."
}
else
{
$strLicenseFailureMsg = "Has O365 license - The devices will not be able to use Skype for Business or Exchange Online services."
}
Validate -Test "$strUpn is licensed" -Condition ($accountOnline.IsLicensed -eq $True) -FailureMsg $strLicenseFailureMsg
Validate -Test "$strUpn is allowed to sign in" -Condition ($accountOnline.BlockCredential -ne $True) -FailureMsg "BlockCredential - This user is not allowed to sign in."
}
}
#If there is an on-prem component, we can get the authorative AD user from mailbox
if ($fHasOnPrem)
{
$accountOnPrem = $null
if ($strLinkedAccount)
{
$accountOnPrem = Get-AdUser $strLinkedUser -server $strLinkedServer -credential $credLinkedDomain -properties PasswordNeverExpires -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
}
else
{
#AD User enabled validation
$accountOnPrem = Get-AdUser $strAlias -properties PasswordNeverExpires -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
}
$strOnPremUpn = $accountOnPrem.UserPrincipalName
Validate -Test "There is a user account for $strOnPremUpn" -Condition ($accountOnprem -ne $null) -FailureMsg "Could not find an Active Directory account for this user"
if ($accountOnPrem)
{
Validate -WarningOnly -Test "The password for $strOnPremUpn will not expire" -Condition ($accountOnprem.PasswordNeverExpires -eq $True) -FailureMsg "PasswordNeverExpires - the admin will need to update the device account's password on the Surface Hub when it expires."
Validate -Test "$strOnPremUpn is enabled" -Condition $accountOnPrem.Enabled -FailureMsg "AccountEnabled - this device account will not sign in"
}
}
$global:iTotalTests = ($global:iTotalFailures + $global:iTotalPasses + $global:iTotalWarnings)
Write-Host -NoNewline $global:iTotalTests "tests executed: "
Write-Host -NoNewline -ForegroundColor Red $Global:iTotalFailures "failures "
Write-Host -NoNewline -ForegroundColor Yellow $Global:iTotalWarnings "warnings "
Write-Host -ForegroundColor Green $Global:iTotalPasses "passes "
Cleanup
Enable Skype for Business
This script will enable Skype for Business on a device account. Use it only if Skype for Business wasn't previously enabled during account creation.
## This script performs only the Enable for Skype for Business step on an account. It should only be run if this step failed in SHAccountCreate and the other steps have been completed ##
# EnableSfb.ps1
$Error.Clear()
$ErrorActionPreference = "Stop"
# Cleans up set state such as remote powershell sessions
function Cleanup()
{
if ($sessCS)
{
Remove-PSSession $sessCS
}
}
function PrintError($strMsg)
{
Write-Host $strMsg -foregroundcolor "red"
}
function PrintSuccess($strMsg)
{
Write-Host $strMsg -foregroundcolor "green"
}
# Cleans up and prints an error message
function CleanupAndFail($strMsg)
{
if ($strMsg)
{
PrintError($strMsg);
}
Cleanup
exit 1
}
# Exits if there is an error set and prints the given message
function ExitIfError($strMsg)
{
if ($Error)
{
CleanupAndFail($strMsg);
}
}
## Check dependencies ##
$input = Read-Host "Is the account you wish to enable part of an online environment (enter O) or on-premises environment (enter P)"
if ($input -eq "P")
{
$online = $false
}
elseif ($input -eq "O")
{
$online = $true
}
else
{
CleanupAndFail "Invalid selection"
}
if ($online)
{
try {
Import-Module LyncOnlineConnector
}
catch
{
PrintError "Some dependencies are missing"
PrintError "Please install the Windows PowerShell Module for Lync Online. For more information go to http://www.microsoft.com/download/details.aspx?id=39366"
PrintError "Please install the Azure Active Directory module for PowerShell from https://go.microsoft.com/fwlink/p/?linkid=236297"
CleanupAndFail
}
}
else
{
$strRegPool = Read-Host "Enter the FQDN of your Skype for Business Registrar Pool"
}
## Collect account data ##
Write-Host "----------- Enter info for the account to enable -----------." -foregroundcolor "magenta"
$strRoomUri=Read-Host 'Please enter the UPN of the account you are enabling (e.g. confroom@surfacehub.microsoft.com)'
if ([System.String]::IsNullOrEmpty($strRoomUri))
{
CleanupAndFail "Please enter all of the requested data to continue."
exit 1
}
Write-Host "--------------------------------------------------------------." -foregroundcolor "magenta"
## Sign in to remote powershell for exchange and lync online ##
Write-Host "`n------------------ Establishing connection -----------------." -foregroundcolor "magenta"
$credAdmin=Get-Credential -Message "Enter credentials of a Skype for Business admin"
if (!$credadmin)
{
CleanupAndFail("Valid admin credentials are required to create and prepare the account.");
}
Write-Host "Connecting to remote sessions. This can occasionally take a while - please do not enter input..."
try
{
if ($online)
{
$sessCS = New-CsOnlineSession -Credential $credAdmin
}
else
{
$sessCS = New-PSSession -Credential $credAdmin -ConnectionURI "https://$strRegPool/OcsPowershell" -AllowRedirection -WarningAction SilentlyContinue
}
}
catch
{
CleanupAndFail("Failed to connect to Skype for Business server. Please check your credentials and try again. Error message: $_")
}
Import-PSSession $sessCS -AllowClobber
# In case there was any uncaught errors
ExitIfError("Remote connection failed. Please check your credentials and try again.")
Write-Host "--------------------------------------------------------------." -foregroundcolor "magenta"
# Getting registrar pool
if ($online)
{
try {
$strRegPool = $null;
$strRegPool = (Get-CsTenant).TenantPoolExtension
} catch {}
if ($Error)
{
$Error.Clear();
$strRegPool = "";
Write-Host "We failed to lookup your Skype for Business Registrar Pool, but you can still enter it manually"
}
else
{
$strRegPool = $strRegPool[0].Substring($strRegPool[0].IndexOf(':') + 1)
}
}
$Error.Clear()
try {
Enable-CsMeetingRoom -Identity $strRoomUri -RegistrarPool $strRegPool -SipAddressType EmailAddress
}
catch {}
ExitIfError("Failed to setup Skype for Business meeting room")
PrintSuccess "Successfully enabled $strRoomUri as a Skype for Business meeting room"
Cleanup
Useful cmdlets
Creating a Surface Hub-compatible ActiveSync policy
For Surface Hub to use Exchange services, a device account configured with a compatible ActiveSync policy must be provisioned on the device. This policy has the following requirements:
PasswordEnabled == 0
In the following cmdlets, $strPolicy
is the name of the ActiveSync policy, and $strRoomUpn
is the UPN of the device account you want to apply the policy to.
Note that in order to run the cmdlets, you need to set up a remote PowerShell session and:
- Your admin account must be remote-PowerShell-enabled. This allows the admin to use the PowerShell cmdlets that are needed by the script. (This permission can be set using
set-user $admin -RemotePowerShellEnabled $true
) - Your admin account must have the "Reset Password" role if you plan to run the creation scripts. This allows the admin to change the password of the account, which is needed for the script. The Reset Password Role can be enabled using the Exchange Admin Center.
Create the policy.
# Create new policy with PasswordEnabled == false
New-MobileDeviceMailboxPolicy -Name $strPolicy -PasswordEnabled $false –AllowNonProvisionableDevices $true
To apply the policy, the mailbox cannot be a room type, so it has to be converted into a user first.
# Convert user to regular type
Set-Mailbox $strRoomUpn -Type Regular
# Set policy for account
Set-CASMailbox $strRoomUpn -ActiveSyncMailboxPolicy $strPolicy
Now the device account just needs to be converted back into a room type.
# Convert back to room mailbox
Set-Mailbox $strRoomUpn -Type Room
Allowing device IDs for ActiveSync
To allow an account $strRoomUpn
, run the following command:
Set-CASMailbox –Identity $strRoomUpn –ActiveSyncAllowedDeviceIDs “<ID>”
To find a device's ID, run:
Get-ActiveSyncDevice -Mailbox $strRoomUpn
This retrieves device information for every device that the account has been provisioned on, Including the DeviceId
property.
Auto-accepting and declining meeting requests
For a device account to automatically accept or decline meeting requests based on its availability, the AutomateProcessing attribute must be set to AutoAccept. This is recommended as to prevent overlapping meetings.
Set-CalendarProcessing $strRoomUpn -AutomateProcessing AutoAccept
Accepting external meeting requests
For a device account to accept external meeting requests (a meeting request from an account not in the same tenant/domain), the device account must be set to allow processing of external meeting requests. Once set, the device account will automatically accept or decline meeting requests from external accounts as well as local accounts.
Note
If the AutomateProcessing attribute is not set to AutoAccept, then setting this will have no effect.
Set-CalendarProcessing $strRoomUpn -ProcessExternalMeetingMessages $true