Created
February 9, 2017 16:40
-
-
Save jhochwald/46a9c9acb1cf47176ce605826f3c15d7 to your computer and use it in GitHub Desktop.
Azure Active Directory (AAD) Connect tooling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -Version 2.0 | |
function Invoke-ADSyncDeltaCycle | |
{ | |
<# | |
.SYNOPSIS | |
Trigger an AAD Connect Sync | |
.DESCRIPTION | |
Trigger an AAD Connect Sync on a remote computer | |
.PARAMETER AADComputer | |
The computer where AAD Connect is installed, needs to be an FQDN | |
.EXAMPLE | |
PS C:\> Invoke-ADSyncDeltaCycle -AADComputer 'aad.domain.tld' | |
Trigger an AAD Connect Sync on aad.domain.tld | |
.NOTES | |
Showcase: We do NOT use the old school import of "C:\Program Files\Microsoft Azure AD Sync\Bin\ADSync\ADSync.psd1" | |
#> | |
param | |
( | |
[Parameter(ValueFromPipeline = $true, | |
Position = 1)] | |
[ValidateNotNullOrEmpty()] | |
[ValidatePattern('(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)')] | |
[string]$AADComputer = 'default.domain.tld' | |
) | |
BEGIN | |
{ | |
try | |
{ | |
# Create a remote powerShell session. | |
$session = (New-PSSession -ComputerName $AADComputer) | |
Write-Verbose -Message "Session created on $AADComputer" | |
} | |
catch | |
{ | |
# Doh! Did you enable remote Powerhell by executing the following: | |
# Enable-PSRemoting -Force | |
# | |
# Did you check the Firewall on the remote system? | |
# Remember? | |
# Enable-NetFirewallRule -DisplayGroup 'Windows Remote Management (Compatibility)' -PolicyStore PersistentStore | |
Write-Error -Message ('{0} - Line Number: {1}' -f $_.Exception.Message, $_.InvocationInfo.ScriptLineNumber) -ErrorAction Stop | |
} | |
} | |
PROCESS | |
{ | |
try | |
{ | |
# If you want to use this within the remote session, you have to tell the REMOTE computer, | |
# that debug/verbose should be displayed. Not only the local one! | |
Write-Verbose -Message "Start AD Sync on $AADComputer" | |
Invoke-Command -Session $session -ScriptBlock { | |
try | |
{ | |
# Import the remote(!) Module, not on the local system... | |
$null = (Import-Module -Name 'ADSync' -Force -ErrorAction Stop -WarningAction SilentlyContinue) | |
# Execute the command we want on the remote system | |
$null = (Start-ADSyncSyncCycle -PolicyType Delta -InteractiveMode $false -ErrorAction Stop -WarningAction SilentlyContinue) | |
} | |
catch | |
{ | |
# No Error Handling on the remote system | |
# Could be a simple throw, as you like | |
Write-Error -Message $_.Exception.Message -ErrorAction Stop | |
} | |
} | |
Write-Verbose -Message "Done with the AD Sync on $AADComputer" | |
} | |
catch | |
{ | |
# Cleanup, if needed | |
if ($session) | |
{ | |
$null = (Remove-PSSession -Id $session.Id) | |
} | |
# Here is the REAL Error handling: On the local system. | |
# You might want to retry something or inform someone... Mail? Eventlog? | |
Write-Error -Message ('{0} - Line Number: {1}' -f $_.Exception.Message, $_.InvocationInfo.ScriptLineNumber) -ErrorAction Stop | |
} | |
} | |
END | |
{ | |
if ($session) | |
{ | |
Write-Verbose -Message 'Cleanup the session' | |
# Something you should do: Do NOT leave the remote session open and stop executing | |
# Yep, it will get a timeout, but you shoul cleanup the session as soon as you are sone! | |
$null = (Remove-PSSession -Id $session.Id) | |
} | |
} | |
} | |
function Invoke-ADSyncCleanup | |
{ | |
<# | |
.SYNOPSIS | |
Trigger an AAD Connect cleanup | |
.DESCRIPTION | |
Trigger an AAD Connect cleanup on a remote computer | |
.PARAMETER AADComputer | |
The computer where AAD Connect is installed, needs to be an FQDN | |
.PARAMETER Days | |
timespan that we pass to the PurgeRunHistoryInterval parameter. The default is 7 | |
.EXAMPLE | |
PS C:\> Invoke-ADSyncCleanup -AADComputer 'aad.enatec.local' -Days '30' | |
Removes the entries of the last 30 days from the logs of the host aad.enatec.local | |
.NOTES | |
Helper function to keep the system clean ;-) | |
#> | |
param | |
( | |
[Parameter(ValueFromPipeline = $true, | |
Position = 1)] | |
[ValidateNotNullOrEmpty()] | |
[ValidatePattern('(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)')] | |
[string]$AADComputer = 'default.domain.tld', | |
[Parameter(ValueFromPipeline = $true, | |
Position = 2)] | |
[ValidateNotNullOrEmpty()] | |
$Days = '7' | |
) | |
BEGIN | |
{ | |
try | |
{ | |
# Open the remote session | |
$session = (New-PSSession -ComputerName $AADComputer) | |
Write-Verbose -Message "Session created on $AADComputer" | |
} | |
catch | |
{ | |
# Whoopsie, unable to open the remote session! | |
Write-Error -Message ('{0} - Line Number: {1}' -f $_.Exception.Message, $_.InvocationInfo.ScriptLineNumber) -ErrorAction Stop | |
} | |
} | |
PROCESS | |
{ | |
try | |
{ | |
Write-Verbose -Message "Cleanup the last $Days of logs on $AADComputer" | |
<# | |
The difference here: | |
We use the 'param' and the 'ArgumentList' to handover the value of 'days' to the remote computer. | |
You might want to use a variable that you declaire on your LOCAL system, | |
That variable can conaint any local variable you like and will be executed on the | |
remote system (think: Like a simple string that is already filled) | |
#> | |
Invoke-Command -Session $session -ScriptBlock { | |
param($Days) | |
try | |
{ | |
$null = (Import-Module -Name 'ADSync' -Force -ErrorAction Stop -WarningAction SilentlyContinue) | |
# Execute the command we want (remote) | |
Start-ADSyncPurgeRunHistory -PurgeRunHistoryInterval $Days | |
} | |
catch | |
{ | |
# No Error Handling on the remote system | |
# Could be a simple throw, as you like | |
Write-Error -Message $_.Exception.Message -ErrorAction Stop | |
} | |
} -ArgumentList $Days | |
# The ArgumentList the what the remote site get in the param. | |
# We use this to handover the Variable from local to the remote system. | |
# See the comment above the ScriptBlock | |
} | |
catch | |
{ | |
# Cleanup, if needed | |
if ($session) | |
{ | |
$null = (Remove-PSSession -Id $session.Id) | |
} | |
# Whoopsie! | |
Write-Error -Message ('{0} - Line Number: {1}' -f $_.Exception.Message, $_.InvocationInfo.ScriptLineNumber) -ErrorAction Stop | |
} | |
} | |
END | |
{ | |
if ($session) | |
{ | |
Write-Verbose -Message 'Cleanup the session' | |
$null = (Remove-PSSession -Id $session.Id) | |
} | |
} | |
} | |
<# | |
Azure Active Directory (AAD) Connect tooling. | |
With Azure Active Directory (AAD) connect you can syncronize an On-Premises Active Directory with the Microsoft Cloud. | |
You might want to do that if you use Office 365 or any other Azure based Microsoft Cloud Service. | |
Requirements to use the functions: | |
- Domain joined PC (if not, you need to tweak a bit. But it IS possible!) | |
- Remote PowerShell is enabled on the remote system (Execute "Enable-PSRemoting -Force") | |
- The Firewalls allow the communication. | |
The functions in this script where created during a PowerShell workshop with the admin of a customer. | |
The admins asked for a solution and we created this approach from scratch together. | |
We developed a lot of functions around the AAD Connect and ADFS Tools from Microsoft. | |
They searched and found sample code and snippets where the "C:\Program Files\Microsoft Azure AD Sync\Bin\ADSync\ADSync.psd1" is parsed. | |
That still works, but newer ADSync versions do NOT need that anymore and by using a native "Import-Module -Name 'ADSync'" you might be | |
more flexible in the future and you do not need to know where the PSD1 file is on the remote computer. | |
You might ask yourself: Why is the code not optimized and have so many comments? | |
The answer: This is code to teach others how to build simple tools ;-) Teaching without so much comments makes no sense, correct? | |
And trust me: It was way more complex during the workshop!!! and I mean a lot more... | |
Nothing fancy, but it should to the job! | |
TODO: We need to find a better REGEX for the FQDN check! The one we use is not perfect and might need some tweaks! | |
#> | |
<# | |
Copyright (c) 2017, Joerg Hochwald | |
All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions are met: | |
1. Redistributions of source code must retain the above copyright notice, | |
this list of conditions and the following disclaimer. | |
2. Redistributions in binary form must reproduce the above copyright notice, | |
this list of conditions and the following disclaimer in the documentation | |
and/or other materials provided with the distribution. | |
3. Neither the name of the copyright holder nor the names of its contributors | |
may be used to endorse or promote products derived from this software without | |
specific prior written permission. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
By using the Software, you agree to the License, Terms and Conditions above! | |
#> | |
<# | |
DISCALIMER: | |
This is a third party Software! | |
The developer of this Software is NOT sponsored by or affiliated with | |
Microsoft Corp (MSFT) or any of it's subsidiaries in any way | |
The Software is not supported by Microsoft Corp (MSFT)! | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment