Added Files

This commit is contained in:
DistractADD
2021-07-06 13:16:46 +10:00
parent f2475a3bdd
commit cfddd4fad2
393 changed files with 65842 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
<#
.SYNOPSIS
Update the DistinguishedName Attribute for all Active Directory Users
.DESCRIPTION
Update the DistinguishedName Attribute for all Active Directory Users.
It will update the 'CN=' to match the SamAccountName
.EXAMPLE
PS C:\> .\Convert-ADDistinguishedNameForAllUser.ps1
.NOTES
MIND THE GAP:
This will change the DistinguishedName and this might break things
It will only update/change the DistinguishedName if the 'CN=' does NOT match the SamAccountName
I created this to bulk migrate older users, they had german umlauts and other crappy character in the DistinguishedName
.LINK
https://github.com/jhochwald/PowerShell-collection/
.LINK
Get-ADUser
.LINK
Rename-ADObject
#>
[CmdletBinding(ConfirmImpact = 'Medium',
SupportsShouldProcess)]
param ()
if ($pscmdlet.ShouldProcess('All Users', 'Set'))
{
try
{
$AllUsers = (Get-ADUser -Filter * -Properties SamAccountName, UserPrincipalName, DistinguishedName -ErrorAction Stop | Select-Object -Property SamAccountName, UserPrincipalName, DistinguishedName | Where-Object -FilterScript {
($_.UserPrincipalName) -and ($_.SamAccountName)
})
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message $e.Exception.Message -ErrorAction Stop
break
}
try
{
foreach ($User in $AllUsers)
{
$OldRDN = (($User | Select-Object -Property @{
l = 'OldRDN'
e = {
$_.DistinguishedName.split(',')[0].split('=')[1]
}
}) | Select-Object -ExpandProperty OldRDN)
if ($OldRDN -ne ($User.SamAccountName))
{
# Mind the Gap: This will change the DistinguishedName and this might break things
$null = (Rename-ADObject -Identity $User.DistinguishedName -NewName $User.SamAccountName -Confirm:$false -ErrorAction Stop)
}
}
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Warning -Message $e.Exception.Message -ErrorAction Continue -WarningAction Continue
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,399 @@
function Copy-ADGroupUserMembership
{
<#
.SYNOPSIS
Copy the membership of a given group to another group in Active Directory
.DESCRIPTION
Copy the membership of a given group to another group in Active Directory.
By default only the members of the Source Group will be copied to the Target Group.
If the Parameter FULL is used, the members of the Target Group that are not a member of the Source Group will be removed.
If the Parameter SYNC is used, the Membership is synced between both groups. If a User is Member of the Target Group only, this membership will be copied to the Source as well.
.PARAMETER SourceGroup
Source-Group Object.
Specifies an Active Directory group object by providing one of the following values. The identifier in
parentheses is the LDAP display name for the attribute.
Distinguished Name
Example: CN=saradavisreports,OU=europe,CN=users,DC=corp,DC=contoso,DC=com
GUID (objectGUID)
Example: 599c3d2e-f72d-4d20-8a88-030d99495f20
Security Identifier (objectSid)
Example: S-1-5-21-3165297888-301567370-576410423-1103
Security Accounts Manager (SAM) Account Name (sAMAccountName)
Example: saradavisreports
The cmdlet searches the default naming context or partition to find the object. If two or more objects are
found, the cmdlet returns a non-terminating error.
This parameter can also get this object through the pipeline or you can set this parameter to an object
instance.
.PARAMETER TargetGroup
Target-Group Object.
Specifies an Active Directory group object by providing one of the following values. The identifier in
parentheses is the LDAP display name for the attribute.
Distinguished Name
Example: CN=saradavisreports,OU=europe,CN=users,DC=corp,DC=contoso,DC=com
GUID (objectGUID)
Example: 599c3d2e-f72d-4d20-8a88-030d99495f20
Security Identifier (objectSid)
Example: S-1-5-21-3165297888-301567370-576410423-1103
Security Accounts Manager (SAM) Account Name (sAMAccountName)
Example: saradavisreports
The cmdlet searches the default naming context or partition to find the object. If two or more objects are
found, the cmdlet returns a non-terminating error.
This parameter can also get this object through the pipeline or you can set this parameter to an object
instance.
.PARAMETER full
Remove all memberships from the Targewt that does NOT exist in the the Source.
.PARAMETER sync
Synchronies the group membership between Source-Group and Target-Group.
Even if a user is a member of the Target-Group only, it will be copied to the Source-Group as well.
.EXAMPLE
PS C:\> Copy-ADGroupUserMembership -SourceGroup 'Sales' -TargetGroup 'Salesforce'
Copy the membership of the Group 'Sales' to 'Salesforce'
.EXAMPLE
PS C:\> Copy-ADGroupUserMembership -SourceGroup 'Sales' -TargetGroup 'Salesforce' -sync
Copy the membership of the Group 'Sales' to 'Salesforce' and the other way around.
All Memberships of 'Salesforce' that does NOT exist in 'Sales' will be created in 'Sales' as well.
.EXAMPLE
PS C:\> Copy-ADGroupUserMembership -SourceGroup 'Sales' -TargetGroup 'Salesforce' -full
Copy the membership of the Group 'Sales' to 'Salesforce'.
All Memberships of 'Salesforce' that does NOT exist in 'Sales' will be removed.
.NOTES
Initial AIT version of the function
.LINK
https://github.com/jhochwald/PowerShell-collection/
.LINK
Get-ADGroupMember
.LINK
Remove-ADGroupMember
.LINK
Add-ADGroupMember
.LINK
Copy-ADUserGroupMemberships
#>
[CmdletBinding(DefaultParameterSetName = 'default',
ConfirmImpact = 'Low',
SupportsShouldProcess)]
param
(
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 0,
HelpMessage = 'Source-Group Object.')]
[ValidateNotNullOrEmpty()]
[Alias('Source')]
[string]
$SourceGroup,
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1,
HelpMessage = 'Target-Group Object.')]
[ValidateNotNullOrEmpty()]
[Alias('Target')]
[string]
$TargetGroup,
[Parameter(ParameterSetName = 'full',
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 2)]
[Alias('RemoveTargetOnlyMembers')]
[switch]
$full = $null,
[Parameter(ParameterSetName = 'sync',
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 2)]
[Alias('MakeFullSync')]
[switch]
$sync = $null
)
begin
{
if ($pscmdlet.ShouldProcess('Groups', 'Get information from Active Directory'))
{
try
{
$SourceMembers = (Get-ADGroupMember -Identity $SourceGroup -ErrorAction Stop | Select-Object -ExpandProperty distinguishedName | Sort-Object)
$TargetMembers = (Get-ADGroupMember -Identity $TargetGroup -ErrorAction Stop | Select-Object -ExpandProperty distinguishedName | Sort-Object)
# Check if we have any diferences
if (($SourceMembers) -and ($TargetMembers))
{
# Yep, there are differences
$Differences = (Compare-Object -ReferenceObject $SourceMembers -DifferenceObject $TargetMembers)
}
elseif (($SourceMembers) -and (-not($TargetMembers)))
{
# Target has no members
$Differences = 'SourceOnly'
}
elseif (-not($SourceMembers))
{
# Source has no members
Write-Error -Message ('{0} has no members!' -f $SourceGroup) -ErrorAction Stop
}
else
{
# Nope, there are no differences
$Differences = $null
}
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message $e.Exception.Message -ErrorAction Stop
break
}
}
}
process
{
switch ($pscmdlet.ParameterSetName)
{
'full'
{
if ($pscmdlet.ShouldProcess($TargetGroup, 'Set'))
{
if ($Differences)
{
Write-Verbose -Message 'Remove Target-User from all groups where the Source-User is not a member of.'
$TargetOnlyMembers = ($Differences | Where-Object -Property SideIndicator -EQ -Value '=>')
if ($TargetOnlyMembers)
{
try
{
foreach ($TargetOnlyMember in $TargetOnlyMembers.InputObject)
{
Write-Verbose -Message ('Process: {0}' -f $TargetOnlyMember)
$paramRemoveADGroupMember = @{
Identity = $TargetGroup
Members = $TargetOnlyMember
ErrorAction = 'Stop'
Confirm = $false
}
$null = (Remove-ADGroupMember @paramRemoveADGroupMember -Verbose)
}
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Warning -Message $e.Exception.Message -ErrorAction Continue -WarningAction Continue
}
}
else
{
Write-Verbose -Message 'No group difference found where the Target-User is a member and Source-User is not.'
}
}
}
}
'sync'
{
if ($pscmdlet.ShouldProcess($SourceGroup, 'Set'))
{
if ($Differences)
{
Write-Verbose -Message 'Make the Source-user a Member of all Groups only the Target-User is a member of.'
$TargetOnlyMembers = ($Differences | Where-Object -Property SideIndicator -EQ -Value '=>')
if ($TargetOnlyMembers)
{
Write-Verbose -Message ('Process: {0}' -f $TargetOnlyMembers)
try
{
$paramAddADGroupMember = @{
Identity = $SourceGroup
Members = $TargetOnlyMembers.InputObject
ErrorAction = 'Stop'
Confirm = $false
}
$null = (Add-ADGroupMember @paramAddADGroupMember)
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Warning -Message $e.Exception.Message -ErrorAction Continue -WarningAction Continue
}
}
else
{
Write-Verbose -Message 'No group difference found where the Target-User is a member and Source-User is not.'
}
}
}
}
'default'
{
# Do nothing special
}
}
if ($pscmdlet.ShouldProcess($TargetGroup, 'Set'))
{
if ($Differences)
{
try
{
Write-Verbose -Message 'Process all Source-Group only members.'
$paramAddADGroupMember = @{
Identity = $TargetGroup
ErrorAction = 'Stop'
Confirm = $false
}
if ($Differences -eq 'SourceOnly')
{
# Target has no members
$paramAddADGroupMember.Members = $SourceMembers
}
else
{
$paramAddADGroupMember.Members = ($Differences | Where-Object -Property SideIndicator -EQ -Value '<=' | Select-Object -ExpandProperty InputObject)
}
$null = (Add-ADGroupMember @paramAddADGroupMember)
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Warning -Message $e.Exception.Message -ErrorAction Continue -WarningAction Continue
}
}
}
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,385 @@
function Copy-ADUserGroupMembership
{
<#
.SYNOPSIS
Copy group memberships from a given Source-User to a Target-User in Active Directory
.DESCRIPTION
Copy group memberships from a given Source-User to a Target-User in Active Directory.
The function can also remove the Target-User from all groups where the Source-User is not a member off (optional) or make the Source-User a member of all groups where only the Target-User is a member of.
.PARAMETER SourceUser
Source-User Object.
Specifies an Active Directory user object by providing one of the following property values.
The identifier in parentheses is the LDAP display name for the attribute.
Distinguished Name
Example: CN=SaraDavis,CN=Europe,CN=Users,DC=corp,DC=contoso,DC=com
GUID (objectGUID)
Example: 599c3d2e-f72d-4d20-8a88-030d99495f20
Security Identifier (objectSid)
Example: S-1-5-21-3165297888-301567370-576410423-1103
SAM account name (sAMAccountName)
Example: saradavis
.PARAMETER TargetUser
Target-User Object.
Specifies an Active Directory user object by providing one of the following property values.
The identifier in parentheses is the LDAP display name for the attribute.
Distinguished Name
Example: CN=SaraDavis,CN=Europe,CN=Users,DC=corp,DC=contoso,DC=com
GUID (objectGUID)
Example: 599c3d2e-f72d-4d20-8a88-030d99495f20
Security Identifier (objectSid)
Example: S-1-5-21-3165297888-301567370-576410423-1103
SAM account name (sAMAccountName)
Example: saradavis
.PARAMETER full
Remove the Target User from all groups where the Source-User is not a member of.
.PARAMETER sync
Make the Source-User a member of all Groups where only the Target-User is a member of.
.EXAMPLE
PS C:\> Copy-ADUserGroupMembership -SourceUser 'johndoe' -TargetUser 'janedoe'
Make janedoe a member of all groups where johndoe is a member of. Existing group memberships of janedoe will NOT be removed.
.EXAMPLE
PS C:\> Copy-ADUserGroupMembership -SourceUser 'johndoe' -TargetUser 'janedoe' -full
Make janedoe a member of all groups where johndoe is a member of. Existing group memberships of janedoe WILL be removed.
.EXAMPLE
PS C:\> Copy-ADUserGroupMembership -SourceUser 'johndoe' -TargetUser 'janedoe' -sync
Make janedoe a member of all groups where johndoe is a member of. Existing group memberships of janedoe WILL be applied to johndoe.
Lets call this a reverse Full Sync :)
.NOTES
Initial AIT version of the function
.LINK
https://github.com/jhochwald/PowerShell-collection/
.LINK
Get-ADUser
.LINK
Remove-ADGroupMember
.LINK
Add-ADGroupMember
.LINK
Copy-ADGroupUserMemberships
#>
[CmdletBinding(DefaultParameterSetName = 'default',
SupportsShouldProcess)]
param
(
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 0,
HelpMessage = 'Source-User Object.')]
[ValidateNotNullOrEmpty()]
[Alias('Source')]
[string]
$SourceUser,
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1,
HelpMessage = 'Target-User Object.')]
[ValidateNotNullOrEmpty()]
[Alias('Target')]
[string]
$TargetUser,
[Parameter(ParameterSetName = 'full',
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 2)]
[Alias('RemoveTargetOnlyGroups')]
[switch]
$full = $null,
[Parameter(ParameterSetName = 'sync',
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 2)]
[Alias('MakeFullSync')]
[switch]
$sync = $null
)
begin
{
if ($pscmdlet.ShouldProcess('User', 'Get information from Active Directory'))
{
try
{
# Get the Target-User
$TargetUserObject = (Get-ADUser -Identity $TargetUser -Properties memberOf -ErrorAction Stop)
# Get the Source-User
$SourceUserObject = (Get-ADUser -Identity $SourceUser -Properties memberOf -ErrorAction Stop)
# Sort and save the information we collected above
$SourceUserMembership = ($SourceUserObject.MemberOf | Sort-Object)
$TargetUserMembership = ($TargetUserObject.MemberOf | Sort-Object)
# Check if we have any diferences
if (($SourceUserMembership) -and ($TargetUserMembership))
{
# Yep, there are differences
$Differences = (Compare-Object -ReferenceObject $SourceUserMembership -DifferenceObject $TargetUserMembership)
}
else
{
# Nope, there are no differences
$Differences = $null
}
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message $e.Exception.Message -ErrorAction Stop
break
}
}
}
process
{
switch ($pscmdlet.ParameterSetName)
{
'full'
{
if ($pscmdlet.ShouldProcess($SourceUser, 'Set'))
{
if ($Differences)
{
Write-Verbose -Message 'Remove Target-User from all groups where the Source-User is not a member of.'
$TargetOnlyGroups = ($Differences | Where-Object -Property SideIndicator -EQ -Value '=>')
if ($TargetOnlyGroups)
{
foreach ($TargetOnlyGroup in $TargetOnlyGroups.InputObject)
{
Write-Verbose -Message ('Process: {0}' -f $TargetOnlyGroup)
try
{
$paramRemoveADGroupMember = @{
Identity = $TargetOnlyGroup
Members = $TargetUser
ErrorAction = 'Stop'
Confirm = $false
}
$null = (Remove-ADGroupMember @paramRemoveADGroupMember)
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Warning -Message $e.Exception.Message -ErrorAction Continue -WarningAction Continue
}
}
}
else
{
Write-Verbose -Message 'No group difference fround where the Target-User is a member and Source-User is not.'
}
}
}
}
'sync'
{
if ($pscmdlet.ShouldProcess($SourceUser, 'Set'))
{
if ($Differences)
{
Write-Verbose -Message 'Make the Source-user a Member of all Groups only the Target-User is a member of.'
$TargetOnlyGroups = ($Differences | Where-Object -Property SideIndicator -EQ -Value '=>')
if ($TargetOnlyGroups)
{
foreach ($TargetOnlyGroup in $TargetOnlyGroups.InputObject)
{
Write-Verbose -Message ('Process: {0}' -f $TargetOnlyGroup)
try
{
$paramAddADGroupMember = @{
Identity = $TargetOnlyGroup
Members = $SourceUser
ErrorAction = 'Stop'
Confirm = $false
}
$null = (Add-ADGroupMember @paramAddADGroupMember)
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Warning -Message $e.Exception.Message -ErrorAction Continue -WarningAction Continue
}
}
}
else
{
Write-Verbose -Message 'No group difference fround where the Target-User is a member and Source-User is not.'
}
}
}
}
'default'
{
# Do nothing special
}
}
if ($pscmdlet.ShouldProcess($TargetUser, 'Set'))
{
if ($Differences)
{
$SourceOnlyGroups = ($Differences | Where-Object -Property SideIndicator -EQ -Value '<=')
if ($SourceOnlyGroups)
{
Write-Verbose -Message 'Process all Groups where only the Source-user is a member of.'
foreach ($SourceOnlyGroup in $SourceOnlyGroups.InputObject)
{
Write-Verbose -Message ('Process: {0}' -f $SourceOnlyGroup)
try
{
$paramAddADGroupMember = @{
Identity = $SourceOnlyGroup
Members = $TargetUser
ErrorAction = 'Stop'
Confirm = $false
}
$null = (Add-ADGroupMember @paramAddADGroupMember)
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Warning -Message $e.Exception.Message -ErrorAction Continue -WarningAction Continue
}
}
}
}
else
{
Write-Warning -Message 'No group difference fround where the Source-User is a member and Source-User is not.' -WarningAction Continue
}
}
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,224 @@
function Copy-ADUserGroupMembershipSimple
{
<#
.SYNOPSIS
Copy group memberships from a given Source User to a Target User(s) in Active Directory
.DESCRIPTION
Copy group memberships from a given Source User to a Target User(s) in Active Directory.
Simple Version of Copy-ADUserGroupMemberships
.PARAMETER SourceUser
Source-User Object.
Specifies an Active Directory group object by providing one of the following values.
The identifier in parentheses is the LDAP display name for the attribute.
Distinguished Name
Example: CN=johndoe,OU=europe,CN=users,DC=corp,DC=contoso,DC=com
GUID (objectGUID)
Example: 599c3d2e-f72d-4d20-8a88-030d99495f20
Security Identifier (objectSid)
Example: S-1-5-21-3165297888-301567370-576410423-1103
Security Accounts Manager (SAM) Account Name (sAMAccountName)
Example: johndoe
.PARAMETER TargetUser
Target-User Object.
Specifies an Active Directory group object by providing one of the following values.
The identifier in parentheses is the LDAP display name for the attribute.
Distinguished Name
Example: CN=janedoe,OU=europe,CN=users,DC=corp,DC=contoso,DC=com
GUID (objectGUID)
Example: 599c3d2e-f72d-4d20-8a88-030d99495f20
Security Identifier (objectSid)
Example: S-1-5-21-3165297888-301567370-576410423-1103
Security Accounts Manager (SAM) Account Name (sAMAccountName)
Example: janedoe
.PARAMETER PassThru
Use the -PassThru parameter with the previous command to receive feedback about what groups the Target is being added as a member of.
.EXAMPLE
PS C:\> Copy-ADUserGroupMembershipSimple -SourceUser 'SourceUser' -TargetUser 'TargetUser'
Copy group memberships from SourceUser to TargetUser
.EXAMPLE
PS C:\> Copy-ADUserGroupMembershipSimple -SourceUser 'SourceUser' -TargetUser 'TargetUser1', 'TargetUser2'
Copy group memberships from SourceUser to TargetUser1 and TargetUser2
.EXAMPLE
PS C:\> Copy-ADUserGroupMembershipSimple -SourceUser 'SourceUser' -TargetUser 'TargetUser' -PassThru
Use the -PassThru parameter with the previous command to receive feedback about what groups the Target is being added as a member of.
.NOTES
Releasenotes:
1.0.0 2019-07-09: Initial Release
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
.LINK
Copy-ADUserGroupMemberships
.LINK
https://github.com/jhochwald/PowerShell-collection/
.LINK
Get-ADUser
.LINK
Add-ADGroupMember
#>
[CmdletBinding(ConfirmImpact = 'Low',
SupportsShouldProcess = $true)]
param
(
[Parameter(Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
Position = 0,
HelpMessage = 'Source-User Object.')]
[ValidateNotNullOrEmpty()]
[Alias('Source')]
[string]
$SourceUser,
[Parameter(Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
Position = 1,
HelpMessage = 'Target-User Object.')]
[ValidateNotNullOrEmpty()]
[Alias('Target')]
[string[]]
$TargetUser,
[Parameter(ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
Position = 2)]
[switch]
$PassThru = $null
)
process
{
if ($pscmdlet.ShouldProcess($TargetUser, 'Modify/add Group Membership'))
{
try
{
$paramGetADUser = @{
Identity = $SourceUser
Properties = 'memberof'
Verbose = $(if ($pscmdlet.MyInvocation.BoundParameters['Verbose'].IsPresent)
{
$true
}
else
{
$false
}
)
}
$paramAddADGroupMember = @{
Members = $TargetUser
Verbose = $(if ($pscmdlet.MyInvocation.BoundParameters['Verbose'].IsPresent)
{
$true
}
else
{
# Workaround: If not present it is empty not false
$false
}
)
PassThru = $(if ($pscmdlet.MyInvocation.BoundParameters['PassThru'].IsPresent)
{
$true
}
else
{
# Workaround: If not present it is empty not false
$false
}
)
}
if (($pscmdlet.MyInvocation.BoundParameters['PassThru'].IsPresent))
{
# Show the output / PassThru in a nice format
((Get-ADUser @paramGetADUser) | Select-Object -ExpandProperty memberof | Add-ADGroupMember @paramAddADGroupMember | Select-Object -ExpandProperty SamAccountName)
}
else
{
# Do not show any output / Verbose will be shown
$null = ((Get-ADUser @paramGetADUser) | Select-Object -ExpandProperty memberof | Add-ADGroupMember @paramAddADGroupMember)
}
}
catch
{
#region ErrorHandler
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message ($info.Exception) -ErrorAction Stop
# Only here to catch a global ErrorAction overwrite
break
#endregion ErrorHandler
}
}
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,169 @@
function Find-enADDuplicateServicePrincipalName
{
<#
.SYNOPSIS
Find all duplicate Service Principal Names (SPNs)
.DESCRIPTION
Find all duplicate Service Principal Names (SPNs) in the Active Directory
.INPUTS
NONE
.OUTPUTS
Boolean
.EXAMPLE
PS C:\> Find-enADDuplicateServicePrincipalName
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
Dependencies:
Active Directory PowerShell Module
.LINK
https://www.enatec.io
.LINK
Get-ADObject
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([bool])]
param ()
begin
{
# Create a new Object
$AllObject = @()
}
process
{
try
{
# We use Get-ADObject because this seems to be fast enough
$paramGetADObject = @{
Filter = "(objectClass -eq 'user') -or (objectClass -eq 'computer') -and (servicePrincipalName -like '*')"
Properties = 'SamAccountName', 'servicePrincipalName'
ErrorAction = 'Stop'
WarningAction = 'Continue'
}
$AllServicePrincipalNames = (Get-ADObject @paramGetADObject)
# Loop over the List we got from Get-ADObject
foreach ($SPNObject in $AllServicePrincipalNames)
{
$SamAccountName = $SPNObject.SamAccountName
$ServicePrincipalNames = $SPNObject.ServicePrincipalName
foreach ($ServicePrincipalName in $ServicePrincipalNames)
{
if ($AllObject.ServicePrincipalName -like $ServicePrincipalName)
{
$MatchedSPNs = ($AllObject.ServicePrincipalName -like $ServicePrincipalName)
# Loop over the matching list og SPNs
foreach ($MatchSPN in $MatchedSPNs)
{
$MatchSamAccountName = $MatchSPN.SamAccountName
# Ding. ding, we have a winner
if ($MatchSamAccountName -ne $SamAccountName)
{
$paramWriteWarning = @{
Message = ('Duplicated SPN has been found for {0}!!!' -f $ServicePrincipalName)
ErrorAction = 'Continue'
WarningAction = 'Continue'
}
Write-Warning @paramWriteWarning
}
}
}
else
{
# Create a new Object
$SingleObject = (New-Object -TypeName PSObject -Property @{
SamAccountName = $SamAccountName
ServicePrincipalName = $ServicePrincipalName
})
# Add the Values to the List
$AllObject += $SingleObject
# Cleanup
$SingleObject = $null
}
}
}
}
catch
{
#region ErrorHandler
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message ($info.Exception) -ErrorAction Stop
# Only here to catch a global ErrorAction overwrite
break
#endregion ErrorHandler
}
}
end
{
# Dump all SPNs, if verbose
$AllObject | Out-String | Write-Verbose
# Cleanup
$AllObject = $null
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,203 @@
function Get-ADUserLockouts
{
<#
.SYNOPSIS
Tracking down account lockout sources with PowerShell
.DESCRIPTION
Tracking down account lockout sources with PowerShell
.PARAMETER Identity
Just scan for a single User?
.PARAMETER StartTime
Start-point
.PARAMETER EndTime
Endpoint
.EXAMPLE
PS C:\> Get-ADUserLockout
Tracking down account lockout sources for all users for the last 7 days
.EXAMPLE
Get-ADUser -Filter {Department -eq 'Development'} | Get-ADUserLockout
Tracking down account lockout sources for all users in the Development Department for the last 7 days
.EXAMPLE
Get-ADUserLockout -StartTime (Get-Date).AddDays(-2) -EndTime (Get-Date).AddDays(-1)
Tracking down account lockout sources for all users for the last day
.NOTES
Original by Anthony Howell (@ThePoShWolf) - MIT Licenses
Copyright (c) 2018 Anthony Howell
.LINK
https://theposhwolf.com/howtos/Get-ADUserLockouts/
.LINK
https://github.com/ThePoShWolf/Utilities/blob/master/ActiveDirectory/Get-ADUserLockouts.ps1
#>
[CmdletBinding(DefaultParameterSetName = 'All',
ConfirmImpact = 'None')]
[OutputType([pscustomobject])]
param
(
[Parameter(ParameterSetName = 'ByUser',
ValueFromPipeline)]
[string]
$Identity,
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias('Start')]
[datetime]
$StartTime = (Get-Date).AddDays(-8),
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias('End')]
[datetime]
$EndTime = (Get-Date).AddDays(-1)
)
begin
{
$filterHt = @{
LogName = 'Security'
ID = 4740
}
if ($PSBoundParameters.ContainsKey('StartTime'))
{
$filterHt['StartTime'] = $StartTime
}
if ($PSBoundParameters.ContainsKey('EndTime'))
{
$filterHt['EndTime'] = $EndTime
}
try
{
$PDCEmulator = ((Get-ADDomain -ErrorAction Stop).PDCEmulator)
Write-Verbose -Message ('Use {0} to find the lockout events' -f $PDCEmulator)
# Query the event log just once instead of for each user if using the pipeline
$events = (Get-WinEvent -ComputerName $PDCEmulator -FilterHashtable $filterHt -ErrorAction Stop)
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
# output information. Post-process collected info, and log info (optional)
$info | Out-String | Write-Verbose
Write-Error -Message $e.Exception.Message -ErrorAction Stop -Exception $e.Exception -TargetObject $e.CategoryInfo.TargetName
break
}
Write-Verbose -Message 'Found the following events:'
Write-Verbose -Message $events
}
process
{
if ($PSCmdlet.ParameterSetName -eq 'ByUser')
{
try
{
Write-Verbose -Message ('Querry AD Info for {0}' -f $Identity)
$user = (Get-ADUser -Identity $Identity -ErrorAction Stop)
Write-Verbose -Message ('Found the following AD Info for {0}:' -f $Identity)
Write-Verbose -Message $user
# Filter the events
$output = $events | Where-Object -FilterScript {
$_.Properties[0].Value -eq $user.SamAccountName
}
}
catch
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
# output information. Post-process collected info, and log info (optional)
$info | Out-String | Write-Verbose
Write-Error -Message $e.Exception.Message -ErrorAction Stop -Exception $e.Exception -TargetObject $e.CategoryInfo.TargetName
break
}
}
else
{
$output = $events
}
foreach ($event in $output)
{
[pscustomobject]@{
UserName = $event.Properties[0].Value
CallerComputer = $event.Properties[1].Value
TimeStamp = $event.TimeCreated
}
}
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,196 @@
function Get-enADDNSServerInformation
{
<#
.SYNOPSIS
Retrieve information about the Active Directory Domain Name Servers
.DESCRIPTION
Retrieve information about the Active Directory Domain Name Servers
.PARAMETER Domain
A description of the Domain parameter.
.EXAMPLE
PS ~> Get-enADDNSServerInformation
Retrieve information about the Active Directory Domain Name Servers, use the current domain
.EXAMPLE
PS ~> Get-enADDNSServerInformation | Export-CSV -Path C:\scripts\PowerShell\Reports\DNS_Zones.csv -NoTypeInformation -Force -Confirm:$false
Retrieve information about the Active Directory Domain Name Servers, use the current domain and exports it to CSV
.EXAMPLE
PS ~> Get-enADDNSServerInformation | ConvertTo-Json -Depth 10 | Set-Content -Path C:\scripts\PowerShell\Reports\DNS_Zones.json -Force -Confirm:$false
Retrieve information about the Active Directory Domain Name Servers, use the current domain and exports it to a JSON File
.EXAMPLE
PS ~> Get-enADDNSServerInformation -Domain 'contoso.com'
Retrieve information about the Active Directory Domain Name Servers in the Domain contoso.com
.EXAMPLE
PS ~> Get-enADDNSServerInformation -Domain 'contoso.com', 'corp.contoso.net'
Retrieve information about the Active Directory Domain Name Servers in the Domain contoso.com and corp.contoso.net
.OUTPUTS
psobject
.INPUTS
String
.NOTES
TODO: Need refactoring: Object handler sucks
TODO: Find a non WMI based Solution for this
Version: 1.0.1
GUID: 4404141a-1731-4786-8bbf-ee6706765050
Author: Joerg Hochwald
Companyname: enabling Technology
Copyright: Copyright (c) 2ß18-2019, enabling Technology - All rights reserved.
License: https://opensource.org/licenses/BSD-3-Clause
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
.LINK
https://www.enatec.io
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa393295(v=vs.85).aspx
.LINK
Get-ADDomainController
.LINK
Get-WmiObject
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param
(
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]
$Domain = ([DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().Name.ToString())
)
begin
{
$DNSReport = @()
}
process
{
foreach ($DomainEach in $Domain)
{
$AllDomainControllers = (Get-ADDomainController -Filter {
Site -like '*' -and Domain -eq $DomainEach
} | Select-Object -ExpandProperty Name)
foreach ($SingleDomainController in $AllDomainControllers)
{
# Prevent Null Pointer Exceptions
if ($SingleDomainController)
{
# TODO: Find a non WMI based Solution for this
$Forwarders = (Get-WmiObject -ComputerName $SingleDomainController -Namespace root\MicrosoftDNS -Class MicrosoftDNS_Server -ErrorAction SilentlyContinue)
# TODO: Find a non WMI based Solution for this
$NetworkInterface = (Get-WmiObject -ComputerName $SingleDomainController -Query 'Select * From Win32_NetworkAdapterConfiguration Where IPEnabled=TRUE' -ErrorAction SilentlyContinue)
$DNSReport += 1 | Select-Object -Property @{
name = 'DC'
expression = {
$SingleDomainController
}
}, @{
name = 'Domain'
expression = {
$DomainEach
}
}, @{
name = 'DNSHostName'
expression = {
$NetworkInterface.DNSHostName
}
}, @{
name = 'IPAddress'
expression = {
$NetworkInterface.IPAddress
}
}, @{
name = 'DNSServerAddresses'
expression = {
$Forwarders.ServerAddresses
}
}, @{
name = 'DNSServerSearchOrder'
expression = {
$NetworkInterface.DNSServerSearchOrder
}
}, @{
name = 'Forwarders'
expression = {
$Forwarders.Forwarders
}
}, @{
name = 'BootMethod'
expression = {
$Forwarders.BootMethod
}
}, @{
name = 'ScavengingInterval'
expression = {
$Forwarders.ScavengingInterval
}
}
}
}
}
}
end
{
$DNSReport
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,100 @@
Function Get-enDomainControllerInfo
{
<#
.SYNOPSIS
Get a list of domain controllers
.DESCRIPTION
Will provide a list of domain controllers in your current domain.
Optionally you can also request a discovery of the "closest" one.
.PARAMETER ComputerName
Retrieve information about the specified domain controller.
This is a RegEx match so you can match multiple domain controllers with your pattern.
.PARAMETER Discover
Use Discover to return the information of the closest domain controller.
.EXAMPLE
Get-enDomainControllerInfo
Retrieve a list of all domain controllers in your domain.
.EXAMPLE
Get-enDomainControllerInfo -Computer 01
Retrieve a list of all domain controllers with "01" in their name.
.EXAMPLE
Get-enDomainControllerInfo -Discover
Retrieve the name of the closest domain controller.
.NOTES
#>
[CmdletBinding(DefaultParameterSetName = 'all')]
Param (
[Parameter(Position = 0, ParameterSetName = 'dc')]
[string]$ComputerName,
[Parameter(ParameterSetName = 'all')]
[switch]$Discover
)
begin
{
$DirectoryContext = [DirectoryServices.ActiveDirectory.DirectoryContext]::New('Domain')
$SelectProperties = 'Name', 'Forest', 'Domain', 'SiteName', 'Roles', 'CurrentTime', 'HighestCommittedUsn', 'OSVersion'
}
process
{
If ($Discover)
{
$LocatorFlag = [DirectoryServices.ActiveDirectory.LocatorOptions]::ForceRediscovery
$Info = ([DirectoryServices.ActiveDirectory.DomainController]::FindOne($DirectoryContext, $LocatorFlag) | Select-Object -Property $SelectProperties)
}
elseif ($ComputerName)
{
$Info = ([DirectoryServices.ActiveDirectory.DomainController]::FindAll($DirectoryContext) | Where-Object -Property Name -Match -Value $ComputerName | Select-Object -Property $SelectProperties)
}
else
{
$Info = ([DirectoryServices.ActiveDirectory.DomainController]::FindAll($DirectoryContext) | Select-Object -Property $SelectProperties)
}
}
end
{
$Info
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,148 @@
#requires -Version 3.0 -Modules ActiveDirectory
function Get-enADFSMORole
{
<#
.SYNOPSIS
Retrieve the FSMO Role in the Forest/Domain
.DESCRIPTION
Retrieve the FSMO Role in the Forest/Domain of Active Directory
.PARAMETER Credential
Specify the alternative credential to use
.EXAMPLE
Get-enADFSMORole
Retrieve the FSMO Role in the Forest/Domain of Active Directory
.EXAMPLE
Get-enADFSMORole -Credential (Get-Credential)
Retrieve the FSMO Role in the Forest/Domain of Active Directory
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
Dependencies:
Active Directory PowerShell Module
.LINK
https://www.enatec.io
.LINK
Get-ADForest
.LINK
Get-ADDomain
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param
(
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[System.Management.Automation.Credential()]
[Alias('RunAs')]
[pscredential]
$Credential = [pscredential]::Empty
)
begin
{
$Properties = $null
}
process
{
try
{
if ($PSBoundParameters['Credential'])
{
# Query with the credentials specified
$ForestRoles = (Get-ADForest -Credential $Credential -ErrorAction 'Stop' -ErrorVariable ErrorGetADForest)
$DomainRoles = (Get-ADDomain -Credential $Credential -ErrorAction 'Stop' -ErrorVariable ErrorGetADDomain)
}
else
{
# Query with the current credentials
$ForestRoles = (Get-ADForest)
$DomainRoles = (Get-ADDomain)
}
# Define Properties
$Properties = @{
SchemaMaster = $ForestRoles.SchemaMaster
DomainNamingMaster = $ForestRoles.DomainNamingMaster
InfraStructureMaster = $DomainRoles.InfraStructureMaster
RIDMaster = $DomainRoles.RIDMaster
PDCEmulator = $DomainRoles.PDCEmulator
}
}
catch
{
#region ErrorHandler
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message ($info.Exception) -ErrorAction Stop
# Only here to catch a global ErrorAction overwrite
break
#endregion ErrorHandler
}
}
end
{
$Properties
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,189 @@
function Get-enADForestInformation
{
<#
.SYNOPSIS
Retrieve information about an Active Directory Forest
.DESCRIPTION
Retrieve information about an Active Directory Forest
.PARAMETER ForestName
Forest name to retrieve information about
.PARAMETER Credential
Credential to use for retrieval
.EXAMPLE
PS ~> Get-enADForestInformation
Retrieve information about the current Active Directory Forest
.EXAMPLE
PS ~> Get-enADForestInformation | Select-Object ApplicationPartitions
Retrieve information about Application Partitions from the current Active Directory Forest
.EXAMPLE
PS ~> Get-enADForestInformation | Select-Object GlobalCatalogs
Retrieve als Global Catalog Servers from the current Active Directory Forest
.EXAMPLE
PS ~> (Get-enADForestInformation) | Select-Object -ExpandProperty GlobalCatalogs
Retrieve als Global Catalog Servers from the current Active Directory Forest. More details then the above example, cause it will show all the details for each Global Catalog Servers.
.EXAMPLE
PS ~> Get-enADForestInformation | Select-Object NamingRoleOwner
Retrieve information about the Naming master Roles holder from the current Active Directory Forest
.EXAMPLE
PS ~> (Get-enADForestInformation).Sites
Retrieve information about Active Directory Sites from the current Active Directory Forest
.EXAMPLE
PS ~> Get-enADForestInformation -Credential (Get-Credential)
Retrieve information about the current Active Directory Forest, with special credentials (e.g. RunAs)
.EXAMPLE
PS ~> Get-enADForestInformation -ForestName Value
Retrieve information about Active Directory Forest specified in Value
.EXAMPLE
PS ~> Get-enADForestInformation -ForestName Value -Credential Value
Retrieve information about Active Directory Forest specified in Value, with special credentials (e.g. RunAs)
.OUTPUTS
psobject
.INPUTS
String
pscredential
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
.LINK
https://www.enatec.io
.LINK
Get-ADForest
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param
(
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias('Forest')]
[string]
$ForestName = ([DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Name.ToString()),
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[System.Management.Automation.Credential()]
[pscredential]
$Credential
)
begin
{
# Cleanup
$output = $null
$ActiveDirectoryContext = $null
}
process
{
try
{
if ($Credential)
{
$credentialUser = ($Credential.UserName.ToString())
$credentialPassword = ($Credential.GetNetworkCredential().Password.ToString())
$ActiveDirectoryContext = (New-Object -TypeName System.DirectoryServices.ActiveDirectory.DirectoryContext -ArgumentList ('forest', $ForestName, $credentialUser, $credentialPassword))
# Cleanup
$credentialUser = $null
$credentialPassword = $null
}
else
{
$ActiveDirectoryContext = (New-Object -TypeName System.DirectoryServices.ActiveDirectory.DirectoryContext -ArgumentList ('forest', $ForestName))
}
$output = ([DirectoryServices.ActiveDirectory.Forest]::GetForest($ActiveDirectoryContext))
}
catch
{
#region ErrorHandler
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message ($info.Exception) -ErrorAction Stop
# Only here to catch a global ErrorAction overwrite
break
#endregion ErrorHandler
}
}
end
{
$output
# Cleanup
$output = $null
$ActiveDirectoryContext = $null
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,158 @@
function Get-enADGPOReplication
{
<#
.SYNOPSIS
Retrieve one or all the GPO and report their DSVersions and SysVolVersions
.DESCRIPTION
Retrieve one or all the GPO and report their DSVersions and SysVolVersions (Users and Computers)
.PARAMETER GPOName
Specify the name of the GPO
.PARAMETER All
Specify that you want to retrieve all the GPO (slow if you have a lot of Domain Controllers)
.EXAMPLE
Get-enADGPOReplication -GPOName "Default Domain Policy"
Retrieve one GPO and report their DSVersions and SysVolVersions (Users and Computers)
.EXAMPLE
Get-enADGPOReplication -All
Retrieve all the GPO and report their DSVersions and SysVolVersions (Users and Computers)
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
Dependencies:
Active Directory PowerShell Module
.LINK
https://www.enatec.io
.LINK
Get-ADDomainController
.LINK
Get-GPO
#>
[CmdletBinding(DefaultParameterSetName = 'All',
ConfirmImpact = 'None')]
param
(
[Parameter(ParameterSetName = 'One', HelpMessage = 'Specify the name of the GPO',
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[Alias('GPO')]
[String[]]
$GPOName,
[Parameter(ParameterSetName = 'All',
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Switch]
$All
)
process
{
foreach ($DomainController in ((Get-ADDomainController -ErrorAction Stop -ErrorVariable ErrorProcessGetDC -Filter *).hostname))
{
try
{
if ($psBoundParameters['GPOName'])
{
foreach ($GPOItem in $GPOName)
{
$GPO = (Get-GPO -Name $GPOItem -Server $DomainController -ErrorAction Stop -ErrorVariable ErrorProcessGetGPO)
[pscustomobject][ordered] @{
GroupPolicyName = $GPOItem
DomainController = $DomainController
UserVersion = $GPO.User.DSVersion
UserSysVolVersion = $GPO.User.SysvolVersion
ComputerVersion = $GPO.Computer.DSVersion
ComputerSysVolVersion = $GPO.Computer.SysvolVersion
}
}
}
if ($psBoundParameters['All'])
{
$GPOList = (Get-GPO -All -Server $DomainController -ErrorAction Stop -ErrorVariable ErrorProcessGetGPOAll)
foreach ($GPO in $GPOList)
{
[pscustomobject][ordered] @{
GroupPolicyName = $GPO.DisplayName
DomainController = $DomainController
UserVersion = $GPO.User.DSVersion
UserSysVolVersion = $GPO.User.SysvolVersion
ComputerVersion = $GPO.Computer.DSVersion
ComputerSysVolVersion = $GPO.Computer.SysvolVersion
}
}
}
}
catch
{
Write-Warning -Message '[PROCESS] Something wrong happened'
if ($ErrorProcessGetDC)
{
Write-Warning -Message '[PROCESS] Error while running retrieving Domain Controllers with Get-ADDomainController'
}
if ($ErrorProcessGetGPO)
{
Write-Warning -Message '[PROCESS] Error while running Get-GPO'
}
if ($ErrorProcessGetGPOAll)
{
Write-Warning -Message '[PROCESS] Error while running Get-GPO -All'
}
Write-Warning -Message "[PROCESS] $($Error[0].exception.message)"
}
}
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,210 @@
function Get-enADGroupChange
{
<#
.SYNOPSIS
Retrieve information about changed Active Directory groups
.DESCRIPTION
Retrieve information about one, or more, changed Active Directory groups
.PARAMETER Server
Active DirectoryDomain Controller to querry.
Default is the logon server
.PARAMETER MonitorGroup
Group to monitor, multi value is supported.
Defaults to all Groups with admins.
Specifies an Active Directory object by providing one of the following property values. The identifier in
parentheses is the LDAP display name for the attribute.
Distinguished Name
Example: CN=DOM-ADM,OU=groups,OU=asia,DC=corp,DC=contoso,DC=com
GUID (objectGUID)
Example: 599c3d2e-f72d-4d20-8a88-030d99495f20
The cmdlet searches the default naming context or partition to find the object. If two or more objects are
found, the cmdlet returns a non-terminating error.
.PARAMETER Hour
Period to query, value in hours
.EXAMPLE
Get-enADGroupChange
Retrieve information about changed Active Directory groups
.EXAMPLE
Get-enADGroupChange -MonitorGroup 'DOM-ADM'
Retrieve information about changes to theActive Directory group DOM-ADM
.EXAMPLE
Get-enADGroupChange -Server DC03
Retrieve information about changed Active Directory groups on DC03
.EXAMPLE
Get-enADGroupChange -Hour 72
Retrieve information about Active Directory groups that have been changed within the last 72 hours
.EXAMPLE
Get-enADGroupChange -Server DC02 -Hour 96
Retrieve information about Active Directory groups that have been changed within the last 96 hours on DC02
.OUTPUTS
psobject
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
.INPUTS
String
Int
.LINK
https://www.enatec.io
.LINK
Get-ADDomainController
.LINK
Get-ADGroup
.LINK
Get-ADReplicationAttributeMetadata
.LINK
Get-Date
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param
(
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[Alias('DomainController')]
[string]
$Server = (Get-ADDomainController -Discover | Select-Object -ExpandProperty HostName),
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[Alias('Group')]
[string[]]
$MonitorGroup = (Get-ADGroup -Filter ' AdminCount -eq 1 ' -Server $Server | Select-Object -ExpandProperty ObjectGUID),
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias('Period')]
[int]
$Hour = 24
)
begin
{
# Create a new object
$Members = @()
Write-Verbose -Message ('Processing group {0} via Server {1}' -f $MonitorGroup, $Server)
}
process
{
try
{
foreach ($SingleGroup in $MonitorGroup)
{
Write-Verbose -Message ('Processing group {0}' -f $SingleGroup)
# Querry the info and add to the Object
$Members += (Get-ADReplicationAttributeMetadata -Server $Server -Object $SingleGroup -ShowAllLinkedValues | Where-Object -FilterScript {
$_.IsLinkValue
} | Select-Object -Property @{
name = 'GroupDN'
expression = {
$SingleGroup.DistinguishedName
}
}, @{
name = 'GroupName'
expression = {
$SingleGroup.Name
}
}, *)
}
# Filter
$Members | Where-Object -FilterScript {
$_.LastOriginatingChangeTime -gt (Get-Date).AddHours(-1 * $Hour)
}
}
catch
{
#region ErrorHandler
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message ($info.Exception) -ErrorAction Stop
# Only here to catch a global ErrorAction overwrite
break
#endregion ErrorHandler
}
}
end
{
$Members = $null
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,378 @@
function Get-enADObject
{
<#
.SYNOPSIS
Export Active Directory Objects
.DESCRIPTION
Export Active Directory Objects
.PARAMETER ADObjectFilter
Provide specific AD Objects to report on. Otherwise, all AD Objects will be reported. Please review the examples provided.
.PARAMETER DetailedReport
Provides a full report of all attributes. Otherwise, only a refined report will be given.
.EXAMPLE
PS ~> Get-enADObject | Export-Csv C:\scripts\PowerShell\Reports\ADObjects.csv -notypeinformation -encoding UTF8
Export Active Directory Objects
.EXAMPLE
PS ~> {objectclass -eq "publicFolder"} | Get-enADObject -DetailedReport | Export-Csv C:\scripts\PowerShell\Reports\PFs.csv -NoTypeInformation -Encoding UTF8
Export Active Directory Objects
.EXAMPLE
PS ~> '{proxyaddresses -like "*contoso.com"}' | Get-enADObject | Export-Csv C:\scripts\PowerShell\Reports\ADObjects.csv -notypeinformation -encoding UTF8
Export Active Directory Objects
.EXAMPLE
PS ~> '{proxyaddresses -like "*contoso.com"}' | Get-enADObject -DetailedReport | Export-Csv C:\scripts\PowerShell\Reports\ADObjects_Detailed.csv -notypeinformation -encoding UTF8
Export Active Directory Objects
.OUTPUTS
PSObject
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
Dependencies:
Active Directory PowerShell Module
.LINK
https://www.enatec.io
.LINK
Get-ADObject
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param (
[switch]
$DetailedReport,
[Parameter(ValueFromPipeline)]
[string[]]
$ADObjectFilter
)
begin
{
if ($DetailedReport)
{
$Selectproperties = @(
'DisplayName', 'UserPrincipalName', 'mail', 'CN', 'mailNickname', 'Name', 'GivenName', 'Surname', 'StreetAddress'
'City', 'State', 'Country', 'PostalCode', 'Company', 'Title', 'Department', 'Description', 'OfficePhone'
'MobilePhone', 'HomePhone', 'Fax', 'SamAccountName', 'DistinguishedName', 'Office', 'Enabled'
'whenChanged', 'whenCreated', 'adminCount', 'AccountNotDelegated', 'AllowReversiblePasswordEncryption'
'CannotChangePassword', 'Deleted', 'DoesNotRequirePreAuth', 'HomedirRequired', 'isDeleted', 'LockedOut'
'mAPIRecipient', 'mDBUseDefaults', 'MNSLogonAccount', 'msExchHideFromAddressLists'
'msNPAllowDialin', 'PasswordExpired', 'PasswordNeverExpires', 'PasswordNotRequired', 'ProtectedFromAccidentalDeletion'
'SmartcardLogonRequired', 'TrustedForDelegation', 'TrustedToAuthForDelegation', 'UseDESKeyOnly', 'logonHours'
'msExchMailboxGuid', 'replicationSignature', 'AccountExpirationDate', 'AccountLockoutTime', 'Created', 'createTimeStamp'
'LastBadPasswordAttempt', 'LastLogonDate', 'Modified', 'modifyTimeStamp', 'msTSExpireDate', 'PasswordLastSet'
'msExchMailboxSecurityDescriptor', 'nTSecurityDescriptor', 'BadLogonCount', 'codePage', 'countryCode'
'deletedItemFlags', 'dLMemDefault', 'garbageCollPeriod', 'instanceType', 'msDS-SupportedEncryptionTypes'
'msDS-User-Account-Control-Computed', 'msExchALObjectVersion', 'msExchMobileMailboxFlags', 'msExchRecipientDisplayType'
'msExchUserAccountControl', 'primaryGroupID', 'replicatedObjectVersion', 'sAMAccountType', 'sDRightsEffective'
'userAccountControl', 'accountExpires', 'lastLogonTimestamp', 'lockoutTime', 'msExchRecipientTypeDetails', 'msExchVersion'
'pwdLastSet', 'uSNChanged', 'uSNCreated', 'ObjectGUID', 'objectSid', 'SID', 'autoReplyMessage', 'CanonicalName'
'displayNamePrintable', 'Division', 'EmployeeID', 'EmployeeNumber', 'HomeDirectory', 'HomeDrive', 'homeMDB', 'homeMTA'
'HomePage', 'Initials', 'LastKnownParent', 'legacyExchangeDN', 'LogonWorkstations'
'Manager', 'msExchHomeServerName', 'msExchUserCulture', 'msTSLicenseVersion', 'msTSManagingLS'
'ObjectCategory', 'ObjectClass', 'Organization', 'OtherName', 'POBox', 'PrimaryGroup'
'ProfilePath', 'ScriptPath', 'sn', 'textEncodedORAddress', 'userParameters'
)
$CalculatedProps = @(
@{
n = 'OU'
e = {
$_.DistinguishedName -replace '^.+?,(?=(OU|CN)=)'
}
},
@{
n = 'proxyAddresses'
e = {
($_.proxyAddresses | Where-Object -FilterScript {
$_ -ne $null
}) -join '|'
}
},
@{
n = 'altRecipientBL'
e = {
($_.altRecipientBL | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'AuthenticationPolicy'
e = {
($_.AuthenticationPolicy | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'AuthenticationPolicySilo'
e = {
($_.AuthenticationPolicySilo | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'Certificates'
e = {
($_.Certificates | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'CompoundIdentitySupported'
e = {
($_.CompoundIdentitySupported | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'dSCorePropagationData'
e = {
($_.dSCorePropagationData | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'KerberosEncryptionType'
e = {
($_.KerberosEncryptionType | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'managedObjects'
e = {
($_.managedObjects | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'MemberOf'
e = {
($_.MemberOf | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'msExchADCGlobalNames'
e = {
($_.msExchADCGlobalNames | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'msExchPoliciesExcluded'
e = {
($_.msExchPoliciesExcluded | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'PrincipalsAllowedToDelegateToAccount'
e = {
($_.PrincipalsAllowedToDelegateToAccount | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'protocolSettings'
e = {
($_.protocolSettings | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'publicDelegatesBL'
e = {
($_.publicDelegatesBL | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'securityProtocol'
e = {
($_.securityProtocol | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'ServicePrincipalNames'
e = {
($_.ServicePrincipalNames | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'showInAddressBook'
e = {
($_.showInAddressBook | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'SIDHistory'
e = {
($_.SIDHistory | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'userCertificate'
e = {
($_.userCertificate | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
}
)
$ExtensionAttribute = @(
'extensionAttribute1', 'extensionAttribute2', 'extensionAttribute3', 'extensionAttribute4', 'extensionAttribute5'
'extensionAttribute6', 'extensionAttribute7', 'extensionAttribute8', 'extensionAttribute9', 'extensionAttribute10'
'extensionAttribute11', 'extensionAttribute12', 'extensionAttribute13', 'extensionAttribute14', 'extensionAttribute15'
)
}
else
{
$Props = @(
'DisplayName', 'UserPrincipalName', 'mail', 'CN', 'mailNickname', 'Name', 'GivenName', 'Surname', 'StreetAddress',
'City', 'State', 'Country', 'PostalCode', 'Company', 'Title', 'Department', 'Description', 'OfficePhone'
'MobilePhone', 'HomePhone', 'Fax', 'SamAccountName', 'DistinguishedName', 'Office', 'Enabled'
'whenChanged', 'whenCreated', 'adminCount', 'Memberof', 'msExchPoliciesExcluded', 'proxyAddresses'
)
$Selectproperties = @(
'DisplayName', 'UserPrincipalName', 'mail', 'CN', 'mailNickname', 'Name', 'GivenName', 'Surname', 'StreetAddress',
'City', 'State', 'Country', 'PostalCode', 'Company', 'Title', 'Department', 'Description', 'OfficePhone'
'MobilePhone', 'HomePhone', 'Fax', 'SamAccountName', 'DistinguishedName', 'Office', 'Enabled'
'whenChanged', 'whenCreated', 'adminCount'
)
$CalculatedProps = @(
@{
n = 'proxyAddresses'
e = {
($_.proxyAddresses | Where-Object -FilterScript {
$_ -ne $null
}) -join '|'
}
},
@{
n = 'OU'
e = {
$_.DistinguishedName -replace '^.+?,(?=(OU|CN)=)'
}
},
@{
n = 'MemberOf'
e = {
($_.MemberOf | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
},
@{
n = 'msExchPoliciesExcluded'
e = {
($_.msExchPoliciesExcluded | Where-Object -FilterScript {
$_ -ne $null
}) -join ';'
}
}
)
}
}
process
{
if ($ADObjectFilter)
{
foreach ($CurADObjectFilter in $ADObjectFilter)
{
if (! $DetailedReport)
{
Get-ADObject -Filter $CurADObjectFilter -Properties $Props -ResultSetSize $null | Select-Object -Property ($Selectproperties + $CalculatedProps)
}
else
{
Get-ADObject -Filter $CurADObjectFilter -Properties * -ResultSetSize $null | Select-Object -Property ($Selectproperties + $CalculatedProps + $ExtensionAttribute)
}
}
}
else
{
if (! $DetailedReport)
{
Get-ADObject -Filter * -Properties $Props -ResultSetSize $null | Select-Object -Property ($Selectproperties + $CalculatedProps)
}
else
{
Get-ADObject -Filter * -Properties * -ResultSetSize $null | Select-Object -Property ($Selectproperties + $CalculatedProps + $ExtensionAttribute)
}
}
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,178 @@
function Get-enADServicePrincipalName
{
<#
.SYNOPSIS
Retrieves all Service Principal Names (SPNs)
.DESCRIPTION
Retrieves all Service Principal Names (SPNs) from Active Directory
.INPUTS
NONE
.OUTPUTS
PSObject
.EXAMPLE
PS /> Get-enADServicePrincipalName
Retrieves all Service Principal Names (SPNs) from Active Directory
.EXAMPLE
PS ~> Get-enADServicePrincipalName | Where-Object -FilterScript { $_.ObjectClass -eq 'user' }
Retrieves all user class Service Principal Names (SPNs) from Active Directory
.EXAMPLE
PS ~> Get-enADServicePrincipalName | Where-Object -FilterScript { $_.DNSHostName -like 'server01.contoso.com' }
Retrieves all Service Principal Names (SPNs) for the Server 'server01.contoso.com' from Active Directory
.EXAMPLE
PS ~> Get-enADServicePrincipalName | Where-Object -FilterScript { $_.Name -like '*Krb*' }
Retrieves all Kerberos related Service Principal Names (SPNs) from Active Directory
.EXAMPLE
PS ~> Get-enADServicePrincipalName | Where-Object -FilterScript { $_.SPN -like '*Krb*' }
Retrieves all Kerberos related Service Principal Names (SPNs) from Active Directory
.EXAMPLE
PS ~> Get-enADServicePrincipalName | Export-Csv -Path C:\scripts\PowerShell\Reports\ADServicePrincipalNames.csv
Retrieves all Service Principal Names (SPNs) from Active Directory and export them to a CSV
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
Dependencies:
Active Directory PowerShell Module
.LINK
https://www.enatec.io
.LINK
Get-ADObject
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param ()
begin
{
# Create a new Object
$AllObject = @()
}
process
{
try
{
# We use Get-ADObject because this seems to be fast enough
$paramGetADObject = @{
Filter = "(objectClass -eq 'user') -or (objectClass -eq 'computer') -and (servicePrincipalName -like '*')"
Properties = 'Name', 'servicePrincipalName', 'DistinguishedName', 'ObjectClass', 'DNSHostName', 'whenCreated'
}
$AllServicePrincipalNames = (Get-ADObject @paramGetADObject)
# Loop over the List we got from Get-ADObject
foreach ($SingleServicePrincipalName in $AllServicePrincipalNames)
{
# Get the values for the Service Principal Name
$ObjectClass = $SingleServicePrincipalName.ObjectClass
$DistinguishedName = $SingleServicePrincipalName.DistinguishedName
$Name = $SingleServicePrincipalName.Name
$whenCreated = $SingleServicePrincipalName.whenCreated
$DNSHostName = $SingleServicePrincipalName.DNSHostName
# Loop over all Service Principal Names - Remeber, there could be more then one Service Principal Names value per record
foreach ($ServicePrincipalName in $SingleServicePrincipalName.servicePrincipalName)
{
# Create a new Object
$SingleObject = (New-Object -TypeName PSObject -Property @{
Name = $Name
SPN = $ServicePrincipalName
ObjectClass = $ObjectClass
DistinguishedName = $DistinguishedName
WhenCreated = $whenCreated
DNSHostName = $DNSHostName
})
# Add the Values to the List
$AllObject += $SingleObject
# Cleanup
$SingleObject = $null
}
}
}
catch
{
#region ErrorHandler
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]@{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
}
$info | Out-String | Write-Verbose
Write-Error -Message ($info.Exception) -ErrorAction Stop
# Only here to catch a global ErrorAction overwrite
break
#endregion ErrorHandler
}
}
end
{
# Dump
$AllObject
# Cleanup
$AllObject = $null
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,132 @@
function Get-enADSiteAndSubnetInfo
{
<#
.SYNOPSIS
Retrieve Site names, subnets names and descriptions.
.DESCRIPTION
Retrieve Site names, subnets names and descriptions from the Active Directory
.EXAMPLE
PS ~> Get-enADSiteAndSubnetInfo
Retrieve Site names, subnets names and descriptions from the Active Directory
.EXAMPLE
PS ~> Get-enADSiteAndSubnetInfo | Export-Csv -Path C:\scripts\PowerShell\Reports\ADSiteInventory.csv
Retrieve Site names, subnets names and descriptions from the Active Directory
.OUTPUTS
PSObject
.NOTES
Releasenotes:
1.0.1 2019-07-26 Refactored, License change to BSD 3-Clause
1.0.0 2019-01-01 Initial Version
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
Dependencies:
Active Directory PowerShell Module
.LINK
https://www.enatec.io
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param ()
begin
{
Write-Verbose -Message '[BEGIN] Starting Script...'
}
process
{
try
{
# Domain and Sites Information
$Forest = ([DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest())
$SiteInfo = ([DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites)
# Forest Context
$ForestType = ([DirectoryServices.ActiveDirectory.DirectoryContexttype]'forest')
$ForestContext = (New-Object -TypeName System.DirectoryServices.ActiveDirectory.DirectoryContext -ArgumentList $ForestType, $Forest)
# Distinguished Name of the Configuration Partition
$Configuration = ([ADSI]'LDAP://RootDSE').configurationNamingContext
# Get the Subnet Container
$SubnetsContainer = ([ADSI]('LDAP://CN=Subnets,CN=Sites,{0}' -f $Configuration))
$SubnetsContainerchildren = ($SubnetsContainer.Children)
foreach ($item in $SiteInfo)
{
Write-Verbose -Message ('[PROCESS] SITE: {0}' -f $item.name)
$output = @{
Name = $item.name
}
foreach ($i in $item.Subnets.name)
{
Write-Verbose -Message ('[PROCESS] SUBNET: {0}' -f $i)
$output.Subnet = $i
$SubnetAdditionalInfo = $SubnetsContainerchildren.Where( {
$_.name -match $i
})
Write-Verbose -Message ('[PROCESS] SUBNET: {0} - DESCRIPTION: {1}' -f $i, $SubnetAdditionalInfo.Description)
$output.Description = $($SubnetAdditionalInfo.Description)
Write-Verbose -Message '[PROCESS] OUTPUT INFO'
New-Object -TypeName PSObject -Property $output
}
}
}
catch
{
Write-Warning -Message '[PROCESS] Something Wrong Happened'
Write-Warning -Message $Error[0]
}
}
end
{
Write-Verbose -Message '[END] Script Completed!'
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,76 @@
Function Get-enDomainInfo
{
<#
.SYNOPSIS
Retrieve domain information include site details
.EXAMPLE
Get-enDomainInfo
.NOTES
#>
[CmdletBinding()]
Param ()
begin
{
$SelectProperties = 'Name', 'Forest', 'Parent', 'Children', 'DomainMode', 'DomainModeLevel', 'DomainControllers', 'PdcRoleOwner', 'RidRoleOwner', 'InfrastructureRoleOwner', 'Sites'
}
process
{
$CurrentDomain = [DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$null = ($CurrentDomain | Add-Member -MemberType NoteProperty -Name Sites -Value ([DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites))
$Domain = ($CurrentDomain | Select-Object -Property $SelectProperties)
<#
switch($domainModeLevel)
{
{$domainModeLevel -like "0"} {"2000 Mixed/Native"}
{$domainModeLevel -like "1"} {"2003 Interim"}
{$domainModeLevel -like "2"} {"2003"}
{$domainModeLevel -like "3"} {"2008"}
{$domainModeLevel -like "4"} {"2008 R2"}
{$domainModeLevel -like "5"} {"2012"}
{$domainModeLevel -like "6"} {"2012 R2"}
{$domainModeLevel -like "7"} {"2016"}
default {"Unknown"}
}
#>
}
end
{
$Domain
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2021, enabling Technology <http://enatec.io>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* 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.
* 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.

View File

@@ -0,0 +1,7 @@
# Legacy Notice
I no longer run Exchange, Skype for Business, or any other Office Server on Premises.
This is my personal [reaction](https://hochwald.net/microsoft-rolls-back-decision-to-take-away-internal-usage-rights-from-partners/) to the changes that Microsoft [announced](https://hochwald.net/microsoft-is-going-to-kill-internal-use-rights-benefit-for-partners/) for the Internal Use Rights (IUR) program. I know that they decided to reverse that changes and in theory, I could still legally use the software. However, I decided to decommission everything licensed under the terms of the Internal Use Rights (IUR) program.
In my opinion, the community always should have some benefits from the Internal Use Rights (IUR) program and/or Action Pack. Now that I decided to drop out, there will be no more such benefits.
I will _no longer maintain_ the scripts related to the Microsoft Office (on Premises) servers. They will remain here, but unmaintained. Fork the repository and maintain or extend them if you like to. The [License](https://github.com/jhochwald/PowerShell-collection/blob/master/LICENSE) allows that easily.

View File

@@ -0,0 +1,413 @@
#requires -Version 3.0 -Modules ActiveDirectory
<#
.SYNOPSIS
Tool that bulk imports or removes User pictures, based on AD Group Membership
.DESCRIPTION
Tool that bulk imports or removes User pictures, based on AD Group Membership
If a user is in both groups, the picture will be removed!
Idea based on my old tool to import Active Directory pictures.
They are a bit to tiny, so I use Exchange now to make them look better in Exchange and Skype.
.PARAMETER AddGroup
Active Directory Group with users that would like to have a picture.
For all Members of this group, the Tool will try to set an image.
.PARAMETER RemGroup
Active Directory Group with users that would like have have the picture removed.
For all Members of this group, the Tool will try to remove the existing image (If set).
.PARAMETER PictureDir
Directory that contains the pictures
.PARAMETER Extension
Extension of the pictures
.PARAMETER workaround
Workaround for Exchange 2016 on Windows Server 2016
.PARAMETER UPNDomain
The default Domain, to add to the UPN
.EXAMPLE
# Use the Groups 'ADDPIXX' and 'NOPIXX' to Set/Remove the User Pictures
# There was an Issue with the User joerg.hochwald (Possible Picture Problem!
PS C:\> .\Set-ADAllUserPicture.ps1 -AddGroup 'ADDPIXX' -RemGroup 'NOPIXX' -PictureDir 'c:\upixx\' -workaround -UPNDomain 'jhochwald.com'
WARNING: Unable to set Image c:\upixx\joerg.hochwald.jpg for User joerg.hochwald
.EXAMPLE
# Use the Groups 'ADDPIXX' and 'NOPIXX' to Set/Remove the User Pictures
# There was an Issue with the User jane.doe - Check that this user has a provissioned Mailbox (on Prem or Cloud)
PS C:\> .\Set-ADAllUserPicture.ps1 -AddGroup 'ADDPIXX' -RemGroup 'NOPIXX' -PictureDir 'c:\upixx\' -workaround -UPNDomain 'jhochwald.com'
WARNING: Unable to handle jane.doe - Check that this user has a valid Mailbox!
.EXAMPLE
# Use the Groups 'ADDPIXX' and 'NOPIXX' to Set/Remove the User Pictures - Everything went well
PS C:\> .\Set-ADAllUserPicture.ps1 -AddGroup 'ADDPIXX' -RemGroup 'NOPIXX' -PictureDir 'c:\upixx\' -workaround -UPNDomain 'jhochwald.com'
WARNING: Unable to handle jane.doe - Check that this user has a valid Mailbox!
.NOTES
TODO: There is no logging! Only the Exchange RBAC logging is in use
TODO: A few error handlers are still missing
If a user is in both groups, the picture will be removed!
Verbose could be very verbose. This is due to the fact, that the complete Exchange logging will be shown!
There are a few possibilities for Warnings and Errors. (Mostly for missing things)
Disclaimer: The code is provided 'as is,' with all possible faults, defects or errors, and without warranty of any kind.
#>
param
(
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1,
HelpMessage = 'Active Directory Group with users that would like to have a picture')]
[ValidateNotNullOrEmpty()]
[Alias('positive')]
[string]
$AddGroup,
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 2,
HelpMessage = 'Active Directory Group with users that would like have have the picture removed.')]
[ValidateNotNullOrEmpty()]
[string]
$RemGroup,
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 3,
HelpMessage = 'Directory that contains the picures')]
[ValidateNotNullOrEmpty()]
[Alias('PixxDir')]
[string]
$PictureDir,
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 5)]
[Alias('defaultDomain')]
[string]
$UPNDomain,
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 4)]
[ValidateSet('png', 'jpg', 'gif', 'bmp')]
[ValidateNotNullOrEmpty()]
[string]
$Extension = 'jpg',
[switch]
$workaround = $false
)
begin
{
if ($workaround)
{
# Unsupported Workaround according to https://hochwald.net/workaround-for-get-help-issue-with-exchange-2016-on-windows-server-2016/
$null = (Add-PSSnapin -Name Microsoft.Exchange.Management.PowerShell.SnapIn)
}
# Cleanup
$AddUserPixx = $null
$NoUserPixx = $null
# Check the source directory string and fix it if needed
if (-not ($PictureDir).EndsWith('\'))
{
# Fix it
$PictureDir = $PictureDir + '\'
$paramWriteVerbose = @{
Message = 'Fixed the Source Directory String!'
}
Write-Verbose @paramWriteVerbose
}
try
{
$paramGetADGroupMember = @{
Identity = $AddGroup
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
$AddUserPixx = (Get-ADGroupMember @paramGetADGroupMember | Select-Object -ExpandProperty samaccountname)
}
catch
{
$paramWriteError = @{
Message = ('Unable to find {0}' -f $AddGroup)
ErrorAction = 'Stop'
}
Write-Error @paramWriteError
return
}
try
{
$paramGetADGroupMember = @{
Identity = $RemGroup
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
$NoUserPixx = (Get-ADGroupMember @paramGetADGroupMember | Select-Object -ExpandProperty samaccountname)
}
catch
{
$paramWriteError = @{
Message = ('Unable to find {0}' -f $AddGroup)
ErrorAction = 'Stop'
}
Write-Error @paramWriteError
return
}
function Test-ValidEmail
{
<#
.SYNOPSIS
Simple Function to check if a String is a valid Mail
.DESCRIPTION
Simple Function to check if a String is a valid Mail and return a Bool
.PARAMETER address
Address String to Check
.EXAMPLE
# Not a valid String
PS C:\> Test-ValidEmail -address 'Joerg.Hochwald'
False
.EXAMPLE
# Valid String
PS C:\> Test-ValidEmail -address 'Joerg.Hochwald@outlook.com'
True
.NOTES
Disclaimer: The code is provided 'as is,' with all possible faults, defects or errors, and without warranty of any kind.
Author: Joerg Hochwald
#>
[OutputType([bool])]
param
(
[Parameter(Mandatory,
HelpMessage = 'Address String to Check')]
[ValidateNotNullOrEmpty()]
[string]
$address
)
process
{
($address -as [mailaddress]).Address -eq $address -and $address -ne $null
}
}
}
process
{
if (-not ($AddUserPixx.samaccountname))
{
$paramWriteVerbose = @{
Message = ('The AD Group {0} has no members.' -f $AddGroup)
}
Write-Verbose @paramWriteVerbose
}
else
{
# Add a counter
$AddUserPixxCount = (($AddUserPixx.samaccountname).count)
$paramWriteVerbose = @{
Message = ('The AD Group {0} has {1} members.' -f $AddGroup, $AddUserPixxCount)
}
Write-Verbose @paramWriteVerbose
foreach ($AddUser in $AddUserPixx.samaccountname)
{
if (($NoUserPixx.samaccountname) -notcontains $AddUser)
{
# Check the UPN and Fix it, if possible
if (-not (Test-ValidEmail -address ($AddUser)))
{
if (-not ($UPNDomain))
{
# Whoopsie
$paramWriteError = @{
Message = 'UPN Default Domain not set but needed!'
ErrorAction = 'Stop'
}
Write-Error @paramWriteError
}
else
{
# Let us fix this
$AddUserUPN = ($AddUser + '@' + $UPNDomain)
}
}
# Build the Full Image Path
$SingleUserPicture = ($PictureDir + $AddUser + '.' + $Extension)
# Check if Picture exists
$paramTestPath = @{
Path = $SingleUserPicture
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
if (Test-Path @paramTestPath)
{
try
{
$paramSetUserPhoto = @{
Identity = $AddUserUPN
PictureData = ([IO.File]::ReadAllBytes($SingleUserPicture))
Confirm = $false
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
$null = (Set-UserPhoto @paramSetUserPhoto)
}
catch
{
$paramWriteWarning = @{
Message = ('Unable to set Image {0} for User {1}' -f $SingleUserPicture, $AddUser)
ErrorAction = 'SilentlyContinue'
}
Write-Warning @paramWriteWarning
}
}
else
{
$paramWriteWarning = @{
Message = ('The Image {0} for User {1} was not found' -f $SingleUserPicture, $AddUser)
ErrorAction = 'SilentlyContinue'
}
Write-Warning @paramWriteWarning
}
}
else
{
$paramWriteVerbose = @{
Message = ('Sorry, User {0} is member of {1} and {2}' -f $AddUser, $AddGroup, $RemGroup)
}
Write-Verbose @paramWriteVerbose
}
}
}
if (-not ($NoUserPixx.samaccountname))
{
$paramWriteVerbose = @{
Message = ('The AD Group {0} has no members.' -f $RemGroup)
}
Write-Verbose @paramWriteVerbose
}
else
{
# Add a counter
$NoUserPixxCount = (($NoUserPixx.samaccountname).count)
$paramWriteVerbose = @{
Message = ('The AD Group {0} has {1} members.' -f $RemGroup, $NoUserPixxCount)
}
Write-Verbose @paramWriteVerbose
foreach ($NoUser in $NoUserPixx.samaccountname)
{
# Check the UPN and Fix it, if possible
if (-not (Test-ValidEmail -address ($NoUser)))
{
if (-not ($UPNDomain))
{
# Whoopsie
$paramWriteError = @{
Message = 'UPN Default Domain not set but needed!'
ErrorAction = 'Stop'
}
Write-Error @paramWriteError
}
else
{
# Let us fix this
$NoUserUPN = ($NoUser + '@' + $UPNDomain)
}
}
$paramSetUserPhoto = @{
Identity = $NoUserUPN
Confirm = $false
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
try
{
$null = (Remove-UserPhoto @paramSetUserPhoto)
}
catch
{
$paramWriteWarning = @{
Message = ('Unable to handle {0} - Check that this user has a valid Mailbox!' -f $NoUser)
ErrorAction = 'SilentlyContinue'
}
Write-Warning @paramWriteWarning
}
}
}
}
end
{
# Cleaniup
$AddUserPixx = $null
$NoUserPixx = $null
$AddUserPixxCount = $null
$NoUserPixxCount = $null
# Do a garbage collection: Call the .NET function to cleanup some stuff
$null = ([GC]::Collect())
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER

View File

@@ -0,0 +1,118 @@
#requires -Version 3.0 -Modules ActiveDirectory
function Set-ADServerUsage
{
<#
.SYNOPSIS
Set all Active Directory related commands to use a special kind of server
.DESCRIPTION
By default the Active Directory related commands search for a DC. By default I want to make
use of the closest one. When I make BULK operations, I would like to use the Server with
the PDC role. This becomes handy often!
.PARAMETER pdc
Use the Active Directory Server who holds the PDC role.
.EXAMPLE
# Use the closest Server
PS> Set-ADServerUsage
.EXAMPLE
# Use the Server with the PDC role
PS> Set-ADServerUsage -pdc
.EXAMPLE
# When it comes to scripts that do bulk operations, especially bulk loads and manipulation,
# I use the following within the Script:
if (Get-Command Set-ADServerUsage -ErrorAction SilentlyContinue)
{
Set-ADServerUsage -pdc
}
.NOTES
I use this helper function in my PROFILE. Therefore, some things a bit special.
Who want's an error message every time a window opens under normal circumstances?
#>
param
(
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1)]
[switch]
$pdc
)
begin
{
# Defaults
$SC = 'SilentlyContinue'
# Cleanup
$dc = $null
}
process
{
<#
The following would do the trick:
#requires -Modules ActiveDirectory
But I don't want any error messages, so I decided to use this old-school way to figure
out if we are capable do what I want.
#>
if ((Get-Command -Name Get-ADDomain -ErrorAction $SC) -and (Get-Command -Name Get-ADDomainController -ErrorAction $SC) )
{
if ($pdc)
{
# Use the PDC instead
$dc = ((Get-ADDomain -ErrorAction $SC -WarningAction $SC).PDCEmulator)
}
else
{
# Use the closest DC
$dc = (Get-ADDomainController -Discover -NextClosestSite -ErrorAction $SC -WarningAction $SC)
}
# Skip everything if we do NOT have the proper information.
<#
Under normal circumstances this is pretty useless, but I use some virtual machines that have the RSAT tools installed, but they are not domain joined.
The fore I make this check. If all the systems that have the RSAT installed are domain joined, this test is obsolete.
#>
if ($dc)
{
# Make use of the Server from above
$PSDefaultParameterValues.add('*-AD*:Server', "$dc")
}
}
}
}
#region LICENSE
<#
BSD 3-Clause License
Copyright (c) 2021, enabling Technology
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.
#>
#endregion LICENSE
#region DISCLAIMER
<#
DISCLAIMER:
- Use at your own risk, etc.
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
- This is a third-party Software
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
- The Software is not supported by Microsoft Corp (MSFT)
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
#>
#endregion DISCLAIMER