Got a Windows 10 machine running in a workgroup but want to administer a Hyper-V server(s)
Enable PSRemoting on the Windows 10 machine:
Enable-PSRemoting
Then enable CredSSP on my Hyper-V server:
Enable-WSManCredSSP –Role Server
Add the Hyper-V server to the TrustedHosts list on the Windows 10 machine:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "HV-Host"
Enable CredSSP on the Windows 10 machine:
Enable-WSManCredSSP -Role client -DelegateComputer "Windows10Client"
Or to allow everything:
Run this in an elevated PowerShell Session:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*'
About: Exchange 2013-2016-2019-Online - Powershell - Windows 2012-2016-2019 - Teams - Office365 - PKI - Microsoft365
19 December 2017
Allow workgroup machine to administer Hyper-V server
Labels:
Hyper-V,
Powershell,
Windows 10
Location:Utrecht
Utrecht, Netherlands
Failed Content Index State - Known Issue KB4045655
After installing KB4045655, the security update for Microsoft Exchange 2013 and 2016 you may encounter failed content index states.
View the status of all database content index:
How to recover from this can be done multiple ways, but the question I have is why did this happen in the first place?
Searching through the services list I came across the "Microsoft Exchange Search Host Controller" and it was in a Disabled startup type.
Strange because it needs to be started automatically as it interacts with the "Microsoft Exchange Search" service.
After setting the service to start as automatic began searching why it would set as disabled.
In the link I posted at the top of this post lays the answer.
And I quote:
Known issues
View the status of all database content index:
Get-MailboxDatabaseCopyStatus *
How to recover from this can be done multiple ways, but the question I have is why did this happen in the first place?
Searching through the services list I came across the "Microsoft Exchange Search Host Controller" and it was in a Disabled startup type.
Strange because it needs to be started automatically as it interacts with the "Microsoft Exchange Search" service.
After setting the service to start as automatic began searching why it would set as disabled.
In the link I posted at the top of this post lays the answer.
And I quote:
Known issues
We are aware of some reports that Exchange services may remain in a disabled state after installing this security update. If this occurs, the update has installed correctly, but the service control script encountered a problem returning Exchange services to a normal state. To resolve this issue, use Services Manager to restore the startup type to Automatic, and then start the affected Exchange services manually.
So there you have it, and it goes to show that reading the Microsoft documentation and knowledge base articles is a must.
Location:Utrecht
Utrecht, Netherlands
28 November 2017
Increase your OneDrive for Business storage quota to the max of your license
I had never seen this or read about it until now.
Turns out that the default storage quota for a OneDrive for Business user is 1 TB.
This goes for
Only after clicking the link "What's the maximum for my Office 365 plan?" you're taken to a page that states the above.
So how do we take advantage of all this storage space?
I'm mostly interested in the way to set it for one specific user:
First we need to get the OneDrive for Business site url, the easiest way to get this is to click in the Office365 menu tile.
You're taken to your OneDrive for Business site.
Copy the url from the browser, it looks something like this:
https://tenant-my.sharepoint.com/personal/firstname_lastname_domain_com
Then we go to PowerShell and fire up the SharePoint Online PowerShell module.
When logged in we view the current settings:
Now to set the maximum of 5 TB for this one User:
Check to see the change:
In case there's the need to reset it to the default value:
Turns out that the default storage quota for a OneDrive for Business user is 1 TB.
This goes for
- Office 365 Enterprise E3 and E5,
- Office 365 Goverment E3 and E5
- Office 365 Education and Office 365 Education E5
- OneDrive for Business Plan 2 and SharePoint Online Plan 2
All these licenses are allowed to increase the storage quota to 5 TB.
It doesn't show this when you check in the admin portal.
Only after clicking the link "What's the maximum for my Office 365 plan?" you're taken to a page that states the above.
So how do we take advantage of all this storage space?
I'm mostly interested in the way to set it for one specific user:
First we need to get the OneDrive for Business site url, the easiest way to get this is to click in the Office365 menu tile.
You're taken to your OneDrive for Business site.
Copy the url from the browser, it looks something like this:
https://tenant-my.sharepoint.com/personal/firstname_lastname_domain_com
Then we go to PowerShell and fire up the SharePoint Online PowerShell module.
When logged in we view the current settings:
get-SPOSite -Identity https://tenant-my.sharepoint.com/personal/firstname_lastname_domain_com | select storagequota StorageQuota ____________ 1048576
Now to set the maximum of 5 TB for this one User:
Set-SPOSite -Identity https://tenant-my.sharepoint.com/personal/firstname_lastname_domain_com -StorageQuota 5242880
Check to see the change:
get-SPOSite -Identity https://tenant-my.sharepoint.com/personal/firstname_lastname_domain_com | select storagequota StorageQuota ____________ 5242880
In case there's the need to reset it to the default value:
Set-SPOSite -Identity https://tenant-my.sharepoint.com/personal/firstname_lastname_domain_com -StorageQuotaReset
Labels:
Office365,
OneDrive for Business,
Powershell,
Quota,
Storage
Location:Utrecht
Utrecht, Netherlands
14 November 2017
Cannot contact web site xxxx-admin.sharepoint.com or the web site does not support SharePoint Online credentials
Trying to pre-provision some OneDrive users on Office365 I came across this error after trying to connect to the Sharepoint site:
Now this error is somewhat fuzzy and clear at the same time, if you know what to look for.
Login to Sharepoint Online PowerShell:
This will allow you to login with an account that has disabled the ability for non-modern (legacy) authentication protocols also known as MFA.
Changes may take 1 minute up to 24 hours to take affect.
And when provisioning has taken place don't forget to set it back to "False".
PS C:\> .\BulkEnqueueOneDriveSite.ps1 -SPOAdminUrl https://tenant.sharepoint.com -InputFilePath .\UserInput.txt Please enter a Tenant Admin username admin@tenant.onmicrosoft.com Please enter your password ******************************* Exception calling "ExecuteQuery" with "0" argument(s): "Cannot contact web site 'https://tenant.sharepoint.com/' or the web site does not support SharePoint Online credentials. The response status code is 'Unauthorized'. The response heade rs are 'X-SharePointHealthScore=5, X-MSDAVEXT_Error=917656; Access+denied.+Before+opening+files+in+this+location%2c+you +must+first+browse+to+the+web+site+and+select+the+option+to+login+automatically., SPRequestGuid=b4c82c9e-5087-4000-7c44 -3b884b58ddef, request-id=b4c82c9e-5087-4000-7c44-3b884b58ddef, MS-CV=nizItIdQAEB8RDuIS1jd7w.0, Strict-Transport-Securi ty=max-age=31536000, X-FRAME-OPTIONS=SAMEORIGIN, SPRequestDuration=113, SPIisLatency=1, MicrosoftSharePointTeamServices =16.0.0.7108, X-Content-Type-Options=nosniff, X-MS-InvokeApp=1; RequireReadOnly, X-MSEdge-Ref=Ref A: 489B56D95E98428AB2 BF5250B429009B Ref B: AMS04EDGE0606 Ref C: 2017-11-14T11:51:12Z, Content-Length=0, Content-Type=text/plain; charset=utf -8, Date=Tue, 14 Nov 2017 11:51:11 GMT, P3P=CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo C NT COM INT NAV ONL PHY PRE PUR UNI", X-Powered-By=ASP.NET'." At BulkEnqueueOneDriveSite.ps1:67 char:1 + $ctx.ExecuteQuery() + ~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : NotSupportedException Exception calling "ExecuteQuery" with "0" argument(s): "Cannot contact web site 'https://tenant.sharepoint.com/' or the web site does not support SharePoint Online credentials. The response status code is 'Unauthorized'. The response heade rs are 'X-SharePointHealthScore=6, X-MSDAVEXT_Error=917656; Access+denied.+Before+opening+files+in+this+location%2c+you +must+first+browse+to+the+web+site+and+select+the+option+to+login+automatically., SPRequestGuid=b4c82c9e-a0a1-4000-7c44 -3e7f7034d943, request-id=b4c82c9e-a0a1-4000-7c44-3e7f7034d943, MS-CV=nizItKGgAEB8RD5/cDTZQw.0, Strict-Transport-Securi ty=max-age=31536000, X-FRAME-OPTIONS=SAMEORIGIN, SPRequestDuration=158, SPIisLatency=2, MicrosoftSharePointTeamServices =16.0.0.7108, X-Content-Type-Options=nosniff, X-MS-InvokeApp=1; RequireReadOnly, X-MSEdge-Ref=Ref A: C1ACEE6EF2A74BC1A7 0B6E46B03C3F5E Ref B: AMS04EDGE0606 Ref C: 2017-11-14T11:51:12Z, Content-Length=0, Content-Type=text/plain; charset=utf -8, Date=Tue, 14 Nov 2017 11:51:11 GMT, P3P=CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo C NT COM INT NAV ONL PHY PRE PUR UNI", X-Powered-By=ASP.NET'." At BulkEnqueueOneDriveSite.ps1:70 char:1 + $ctx.ExecuteQuery() + ~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : NotSupportedException Exception calling "ExecuteQuery" with "0" argument(s): "Cannot contact web site 'https://tenant.sharepoint.com/' or the web site does not support SharePoint Online credentials. The response status code is 'Unauthorized'. The response heade rs are 'X-SharePointHealthScore=5, X-MSDAVEXT_Error=917656; Access+denied.+Before+opening+files+in+this+location%2c+you +must+first+browse+to+the+web+site+and+select+the+option+to+login+automatically., SPRequestGuid=b4c82c9e-90a7-4000-7c44 -3c52af78ea1f, request-id=b4c82c9e-90a7-4000-7c44-3c52af78ea1f, MS-CV=nizItKeQAEB8RDxSr3jqHw.0, Strict-Transport-Securi ty=max-age=31536000, X-FRAME-OPTIONS=SAMEORIGIN, SPRequestDuration=102, SPIisLatency=1, MicrosoftSharePointTeamServices =16.0.0.7108, X-Content-Type-Options=nosniff, X-MS-InvokeApp=1; RequireReadOnly, X-MSEdge-Ref=Ref A: 36059A7BC84248D8BB 44EB130477745C Ref B: AMS04EDGE0606 Ref C: 2017-11-14T11:51:12Z, Content-Length=0, Content-Type=text/plain; charset=utf -8, Date=Tue, 14 Nov 2017 11:51:12 GMT, P3P=CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo C NT COM INT NAV ONL PHY PRE PUR UNI", X-Powered-By=ASP.NET'." At BulkEnqueueOneDriveSite.ps1:73 char:1 + $loader.Context.ExecuteQuery() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : NotSupportedException Script Completed
Now this error is somewhat fuzzy and clear at the same time, if you know what to look for.
Login to Sharepoint Online PowerShell:
Connect-SPOService -Url https://tenant-admin.sharepoint.comCheck this setting:
Get-SPOTenant | select legacy* LegacyAuthProtocolsEnabled __________________________ FalseThen set the legacy authentication protocol back to enabled:
Set-SPOTenant -LegacyAuthProtocolsEnabled $trueAnd check once more:
Get-SPOTenant | select legacy* LegacyAuthProtocolsEnabled __________________________ True
This will allow you to login with an account that has disabled the ability for non-modern (legacy) authentication protocols also known as MFA.
Changes may take 1 minute up to 24 hours to take affect.
And when provisioning has taken place don't forget to set it back to "False".
Labels:
MFA,
Powershell,
Sharepoint Online
Location:Utrecht
Utrecht, Netherlands
12 October 2017
Enable MFA for Exchange Online and Outlook, Skype Online and the Skype client
For the Office 365 services, the default state of modern authentication is:
For Exchange Online:
Connect to Exchange Online PowerShell as shown here.
Do one of these steps:
Connect to Skype for Business Online using remote PowerShell: https://aka.ms/SkypePowerShell
Run the following command:
- Exchange Online - off by default
- Skype Online - off by default
- SharePoint Online - on by default
This means you have to enable it for Exchange Online and Skype Online after enabling MFA for your users.
Here how:
For Exchange Online:
Connect to Exchange Online PowerShell as shown here. Do one of these steps:
- Run this command to enable modern authentication in Exchange Online:
Set-OrganizationConfig -OAuth2ClientProfileEnabled $true
- Run this command to disable modern authentication in Exchange Online:
Set-OrganizationConfig -OAuth2ClientProfileEnabled $false
- To verify that the change was successful, run this command:
Get-OrganizationConfig | Format-Table -Auto Name,OAuth*
For Skype Online:
Connect to Skype for Business Online using remote PowerShell: https://aka.ms/SkypePowerShell
Run the following command:
- Run this command to enable modern authentication in Skype Online:
Set-CsOAuthConfiguration -ClientAdalAuthOverride Allowed
- Verify that the change was successful by running the following:
get-CsOAuthConfiguration | select ClientAdalAuthOverride
Get-OrganizationConfig | Select OAuth2ClientProfileEnabled OAuth2ClientProfileEnabled -------------------------- False Set-OrganizationConfig -OAuth2ClientProfileEnabled $True Get-OrganizationConfig | Select OAuth2ClientProfileEnabled OAuth2ClientProfileEnabled -------------------------- True Get-CsOAuthConfiguration | Select ClientAdalAuthOverride ClientAdalAuthOverride ---------------------- Disallowed Set-CsOAuthConfiguration -ClientAdalAuthOverride Allowed Get-CsOAuthConfiguration | Select ClientAdalAuthOverride ClientAdalAuthOverride ---------------------- Allowed
Labels:
Exchange Online,
MFA,
Modern Authentication,
Oauth,
Office365,
Sharepoint Online,
Skype Online
Location:Utrecht
Utrecht, Netherlands
14 September 2017
LAPS - Restore machine from backup - Password not in AD
Updated 19-09-2017
LAPS short for Local Administrator Password Solution tool is a great way to secure your local administrator accounts on servers.
But there is one problem with the tool.
Password's that have been changed by LAPS are stored in AD, but only for 30 days. After 30 days it's automatically changed and overwritten. So when you use the LAPS tool or check the AD attribute, the password that you see there is valid at that time, the one from 100 days ago isn't there.
But what if you needed to restore a machine that is 31 days old or 40 days, heck even 100 days.
There is no way to find the password for the local admin account, because every 30 days it gets changed and overwritten in AD by LAPS.
Now this is where this script comes in.
The idea is really simple and there's a draw back with it at the same time.
The script exports all the passwords from all servers from a specific OU, every week or month, you decide, and writes a password protected zip file on a file share or sends it to an email address of your choice.
I can hear you think, that's a nice little security issue you just created there.
I know, I only provide the tool, it's up to you whether you want to use it or not.
I've seen someone say somewhere that you could use ADExplorer to export the AD to keep the passwords from longer than 30 days ago stored somewhere.
If you think that's a good idea you can go ahead and use that.
To give you an idea, the output looks like this:
Now on your fileshare there is a zip file protected by a password that you store some where (in Keepass for instance). In case of an emergency you unzip the file and browse the html file for the servername and the associated administrator password.
Advantage is that this is a little more secure than just dumping all the passwords in a mailbox.
On the otherhand if you bury this deep in a mailbox and create a scheduled task that runs every 30 days, you have every password ever changed by LAPS right in your mailbox.
And if your worried about your security, it's local admin accounts not domain admin accounts.
So you're pretty safe.
Update:
Wanted to have the passwords written in a password protected zip file on a file share:
Here's the script or download from here
Requires the ActiveDirectory and LAPS admpwd.ps1 modules to be installed.
LAPS short for Local Administrator Password Solution tool is a great way to secure your local administrator accounts on servers.
But there is one problem with the tool.
Password's that have been changed by LAPS are stored in AD, but only for 30 days. After 30 days it's automatically changed and overwritten. So when you use the LAPS tool or check the AD attribute, the password that you see there is valid at that time, the one from 100 days ago isn't there.
But what if you needed to restore a machine that is 31 days old or 40 days, heck even 100 days.
There is no way to find the password for the local admin account, because every 30 days it gets changed and overwritten in AD by LAPS.
Now this is where this script comes in.
The idea is really simple and there's a draw back with it at the same time.
The script exports all the passwords from all servers from a specific OU, every week or month, you decide, and writes a password protected zip file on a file share or sends it to an email address of your choice.
I can hear you think, that's a nice little security issue you just created there.
I know, I only provide the tool, it's up to you whether you want to use it or not.
I've seen someone say somewhere that you could use ADExplorer to export the AD to keep the passwords from longer than 30 days ago stored somewhere.
If you think that's a good idea you can go ahead and use that.
To give you an idea, the output looks like this:
Now on your fileshare there is a zip file protected by a password that you store some where (in Keepass for instance). In case of an emergency you unzip the file and browse the html file for the servername and the associated administrator password.
Advantage is that this is a little more secure than just dumping all the passwords in a mailbox.
On the otherhand if you bury this deep in a mailbox and create a scheduled task that runs every 30 days, you have every password ever changed by LAPS right in your mailbox.
And if your worried about your security, it's local admin accounts not domain admin accounts.
So you're pretty safe.
Update:
Wanted to have the passwords written in a password protected zip file on a file share:
Here's the script or download from here
Requires the ActiveDirectory and LAPS admpwd.ps1 modules to be installed.
PS: Remove the spaces before and after "< style > and </ style >"
############################################################################## ## Get-PWDOverviewMonthly ## Purpose: Sends report on the passwords set by LAPS ## Author: Edwin van Brenk ## Date: 19 september 2017 ## Version: 1.1 ############################################################################## #Load Modules Import-module activedirectory Import-Module AdmPwd* # Password for the ZIP file # # ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION-ATTENTION # # Use the section below to generate an encrypted password file for the zip file # Needs to be run only at initial script setup # Uncomment before use, comment after use # # Type your password #$password = Read-Host "Password" -AsSecureString # Write to file #$encrypted = ConvertFrom-SecureString -SecureString $password | Set-Content "C:\Scripts\Get-LAPSOverviewMonthly\Password.txt" # Get password $secured = ConvertTo-SecureString -String $(Get-Content C:\Scripts\Get-LAPSOverviewMonthly\Password.txt) # Do password stuff $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "userid", $secured # Zip function function Write-ZipUsing7Zip([string]$FilesToZip, [string]$ZipOutputFilePath, [string]$Password, [ValidateSet('7z','zip','gzip','bzip2','tar','iso','udf')][string]$CompressionType = 'zip', [switch]$HideWindow) { # Look for the 7zip executable. $pathTo32Bit7Zip = "C:\Program Files (x86)\7-Zip\7z.exe" $pathTo64Bit7Zip = "C:\Program Files\7-Zip\7z.exe" $THIS_SCRIPTS_DIRECTORY = Split-Path $script:MyInvocation.MyCommand.Path $pathToStandAloneExe = Join-Path $THIS_SCRIPTS_DIRECTORY "7za.exe" if (Test-Path $pathTo64Bit7Zip) { $pathTo7ZipExe = $pathTo64Bit7Zip } elseif (Test-Path $pathTo32Bit7Zip) { $pathTo7ZipExe = $pathTo32Bit7Zip } elseif (Test-Path $pathToStandAloneExe) { $pathTo7ZipExe = $pathToStandAloneExe } else { throw "Could not find the 7-zip executable." } # Delete the destination zip file if it already exists (i.e. overwrite it). if (Test-Path $ZipOutputFilePath) { Remove-Item $ZipOutputFilePath -Force } $windowStyle = "Normal" if ($HideWindow) { $windowStyle = "Hidden" } # Create the arguments to use to zip up the files. # Command-line argument syntax can be found at: http://www.dotnetperls.com/7-zip-examples $arguments = "a -t$CompressionType ""$ZipOutputFilePath"" ""$FilesToZip"" -mx9" if (!([string]::IsNullOrEmpty($Password))) { $arguments += " -p$Password" } # Zip up the files. $p = Start-Process $pathTo7ZipExe -ArgumentList $arguments -Wait -PassThru -WindowStyle $windowStyle # If the files were not zipped successfully. if (!(($p.HasExited -eq $true) -and ($p.ExitCode -eq 0))) { throw "There was a problem creating the zip file '$ZipFilePath'." } } # Various Settings $Date = Get-Date -Format dd-MM-yyyy $reportPath = "\\domain.lan\Fileshare\"# Build table for html files, remove the spaces before and after "< style > and </ style >" $style = "< style >BODY{font-family: Arial; font-size: 10pt;}" $style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}" $style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }" $style = $style + "TD{border: 1px solid black; padding: 5px; }" $style = $style + "</ style >" # End HTML Output file style# Get all computers in OU, convert output to HTML table $pwd=Get-ADComputer -Filter * -SearchBase "ou=servers,ou=systems,dc=domain,dc=lan" | Get-AdmPwdPassword -ComputerName {$_.Name} | ConvertTo-HTML -Head $style | out-file $reportPath\Report.html # Zip HTML file Write-ZipUsing7Zip -FilesToZip "$reportPath\Report.html" -ZipOutputFilePath "$reportPath\Report-$Date.zip" -Password $cred.GetNetworkCredential().Password -HideWindow # Delete temporary html file Remove-Item $reportPath\Report.html
Here's the script or download from hereRequires the ActiveDirectory and LAPS admpwd.ps1 modules to be installed.PS: Remove the spaces before and after "< style > and </ style >"############################################################################## ## Get-PWDOverviewMonthly ## Purpose: Sends report on the passwords set by LAPS ## Author: Edwin van Brenk ## Date: 14 september 2017 ## Version: 1.0 ############################################################################## #Load Modules Import-module activedirectory Import-Module AdmPwd* $Date = Get-Date -Format dd-MM-yyyy #SMTP options for sending the report email $smtpServer = "smtp.domain.lan" $smtpFrom = "LAPS@domain.lan" $smtpTo = "edwin@domain.lan" $Subject = "LAPS monthly overview $Date" # Build table for html files, remove the spaces before and after "< style > and </ style >" $style = "< style >BODY{font-family: Arial; font-size: 10pt;}" $style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}" $style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }" $style = $style + "TD{border: 1px solid black; padding: 5px; }" $style = $style + "</ style >" # End HTML Output file style # Get all computers in OU, convert output to HTML table $pwd=Get-ADComputer -Filter * -SearchBase "ou=servers,ou=systems,dc=domain,dc=lan" | Get-AdmPwdPassword -ComputerName {$_.Name} | ConvertTo-HTML -Head $style # Send email Send-MailMessage -To $smtpTo -From $smtpFrom -SmtpServer $smtpServer -Subject $Subject -Body ($pwd | out-string) -BodyAsHtml
Labels:
LAPS,
Password,
Powershell
Location:Utrecht
Utrecht, Netherlands
12 September 2017
Exchange Management Shell not connecting to the server - PowerShell Exchange 2013 - EMS
PSSession : [sr-xxxxx.domain.lan] Processing data from
remote server sr-xxxxx.domain.lan failed with the following error message:
[ClientAccessServer=SR-xxxxx,BackEndServer=sr-xxxxx.domain.lan,RequestId=8aa81a77-bea6-408f-a4c6-83657ecc222f,TimeStamp=6-9-2017
19:29:58] [FailureCategory=WSMan-Others] The EndpointConfiguration with the http://schemas.microsoft.com/powershell/microsoft.exchange identifier is not in a valid initial
session state on the remote computer. Contact your Windows PowerShell
administrator, or the owner or creator of the endpoint configurat
ion. For more information, see the
about_Remote_Troubleshooting Help topic.
At line:1 char:12
+ $session = New-PSSession -ConfigurationName
microsoft.exchange -Conne ...
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
CategoryInfo : OpenError:
(System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession],
PSRemotingTransportException
+ FullyQualifiedErrorId :
IncorrectProtocolVersion,PSSessionOpenFailed
Well, that's a nice one isn't it?
Problem is that on the local Exchange server you cannot start the management shell to administer your Exchange server. It does not want to connect to itself.
And by that I mean to the server name and domain name.
You can however start a PowerShell console and import the exchange module, this will load up and you can do your Exchange administration stuff.
But remoting is out of the question.
Now check this:
Event ID: 2112
But remoting is out of the question.
Now check this:
Event ID: 2112
The server doesn't have the Audit Security privilege on a domain controller. This privilege is used by ADAccess. Run policytest.exe. See KB 314294
The problem is that there is a group missing in the default domain controller policy, and notice the words "domain controller". Or the group is missing in a hardening policy that you created yourself for the domain controllers. The group we're looking for is "Exchange Servers".
In the console tree, expand Local Computer Policy, Windows Settings, Security Settings and Local Policies. Under Local Policies, click User Rights Assignments.
In the results pane, double-click Manage auditing and security log. Verify that the "Exchange Servers" group is listed.
Make sure that the group permissions are inherited by the Microsoft Exchange computer account.
Labels:
ADAccess,
EMS,
Event ID:2112,
Exchange 2013,
Powershell,
PowerShell Remoting
Location:Utrecht
Utrecht, Netherlands
09 September 2017
New version of the Exchange Certificate Wizard for Let's Encrypt in English by Franky's web
I think Let's encrypt is the best initiative I've seen in a long while on the internet.
It let's you create signed certificates for your website for free.
So a safe connection to your website is no longer gonna cost you money, so there is no more reason not to offer it to your visitors.
This script by Franky's web (a German Exchange enthusiast) put this script up on his site to create automatically create a certificate request and have it approved if valid and set as the default certificate in IIS for Exchange 2010, 2013 and 2016.
Now the script on his site is in German, and since it requests some input I translated it to English with the idea that as many people as possible can use it.
Download the script here or copy and paste it from below.
All thanks and credit go out to Frank Zochling and Bjoern over at https://www.frankysweb.de
It let's you create signed certificates for your website for free.
So a safe connection to your website is no longer gonna cost you money, so there is no more reason not to offer it to your visitors.
This script by Franky's web (a German Exchange enthusiast) put this script up on his site to create automatically create a certificate request and have it approved if valid and set as the default certificate in IIS for Exchange 2010, 2013 and 2016.
Now the script on his site is in German, and since it requests some input I translated it to English with the idea that as many people as possible can use it.
Download the script here or copy and paste it from below.
All thanks and credit go out to Frank Zochling and Bjoern over at https://www.frankysweb.de
Param( [bool]$Renew ) clear write-host "" write-host "----------------------------------------------------------------" write-host " _______ _ ___ _ (_______) _ (_) / __|_) _ _ _____ ____ _| |_ _ _| |__ _ ____ _____ _| |_ _____ | | | ___ |/ ___|_ _) (_ __) |/ ___|____ (_ _) ___ | | |_____| ____| | | |_| | | | | ( (___/ ___ | | |_| ____| \______)_____)_| \__)_| |_| |_|\____)_____| \__)_____) _______ _ (_______) (_) _ _ _______ ___ ___ _ ___ _| |_ _____ ____ _| |_ | ___ |/___)/___) |/___|_ _|____ | _ (_ _) | | | |___ |___ | |___ | | |_/ ___ | | | || |_ |_| |_(___/(___/|_(___/ \__)_____|_| |_| \__) " -foregroundcolor cyan write-host "" write-host " Certificate Assistant v1.1" write-host " Automatic Let's Encrypt Certificate for Exchange 2010/2013/2016" write-host "" write-host " Frank Zoechling (www.FrankysWeb.de)" write-host "" write-host "----------------------------------------------------------------" #ACME Sharp Modul laden write-host " Loading ACMESharp Module..." Import-Module ACMESharp -ea 0 $CheckACMEModule = get-module ACMESharp if (!$CheckACMEModule) { write-host " Warning: ACME Sharp Module not found" -foregroundcolor yellow write-host " Please install ACMESharp Module" -foregroundcolor yellow Install-Module -Name ACMESharp -RequiredVersion 0.8.1 -AllowClobber #Specific Module version will be installed Import-Module ACMESharp -ea 0 $CheckACMEModule = get-module ACMESharp if (!$CheckACMEModule) { write-host " Failed: ACME Sharp Module couldn't be installed" -foregroundcolor red exit } } #IIS PowerShell Modul laden write-host " Load IIS Webadministration Module" Import-Module Webadministration -ea 0 $CheckIISModule = get-module Webadministration if (!$CheckIISModule) { write-host " Webadministration Module not found" -foregroundcolor red exit } #IIS SnapIn laden write-host " Load Exchange Management Shell..." Add-PSSnapin *exchange* -ea 0 $CheckExchangeSnapin = Get-PSSnapin *exchange* if (!$CheckExchangeSnapin) { write-host " Exchange SnapIn not found" -foregroundcolor red exit } #Exchange-Version erkennen $ExchangeVersion = (Get-ExchangeServer -Identity $env:COMPUTERNAME | ForEach {$_.AdminDisplayVersion}) if ($ExchangeVersion -match "Version 15") { write-host " Exchange Server 2013/2016 recognized" } elseif ($ExchangeVersion -match "Version 14") { write-host " Exchange Server 2010 recognized" } else { write-host " No supported Exchange Server Version was found. Script halted." -foregroundcolor Red exit } if ($ExchangeVersion -match "Version 14" -Or $ExchangeVersion -match "Version 15") { if ($renew -ne $True) { #Search for configured DNS-Names write-host "" write-host " Read Exchange configuration..." $ExchangeServer = (Get-ExchangeServer $env:computername).Name [array]$CertNames += ((Get-ClientAccessServer -Identity $ExchangeServer).AutoDiscoverServiceInternalUri.Host).ToLower() [array]$CertNames += ((Get-OutlookAnywhere -Server $ExchangeServer).ExternalHostname.Hostnamestring).ToLower() [array]$CertNames += ((Get-OabVirtualDirectory -Server $ExchangeServer).Internalurl.Host).ToLower() [array]$CertNames += ((Get-OabVirtualDirectory -Server $ExchangeServer).ExternalUrl.Host).ToLower() [array]$CertNames += ((Get-ActiveSyncVirtualDirectory -Server $ExchangeServer).Internalurl.Host).ToLower() [array]$CertNames += ((Get-ActiveSyncVirtualDirectory -Server $ExchangeServer).ExternalUrl.Host).ToLower() [array]$CertNames += ((Get-WebServicesVirtualDirectory -Server $ExchangeServer).Internalurl.Host).ToLower() [array]$CertNames += ((Get-WebServicesVirtualDirectory -Server $ExchangeServer).ExternalUrl.Host).ToLower() [array]$CertNames += ((Get-EcpVirtualDirectory -Server $ExchangeServer).Internalurl.Host).ToLower() [array]$CertNames += ((Get-EcpVirtualDirectory -Server $ExchangeServer).ExternalUrl.Host).ToLower() [array]$CertNames += ((Get-OwaVirtualDirectory -Server $ExchangeServer).Internalurl.Host).ToLower() [array]$CertNames += ((Get-OwaVirtualDirectory -Server $ExchangeServer).ExternalUrl.Host).ToLower() if ($ExchangeVersion -match "Version 15") { [array]$CertNames += ((Get-OutlookAnywhere -Server $ExchangeServer).Internalhostname.Hostnamestring).ToLower() [array]$CertNames += ((Get-MapiVirtualDirectory -Server $ExchangeServer).Internalurl.Host).ToLower() [array]$CertNames += ((Get-MapiVirtualDirectory -Server $ExchangeServer).ExternalUrl.Host).ToLower() } $CertNames = $CertNames | select –Unique write-host "----------------------------------------------------------------" write-host "" write-host " The following DNS-Namen were found:" write-host "" foreach ($Certname in $CertNames) { write-host " $certname" -foregroundcolor cyan } write-host "" #Add additional names? $AddName = "y" while ($AddName -match "y") { $AddName = read-host " Add additional DNS names to the certificate? (y/n)" if ($AddName -match "y") { $AddHost = read-host " Enter DNS-Names" $CertNames += "$addhost" } } #Output the DNS names write-host "" write-host " The following DNS Names were configured:" write-host "" foreach ($Certname in $CertNames) { write-host " $certname" -foregroundcolor cyan } write-host "" #Email-Address for the ACME Registration write-host " Which E-Mail Address should be used to register with Let's Encrypt?" write-host "" write-host " If a Let's Encrypt registry has already been performed on this computer" write-host " no e-mail address is required." write-host $contact = read-host " E-Mail Address" $contactmail = "mailto:$contact" write-host #Add task to renew? write-host " Do you want to add a scheduled task to automatically renew the" write-host " certificate?" write-host "" $AutoRenewTask = read-host " Automatic renew? (y/n)" if ($AutoRenewTask -match "y") { $username = read-host " Username for the task (Domain\Username)" $SecurePassword = read-host " Password" -AsSecureString } write-host "" #---------------------------------------------- #Create automatic renew task if ($AutoRenewTask -match "y") { $installpath = (get-location).Path #Create a scheduled task $zeitpunkt = "23:00" $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword) $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) $startTime = "$zeitpunkt" | get-date -format s $taskService = New-Object -ComObject Schedule.Service $taskService.Connect() $rootFolder = $taskService.GetFolder($NULL) $taskDefinition = $taskService.NewTask(0) $registrationInformation = $taskDefinition.RegistrationInfo $registrationInformation = $taskDefinition.RegistrationInfo $registrationInformation.Description = "Let's Encrypt certificaterenewal - www.FrankysWeb.de" $registrationInformation.Author = $username $taskPrincipal = $taskDefinition.Principal $taskPrincipal.LogonType = 1 $taskPrincipal.UserID = $username $taskPrincipal.RunLevel = 0 $taskSettings = $taskDefinition.Settings $taskSettings.StartWhenAvailable = $true $taskSettings.RunOnlyIfNetworkAvailable = $true $taskSettings.Priority = 7 $taskTriggers = $taskDefinition.Triggers $executionTrigger = $taskTriggers.Create(2) $executionTrigger.StartBoundary = $startTime $taskAction = $taskDefinition.Actions.Create(0) $taskAction.Path = "powershell.exe" $taskAction.Arguments = "-Command `"&'$installpath\CertificateAssistant.ps1' -renew:`$true`"" $job = $rootFolder.RegisterTaskDefinition("Let's Encrypt certificaterenewal (www.FrankysWeb.de)" , $taskDefinition, 6, $username, $password, 1) } #---------------------------------------------- clear write-host "" write-host "---------------------------------------------------------------------------" -foregroundcolor green write-host "All information is available, configure the certificate?" -foregroundcolor green write-host "---------------------------------------------------------------------------" -foregroundcolor green write-host "" read-host "Start Configuration? (Enter for continue / STRG+C to abort" write-host "" #Check if a vault already exists write-host "Check if a vault already exists..." $Vault = Get-ACMEVault if (!$Vault) { write-host "No vault found, trying to create new vault..." $CreateVault = Initialize-ACMEVault sleep 1 $Vault = Get-ACMEVault if (!$Vault) { write-host "Error: Vault could not be created" -foregroundcolor red exit } } #Check if Let's Encrypt registry is present write-host "Check Let's Encrypt Registration..." $Registration = Get-ACMERegistration if (!$Registration) { write-host "Warning: No registration was found at Let's Encrypt, new registration is being performed" -foregroundcolor yellow $Registration = New-ACMERegistration -Contacts $contactmail -AcceptTos if (!$Registration) { write-host "Error: Could not register with Let's Encrypt" -foregroundcolor red exit } else { write-host "Registration at Let's Encrypt was done" -foregroundcolor green } } #Prepare Domain Names Validation $CertSubject = ((Get-OutlookAnywhere -Server $ExchangeServer).ExternalHostname.Hostnamestring).ToLower() $ExchangeSANID = 1 foreach ($ExchangeSAN in $CertNames) { $CurrentDate = get-date -format ddMMyyyyhhmm #CurrentDate $ACMEAlias = "Cert" + "$CurrentDate" + "-" + "$ExchangeSANID" $ExchangeSANID++ write-host "New identifier:" write-host " DNS: $ExchangeSAN" write-host " Alias: $ACMEAlias" $NewID = New-ACMEIdentifier -Dns $ExchangeSAN -Alias $ACMEAlias write-host "Prepare validation:" write-host " Alias $ACMEAlias" $ValidateReq = Complete-ACMEChallenge $ACMEAlias -ChallengeType http-01 -Handler iis -HandlerParameters @{ WebSiteRef = 'Default Web Site' } [Array]$ACMEAliasArray += $ACMEAlias if ($ExchangeSAN -eq $CertSubject) {$SubjectAlias = $ACMEAlias} } #Let's Encrypt IIS directory to HTTP write-host "Let's Encrypt IIS Change the directory to HTTP..." $IISDir = Set-WebConfigurationProperty -Location "Default Web Site/.well-known" -Filter 'system.webserver/security/access' -name "sslFlags" -Value None $IISDirCeck = (Get-WebConfigurationProperty -Location "Default Web Site/.well-known" -Filter 'system.webserver/security/access' -name "sslFlags").Value if ($IISDirCeck -match 0) { write-host "Change to HTTP successfully" -foregroundcolor green } else { write-host "Error: Change to HTTP was unsuccessful" -foregroundcolor red exit } #Validate Domain Names write-host "Let DNS names be validated by Let's Encrypt..." foreach ($ACMEAlias in $ACMEAliasArray) { write-host "Carry out validation: $ACMEAlias" $Validate = Submit-ACMEChallenge $ACMEAlias -ChallengeType http-01 } write-host "wait 30 Seconds..." sleep -seconds 30 #Check the validation write-host "Check whether the DNS names have been validated..." foreach ($ACMEAlias in $ACMEAliasArray) { write-host "Update Alias: $ACMEAlias" $ACMEIDUpdate = Update-ACMEIdentifier $ACMEAlias $ACMEIDStatus = $ACMEIDUpdate.Status if ($ACMEIDStatus -eq "valid") { write-host "Validation OK" -foregroundcolor green } else { write-host "Error: Validation failed for alias $ACMEAlias" -foregroundcolor red exit } } #Prepare and submit the certificate $SANAlias = "SAN" + "$CurrentDate" $NewCert = New-ACMECertificate $SubjectAlias -Generate -AlternativeIdentifierRefs $ACMEAliasArray -Alias $SANAlias $SubmitNewCert = Submit-ACMECertificate $SANAlias #Wait until the certificate has been issued write-host "wait 30 Seconds..." sleep -seconds 30 #Check status write-host "Check the certificate..." $UpdateNewCert = Update-ACMECertificate $SANAlias $CertStatus = (Get-ACMECertificate $SANAlias).CertificateRequest.Statuscode sleep 5 if ($CertStatus -match "OK") { write-host "Certificate OK" -foregroundcolor green } else { write-host "Error: Certificate not issued" -foregroundcolor red exit } #Export the certificate from Vault and assign Exchange write-host "Export the certificate to $env:temp" $CertPath = "$env:temp" + "\" + "$SANAlias" + ".pfx" $PFXPasswort = Get-Random -Minimum 1000000 -Maximum 9999999 $CertExport = Get-ACMECertificate $SANAlias -ExportPkcs12 $CertPath -CertificatePassword $PFXPasswort write-host "Check whether the certificate has been exported..." if (test-path $CertPath) { write-host "Certificate successfully exported" -foregroundcolor green write-host "Password for the PFX file: $PFXPasswort" } else { write-host "Error: The certificate was not exported" -foregroundcolor red exit } write-host "Exchange certificate is assigned and activated" $ImportPassword = ConvertTo-SecureString -String $PFXPasswort -Force –AsPlainText if ($ExchangeVersion -match "Version 15") { Import-ExchangeCertificate -FileName $CertPath -FriendlyName $ExchangeSubject -Password $ImportPassword -PrivateKeyExportable:$true | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" –force } elseif ($ExchangeVersion -match "Version 14") { Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path $CertPath -Encoding byte -ReadCount 0)) -FriendlyName $ExchangeSubject -Password $ImportPassword -PrivateKeyExportable:$true | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" -force } write-host "Check whether the certificate has been activated" $CurrentCertThumbprint = (Get-ChildItem -Path IIS:SSLBindings | where {$_.port -match "443" -and $_.IPAddress -match "0.0.0.0" } | select Thumbprint).Thumbprint $ExportThumbprint = $CertExport.Thumbprint if ($CurrentCertThumbprint -eq $ExportThumbprint) { write-host "The certificate has been successfully activated" -foregroundcolor green } else { write-host "Activation failed" -foregroundcolor red exit } } #---------------------------------------Renewal------------------------------------------------ #Automatic Renewal if ($renew -eq $True) { $PFXPasswort = Get-Random -Minimum 1000000 -Maximum 9999999 $CurrentCertThumbprint = (Get-ChildItem -Path IIS:SSLBindings | where {$_.port -match "443" -and $_.IPAddress -match "0.0.0.0" } | select Thumbprint).Thumbprint $ExchangeCertificate = Get-ExchangeCertificate -Thumbprint $CurrentCertThumbprint $ExchangeSANs = ($ExchangeCertificate.CertificateDomains).Address $ExchangeSubject = $ExchangeCertificate.Subject.Replace("CN=","") if ($ExchangeSANs -notcontains $ExchangeSubject) {$ExchangeSANs += $ExchangeSubject} $CurrentDate = get-date $VaildTill = $ExchangeCertificate.NotAfter $DaysLeft = ($VaildTill - $CurrentDate).Days if ($DaysLeft -le 4) #Renew 4 days before expiration { $ExchangeSANID = 1 foreach ($ExchangeSAN in $ExchangeSANs) { $CurrentDate = get-date -format ddMMyyyy $ACMEAlias = "Cert" + "$CurrentDate" + "-" + "$ExchangeSANID" $ExchangeSANID++ New-ACMEIdentifier -Dns $ExchangeSAN -Alias $ACMEAlias Complete-ACMEChallenge $ACMEAlias -ChallengeType http-01 -Handler iis -HandlerParameters @{ WebSiteRef = 'Default Web Site' } [Array]$ACMEAliasArray += $ACMEAlias if ($ExchangeSAN -match $ExchangeSubject) {$ExchangeSubjectAlias = $ACMEAlias} } foreach ($ACMEAlias in $ACMEAliasArray) { Submit-ACMEChallenge $ACMEAlias -ChallengeType http-01 } sleep -seconds 30 foreach ($ACMEAlias in $ACMEAliasArray) { Update-ACMEIdentifier $ACMEAlias } $SANAlias = "SAN" + "$CurrentDate" New-ACMECertificate $ExchangeSubjectAlias -Generate -AlternativeIdentifierRefs $ACMEAliasArray -Alias $SANAlias Submit-ACMECertificate $SANAlias sleep -seconds 30 Update-ACMECertificate $SANAlias $CertPath = "$env:temp" + "\" + "$SANAlias" + ".pfx" $CertExport = Get-ACMECertificate $SANAlias -ExportPkcs12 $CertPath -CertificatePassword $PFXPasswort $ImportPassword = ConvertTo-SecureString -String $PFXPasswort -Force –AsPlainText if ($ExchangeVersion -match "Version 15") { Import-ExchangeCertificate -FileName $CertPath -FriendlyName $ExchangeSubject -Password $ImportPassword -PrivateKeyExportable:$true | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" –force } elseif ($ExchangeVersion -match "Version 14") { Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path $CertPath -Encoding byte -ReadCount 0)) -FriendlyName $ExchangeSubject -Password $ImportPassword -PrivateKeyExportable:$true | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" -force } } } }
Labels:
Certificate,
Exchange 2010,
Exchange 2013,
Exchange 2016,
let's encrypt,
Powershell,
scheduled task
Location:Utrecht
Utrecht, Netherlands
Subscribe to:
Posts (Atom)