Added Files
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
29
Powershell/PowerShell-collection/ActiveDirectory/LICENSE
Normal file
29
Powershell/PowerShell-collection/ActiveDirectory/LICENSE
Normal 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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,255 @@
|
||||
function Invoke-AdvancedInstallerUpdate
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sample function to rebuild a given Advanced Installer Project
|
||||
|
||||
.DESCRIPTION
|
||||
Rebuild a given Advanced Installer Project.
|
||||
Sample script to update the build Number from our build server and create a new MSI installer.
|
||||
|
||||
.PARAMETER Project
|
||||
Advanced installer project name (the name of the Project file, without the AIP extension).
|
||||
Example: DummyProduct for DummyProduct.aip
|
||||
|
||||
.PARAMETER Path
|
||||
Specifies the path to Advanced Installer Project File.
|
||||
|
||||
.PARAMETER Version
|
||||
Version of the new build.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-AdvancedInstallerUpdate -Project 'DummyProduct' -Path 'x:\dev\projects\DummyProduct\' -Version '1.0.3'
|
||||
|
||||
.NOTES
|
||||
Sample Project
|
||||
|
||||
.LINK
|
||||
https://www.advancedinstaller.com/user-guide/powershell-automation.html
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Advanced installer project name (the name of the Project file, without the AIP extension).')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('ProjectName', 'aipName')]
|
||||
[string]
|
||||
$Project,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Specifies the path to Advanced Installer Project File.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('aipPath')]
|
||||
[string]
|
||||
$Path,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2,
|
||||
HelpMessage = 'Version of the new build.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('aipVersion')]
|
||||
[string]
|
||||
$Version
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Create the full path of the Avanced Installer Project file
|
||||
$AdvancedInstallerProjectName = $Path + $Project + '.aip'
|
||||
|
||||
# Check if the File exists
|
||||
if (-not (Test-Path -Path $AdvancedInstallerProjectName -ErrorAction SilentlyContinue))
|
||||
{
|
||||
#region ErrorHandler
|
||||
$paramWriteError = @{
|
||||
Message = ('The given File {0} was not found' -f $AdvancedInstallerProjectName)
|
||||
TargetObject = $AdvancedInstallerProjectName
|
||||
Category = 'ObjectNotFound'
|
||||
RecommendedAction = 'Check filename'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
|
||||
# New Version number
|
||||
$AdvancedInstallerProjectVersion = $Version
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Cleanup
|
||||
$AdvancedInstallerProject = $null
|
||||
|
||||
# Creates a new PS object for Advanced Installer interaction
|
||||
$AdvancedInstaller = (New-Object -ComObject AdvancedInstaller)
|
||||
|
||||
# Load the Advanced Installer object
|
||||
try
|
||||
{
|
||||
$AdvancedInstallerProject = $AdvancedInstaller.LoadProject($AdvancedInstallerProjectName)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
if ($AdvancedInstallerProject)
|
||||
{
|
||||
# Modidy the version number
|
||||
$AdvancedInstallerProject.ProductDetails.Version = $AdvancedInstallerProjectVersion
|
||||
|
||||
try
|
||||
{
|
||||
# Build the project
|
||||
$AdvancedInstallerProjectBuild = ($AdvancedInstallerProject.Build())
|
||||
|
||||
Write-Verbose -Message $AdvancedInstallerProjectBuild
|
||||
|
||||
# Save the modified file
|
||||
try
|
||||
{
|
||||
# Note: Remove the $null if you would like to see the output
|
||||
$null = ($AdvancedInstallerProject.SaveAs($AdvancedInstallerProjectName))
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Error -Message 'Build failed'
|
||||
}
|
||||
finally
|
||||
{
|
||||
# Cleanup
|
||||
$AdvancedInstallerProject = $null
|
||||
$AdvancedInstaller = $null
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#region ErrorHandler
|
||||
$paramWriteError = @{
|
||||
Message = ('Unable to load {0}' -f $AdvancedInstallerProjectName)
|
||||
TargetObject = $AdvancedInstallerProjectName
|
||||
Category = 'InvalidData'
|
||||
RecommendedAction = 'Check file'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Create a filter for the MSI
|
||||
$AdvancedInstallerProjectMSI = $Project + '.msi'
|
||||
|
||||
# Cleanup
|
||||
$AdvancedInstallerProjectMSIPath = $null
|
||||
|
||||
# Loop over the returned object and try to find the MSI
|
||||
$AdvancedInstallerProjectMSIPath = ($AdvancedInstallerProjectBuild.Split("`n") | ForEach-Object {
|
||||
if ($_ -match $AdvancedInstallerProjectMSI)
|
||||
{
|
||||
$_
|
||||
}
|
||||
})
|
||||
# TODO: The method is a bit crappy
|
||||
|
||||
if ($AdvancedInstallerProjectMSIPath)
|
||||
{
|
||||
Write-Host -Object $AdvancedInstallerProjectMSIPath
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'New MSI was not found' -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
|
||||
29
Powershell/PowerShell-collection/AdvancedInstaller/LICENSE
Normal file
29
Powershell/PowerShell-collection/AdvancedInstaller/LICENSE
Normal 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.
|
||||
@@ -0,0 +1,199 @@
|
||||
#requires -Version 3.0 -Modules AzureAD
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Script to monitor and return large number of user devices in Azure Active Directory.
|
||||
|
||||
.DESCRIPTION
|
||||
Script to monitor and return large number of user devices in Active Directory.
|
||||
The default limit in Azure is 20 devices
|
||||
|
||||
.PARAMETER All
|
||||
If true, return all users.
|
||||
|
||||
.PARAMETER HighDeviceCount
|
||||
Enter the threshold for devices that you want to return
|
||||
|
||||
.EXAMPLE
|
||||
Get-AzureADUserDevices.ps1 -HighDeviceCount 15 -All $true
|
||||
|
||||
.EXAMPLE
|
||||
Get-AzureADUserDevices.ps1 -HighDeviceCount 5 -All $true
|
||||
|
||||
.NOTES
|
||||
Reworked version of Ben Whitmore Get-UserDevices that use the AzureAD module instead of the MsolService module
|
||||
|
||||
.LINK
|
||||
https://github.com/byteben/AzureAD/blob/master/Get-UserDevices.ps1
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$HighDeviceCount = 15,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1)]
|
||||
[bool]
|
||||
$All
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Defaults
|
||||
$STP = 'Stop'
|
||||
|
||||
# Set some default
|
||||
if (-not ($HighDeviceCount))
|
||||
{
|
||||
$HighDeviceCount = 15
|
||||
}
|
||||
|
||||
# Connect to Azure Active Directory, if needed
|
||||
if ($AzureActiveDirectoryConnection.Account -eq $null)
|
||||
{
|
||||
try
|
||||
{
|
||||
$Global:AzureActiveDirectoryConnection = (Connect-AzureAD -ErrorAction $STP)
|
||||
}
|
||||
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 $STP
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
# Initialize Array to hold users and number of devices
|
||||
$DeviceCountHigh = @()
|
||||
|
||||
try
|
||||
{
|
||||
# Splatting
|
||||
$paramGetAzureADUser = @{
|
||||
filter = "userType eq 'Member'"
|
||||
All = $All
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Get list of users from Azure Active Directory
|
||||
$Users = (Get-AzureADUser @paramGetAzureADUser | Select-Object -Property UserPrincipalName, ObjectId)
|
||||
|
||||
# Splatting
|
||||
$paramGetAzureADDevice = @{
|
||||
All = $true
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Get a list of Devices and the ownership information from the Azure Active Directory
|
||||
$Devices = (Get-AzureADDevice @paramGetAzureADDevice | Get-AzureADDeviceRegisteredOwner -ErrorAction $STP)
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
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 $STP
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
foreach ($User in $Users)
|
||||
{
|
||||
# For each user returned, count their Registered Devices
|
||||
$Device = ($Devices | Where-Object {
|
||||
$_.UserPrincipalName -eq $User.UserPrincipalName
|
||||
} | Measure-Object)
|
||||
|
||||
# If the number of registered devices measured is high, create a new PSObject
|
||||
if ($Device.Count -ge $HighDeviceCount)
|
||||
{
|
||||
# Create a new PSObject
|
||||
$DeviceCountMember = @()
|
||||
|
||||
# Fill the values
|
||||
$DeviceCountMember = (New-Object -TypeName PSObject)
|
||||
$DeviceCountMember | Add-Member -MemberType NoteProperty -Name 'UserPrincipalName' -Value $User.UserPrincipalName
|
||||
$DeviceCountMember | Add-Member -MemberType NoteProperty -Name 'DeviceCount' -Value $Device.Count
|
||||
|
||||
# Add to the PSObject
|
||||
$DeviceCountHigh += $DeviceCountMember
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Display Users with high number of devices
|
||||
$DeviceCountHigh | Sort-Object -Property DeviceCount -Descending
|
||||
}
|
||||
|
||||
#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
|
||||
29
Powershell/PowerShell-collection/AzureAD/LICENSE
Normal file
29
Powershell/PowerShell-collection/AzureAD/LICENSE
Normal 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.
|
||||
@@ -0,0 +1,87 @@
|
||||
#requires -Version 1.0
|
||||
|
||||
function Get-DsRegStatusInfo
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Wrapper function for the dsregcmd command
|
||||
|
||||
.DESCRIPTION
|
||||
Wrapper function for the dsregcmd command
|
||||
Nothing fancy, but it should convert the plain text output of dsregcmd to a PSObject
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-DsRegStatusInfo
|
||||
|
||||
Returns a PSObject with the values of dsregcmd
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> $AADInfo = (Get-DsRegStatusInfo | Select-Object -Property AzureAdJoined,WorkplaceJoined)
|
||||
PS C:\> if ( ($AADInfo.AzureAdJoined -ne 'YES') -and ($AADInfo.WorkplaceJoined -ne 'YES') ) {throw 'Not AzureAD bound'}
|
||||
|
||||
Check if the system is joined to the AzureAD (fully or just WorkplaceJoined)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> $AADInfo = (Get-DsRegStatusInfo | Select-Object -Property AzureAdJoined, WorkplaceJoined)
|
||||
PS C:\> if ($AADInfo.AzureAdJoined -eq 'YES') {'AzureAd Joined'} elseif ($AADInfo.WorkplaceJoined -eq 'YES') {'Workplace Joined'} else {'Unknown'}
|
||||
|
||||
Check if the system is joined to the AzureAD (fully or just WorkplaceJoined)
|
||||
|
||||
.NOTES
|
||||
Replaced my old ConvertFrom-String based wrapper implementation, this is more flexible
|
||||
|
||||
.LINK
|
||||
http://hochwald.net
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
$DsRegCmdPlain = (& "$env:windir\system32\dsregcmd.exe" /status)
|
||||
$DsRegStatusInfo = (New-Object -TypeName PSObject)
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$DsRegCmdPlain | Select-String -Pattern ' *[A-z]+ : [A-z]+ *' | ForEach-Object -Process {
|
||||
$null = (Add-Member -InputObject $DsRegStatusInfo -MemberType NoteProperty -Name (([String]$_).Trim() -split ' : ')[0] -Value (([String]$_).Trim() -split ' : ')[1] -ErrorAction SilentlyContinue)
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
$DsRegStatusInfo
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,152 @@
|
||||
#requires -Version 2.0 -Modules BitLocker
|
||||
#requires -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Backup the BitLocker Recovery Information to the Azure Active Directory
|
||||
|
||||
.DESCRIPTION
|
||||
Backup the BitLocker Recovery Information to the Azure Active Directory
|
||||
If the Boot Drive is not encrypted, the Script will try to enable the quick protection
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-BackupBitlockerRecoveryKey.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> $AADInfo = (Get-DsRegStatusInfo | Select-Object -Property AzureAdJoined,WorkplaceJoined)
|
||||
PS C:\> if ( ($AADInfo.AzureAdJoined -ne 'YES') -and ($AADInfo.WorkplaceJoined -ne 'YES') ) {throw 'Not AzureAD bound'} else {.\Invoke-BackupBitlockerRecoveryKey.ps1}
|
||||
|
||||
You may want to check if the device is AzureAD joined with Get-DsRegStatusInfo first
|
||||
|
||||
.NOTES
|
||||
Quick and relative dirty solution for a challenge I had in the last couple of days
|
||||
|
||||
.LINK
|
||||
Get-DsRegStatusInfo
|
||||
|
||||
.LINK
|
||||
http://hochwald.net
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# Defaults
|
||||
$LogName = 'Application'
|
||||
$STP = 'Stop'
|
||||
$SCT = 'SilentlyContinue'
|
||||
$LogSource = 'enAutomate'
|
||||
|
||||
# Register the event log source
|
||||
$null = (New-EventLog -LogName $LogName -Source $LogSource -ErrorAction $SCT)
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
try
|
||||
{
|
||||
# Get BitLocker Volume info
|
||||
$BitLockerVolumeInfo = (Get-BitLockerVolume -ErrorAction $STP | Where-Object -FilterScript {
|
||||
$_.VolumeType -eq 'OperatingSystem'
|
||||
})
|
||||
|
||||
# Get the Mount Point
|
||||
$BootDrive = $BitLockerVolumeInfo.MountPoint
|
||||
|
||||
# Check if the drive is encrypted
|
||||
if ($BitLockerVolumeInfo.ProtectionStatus -ne 'On')
|
||||
{
|
||||
$InfoMessage = ('Enable BitLocker for ' + $BootDrive)
|
||||
Write-Verbose -Message $InfoMessage
|
||||
$null = (Write-EventLog -LogName $LogName -Source $LogSource -EntryType Information -EventId 1000 -Message $InfoMessage -ErrorAction $SCT)
|
||||
|
||||
# Now we try to activate BitLocker (-UsedSpaceOnly is not perfect, but much faster in this case
|
||||
$null = (Enable-BitLocker -MountPoint $BootDrive -EncryptionMethod XtsAes128 -UsedSpaceOnly -SkipHardwareTest -RecoveryPasswordProtector -Confirm:$false -ErrorAction $STP)
|
||||
}
|
||||
|
||||
# Get the correct ID (The one from the RecoveryPassword)
|
||||
$BitLockerKeyProtectorId = ($BitLockerVolumeInfo.KeyProtector | Where-Object -FilterScript {
|
||||
$_.KeyProtectorType -eq 'RecoveryPassword'
|
||||
} | Select-Object -ExpandProperty KeyProtectorId)
|
||||
|
||||
# Check if we have a recovery password/id
|
||||
if ($BitLockerKeyProtectorId)
|
||||
{
|
||||
# Do the backup towards AzureAD
|
||||
$null = (BackupToAAD-BitLockerKeyProtector -MountPoint $BootDrive -KeyProtectorId $BitLockerKeyProtectorId -Confirm:$false -ErrorAction $STP)
|
||||
|
||||
$InfoMessage = ('The Recovery Infor for ' + $BootDrive + ' was saved to the Azure Active Directory')
|
||||
Write-Verbose -Message $InfoMessage
|
||||
$null = (Write-EventLog -LogName $LogName -Source $LogSource -EntryType Information -EventId 1000 -Message $InfoMessage -ErrorAction $SCT)
|
||||
}
|
||||
else
|
||||
{
|
||||
$WarningMessage = ('No Recorvery Information for ' + $BootDrive + ' found...')
|
||||
Write-Warning -Message $WarningMessage
|
||||
$null = (Write-EventLog -LogName $LogName -Source $LogSource -EntryType Warning -EventId 1001 -Message $WarningMessage -ErrorAction $SCT)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# Error Stack
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
# Save to the Event Log
|
||||
$null = (Write-EventLog -LogName $LogName -Source $LogSource -EntryType Error -EventId 1001 -Message ($info.Exception) -ErrorAction $SCT)
|
||||
|
||||
# Just display the info on continue with the rest of the list
|
||||
$paramWriteError = @{
|
||||
Message = ($info.Exception)
|
||||
Exception = $info.Exception
|
||||
TargetObject = $info.Target
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
29
Powershell/PowerShell-collection/BitLocker/LICENSE
Normal file
29
Powershell/PowerShell-collection/BitLocker/LICENSE
Normal 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.
|
||||
@@ -0,0 +1,144 @@
|
||||
#requires -Version 2.0 -Modules BitLocker
|
||||
#requires -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create a new BitLocker Recovery Key
|
||||
|
||||
.DESCRIPTION
|
||||
Create a new BitLocker Recovery Key
|
||||
We will just create a new one, but we will not show it.
|
||||
You should store it into the AzureAD, or a least in the Active Directory
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-BitlockerRecoveryKey.ps1
|
||||
|
||||
.NOTES
|
||||
Quick and relative dirty solution for a challange I had in the last couple of days
|
||||
By the way: Only the Boot Drive is supported by default.
|
||||
|
||||
.LINK
|
||||
Add-BitLockerKeyProtector
|
||||
|
||||
.LINK
|
||||
http://hochwald.net
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# Defaults
|
||||
$LogName = 'Application'
|
||||
$STP = 'Stop'
|
||||
$SCT = 'SilentlyContinue'
|
||||
$LogSource = 'enAutomate'
|
||||
|
||||
# Register the event log source
|
||||
$null = (New-EventLog -LogName $LogName -Source $LogSource -ErrorAction $SCT)
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get BitLocker Volume info
|
||||
$BitLockerVolumeInfo = (Get-BitLockerVolume | Where-Object -FilterScript {
|
||||
$_.VolumeType -eq 'OperatingSystem'
|
||||
})
|
||||
|
||||
# Get the Mount Point
|
||||
$BootDrive = $BitLockerVolumeInfo.MountPoint
|
||||
|
||||
# Get the Key
|
||||
$KeyProtectors = $BitLockerVolumeInfo.KeyProtector
|
||||
|
||||
# Check if the Boot Drive is encrypted
|
||||
if (($BitLockerVolumeInfo.VolumeStatus -eq 'FullyDecrypted') -or ($BitLockerVolumeInfo.ProtectionStatus -eq 'Off') -or (-not ($KeyProtectors)))
|
||||
{
|
||||
Write-Warning -Message ('Please Exceute: "Enable-BitLocker -MountPoint {0}"' -f $BootDrive)
|
||||
break
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($KeyProtector in $KeyProtectors)
|
||||
{
|
||||
if ($KeyProtector.KeyProtectorType -eq 'RecoveryPassword')
|
||||
{
|
||||
try
|
||||
{
|
||||
# Remove the existing Recovery Password
|
||||
$null = (Remove-BitLockerKeyProtector -MountPoint $BootDrive -KeyProtectorId $KeyProtector.KeyProtectorId -ErrorAction $STP)
|
||||
|
||||
# Just add a new Recovery Password without showing it here. We store than in the AzureAD anyway!
|
||||
$null = (Add-BitLockerKeyProtector -MountPoint $BootDrive -RecoveryPasswordProtector -WarningAction SilentlyContinue)
|
||||
|
||||
# If we get this far, eveything has worked, write a success to the event log
|
||||
$InfoText = 'Changed the BitLocker Recovery Password for ' + $BootDrive + ' successfully'
|
||||
Write-EventLog -LogName $LogName -Source $LogSource -EntryType Information -EventId 1000 -Message $InfoText
|
||||
Write-Output -InputObject $InfoText
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# Error Stack
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
# Save to the Event Log
|
||||
$null = (Write-EventLog -LogName $LogName -Source $LogSource -EntryType Error -EventId 1001 -Message ($info.Exception) -ErrorAction $SCT)
|
||||
|
||||
# Just display the info on continue with the rest of the list
|
||||
$paramWriteError = @{
|
||||
Message = ($info.Exception)
|
||||
Exception = $info.Exception
|
||||
TargetObject = $info.Target
|
||||
ErrorAction = $STP
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,420 @@
|
||||
#requires -Version 2.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Exchange Server Logs Cleanup
|
||||
|
||||
.DESCRIPTION
|
||||
Cleanup some Exchange Server logs.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\CleanupExchangeLogs.ps1
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.1 2019-07-08: Move the delete process to the dedicated Invoke-CleanupOldFiles function
|
||||
1.0.0 2019-02-04: Internal 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
|
||||
Invoke-CleanupOldFiles
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# You can change the number of days here
|
||||
$days = 30
|
||||
|
||||
#region PowerShell2WorkArounds
|
||||
<#
|
||||
The following stuff is a workaround to make everything compatible to PowerShell 2.0
|
||||
Old, but some still have the old crap on the Exchange server running, sorry!
|
||||
#>
|
||||
#region RequiredModuleWorkAround
|
||||
if (Get-Module -Name webadministration -ListAvailable -ErrorAction SilentlyContinue)
|
||||
{
|
||||
try
|
||||
{
|
||||
$null = (Import-Module -Name webadministration -Force -ErrorAction Stop)
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
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
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#region ErrorHandler
|
||||
$paramWriteError = @{
|
||||
Message = 'The required Module (webadministration) is missing!'
|
||||
Category = 'ObjectNotFound'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
#endregion RequiredModuleWorkAround
|
||||
|
||||
#region RunAsAdministrator
|
||||
function Test-Administrator
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Check if this is an elevated shell
|
||||
|
||||
.DESCRIPTION
|
||||
Check if this is an elevated shell.
|
||||
|
||||
In Powershell 4.0 it can be replaced with:
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Test-Administrator
|
||||
|
||||
.NOTES
|
||||
In Powershell 4.0 it can be replaced with: Requires -RunAsAdministrator
|
||||
|
||||
License: Public Domain
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([bool])]
|
||||
param ()
|
||||
|
||||
process
|
||||
{
|
||||
$user = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
(New-Object -TypeName Security.Principal.WindowsPrincipal -ArgumentList $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
|
||||
}
|
||||
}
|
||||
|
||||
if ((Test-Administrator) -ne $true)
|
||||
{
|
||||
#region ErrorHandler
|
||||
Write-Error -Message 'The current Windows PowerShell session is not running as Administrator. Start Windows PowerShell by using the Run as Administrator option, and then try running the script again.' -Category NotEnabled -ErrorAction Stop
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
#endregion RunAsAdministrator
|
||||
#endregion PowerShell2WorkArounds
|
||||
|
||||
# Cleanup
|
||||
$LogDirList = $null
|
||||
|
||||
# Create a new List
|
||||
$LogDirList = (New-Object -TypeName System.Collections.Generic.List[System.Object])
|
||||
|
||||
# Add static Directories to the new list
|
||||
if ($env:ExchangeInstallPath)
|
||||
{
|
||||
$LogDirList.Add($env:ExchangeInstallPath + 'Logging\')
|
||||
|
||||
# Another possible Directory
|
||||
#$LogDirList.Add($env:ExchangeInstallPath + 'Bin\Search\Ceres\Diagnostics\Logs\')
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'This is not a Exchange Server!'
|
||||
}
|
||||
|
||||
# Get a list of all IIS Websites and add to the new list
|
||||
$AllIISSites = (Get-Website)
|
||||
|
||||
if ($AllIISSites)
|
||||
{
|
||||
# Loop over the IIS Site list
|
||||
foreach ($SingleWebSite in $AllIISSites)
|
||||
{
|
||||
# Cleanup
|
||||
$IISLogDirectory = $null
|
||||
|
||||
# Get the Log-Directory from the IIS Info
|
||||
$IISLogDirectory = ($SingleWebSite.logfile.directory)
|
||||
|
||||
<#
|
||||
Replace the returned %SystemDrive% with your system drive.
|
||||
This is your BOOT Drive!!! Usually it is C:
|
||||
#>
|
||||
if ($IISLogDirectory -match '%SystemDrive%')
|
||||
{
|
||||
Write-Verbose -Message 'Mangle the SystemDrive within the variable...'
|
||||
|
||||
$IISLogDirectory = ($IISLogDirectory -replace '%SystemDrive%', 'C:')
|
||||
}
|
||||
|
||||
# Add the log Directory to the List
|
||||
$LogDirList.Add($IISLogDirectory)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No IIS Log-Directory found!'
|
||||
}
|
||||
|
||||
# Make all entries in the List unique
|
||||
$LogDirList = ($LogDirList | Sort-Object | Get-Unique)
|
||||
|
||||
#region Invoke-CleanupOldFiles
|
||||
function Invoke-CleanupOldFiles
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remove files older then a given number of days
|
||||
|
||||
.DESCRIPTION
|
||||
Remove files older then a given number of days.
|
||||
Mostly used within cleanup Tasks.
|
||||
|
||||
.PARAMETER Path
|
||||
Path to search.
|
||||
|
||||
.PARAMETER Age
|
||||
Age of files to remove, in days.
|
||||
Defaults to 30
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-CleanupoldFiles -Path 'C:\inetpub\logs\LogFiles'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-CleanupoldFiles -Path 'C:\inetpub\logs\LogFiles' -Age 14
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.1 2019-07-08: Rework and splatting
|
||||
1.0.0 2019-02-04: Internal 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
|
||||
Get-ChildItem
|
||||
|
||||
.LINK
|
||||
Test-Path
|
||||
|
||||
.LINK
|
||||
Get-Date
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true,
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
Position = 0,
|
||||
HelpMessage = 'Path to search.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('TargetFolder')]
|
||||
[string]
|
||||
$Path,
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
Position = 1)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Days')]
|
||||
[int]
|
||||
$Age = 30
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
if (Test-Path -Path $Path)
|
||||
{
|
||||
# Save the date to use it for the compare
|
||||
$Now = (Get-Date)
|
||||
|
||||
# Today minus given days
|
||||
$LastWrite = $Now.AddDays(-$days)
|
||||
|
||||
# Splatting the parameters
|
||||
$paramGetChildItem = @{
|
||||
Path = $Path
|
||||
Include = '*.log', '*.blg'
|
||||
Recurse = $true
|
||||
}
|
||||
|
||||
# Find all Files to Delete (e.g. older then the given value)
|
||||
$Files = (Get-ChildItem @paramGetChildItem | Where-Object -FilterScript {
|
||||
(-not ($_.PSIsContainer)) -and ($_.LastWriteTime -le $LastWrite)
|
||||
} | Select-Object -ExpandProperty fullname)
|
||||
|
||||
# Loop over the list of Files
|
||||
foreach ($File in $Files)
|
||||
{
|
||||
# Support for WhatIf and Verbose
|
||||
if ($pscmdlet.ShouldProcess($File, 'Remove'))
|
||||
{
|
||||
# Splatting the parameters
|
||||
$paramRemoveItem = @{
|
||||
Path = $File
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
Force = $true
|
||||
WhatIf = $false
|
||||
}
|
||||
# Remove the files that we found
|
||||
$null = (Remove-Item @paramRemoveItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Invoke-CleanupOldFiles
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Do we have a lif of directories?
|
||||
if ($LogDirList)
|
||||
{
|
||||
# Loop over the List of Directories
|
||||
foreach ($LogDir in $LogDirList)
|
||||
{
|
||||
Write-Verbose -Message "Removing logs from $LogDir older then $days days"
|
||||
|
||||
try
|
||||
{
|
||||
# Do we have a DAY value
|
||||
if ($days)
|
||||
{
|
||||
# Splatting the parameters
|
||||
$paramInvokeCleanupoldFiles = @{
|
||||
Path = $LogDir
|
||||
Age = $days
|
||||
ErrorAction = 'Stop'
|
||||
verbose = $true
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Splatting the parameters
|
||||
$paramInvokeCleanupoldFiles = @{
|
||||
Path = $LogDir
|
||||
ErrorAction = 'Stop'
|
||||
verbose = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Invoke the internal Fun
|
||||
Invoke-CleanupOldFiles @paramInvokeCleanupoldFiles
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#region ErrorHandler
|
||||
$paramWriteError = @{
|
||||
Message = 'No directories found to cleanup'
|
||||
Category = 'ObjectNotFound'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# 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
|
||||
@@ -0,0 +1,219 @@
|
||||
#requires -Version 3.0 -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Cleanup some of the Exchange Logs
|
||||
|
||||
.DESCRIPTION
|
||||
Cleanup some of the Exchange Logs
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-LogFileDirectory.ps1
|
||||
|
||||
.NOTES
|
||||
Wrapper for the Clear-LogFileDirectory function
|
||||
Everything is hardcoded for this wrapper ;-)
|
||||
|
||||
.LINK
|
||||
Clear-LogFileDirectory
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
# Files older then 1 day are deleted
|
||||
$Days = 1
|
||||
|
||||
# Exchange Base Directory
|
||||
$ExchangeBaseDir = 'D:\Exchange Server'
|
||||
|
||||
# Exchange Version (Directory)
|
||||
$ExchangeVersion = 'V15'
|
||||
|
||||
# Where to find the IIS stuff
|
||||
$IISBaseDir = "$env:HOMEDRIVE\inetpub"
|
||||
|
||||
|
||||
#region IIS
|
||||
# Append the Log Stuff for the Call below
|
||||
$IISLogPath = $IISBaseDir + '\logs\LogFiles\'
|
||||
#endregion IIS
|
||||
|
||||
#region Exchange
|
||||
# Combine the values
|
||||
$ExchangeDirectoryPath = $ExchangeBaseDir + '\' + $ExchangeVersion
|
||||
|
||||
# Append the Log Stuff for the Call below
|
||||
$ExchangeLoggingPath = $ExchangeDirectoryPath + '\Logging\'
|
||||
$ExchangeETLTraces = $ExchangeDirectoryPath + '\Bin\Search\Ceres\Diagnostics\ETLTraces\'
|
||||
$ExchangeETLLogs = $ExchangeDirectoryPath + '\Bin\Search\Ceres\Diagnostics\Logs'
|
||||
#endregion Exchange
|
||||
|
||||
#region HelperFunction
|
||||
function Clear-LogFileDirectory
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Cleanup Files in a given Directory
|
||||
|
||||
.DESCRIPTION
|
||||
Cleanup Files in a given Directory
|
||||
|
||||
.PARAMETER Path
|
||||
Specifies a path, multi-value or wildcards are not yet supported!
|
||||
No default so far!
|
||||
|
||||
.PARAMETER Days
|
||||
Age of the Files to Delete.
|
||||
Default is 7
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-LogFileDirectory -Path "c:\inetpub\logs\LogFiles\"
|
||||
|
||||
.NOTES
|
||||
Mind the Gap:
|
||||
Everything within the given directory will be deleted, without any further interaction!
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
HelpMessage = 'Specifies a path, multivalue or wildcards are not yet supported!')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Folder', 'TargetFolder')]
|
||||
[string]
|
||||
$Path,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Age', 'FileAge')]
|
||||
[int]
|
||||
$Days = 7
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$CNT = 'Continue'
|
||||
$SCT = 'SilentlyContinue'
|
||||
#endregion Defaults
|
||||
|
||||
Write-Verbose -Message ('START: Processing of {0}' -f $Path)
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if (Test-Path -Path $Path -ErrorAction $SCT)
|
||||
{
|
||||
$Now = (Get-Date)
|
||||
$LastWrite = $Now.AddDays(-$Days)
|
||||
|
||||
#region FindAndFilterFiles
|
||||
# Splat the Parameters
|
||||
$paramFindAndFilterFiles = @{
|
||||
Path = $Path
|
||||
Recurse = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$Files = (Get-ChildItem @paramFindAndFilterFiles | Where-Object -FilterScript {
|
||||
($_.Name -like '*.log') -or ($_.Name -like '*.blg') -or ($_.Name -like '*.etl')
|
||||
} | Where-Object -FilterScript {
|
||||
$_.lastWriteTime -le $LastWrite
|
||||
} | Select-Object -ExpandProperty FullName)
|
||||
#endregion FindAndFilterFiles
|
||||
|
||||
#region FileLooper
|
||||
foreach ($File in $Files)
|
||||
{
|
||||
Write-Verbose -Message ('Deleting file {0}' -f $File)
|
||||
try
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($File, 'Delete'))
|
||||
{
|
||||
#region DeleteFilesFound
|
||||
# Splat the Parameters
|
||||
$paramDeleteFilesFound = @{
|
||||
Path = $File
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Remove-Item @paramDeleteFilesFound)
|
||||
#endregion DeleteFilesFound
|
||||
}
|
||||
}
|
||||
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-Warning -Message ($info.Exception) -ErrorAction $CNT -WarningAction $CNT
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
#endregion FileLooper
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error -Message ("The folder {0} doesn't exist! Check the folder path!" -f $Path)
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message ('DONE: Processed {0}' -f $Path)
|
||||
}
|
||||
}
|
||||
#endregion HelperFunction
|
||||
|
||||
#region FunctionWrapper
|
||||
Clear-LogFileDirectory -Path $IISLogPath -Days $Days
|
||||
Clear-LogFileDirectory -Path $ExchangeLoggingPath -Days $Days
|
||||
Clear-LogFileDirectory -Path $ExchangeETLTraces -Days $Days
|
||||
Clear-LogFileDirectory -Path $ExchangeETLLogs -Days $Days
|
||||
#endregion FunctionWrapper
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,91 @@
|
||||
#requires -Version 2.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Enabling Modern Authentication for Exchange Online
|
||||
|
||||
.DESCRIPTION
|
||||
Enabling Modern Authentication for Exchange Online (Office 365)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Enable-ModernAuth-Exchange.ps1
|
||||
|
||||
.NOTES
|
||||
Works fine with Office 2013 and Office 2016 on Windows. Tested with Office 2016 on the Mac.
|
||||
You must enable it on your computers (Windows and Mac) as well! It is disabled by default.
|
||||
|
||||
.LINK
|
||||
https://blogs.technet.microsoft.com/canitpro/2015/09/11/step-by-step-setting-up-ad-fs-and-enabling-single-sign-on-to-office-365/
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# The Exchange Online URL
|
||||
$ExoURL = 'https://outlook.office365.com/powershell-liveid/'
|
||||
|
||||
# Same as above, but for the German Office 365 (MCD)
|
||||
#$ExoURL = 'https://outlook.office.de/powershell-liveid/'
|
||||
|
||||
# The Exchange Online Authentication method
|
||||
$ExoAuth = 'Basic'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the Credentials (Could also be imported if you have dem saved)
|
||||
$credentials = (Get-Credential)
|
||||
|
||||
# Create the new session
|
||||
$paramNewPSSession = @{
|
||||
ConfigurationName = 'Microsoft.Exchange'
|
||||
ConnectionUri = $ExoURL
|
||||
Credential = $credentials
|
||||
Authentication = $ExoAuth
|
||||
AllowRedirection = $true
|
||||
}
|
||||
$ExoSession = (New-PSSession @paramNewPSSession)
|
||||
|
||||
# Start the Session by importing it to the PowerShell Session
|
||||
$null = (Import-PSSession -Session $ExoSession)
|
||||
|
||||
# Enable Modern Authentication, use $false to disable it
|
||||
$null = (Set-OrganizationConfig -OAuth2ClientProfileEnabled $true)
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Cleanup
|
||||
$ExoSession = $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
|
||||
@@ -0,0 +1,226 @@
|
||||
function Get-ADExchangeServers
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get all Exchange Servers from Active Directory
|
||||
|
||||
.DESCRIPTION
|
||||
This function gets a list with info of all Exchange Servers from the Active Directory.
|
||||
The Exchange tools (or a PowerShell Connection) is not needed.
|
||||
That is the major difference to Get-ExchangeServer
|
||||
|
||||
.EXAMPLE
|
||||
# Get all Exchange Servers from Active Directory
|
||||
PS> Get-ADExchangeServers
|
||||
|
||||
path : http://nycexch01.contoso.com/powershell
|
||||
server : NYCEXCH01
|
||||
Fullver : Version 15.1 (Build 31034.26)
|
||||
version : 15.1
|
||||
Site : HQ
|
||||
|
||||
path : http://nycexch02.contoso.com/powershell
|
||||
server : NYCEXCH02
|
||||
Fullver : Version 15.1 (Build 31034.26)
|
||||
version : 15.1
|
||||
Site : HQ
|
||||
|
||||
.EXAMPLE
|
||||
# No Exchange Server found! (Error)
|
||||
PS> Get-ADExchangeServers
|
||||
|
||||
Get-ADExchangeServers : Unable to get the Exchange Information from the Active Directory!
|
||||
|
||||
.NOTES
|
||||
Only Exchange Servers with a configured PowerShell URI will be dumped
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
[OutputType([psobject])]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# Define some defaults
|
||||
$ErrorMessage = 'Unable to get the Exchange Information from the Active Directory!'
|
||||
$SC = 'SilentlyContinue'
|
||||
$STP = 'Stop'
|
||||
|
||||
# Search configuration partition for Exchange Servers where the powershell virtual directory is enabled
|
||||
try
|
||||
{
|
||||
$ActiveDirectoryInfo = (New-Object -TypeName adsisearcher -ArgumentList ([adsi]"LDAP://$(([adsi]'LDAP://rootdse').configurationNamingContext)"), '(&(objectclass=msExchPowerShellVirtualDirectory)(msexchinternalhostname=*))')
|
||||
}
|
||||
catch
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = $ErrorMessage
|
||||
ErrorAction = $STP
|
||||
WarningAction = $SC
|
||||
}
|
||||
|
||||
Write-Error @paramWriteError
|
||||
break
|
||||
}
|
||||
|
||||
if (-not ($ActiveDirectoryInfo))
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = $ErrorMessage
|
||||
ErrorAction = $STP
|
||||
WarningAction = $SC
|
||||
}
|
||||
|
||||
Write-Error @paramWriteError
|
||||
break
|
||||
}
|
||||
|
||||
# Create a new Object
|
||||
$ADExchangeInfo = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
try
|
||||
{
|
||||
$ActiveDirectoryInfo.findall() | Sort-Object -Descending -Property {
|
||||
$_.properties.msexchversion[0]
|
||||
} | ForEach-Object -Process {
|
||||
# Define some defauts
|
||||
$NONE = ' '
|
||||
$COM = ','
|
||||
|
||||
if ($_.properties.msexchinternalhostname[0])
|
||||
{
|
||||
if ($_.properties.distinguishedname[0])
|
||||
{
|
||||
$SrvLdapPath = ($_.properties.distinguishedname[0] -split $COM)[3 .. 100] -join $COM
|
||||
|
||||
try
|
||||
{
|
||||
$SingleServerObject = [adsi]"LDAP://$SrvLdapPath"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$SingleServerObject = $null
|
||||
}
|
||||
|
||||
if ($SingleServerObject)
|
||||
{
|
||||
if ($SingleServerObject.serialnumber[0])
|
||||
{
|
||||
$SingleFullVersion = $SingleServerObject.serialnumber[0]
|
||||
}
|
||||
else
|
||||
{
|
||||
$SingleFullVersion = $null
|
||||
}
|
||||
|
||||
if (($SingleServerObject.serialNumber -split $NONE)[1])
|
||||
{
|
||||
$SingleShortVersion = ($SingleServerObject.serialNumber -split $NONE)[1]
|
||||
}
|
||||
else
|
||||
{
|
||||
$SingleShortVersion = $null
|
||||
}
|
||||
|
||||
if ($SingleServerObject.name[0])
|
||||
{
|
||||
$SingleServer = $SingleServerObject.name[0]
|
||||
}
|
||||
else
|
||||
{
|
||||
$SingleServer = $null
|
||||
}
|
||||
|
||||
if ($SingleServerObject.msExchServerSite[0])
|
||||
{
|
||||
$SingleActiveDirectorySite = $SingleServerObject.msExchServerSite[0] -replace '^CN=|,.*$', ''
|
||||
}
|
||||
else
|
||||
{
|
||||
$SingleActiveDirectorySite = $null
|
||||
}
|
||||
}
|
||||
|
||||
if ($_.properties.msexchinternalhostname[0])
|
||||
{
|
||||
# With each virtual directory create an object to represent its details,
|
||||
# if List Version or site is included, also find the server object
|
||||
$paramNewObject = @{
|
||||
TypeName = 'psobject'
|
||||
Property = @{
|
||||
path = $_.properties.msexchinternalhostname[0]
|
||||
server = $SingleServer
|
||||
Site = $SingleActiveDirectorySite
|
||||
version = $SingleShortVersion
|
||||
Fullver = $SingleFullVersion
|
||||
}
|
||||
}
|
||||
|
||||
$SingleExchangeInfo = (New-Object @paramNewObject)
|
||||
|
||||
# Append the Info to the Object
|
||||
$ADExchangeInfo += $SingleExchangeInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Do nothing
|
||||
Write-Verbose -Message 'Something went wrong...'
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Just dump the plain object
|
||||
if ($ADExchangeInfo)
|
||||
{
|
||||
$ADExchangeInfo
|
||||
}
|
||||
else
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = $ErrorMessage
|
||||
ErrorAction = $STP
|
||||
WarningAction = $SC
|
||||
}
|
||||
|
||||
Write-Error @paramWriteError
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,91 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Helper script to investigate a Hafnium attack
|
||||
|
||||
.DESCRIPTION
|
||||
Helper script to investigate a Hafnium attack
|
||||
|
||||
.PARAMETER ReportPath
|
||||
Where to save the reports
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-HafniumReports.ps1
|
||||
|
||||
.LINK
|
||||
https://discuss.elastic.co/t/detection-and-response-for-hafnium-activity/266289
|
||||
|
||||
. LINK
|
||||
https://www.msxfaq.de/exchange/update/hafnium-nachbereitung.htm
|
||||
|
||||
.NOTES
|
||||
This does NOT replace a Anti Virus scanner and also does NOT replace the Microsoft investigation scripts!
|
||||
You can use this to bring your ongoing security investigation(s) a step forward, not more but not less.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateNotNull()]
|
||||
[Alias('Path')]
|
||||
[string]
|
||||
$ReportPath = 'C:\scripts\PowerShell\reports\Hafnium\'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Create the report directory, if needed
|
||||
if (-not (Test-Path -Path $ReportPath -ErrorAction SilentlyContinue))
|
||||
{
|
||||
$null = (New-Item -Path $ReportPath -ItemType Directory -Force -ErrorAction Stop)
|
||||
}
|
||||
|
||||
# Create a Timestamp
|
||||
$TimeStamp = (Get-Date -Format 'yyyyMMdd_HHmmss')
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
<#
|
||||
Look for commands like "Set-OABVirtualDirectory" - This is one of the known commands that the attackers used.
|
||||
#>
|
||||
|
||||
# Get Exchange Event Logs
|
||||
$null = (Get-WinEvent -LogName 'MSExchange Management' -ErrorAction SilentlyContinue | Export-Csv -Path ($ReportPath + 'MSExchangeManagement_' + $TimeStamp + '.csv') -NoTypeInformation -Force -Encoding UTF8 -ErrorAction SilentlyContinue)
|
||||
|
||||
<#
|
||||
Look for tasks that you don't know.
|
||||
"WwanSvcdcs" is one of the names that are known as related to Hafnium
|
||||
|
||||
Please keep in mind: Windows itself use Scheduled Tasks a lot!
|
||||
#>
|
||||
|
||||
# Get Scheduled Task info
|
||||
$null = (Get-ScheduledTask -ErrorAction SilentlyContinue | Select-Object -Property actions -ExpandProperty actions -ErrorAction SilentlyContinue | Export-Csv -Path ($ReportPath + 'ScheduledTaskInfo_' + $TimeStamp + '.csv') -NoTypeInformation -Force -Encoding UTF8 -ErrorAction SilentlyContinue)
|
||||
|
||||
<#
|
||||
See above, and watch for tasks that are created since January 2021 that you can not identify.
|
||||
|
||||
Please keep in mind: Windows itself use Scheduled Tasks a lot!
|
||||
#>
|
||||
|
||||
# TaskScheduler info
|
||||
$null = (Get-WinEvent -LogName 'Microsoft-Windows-TaskScheduler/Operational' -ErrorAction SilentlyContinue | Export-Csv -Path ($ReportPath + 'TaskScheduler_' + $TimeStamp + '.csv') -NoTypeInformation -Force -Encoding UTF8 -ErrorAction SilentlyContinue)
|
||||
|
||||
<#
|
||||
PowerShell keeps a history that will be saved into a plain ASC File. At least if the ReadLine Module is installed!
|
||||
A bit work, but you can at least try to identify something strange here!
|
||||
#>
|
||||
|
||||
# Get all History Files from PowerShell
|
||||
$null = (Get-ChildItem -Path 'C:\Users' -Filter 'ConsoleHost_history.txt' -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object -Process {
|
||||
$null = (Get-Content -Path $_.FullName -ErrorAction SilentlyContinue | Out-File -FilePath ($ReportPath + 'PowerShell_History_' + $TimeStamp + '.txt') -Encoding utf8 -Append -ErrorAction SilentlyContinue)
|
||||
})
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Open the directory in the File Explorer
|
||||
Invoke-Item -Path $ReportPath
|
||||
}
|
||||
29
Powershell/PowerShell-collection/Exchange/LICENSE
Normal file
29
Powershell/PowerShell-collection/Exchange/LICENSE
Normal 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.
|
||||
8
Powershell/PowerShell-collection/Exchange/README.md
Normal file
8
Powershell/PowerShell-collection/Exchange/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# 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.
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#requires -Version 1.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Uninstalls the old and retired Anti-spam Agents from an Exchange Server
|
||||
|
||||
.DESCRIPTION
|
||||
Microsoft announced that they deprecated the support for the SmartScreen Anti-spam content filters for Exchange Servers. This script uninstalls the old an retired SmartScreen Anti-spam Agents from the local Exchange Server.
|
||||
This is an easy to use and light weight replacement for Uninstall-AntiSpamAgents.ps1 from the \Scripts of your Exchange Installation, it will remove just the dead parts and leave the rest as it is. Some find that it might be better to leave the rest intact.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-AntiSpamAgents
|
||||
|
||||
.NOTES
|
||||
Find a suitable an solid replacement solution for your email hygiene. This could be any 3rd party solution on premise or cloud. Never use email without any good email hygiene!
|
||||
|
||||
If you want, you might run the Uninstall-AntiSpamAgents.ps1 from the \Scripts folder created by Setup during Exchange installation. It removes everything related to the AntiSpamAgents.
|
||||
|
||||
Taken from the links below.
|
||||
|
||||
.LINK
|
||||
https://blogs.technet.microsoft.com/exchange/2016/09/01/deprecating-support-for-smartscreen-in-outlook-and-exchange/
|
||||
|
||||
.LINK
|
||||
https://blogs.technet.microsoft.com/exchange/2017/03/23/exchange-server-edge-support-on-windows-server-2016-update/
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess = $true)]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# Constants
|
||||
$STP = 'SilentlyContinue'
|
||||
|
||||
# Agents to remove
|
||||
$TransportAgentsToRemove = 'Content Filter Agent', 'Sender Id Agent', 'Protocol Analysis Agent'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Loop over the List
|
||||
foreach ($TransportAgentToRemove in $TransportAgentsToRemove)
|
||||
{
|
||||
# Do we have the agent we would like to remove?
|
||||
if (Get-TransportAgent -Identity $TransportAgentToRemove -ErrorAction $STP -WarningAction $STP)
|
||||
{
|
||||
Write-Verbose -Message "Try to remove $TransportAgentToRemove"
|
||||
|
||||
try
|
||||
{
|
||||
# Do it, or dry run it?
|
||||
if ($pscmdlet.ShouldProcess("$TransportAgentToRemove", 'Remove TransportAgent'))
|
||||
{
|
||||
# Remove it...
|
||||
$paramUninstallTransportAgent = @{
|
||||
Identity = $TransportAgentToRemove
|
||||
ErrorAction = $STP
|
||||
WarningAction = $STP
|
||||
Confirm = $false
|
||||
}
|
||||
$null = (Uninstall-TransportAgent @paramUninstallTransportAgent)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Whoopsss
|
||||
Write-Warning -Message "Unable to remove $TransportAgentToRemove"
|
||||
}
|
||||
|
||||
Write-Verbose -Message "$TransportAgentToRemove was removed"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message "Sorry, $TransportAgentToRemove was not found..."
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,3 @@
|
||||
# ExchangeNodeMaintenanceMode
|
||||
|
||||
New location: [https://github.com/jhochwald/ExchangeNodeMaintenanceMode](https://github.com/jhochwald/ExchangeNodeMaintenanceMode)
|
||||
@@ -0,0 +1,395 @@
|
||||
#requires -Version 3.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remove the access to Outlook for all Mailboxes in an Microsoft Office 365 Tenant
|
||||
|
||||
.DESCRIPTION
|
||||
Remove the access to Outlook for all Mailboxes in an Microsoft Office 365 Tenant
|
||||
It will remove access to OWA (Outlook Web Application), Exchange Active Sync (EAS), Outlook App and Outlook (part of the Office Suite).
|
||||
|
||||
.PARAMETER CredentialUser
|
||||
The UPN of the admin user
|
||||
|
||||
.PARAMETER CredentialFile
|
||||
File where the credential will be stored
|
||||
|
||||
Make sure that this is secured!
|
||||
|
||||
.PARAMETER ProxyAccessType
|
||||
Determines which mechanism is used to resolve the host name. The acceptable values for this parameter are:
|
||||
- IEConfig
|
||||
- WinHttpConfig
|
||||
- AutoDetect
|
||||
- NoProxyServer
|
||||
- None
|
||||
|
||||
The default value is None.
|
||||
|
||||
For information about the values of this parameter, see the description of the System.Management.Automation.Remoting.ProxyAccessTypehttp://go.microsoft.com/fwlink/?LinkId=144756 (http://go.microsoft.com/fwlink/?LinkId=144756) enumeration in the Microsoft Developer Network (MSDN) library.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Approve-CASMailboxSettings.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Approve-CASMailboxSettings.ps1 -verbose
|
||||
|
||||
.NOTES
|
||||
I created the script to run automated (via Windows scheduler) and it will save the password in a plain text file.
|
||||
You might want to use another option to gain access to Exchange Online
|
||||
|
||||
Please check all values before using the script!
|
||||
|
||||
TODO: Run the script once before using it as scheduled task! This will create and save the credentials.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Username', 'AdminUser')]
|
||||
[string]
|
||||
$CredentialUser = 'youradmin.user@contoso.com',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('CredFile', 'SecretFile')]
|
||||
[string]
|
||||
$CredentialFile = ($env:LOCALAPPDATA + '\exocreds.txt'),
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateSet('IEConfig', 'WinHttpConfig', 'AutoDetect', 'NoProxyServer', 'None', IgnoreCase = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('PSSessionOptionProxy')]
|
||||
[string]
|
||||
$ProxyAccessType = 'None'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Admin User (Global Admin or min. Exchange Online Admin role)
|
||||
if (-not ($CredentialUser))
|
||||
{
|
||||
$CredentialUser = 'youradmin.user@contoso.com'
|
||||
}
|
||||
|
||||
# Where to store the password?
|
||||
if (-not ($CredentialFile))
|
||||
{
|
||||
$CredentialFile = ($env:LOCALAPPDATA + '\exocreds.txt')
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
#region CredentialHandler
|
||||
try
|
||||
{
|
||||
if (-not (Test-Path -Path $CredentialFile -ErrorAction SilentlyContinue))
|
||||
{
|
||||
# Do we have any credentials in memory (variable)
|
||||
if (-not ($ExoCreds))
|
||||
{
|
||||
#
|
||||
$paramGetCredential = @{
|
||||
Message = 'Bitte mit einem Exchange Online Admin Benutzer anmelden'
|
||||
UserName = $CredentialUser
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$ExoCreds = (Get-Credential @paramGetCredential)
|
||||
}
|
||||
|
||||
# Splat the parameters
|
||||
$paramOutFile = @{
|
||||
FilePath = $CredentialFile
|
||||
Force = $true
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Stop'
|
||||
Confirm = $false
|
||||
}
|
||||
|
||||
# Save the file
|
||||
$null = ($ExoCreds.Password | ConvertFrom-SecureString | Out-File @paramOutFile)
|
||||
}
|
||||
else
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramGetContent = @{
|
||||
Path = $CredentialFile
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$paramConvertToSecureString = @{
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
# Read and convert the file wit the password
|
||||
$PwdSecureString = (Get-Content @paramGetContent | ConvertTo-SecureString @paramConvertToSecureString)
|
||||
|
||||
# Splat the parameters
|
||||
$paramNewObject = @{
|
||||
TypeName = 'System.Management.Automation.PSCredential'
|
||||
ArgumentList = $CredentialUser, $PwdSecureString
|
||||
}
|
||||
|
||||
# Create the credential object
|
||||
$ExoCreds = (New-Object @paramNewObject)
|
||||
|
||||
# Remove the password string from memory
|
||||
$PwdSecureString = $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
|
||||
}
|
||||
#endregion CredentialHandler
|
||||
|
||||
#region ConnectExchangeOnline
|
||||
try
|
||||
{
|
||||
# Proxy Handling
|
||||
<#
|
||||
-ProxyAccessType <ProxyAccessType>
|
||||
Determines which mechanism is used to resolve the host name. The acceptable values for this parameter are:
|
||||
- IEConfig
|
||||
- WinHttpConfig
|
||||
- AutoDetect
|
||||
- NoProxyServer
|
||||
- None
|
||||
|
||||
The default value is None.
|
||||
For information about the values of this parameter, see the description of the System.Management.Automation.Remoting.ProxyAccessTypehttp://go.microsoft.com/fwlink/?LinkId=144756 (http://go.microsoft.com/fwlink/?LinkId=144756) enumeration in the Microsoft Developer Network (MSDN) library.
|
||||
|
||||
Source:
|
||||
Get-Help New-PSSessionOption -Detailed
|
||||
#>
|
||||
if ($ProxyAccessType)
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewPSSessionOption = @{
|
||||
ProxyAccessType = $ProxyAccessType
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
# Do we need a proxy to access Office 365?
|
||||
$ProxyOptions = (New-PSSessionOption @paramNewPSSessionOption)
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$ExoSession = $null
|
||||
|
||||
# Splat the parameters
|
||||
$paramGetPSSession = @{
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramRemovePSSession = @{
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
Confirm = $false
|
||||
}
|
||||
|
||||
# Remove all existing Exchange Online Sessions
|
||||
$null = (Get-PSSession @paramGetPSSession | Where-Object {
|
||||
$_.ComputerName -eq 'outlook.office365.com'
|
||||
} | Remove-PSSession @paramRemovePSSession)
|
||||
|
||||
# Splat the parameters
|
||||
$paramNewPSSession = @{
|
||||
ConfigurationName = 'Microsoft.Exchange'
|
||||
ConnectionUri = 'https://outlook.office365.com/powershell-liveid/'
|
||||
Credential = $ExoCreds
|
||||
Authentication = 'Basic'
|
||||
AllowRedirection = $true
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
# Proxy settings needed?
|
||||
if ($ProxyOptions)
|
||||
{
|
||||
$paramNewPSSession.SessionOption = $ProxyOptions
|
||||
}
|
||||
|
||||
# Create the session
|
||||
$ExoSession = (New-PSSession @paramNewPSSession)
|
||||
|
||||
# Splat the parameters
|
||||
$paramImportPSSession = @{
|
||||
Session = $ExoSession
|
||||
DisableNameChecking = $true
|
||||
AllowClobber = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
|
||||
# Create the Session
|
||||
$null = (Import-PSSession @paramImportPSSession)
|
||||
}
|
||||
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
|
||||
}
|
||||
#endregion ConnectExchangeOnline
|
||||
|
||||
#region SetCASMailbox
|
||||
try
|
||||
{
|
||||
# Check if the session is alive
|
||||
if (-not (Get-Command -Name Get-CASMailbox))
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramWriteError = @{
|
||||
Exception = 'Es scheint ein Problem mit der Exchange Online Verbindung zu geben!'
|
||||
Message = 'Die erforderlichen Exchnage Online Befehle wurden nicht gefunden!'
|
||||
Category = 'ResourceUnavailable'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Make sure we are done!
|
||||
throw
|
||||
}
|
||||
|
||||
# Splat the parameters
|
||||
$paramGetCASMailbox = @{
|
||||
ResultSize = 'unlimited'
|
||||
Filter = {
|
||||
(name -notlike 'DiscoverysearchMailbox*')
|
||||
}
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$paramSetCASMailbox = @{
|
||||
ActiveSyncEnabled = $false
|
||||
ImapEnabled = $false
|
||||
MAPIEnabled = $false
|
||||
OutlookMobileEnabled = $false
|
||||
OWAEnabled = $false
|
||||
OWAforDevicesEnabled = $false
|
||||
PopEnabled = $false
|
||||
SmtpClientAuthenticationDisabled = $false
|
||||
UniversalOutlookEnabled = $false
|
||||
Confirm = $false
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
|
||||
# Remove the outlook access from all mailboxes
|
||||
$null = (Get-CASMailbox @paramGetCASMailbox | Set-CASMailbox @paramSetCASMailbox)
|
||||
}
|
||||
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
|
||||
}
|
||||
#endregion SetCASMailbox
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Cleanup
|
||||
$ExoSession = $null
|
||||
|
||||
# Splat the parameters
|
||||
$paramGetPSSession = @{
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramRemovePSSession = @{
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
Confirm = $false
|
||||
}
|
||||
|
||||
# Remove all existing Exchange Online Sessions
|
||||
$null = (Get-PSSession @paramGetPSSession | Where-Object {
|
||||
$_.ComputerName -eq 'outlook.office365.com'
|
||||
} | Remove-PSSession @paramRemovePSSession)
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,617 @@
|
||||
function Export-DistributionGroup2Cloud
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Function to convert/migrate on-premises Exchange distribution group to a Cloud (Exchange Online) distribution group
|
||||
|
||||
.DESCRIPTION
|
||||
Copies attributes of a synchronized group to a placeholder group and CSV file.
|
||||
After initial export of group attributes, the on-premises group can have the attribute "AdminDescription" set to "Group_NoSync" which will stop it from be synchronized.
|
||||
The "-Finalize" switch can then be used to write the addresses to the new group and convert the name. The final group will be a cloud group with the same attributes as the previous but with the additional ability of being able to be "self-managed".
|
||||
Once the contents of the new group are validated, the on-premises group can be deleted.
|
||||
|
||||
.PARAMETER Group
|
||||
Name of group to recreate.
|
||||
|
||||
.PARAMETER CreatePlaceHolder
|
||||
Create placeholder DistributionGroup wit ha given name.
|
||||
|
||||
.PARAMETER Finalize
|
||||
Convert a given placeholder group to final DistributionGroup.
|
||||
|
||||
.PARAMETER ExportDirectory
|
||||
Export Directory for internal CSV handling.
|
||||
|
||||
.EXAMPLE
|
||||
PS> Export-DistributionGroup2Cloud -Group "DL-Marketing" -CreatePlaceHolder
|
||||
|
||||
Create the Placeholder for the distribution group "DL-Marketing"
|
||||
|
||||
.EXAMPLE
|
||||
PS> Export-DistributionGroup2Cloud -Group "DL-Marketing" -Finalize
|
||||
|
||||
Transform the Placeholder for the distribution group "DL-Marketing" to the real distribution group in the cloud
|
||||
|
||||
.NOTES
|
||||
This function is based on the Recreate-DistributionGroup.ps1 script of Joe Palarchio
|
||||
|
||||
License: BSD 3-Clause
|
||||
|
||||
.LINK
|
||||
https://gallery.technet.microsoft.com/PowerShell-Script-to-Move-5c3cd668
|
||||
|
||||
.LINK
|
||||
http://blogs.perficient.com/microsoft/?p=32092
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage = 'Name of group to recreate.')]
|
||||
[string]
|
||||
$Group,
|
||||
[switch]
|
||||
$CreatePlaceHolder,
|
||||
[switch]
|
||||
$Finalize,
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$ExportDirectory = 'C:\scripts\PowerShell\exports\ExportedAddresses\'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Defaults
|
||||
$SCN = 'SilentlyContinue'
|
||||
$CNT = 'Continue'
|
||||
$STP = 'Stop'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
If ($CreatePlaceHolder.IsPresent)
|
||||
{
|
||||
# Create the Placeholder
|
||||
If (((Get-DistributionGroup -Identity $Group -ErrorAction $SCN).IsValid) -eq $True)
|
||||
{
|
||||
# Splat to make it more human readable
|
||||
$paramGetDistributionGroup = @{
|
||||
Identity = $Group
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$OldDG = (Get-DistributionGroup @paramGetDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
[IO.Path]::GetInvalidFileNameChars() | ForEach-Object -Process {
|
||||
$Group = $Group.Replace($_, '_')
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
$OldName = [string]$OldDG.Name
|
||||
$OldDisplayName = [string]$OldDG.DisplayName
|
||||
$OldPrimarySmtpAddress = [string]$OldDG.PrimarySmtpAddress
|
||||
$OldAlias = [string]$OldDG.Alias
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramGetDistributionGroupMember = @{
|
||||
Identity = $OldDG.Name
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$OldMembers = ((Get-DistributionGroupMember @paramGetDistributionGroupMember).Name)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
If (!(Test-Path -Path $ExportDirectory -ErrorAction $SCN -WarningAction $CNT))
|
||||
{
|
||||
Write-Verbose -Message (' Creating Directory: {0}' -f $ExportDirectory)
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramNewItem = @{
|
||||
ItemType = 'directory'
|
||||
Path = $ExportDirectory
|
||||
Force = $True
|
||||
Confirm = $False
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$null = (New-Item @paramNewItem)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# Define variables - mostly for future use
|
||||
$ExportDirectoryGroupCsv = $ExportDirectory + '\' + $Group + '.csv'
|
||||
|
||||
try
|
||||
{
|
||||
# TODO: Refactor in future version
|
||||
'EmailAddress' > $ExportDirectoryGroupCsv
|
||||
$OldDG.EmailAddresses >> $ExportDirectoryGroupCsv
|
||||
'x500:' + $OldDG.LegacyExchangeDN >> $ExportDirectoryGroupCsv
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
# Define variables - mostly for future use
|
||||
$NewDistributionGroupName = 'Cloud- ' + $OldName
|
||||
$NewDistributionGroupAlias = 'Cloud-' + $OldAlias
|
||||
$NewDistributionGroupDisplayName = 'Cloud-' + $OldDisplayName
|
||||
$NewDistributionGroupPrimarySmtpAddress = 'Cloud-' + $OldPrimarySmtpAddress
|
||||
|
||||
# TODO: Replace with Write-Verbose in future version of the function
|
||||
Write-Output -InputObject (' Creating Group: {0}' -f $NewDistributionGroupDisplayName)
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramNewDistributionGroup = @{
|
||||
Name = $NewDistributionGroupName
|
||||
Alias = $NewDistributionGroupAlias
|
||||
DisplayName = $NewDistributionGroupDisplayName
|
||||
ManagedBy = $OldDG.ManagedBy
|
||||
Members = $OldMembers
|
||||
PrimarySmtpAddress = $NewDistributionGroupPrimarySmtpAddress
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$null = (New-DistributionGroup @paramNewDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
# Wait for 3 seconds
|
||||
$null = (Start-Sleep -Seconds 3)
|
||||
|
||||
# Define variables - mostly for future use
|
||||
$SetDistributionGroupIdentity = 'Cloud-' + $OldName
|
||||
$SetDistributionGroupDisplayName = 'Cloud-' + $OldDisplayName
|
||||
|
||||
# TODO: Replace with Write-Verbose in future version of the function
|
||||
Write-Output -InputObject (' Setting Values For: {0}' -f $SetDistributionGroupDisplayName)
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramSetDistributionGroup = @{
|
||||
Identity = $SetDistributionGroupIdentity
|
||||
AcceptMessagesOnlyFromSendersOrMembers = $OldDG.AcceptMessagesOnlyFromSendersOrMembers
|
||||
RejectMessagesFromSendersOrMembers = $OldDG.RejectMessagesFromSendersOrMembers
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$null = (Set-DistributionGroup @paramSetDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
# Define variables - mostly for future use
|
||||
$SetDistributionGroupIdentity = 'Cloud-' + $OldName
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramSetDistributionGroup = @{
|
||||
Identity = $SetDistributionGroupIdentity
|
||||
AcceptMessagesOnlyFrom = $OldDG.AcceptMessagesOnlyFrom
|
||||
AcceptMessagesOnlyFromDLMembers = $OldDG.AcceptMessagesOnlyFromDLMembers
|
||||
BypassModerationFromSendersOrMembers = $OldDG.BypassModerationFromSendersOrMembers
|
||||
BypassNestedModerationEnabled = $OldDG.BypassNestedModerationEnabled
|
||||
CustomAttribute1 = $OldDG.CustomAttribute1
|
||||
CustomAttribute2 = $OldDG.CustomAttribute2
|
||||
CustomAttribute3 = $OldDG.CustomAttribute3
|
||||
CustomAttribute4 = $OldDG.CustomAttribute4
|
||||
CustomAttribute5 = $OldDG.CustomAttribute5
|
||||
CustomAttribute6 = $OldDG.CustomAttribute6
|
||||
CustomAttribute7 = $OldDG.CustomAttribute7
|
||||
CustomAttribute8 = $OldDG.CustomAttribute8
|
||||
CustomAttribute9 = $OldDG.CustomAttribute9
|
||||
CustomAttribute10 = $OldDG.CustomAttribute10
|
||||
CustomAttribute11 = $OldDG.CustomAttribute11
|
||||
CustomAttribute12 = $OldDG.CustomAttribute12
|
||||
CustomAttribute13 = $OldDG.CustomAttribute13
|
||||
CustomAttribute14 = $OldDG.CustomAttribute14
|
||||
CustomAttribute15 = $OldDG.CustomAttribute15
|
||||
ExtensionCustomAttribute1 = $OldDG.ExtensionCustomAttribute1
|
||||
ExtensionCustomAttribute2 = $OldDG.ExtensionCustomAttribute2
|
||||
ExtensionCustomAttribute3 = $OldDG.ExtensionCustomAttribute3
|
||||
ExtensionCustomAttribute4 = $OldDG.ExtensionCustomAttribute4
|
||||
ExtensionCustomAttribute5 = $OldDG.ExtensionCustomAttribute5
|
||||
GrantSendOnBehalfTo = $OldDG.GrantSendOnBehalfTo
|
||||
HiddenFromAddressListsEnabled = $True
|
||||
MailTip = $OldDG.MailTip
|
||||
MailTipTranslations = $OldDG.MailTipTranslations
|
||||
MemberDepartRestriction = $OldDG.MemberDepartRestriction
|
||||
MemberJoinRestriction = $OldDG.MemberJoinRestriction
|
||||
ModeratedBy = $OldDG.ModeratedBy
|
||||
ModerationEnabled = $OldDG.ModerationEnabled
|
||||
RejectMessagesFrom = $OldDG.RejectMessagesFrom
|
||||
RejectMessagesFromDLMembers = $OldDG.RejectMessagesFromDLMembers
|
||||
ReportToManagerEnabled = $OldDG.ReportToManagerEnabled
|
||||
ReportToOriginatorEnabled = $OldDG.ReportToOriginatorEnabled
|
||||
RequireSenderAuthenticationEnabled = $OldDG.RequireSenderAuthenticationEnabled
|
||||
SendModerationNotifications = $OldDG.SendModerationNotifications
|
||||
SendOofMessageToOriginatorEnabled = $OldDG.SendOofMessageToOriginatorEnabled
|
||||
BypassSecurityGroupManagerCheck = $True
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$null = (Set-DistributionGroup @paramSetDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Error -Message ('The distribution group {0} was not found' -f $Group) -ErrorAction $CNT
|
||||
}
|
||||
}
|
||||
ElseIf ($Finalize.IsPresent)
|
||||
{
|
||||
# Do the final steps
|
||||
|
||||
# Define variables - mostly for future use
|
||||
$GetDistributionGroupIdentity = 'Cloud-' + $Group
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramGetDistributionGroup = @{
|
||||
Identity = $GetDistributionGroupIdentity
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$TempDG = (Get-DistributionGroup @paramGetDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
$TempPrimarySmtpAddress = $TempDG.PrimarySmtpAddress
|
||||
|
||||
try
|
||||
{
|
||||
[IO.Path]::GetInvalidFileNameChars() | ForEach-Object -Process {
|
||||
$Group = $Group.Replace($_, '_')
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
$OldAddressesPatch = $ExportDirectory + '\' + $Group + '.csv'
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramImportCsv = @{
|
||||
Path = $OldAddressesPatch
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$OldAddresses = @(Import-Csv @paramImportCsv)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$NewAddresses = $OldAddresses | ForEach-Object -Process {
|
||||
$_.EmailAddress.Replace('X500', 'x500')
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
$NewDGName = $TempDG.Name.Replace('Cloud-', '')
|
||||
$NewDGDisplayName = $TempDG.DisplayName.Replace('Cloud-', '')
|
||||
$NewDGAlias = $TempDG.Alias.Replace('Cloud-', '')
|
||||
|
||||
try
|
||||
{
|
||||
$NewPrimarySmtpAddress = ($NewAddresses | Where-Object -FilterScript {
|
||||
$_ -clike 'SMTP:*'
|
||||
}).Replace('SMTP:', '')
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramSetDistributionGroup = @{
|
||||
Identity = $TempDG.Name
|
||||
Name = $NewDGName
|
||||
Alias = $NewDGAlias
|
||||
DisplayName = $NewDGDisplayName
|
||||
PrimarySmtpAddress = $NewPrimarySmtpAddress
|
||||
HiddenFromAddressListsEnabled = $False
|
||||
BypassSecurityGroupManagerCheck = $True
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$null = (Set-DistributionGroup @paramSetDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
$paramSetDistributionGroup = @{
|
||||
Identity = $NewDGName
|
||||
EmailAddresses = @{
|
||||
Add = $NewAddresses
|
||||
}
|
||||
BypassSecurityGroupManagerCheck = $True
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$null = (Set-DistributionGroup @paramSetDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
|
||||
# Splat to make it more human readable
|
||||
$paramSetDistributionGroup = @{
|
||||
Identity = $NewDGName
|
||||
EmailAddresses = @{
|
||||
Remove = $TempPrimarySmtpAddress
|
||||
}
|
||||
BypassSecurityGroupManagerCheck = $True
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
try
|
||||
{
|
||||
$null = (Set-DistributionGroup @paramSetDistributionGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$line = ($_.InvocationInfo.ScriptLineNumber)
|
||||
|
||||
# Dump the Info
|
||||
Write-Warning -Message ('Error was in Line {0}' -f $line)
|
||||
|
||||
# Dump the Error catched
|
||||
Write-Error -Message $_ -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Error -Message " ERROR: No options selected, please use '-CreatePlaceHolder' or '-Finalize'" -ErrorAction $STP
|
||||
|
||||
# Something that should never be reached
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
<#
|
||||
From the original Script Author
|
||||
|
||||
Name: Recreate-DistributionGroup.ps1
|
||||
|
||||
Version: 1.0
|
||||
|
||||
Description: Copies attributes of a synchronized group to a placeholder group and CSV file.
|
||||
After initial export of group attributes, the on-premises group can have the attribute "AdminDescription" set to "Group_NoSync" which will stop it from be synchronized.
|
||||
The "-Finalize" switch can then be used to write the addresses to the new group and convert the name. The final group will be a cloud group with the same attributes as the previous but with the additional ability of being able to be "self-managed".
|
||||
Once the contents of the new group are validated, the on-premises group can be deleted.
|
||||
|
||||
Requires: Remote PowerShell Connection to Exchange Online
|
||||
|
||||
Author: Joe Palarchio
|
||||
|
||||
Usage: Additional information on the usage of this script can found at the following blog post: http://blogs.perficient.com/microsoft/?p=32092
|
||||
|
||||
Disclaimer: This script is provided AS IS without any support. Please test in a lab environment prior to production use.
|
||||
#>
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,275 @@
|
||||
#requires -Version 3.0 -Modules ExchangeOnlineManagement
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a basic report of Mobile Devices
|
||||
|
||||
.DESCRIPTION
|
||||
Get a basic report of Mobile Devices connected to the Microsoft 365 Tenant
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-MobileDeviceReporting.ps1
|
||||
|
||||
.LINK
|
||||
Connect-ExchangeOnline
|
||||
|
||||
.LINK
|
||||
Get-MobileDevice
|
||||
|
||||
.LINK
|
||||
Get-MobileDeviceStatistics
|
||||
|
||||
.NOTES
|
||||
Nothing fancy! Only a basic report as CSV
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# Cleanup
|
||||
$Stats = $null
|
||||
$DeviceStats = $null
|
||||
$Report = $null
|
||||
$MobileDeviceList = $null
|
||||
|
||||
# Garbage Collection
|
||||
[GC]::Collect()
|
||||
|
||||
try
|
||||
{
|
||||
$paramConnectExchangeOnline = @{
|
||||
ShowBanner = $true
|
||||
BypassMailboxAnchoring = $true
|
||||
ExchangeEnvironmentName = 'O365Default'
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Connect-ExchangeOnline @paramConnectExchangeOnline)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
exit 1
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
|
||||
# Create new object
|
||||
$Report = @()
|
||||
}
|
||||
|
||||
|
||||
process
|
||||
{
|
||||
# Get all mobile devices in the Microsoft 365 tenant
|
||||
<#
|
||||
Option: -ActiveSync
|
||||
Description: The ActiveSync switch filters the results by Exchange ActiveSync devices.
|
||||
Source: https://docs.microsoft.com/en-us/powershell/module/exchange/get-mobiledevice?view=exchange-ps
|
||||
#>
|
||||
try
|
||||
{
|
||||
$paramGetMobileDevice = @{
|
||||
ResultSize = 'unlimited'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$MobileDeviceList = (Get-MobileDevice @paramGetMobileDevice)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
exit 1
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
|
||||
# Loop over the List
|
||||
foreach ($Device in $MobileDeviceList)
|
||||
{
|
||||
$Stats = $null
|
||||
$DeviceStats = $null
|
||||
|
||||
try
|
||||
{
|
||||
$paramGetMobileDeviceStatistics = @{
|
||||
Identity = $Device.Guid.toString()
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$Stats = (Get-MobileDeviceStatistics @paramGetMobileDeviceStatistics)
|
||||
|
||||
$DeviceStats = [PSCustomObject]@{
|
||||
Identity = $Device.Identity -replace '\\.+'
|
||||
DeviceType = $Device.DeviceType
|
||||
DeviceOS = $Device.DeviceOS
|
||||
DeviceUserAgent = $Stats.DeviceUserAgent
|
||||
DeviceModel = $Stats.DeviceModel
|
||||
ClientType = $Stats.ClientType
|
||||
FirstSyncTime = $Stats.FirstSyncTime
|
||||
LastSuccessSync = $Stats.LastSuccessSync
|
||||
LastSyncAttemptTime = $Stats.LastSyncAttemptTime
|
||||
LastPolicyUpdateTime = $Stats.LastPolicyUpdateTime
|
||||
LastPingHeartbeat = $Stats.LastPingHeartbeat
|
||||
}
|
||||
|
||||
$Report += $DeviceStats
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
Write-Warning -Message $info.Exception
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
# Create a Timestamp (check if this is OK for you)
|
||||
$TimeStamp = (Get-Date -Format yyyyMMdd_HHmmss)
|
||||
|
||||
# Export the CSV Report
|
||||
try
|
||||
{
|
||||
$paramExportCsv = @{
|
||||
Path = ('.\MobileDeviceReport' + $TimeStamp + '.csv')
|
||||
Force = $true
|
||||
Encoding = 'UTF8'
|
||||
Delimiter = ';'
|
||||
NoTypeInformation = $true
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
($Report | Export-Csv @paramExportCsv)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
finally
|
||||
{
|
||||
# Disconnect from Exchange Online
|
||||
$paramDisconnectExchangeOnline = @{
|
||||
Confirm = $false
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Disconnect-ExchangeOnline @paramDisconnectExchangeOnline)
|
||||
|
||||
# Cleanup
|
||||
$Stats = $null
|
||||
$DeviceStats = $null
|
||||
$Report = $null
|
||||
$MobileDeviceList = $null
|
||||
|
||||
# Garbage Collection
|
||||
[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
|
||||
@@ -0,0 +1,393 @@
|
||||
function Get-enMailboxFolderPermissionReport
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a detailed mailbox folder permission report
|
||||
|
||||
.DESCRIPTION
|
||||
Get a detailed mailbox folder permission report and exports this report to a given CSV file.
|
||||
You can select only user-mailboxes, only shared-mailboxes or both for the reporting.
|
||||
|
||||
.PARAMETER Identity
|
||||
The Identity parameter specifies the mailbox that you want to view.
|
||||
You can use any value that uniquely identifies the mailbox.
|
||||
|
||||
Default is * (all)
|
||||
|
||||
.PARAMETER MailboxType
|
||||
The type is the value for the regular RecipientTypeDetails.
|
||||
|
||||
The acceptable values for this parameter are:
|
||||
- UserMailbox
|
||||
- User
|
||||
- SharedMailbox
|
||||
- Shared
|
||||
- All
|
||||
|
||||
The Default is ALL
|
||||
|
||||
.PARAMETER ResultSize
|
||||
The ResultSize parameter specifies the maximum number of results to return.
|
||||
If you want to return all requests that match the query, use unlimited for the value of this parameter.
|
||||
|
||||
The default value is unlimited.
|
||||
|
||||
.PARAMETER Path
|
||||
Specifies the path to the CSV output file.
|
||||
|
||||
The default is 'C:\scripts\PowerShell\Reports\MailboxFolderPermissionReport.csv'
|
||||
|
||||
.PARAMETER Encoding
|
||||
Specifies the encoding for the exported CSV file.
|
||||
The acceptable values for this parameter are:
|
||||
- Unicode
|
||||
- UTF7
|
||||
- UTF8
|
||||
- ASCII
|
||||
- UTF32
|
||||
- BigEndianUnicode
|
||||
- Default
|
||||
- OEM
|
||||
|
||||
Default is UTF8
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-enMailboxFolderPermissionReport
|
||||
|
||||
Get a detailed mailbox folder permission report
|
||||
|
||||
.NOTES
|
||||
Developed and tested with Exchange Online, it should work with on Premises Exchange 2010/2010/2016/2019
|
||||
|
||||
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
|
||||
|
||||
.LINK
|
||||
http://www.enatec.io
|
||||
|
||||
.LINK
|
||||
Get-Mailbox
|
||||
|
||||
.LINK
|
||||
Get-MailboxFolderStatistics
|
||||
|
||||
.LINK
|
||||
Get-MailboxFolderPermission
|
||||
|
||||
.LINK
|
||||
Export-Csv
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[Alias('Mailbox', 'MailboxID', 'MailboxIdentity')]
|
||||
[string]
|
||||
$Identity = '*',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateSet('UserMailbox', 'User', 'SharedMailbox', 'Shared', 'All', IgnoreCase = $true)]
|
||||
[string]
|
||||
$MailboxType = 'All',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('MailboxResultSize')]
|
||||
[string]
|
||||
$ResultSize = 'Unlimited',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('CsvReport', 'CsvFile')]
|
||||
[string]
|
||||
$Path = 'C:\scripts\PowerShell\Reports\MailboxFolderPermissionReport.csv',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateSet('Unicode', 'UTF7', 'UTF8', 'ASCII', 'UTF32', 'BigEndianUnicode', 'Default', 'OEM', IgnoreCase = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('CsvEncoding')]
|
||||
[string]
|
||||
$Encoding = 'UTF8'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Cleanup
|
||||
$MailboxPermissionReport = $null
|
||||
$AllMailboxes = $null
|
||||
$MailboxCount = $null
|
||||
$MailboxFolderPermission = $null
|
||||
$ProgressStatus = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region Defaults
|
||||
$SCT = 'SilentlyContinue'
|
||||
$CNT = 'Continue'
|
||||
|
||||
if (-not ($Identity))
|
||||
{
|
||||
$Identity = '*'
|
||||
}
|
||||
|
||||
if (-not ($MailboxType))
|
||||
{
|
||||
$MailboxType = 'All'
|
||||
}
|
||||
|
||||
if (-not ($ResultSize))
|
||||
{
|
||||
$ResultSize = 'Unlimited'
|
||||
}
|
||||
|
||||
if (-not ($Path))
|
||||
{
|
||||
$Path = 'C:\scripts\PowerShell\Reports\MailboxFolderPermissionReport.csv'
|
||||
}
|
||||
|
||||
if (-not ($Encoding))
|
||||
{
|
||||
$Encoding = 'UTF8'
|
||||
}
|
||||
#endregion Defaults
|
||||
|
||||
#region MailboxType
|
||||
Write-Verbose -Message 'Get the mailboxes'
|
||||
|
||||
#region paramGetMailbox
|
||||
$paramGetMailbox = @{
|
||||
Identity = $Identity
|
||||
ResultSize = $ResultSize
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $CNT
|
||||
}
|
||||
#endregion paramGetMailbox
|
||||
|
||||
#region MailboxTypeSwitch
|
||||
switch ($MailboxType)
|
||||
{
|
||||
UserMailbox
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
User
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
SharedMailbox
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
Shared
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
All
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox' -or $_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
default
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox' -or $_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion MailboxTypeSwitch
|
||||
|
||||
#region GetAllMailboxes
|
||||
$AllMailboxes = (Get-Mailbox @paramGetMailbox | Where-Object @paramWhereObject | Sort-Object)
|
||||
#endregion GetAllMailboxes
|
||||
#endregion MailboxType
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($AllMailboxes)
|
||||
{
|
||||
# Create a new object for the report
|
||||
$MailboxPermissionReport = @()
|
||||
|
||||
# Create a counter for Write-Progress
|
||||
$MailboxCounter = ($AllMailboxes | Measure-Object).Count
|
||||
|
||||
# Set the start counter for Write-Progress to 1
|
||||
$MailboxCount = 1
|
||||
|
||||
#region MailboxLoop
|
||||
Write-Verbose -Message 'Process all mailboxes'
|
||||
|
||||
ForEach ($SingleMailbox in $AllMailboxes)
|
||||
{
|
||||
# Update Write-Progress
|
||||
$ProgressActivity = ('Working on Mailbox {0} of {1} ({2})' -f $MailboxCount, $MailboxCounter, $SingleMailbox.UserPrincipalName)
|
||||
$ProgressStatus = ('Getting folders for mailbox: {0} ({1})' -f $SingleMailbox.DisplayName, $SingleMailbox.UserPrincipalName)
|
||||
|
||||
Write-Verbose -Message $ProgressStatus
|
||||
|
||||
$paramWriteProgress = @{
|
||||
Status = $ProgressStatus
|
||||
Activity = $ProgressActivity
|
||||
PercentComplete = (($MailboxCount/$MailboxCounter) * 100)
|
||||
}
|
||||
Write-Progress @paramWriteProgress
|
||||
|
||||
# Get all folder for the mailbox
|
||||
$AllFolders = ($SingleMailbox | Get-MailboxFolderStatistics -FolderScope All | ForEach-Object -Process {
|
||||
$_.folderpath
|
||||
} | ForEach-Object -Process {
|
||||
$_.replace('/', '\')
|
||||
})
|
||||
|
||||
ForEach ($SingleFolder in $AllFolders)
|
||||
{
|
||||
# Update Write-Progress
|
||||
$ProgressStatus = ('Get permissions for {0}' -f ($SingleMailbox.UserPrincipalName + ':' + $SingleFolder))
|
||||
|
||||
Write-Verbose -Message $ProgressStatus
|
||||
|
||||
$paramWriteProgress = @{
|
||||
Status = $ProgressStatus
|
||||
Activity = $ProgressActivity
|
||||
PercentComplete = (($MailboxCount/$MailboxCounter) * 100)
|
||||
}
|
||||
Write-Progress @paramWriteProgress
|
||||
|
||||
# Get mailbox folder permissions with Get-MailboxFolderPermission
|
||||
$MailboxFolderPermission = $null
|
||||
$paramGetMailboxFolderPermission = @{
|
||||
Identity = ($SingleMailbox.Alias + ':' + $SingleFolder)
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$MailboxFolderPermission = (Get-MailboxFolderPermission @paramGetMailboxFolderPermission)
|
||||
|
||||
# store results in variable
|
||||
$MailboxPermissionReport += $MailboxFolderPermission | Where-Object -FilterScript {
|
||||
$_.User -notlike 'Default' -and $_.User -notlike 'Anonymous' -and $_.AccessRights -notlike 'None' -and $_.AccessRights -notlike 'Owner'
|
||||
} | Select-Object -Property @{
|
||||
name = 'Name'
|
||||
expression = {
|
||||
$SingleMailbox.Name
|
||||
}
|
||||
}, @{
|
||||
name = 'UserPrincipalName'
|
||||
expression = {
|
||||
$SingleMailbox.UserPrincipalName
|
||||
}
|
||||
}, FolderName, @{
|
||||
name = 'User'
|
||||
expression = {
|
||||
$_.User -join ','
|
||||
}
|
||||
}, @{
|
||||
name = 'AccessRights'
|
||||
expression = {
|
||||
$_.AccessRights -join ','
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$MailboxFolderPermission = $null
|
||||
}
|
||||
|
||||
# Update the counter
|
||||
$MailboxCount++
|
||||
|
||||
Write-Verbose -Message ('Done with processing {0}' -f $SingleMailbox.UserPrincipalName)
|
||||
}
|
||||
#endregion MailboxLoop
|
||||
|
||||
#region Reporter
|
||||
if ($MailboxPermissionReport)
|
||||
{
|
||||
$paramExportCsv = @{
|
||||
Path = $Path
|
||||
Force = $true
|
||||
NoTypeInformation = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$null = ($MailboxPermissionReport | Export-Csv @paramExportCsv)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'None of the Mailboxes has special permissions set'
|
||||
}
|
||||
#endregion Reporter
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No Mailboxes found that matches your search criteria'
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region Cleanup
|
||||
$MailboxPermissionReport = $null
|
||||
$AllMailboxes = $null
|
||||
$MailboxCount = $null
|
||||
$MailboxFolderPermission = $null
|
||||
$ProgressStatus = $null
|
||||
#endregion Cleanup
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,335 @@
|
||||
function Get-enMailboxPermissionReport
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a detailed mailbox permission report
|
||||
|
||||
.DESCRIPTION
|
||||
Get a detailed mailbox permission report and exports this report to a given CSV file.
|
||||
You can select only user-mailboxes, only shared-mailboxes or both for the reporting.
|
||||
|
||||
.PARAMETER Identity
|
||||
The Identity parameter specifies the mailbox that you want to view.
|
||||
You can use any value that uniquely identifies the mailbox.
|
||||
|
||||
Default is * (all)
|
||||
|
||||
.PARAMETER MailboxType
|
||||
The type is the value for the regular RecipientTypeDetails.
|
||||
|
||||
The acceptable values for this parameter are:
|
||||
- UserMailbox
|
||||
- User
|
||||
- SharedMailbox
|
||||
- Shared
|
||||
- All
|
||||
|
||||
The Default is ALL
|
||||
|
||||
.PARAMETER ResultSize
|
||||
The ResultSize parameter specifies the maximum number of results to return.
|
||||
If you want to return all requests that match the query, use unlimited for the value of this parameter.
|
||||
|
||||
The default value is unlimited.
|
||||
|
||||
.PARAMETER Path
|
||||
Specifies the path to the CSV output file.
|
||||
|
||||
The default is 'C:\scripts\PowerShell\Reports\MailboxPermissionReport.csv'
|
||||
|
||||
.PARAMETER Encoding
|
||||
Specifies the encoding for the exported CSV file.
|
||||
The acceptable values for this parameter are:
|
||||
- Unicode
|
||||
- UTF7
|
||||
- UTF8
|
||||
- ASCII
|
||||
- UTF32
|
||||
- BigEndianUnicode
|
||||
- Default
|
||||
- OEM
|
||||
|
||||
Default is UTF8
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-enMailboxPermissionReport
|
||||
|
||||
Get a detailed mailbox permission report
|
||||
|
||||
.NOTES
|
||||
Developed and tested with Exchange Online, it should work with on Premises Exchange 2010/2010/2016/2019
|
||||
|
||||
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
|
||||
|
||||
.LINK
|
||||
http://www.enatec.io
|
||||
|
||||
.LINK
|
||||
Get-Mailbox
|
||||
|
||||
.LINK
|
||||
Get-RecipientPermission
|
||||
|
||||
.LINK
|
||||
Export-Csv
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[Alias('Mailbox', 'MailboxID', 'MailboxIdentity')]
|
||||
[string]
|
||||
$Identity = '*',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateSet('UserMailbox', 'User', 'SharedMailbox', 'Shared', 'All', IgnoreCase = $true)]
|
||||
[string]
|
||||
$MailboxType = 'All',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('MailboxResultSize')]
|
||||
[string]
|
||||
$ResultSize = 'Unlimited',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('CsvReport', 'CsvFile')]
|
||||
[string]
|
||||
$Path = 'C:\scripts\PowerShell\Reports\MailboxPermissionReport.csv',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateSet('Unicode', 'UTF7', 'UTF8', 'ASCII', 'UTF32', 'BigEndianUnicode', 'Default', 'OEM', IgnoreCase = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('CsvEncoding')]
|
||||
[string]
|
||||
$Encoding = 'UTF8'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Cleanup
|
||||
$MailboxPermissionReport = $null
|
||||
$AllMailboxes = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region Defaults
|
||||
$SCT = 'SilentlyContinue'
|
||||
$CNT = 'Continue'
|
||||
|
||||
if (-not ($Identity))
|
||||
{
|
||||
$Identity = '*'
|
||||
}
|
||||
|
||||
if (-not ($MailboxType))
|
||||
{
|
||||
$MailboxType = 'All'
|
||||
}
|
||||
|
||||
if (-not ($ResultSize))
|
||||
{
|
||||
$ResultSize = 'Unlimited'
|
||||
}
|
||||
|
||||
if (-not ($Path))
|
||||
{
|
||||
$Path = 'C:\scripts\PowerShell\Reports\MailboxPermissionReport.csv'
|
||||
}
|
||||
|
||||
if (-not ($Encoding))
|
||||
{
|
||||
$Encoding = 'UTF8'
|
||||
}
|
||||
#endregion Defaults
|
||||
|
||||
#region MailboxType
|
||||
Write-Verbose -Message 'Get the mailboxes'
|
||||
|
||||
#region paramGetMailbox
|
||||
$paramGetMailbox = @{
|
||||
Identity = $Identity
|
||||
ResultSize = $ResultSize
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $CNT
|
||||
}
|
||||
#endregion paramGetMailbox
|
||||
|
||||
#region MailboxTypeSwitch
|
||||
switch ($MailboxType)
|
||||
{
|
||||
UserMailbox
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
User
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
SharedMailbox
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
Shared
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
All
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox' -or $_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
default
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox' -or $_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion MailboxTypeSwitch
|
||||
|
||||
#region GetAllMailboxes
|
||||
$AllMailboxes = (Get-Mailbox @paramGetMailbox | Where-Object @paramWhereObject | Sort-Object)
|
||||
#endregion GetAllMailboxes
|
||||
#endregion MailboxType
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($AllMailboxes)
|
||||
{
|
||||
# Create a new object for the report
|
||||
$MailboxPermissionReport = @()
|
||||
|
||||
# Create a counter for Write-Progress
|
||||
$MailboxCounter = ($AllMailboxes | Measure-Object).Count
|
||||
|
||||
# Set the start counter for Write-Progress to 1
|
||||
$MailboxCount = 1
|
||||
|
||||
#region MailboxLoop
|
||||
Write-Verbose -Message 'Process all mailboxes'
|
||||
|
||||
ForEach ($SingleMailbox in $AllMailboxes)
|
||||
{
|
||||
# Update Write-Progress
|
||||
$ProgressActivity = ('Working on Mailbox {0} of {1} ({2})' -f $MailboxCount, $MailboxCounter, $SingleMailbox.UserPrincipalName)
|
||||
$ProgressStatus = ('Getting folders for mailbox: {0} ({1})' -f $SingleMailbox.DisplayName, $SingleMailbox.UserPrincipalName)
|
||||
|
||||
Write-Verbose -Message $ProgressStatus
|
||||
|
||||
$paramWriteProgress = @{
|
||||
Status = $ProgressStatus
|
||||
Activity = $ProgressActivity
|
||||
PercentComplete = (($MailboxCount/$MailboxCounter) * 100)
|
||||
}
|
||||
Write-Progress @paramWriteProgress
|
||||
|
||||
$MailboxPermissionReport += $SingleMailbox | Get-MailboxPermission | Where-Object -FilterScript {
|
||||
($_.IsInherited -eq $false) -and -not ($_.User -match 'NT AUTHORITY')
|
||||
} | Select-Object -Property 'Identity', @{
|
||||
Name = 'UserPrincipalName'
|
||||
Expression = {
|
||||
$SingleMailbox.UserPrincipalName
|
||||
}
|
||||
}, 'User', @{
|
||||
Name = 'Access Rights'
|
||||
Expression = {
|
||||
$_.AccessRights -join ','
|
||||
}
|
||||
} -ErrorAction $CNT -WarningAction $CNT
|
||||
}
|
||||
#endregion MailboxLoop
|
||||
|
||||
#region Reporter
|
||||
if ($MailboxPermissionReport)
|
||||
{
|
||||
$paramExportCsv = @{
|
||||
Path = $Path
|
||||
Force = $true
|
||||
NoTypeInformation = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$null = ($MailboxPermissionReport | Export-Csv @paramExportCsv)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'None of the Mailboxes has special permissions set'
|
||||
}
|
||||
#endregion Reporter
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No Mailboxes found that matches your search criteria'
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region Cleanup
|
||||
$MailboxPermissionReport = $null
|
||||
$AllMailboxes = $null
|
||||
#endregion Cleanup
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,335 @@
|
||||
function Get-enMailboxSendAsReport
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a detailed mailbox Send permission report
|
||||
|
||||
.DESCRIPTION
|
||||
Get a detailed mailbox Send permission report and exports this report to a given CSV file.
|
||||
You can select only user-mailboxes, only shared-mailboxes or both for the reporting.
|
||||
|
||||
.PARAMETER Identity
|
||||
The Identity parameter specifies the mailbox that you want to view.
|
||||
You can use any value that uniquely identifies the mailbox.
|
||||
|
||||
Default is * (all)
|
||||
|
||||
.PARAMETER MailboxType
|
||||
The type is the value for the regular RecipientTypeDetails.
|
||||
|
||||
The acceptable values for this parameter are:
|
||||
- UserMailbox
|
||||
- User
|
||||
- SharedMailbox
|
||||
- Shared
|
||||
- All
|
||||
|
||||
The Default is ALL
|
||||
|
||||
.PARAMETER ResultSize
|
||||
The ResultSize parameter specifies the maximum number of results to return.
|
||||
If you want to return all requests that match the query, use unlimited for the value of this parameter.
|
||||
|
||||
The default value is unlimited.
|
||||
|
||||
.PARAMETER Path
|
||||
Specifies the path to the CSV output file.
|
||||
|
||||
The default is 'C:\scripts\PowerShell\Reports\MailboxSendAsReport.csv'
|
||||
|
||||
.PARAMETER Encoding
|
||||
Specifies the encoding for the exported CSV file.
|
||||
The acceptable values for this parameter are:
|
||||
- Unicode
|
||||
- UTF7
|
||||
- UTF8
|
||||
- ASCII
|
||||
- UTF32
|
||||
- BigEndianUnicode
|
||||
- Default
|
||||
- OEM
|
||||
|
||||
Default is UTF8
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-enMailboxSendAsReport
|
||||
|
||||
Get a detailed mailbox permission report
|
||||
|
||||
.NOTES
|
||||
Developed and tested with Exchange Online, it should work with on Premises Exchange 2010/2010/2016/2019
|
||||
|
||||
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
|
||||
|
||||
.LINK
|
||||
http://www.enatec.io
|
||||
|
||||
.LINK
|
||||
Get-Mailbox
|
||||
|
||||
.LINK
|
||||
Get-RecipientPermission
|
||||
|
||||
.LINK
|
||||
Export-Csv
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[Alias('Mailbox', 'MailboxID', 'MailboxIdentity')]
|
||||
[string]
|
||||
$Identity = '*',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateSet('UserMailbox', 'User', 'SharedMailbox', 'Shared', 'All', IgnoreCase = $true)]
|
||||
[string]
|
||||
$MailboxType = 'All',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('MailboxResultSize')]
|
||||
[string]
|
||||
$ResultSize = 'Unlimited',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('CsvReport', 'CsvFile')]
|
||||
[string]
|
||||
$Path = 'C:\scripts\PowerShell\Reports\MailboxSendAsReport.csv',
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateSet('Unicode', 'UTF7', 'UTF8', 'ASCII', 'UTF32', 'BigEndianUnicode', 'Default', 'OEM', IgnoreCase = $true)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[Alias('CsvEncoding')]
|
||||
[string]
|
||||
$Encoding = 'UTF8'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Cleanup
|
||||
$MailboxPermissionReport = $null
|
||||
$AllMailboxes = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region Defaults
|
||||
$SCT = 'SilentlyContinue'
|
||||
$CNT = 'Continue'
|
||||
|
||||
if (-not ($Identity))
|
||||
{
|
||||
$Identity = '*'
|
||||
}
|
||||
|
||||
if (-not ($MailboxType))
|
||||
{
|
||||
$MailboxType = 'All'
|
||||
}
|
||||
|
||||
if (-not ($ResultSize))
|
||||
{
|
||||
$ResultSize = 'Unlimited'
|
||||
}
|
||||
|
||||
if (-not ($Path))
|
||||
{
|
||||
$Path = 'C:\scripts\PowerShell\Reports\MailboxSendAsReport.csv'
|
||||
}
|
||||
|
||||
if (-not ($Encoding))
|
||||
{
|
||||
$Encoding = 'UTF8'
|
||||
}
|
||||
#endregion Defaults
|
||||
|
||||
#region MailboxType
|
||||
Write-Verbose -Message 'Get the mailboxes'
|
||||
|
||||
#region paramGetMailbox
|
||||
$paramGetMailbox = @{
|
||||
Identity = $Identity
|
||||
ResultSize = $ResultSize
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $CNT
|
||||
}
|
||||
#endregion paramGetMailbox
|
||||
|
||||
#region MailboxTypeSwitch
|
||||
switch ($MailboxType)
|
||||
{
|
||||
UserMailbox
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
User
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
SharedMailbox
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
Shared
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
All
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox' -or $_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
default
|
||||
{
|
||||
$paramWhereObject = @{
|
||||
FilterScript = {
|
||||
$_.RecipientTypeDetails -eq 'UserMailbox' -or $_.RecipientTypeDetails -eq 'SharedMailbox'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion MailboxTypeSwitch
|
||||
|
||||
#region GetAllMailboxes
|
||||
$AllMailboxes = (Get-Mailbox @paramGetMailbox | Where-Object @paramWhereObject | Sort-Object)
|
||||
#endregion GetAllMailboxes
|
||||
#endregion MailboxType
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($AllMailboxes)
|
||||
{
|
||||
# Create a new object for the report
|
||||
$MailboxPermissionReport = @()
|
||||
|
||||
# Create a counter for Write-Progress
|
||||
$MailboxCounter = ($AllMailboxes | Measure-Object).Count
|
||||
|
||||
# Set the start counter for Write-Progress to 1
|
||||
$MailboxCount = 1
|
||||
|
||||
#region MailboxLoop
|
||||
Write-Verbose -Message 'Process all mailboxes'
|
||||
|
||||
ForEach ($SingleMailbox in $AllMailboxes)
|
||||
{
|
||||
# Update Write-Progress
|
||||
$ProgressActivity = ('Working on Mailbox {0} of {1} ({2})' -f $MailboxCount, $MailboxCounter, $SingleMailbox.UserPrincipalName)
|
||||
$ProgressStatus = ('Getting folders for mailbox: {0} ({1})' -f $SingleMailbox.DisplayName, $SingleMailbox.UserPrincipalName)
|
||||
|
||||
Write-Verbose -Message $ProgressStatus
|
||||
|
||||
$paramWriteProgress = @{
|
||||
Status = $ProgressStatus
|
||||
Activity = $ProgressActivity
|
||||
PercentComplete = (($MailboxCount/$MailboxCounter) * 100)
|
||||
}
|
||||
Write-Progress @paramWriteProgress
|
||||
|
||||
$MailboxPermissionReport += $SingleMailbox | Get-RecipientPermission | Where-Object -FilterScript {
|
||||
($_.IsInherited -eq $false) -and -not ($_.Trustee -match 'NT AUTHORITY')
|
||||
} | Select-Object -Property 'Identity', @{
|
||||
Name = 'UserPrincipalName'
|
||||
Expression = {
|
||||
$SingleMailbox.UserPrincipalName
|
||||
}
|
||||
}, 'Trustee', @{
|
||||
Name = 'Access Rights'
|
||||
Expression = {
|
||||
$_.AccessRights -join ','
|
||||
}
|
||||
} -ErrorAction $CNT -WarningAction $CNT
|
||||
}
|
||||
#endregion MailboxLoop
|
||||
|
||||
#region Reporter
|
||||
if ($MailboxPermissionReport)
|
||||
{
|
||||
$paramExportCsv = @{
|
||||
Path = $Path
|
||||
Force = $true
|
||||
NoTypeInformation = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$null = ($MailboxPermissionReport | Export-Csv @paramExportCsv)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'None of the Mailboxes has special permissions set'
|
||||
}
|
||||
#endregion Reporter
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No Mailboxes found that matches your search criteria'
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region Cleanup
|
||||
$MailboxPermissionReport = $null
|
||||
$AllMailboxes = $null
|
||||
#endregion Cleanup
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
29
Powershell/PowerShell-collection/ExchangeOnline/LICENSE
Normal file
29
Powershell/PowerShell-collection/ExchangeOnline/LICENSE
Normal 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.
|
||||
@@ -0,0 +1,370 @@
|
||||
function Search-MailboxItemDeletion
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Search for deletions in mailboxes
|
||||
|
||||
.DESCRIPTION
|
||||
Search for deletions in mailboxes, single or all
|
||||
|
||||
.PARAMETER Days
|
||||
Day (period) to search, max. 90 (or 30, based on your O365/M365 license).
|
||||
The default is 7 (for the last 7 days)
|
||||
Minimum is 1, maximum is 90. This will be checked
|
||||
|
||||
.PARAMETER Mailbox
|
||||
Mailbox Address
|
||||
e.g. info@contoso.com
|
||||
|
||||
.PARAMETER All
|
||||
Get all deletes, for all mailboxes
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -All
|
||||
|
||||
Get all deletes, for all mailboxes
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -Days 2 | Where-Object -FilterScript { $_.Folder -ne 'Deleted Items' }
|
||||
|
||||
Get all deletes of the last 2 days, for all mailboxes, but we exclude one Folder.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -Days 7 | Where-Object -FilterScript { $_.Folder -ne 'Deleted Items' }
|
||||
|
||||
Get all deletes of the last 7 days, for all mailboxes, but we exclude one Folder.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -Days 30 | Where-Object -FilterScript { ($_.Folder -ne 'Drafts') -and ($_.Action -ne 'SoftDelete') }
|
||||
|
||||
Get all deletes of the last 30 days, for all mailboxes, but we exclude one Folder and the 'SoftDelete' action
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -Days 21 -All
|
||||
|
||||
Get all deletes for the last 21 days, for all mailboxes
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -All | Out-GridView
|
||||
|
||||
Search for Deletions in all mailboxes and open the result in the GridView (e.g. for filtering)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -Mailbox 'info@contoso.com'
|
||||
|
||||
Search for Deletions in the mailbox 'info@contoso.com'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -Mailbox 'info@contoso.com' | Select-Object -Property 'Timestamp', 'Action', 'Status' , 'User', 'Mailbox', 'Subject', 'Folder', 'Client', 'ClientIP'
|
||||
|
||||
Search for Deletions in the mailbox 'info@contoso.com', and get a few more properties (e.g. Status, Client, and ClientIP).
|
||||
Might be handy to see from where it was triggered and what client was used.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Search-MailboxItemDeletion -Mailbox 'info@contoso.com' | Export-CSV -NoTypeInformation -Path c:\scripts\PowerShell\exports\ExchangeOnlineMailboxDeletes.csv
|
||||
|
||||
Search for Deletions in the mailbox 'info@contoso.com' and export the result into a CSV File (e.g. for a basic reporting or further investigation in Excel)
|
||||
|
||||
.OUTPUTS
|
||||
array
|
||||
|
||||
.LINK
|
||||
Search-UnifiedAuditLog
|
||||
|
||||
.NOTES
|
||||
For now, the following properties are supported:
|
||||
Action string
|
||||
AppId string
|
||||
Client string
|
||||
ClientIP string
|
||||
External bool
|
||||
ExternalAccess bool
|
||||
Folder string
|
||||
InternalLogonType int
|
||||
InternetMessageId string
|
||||
LogonType int
|
||||
Mailbox string
|
||||
MailboxGuid string
|
||||
MessageId string
|
||||
OrganizationId string
|
||||
OrganizationName string
|
||||
OriginatingServer string
|
||||
SessionId string
|
||||
Status string
|
||||
Subject string
|
||||
TimeStamp string
|
||||
User string
|
||||
|
||||
By default, the following properties are returned (all others can be selected):
|
||||
TimeStamp string
|
||||
Action string
|
||||
User string
|
||||
Mailbox string
|
||||
Subject string
|
||||
Folder string
|
||||
|
||||
Requirements:
|
||||
PowerShell or Windows PowerShell
|
||||
Exchange Online connection (e.g. the installed Module and you need to be connected with a user that has rights to use Search-UnifiedAuditLog)
|
||||
|
||||
A future version might support Wildcards in the Mailbox parameter and/or multi Mailbox searches.
|
||||
Workaround: use Where-Object with a powerful FilterScript!
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName = 'All',
|
||||
ConfirmImpact = 'None')]
|
||||
[OutputType([array])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateNotNull()]
|
||||
[int]
|
||||
$Days = 7,
|
||||
[Parameter(ParameterSetName = 'Single', HelpMessage = 'Mailbox Address e.g. info@contoso.com',
|
||||
Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateNotNull()]
|
||||
[Alias('MailboxName', 'MailboxAddress')]
|
||||
[string]
|
||||
$Mailbox,
|
||||
[Parameter(ParameterSetName = 'All')]
|
||||
[switch]
|
||||
$All
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Garbage Collection
|
||||
[GC]::Collect()
|
||||
|
||||
# Cleanup
|
||||
$Records = $null
|
||||
|
||||
# TimeSpan
|
||||
$StartDate = (Get-Date).AddDays(-$Days)
|
||||
|
||||
# Now
|
||||
$EndDate = (Get-Date)
|
||||
|
||||
#region HelperFunctions
|
||||
function Get-StandardMembersFromPSObject
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Filter the given properties from a given Object
|
||||
|
||||
.DESCRIPTION
|
||||
Filter the given properties from a given Object
|
||||
|
||||
.PARAMETER InputObject
|
||||
The input object, must be a psobject.
|
||||
|
||||
.PARAMETER Properties
|
||||
The properties to select from the given input object.
|
||||
Multiple values needs to separated by a comma.
|
||||
|
||||
.EXAMPLE
|
||||
Get-StandardMembersFromPSObject -InputObject Value -Properties Value
|
||||
Describe what this call does
|
||||
|
||||
.OUTPUTS
|
||||
psobject
|
||||
|
||||
.NOTES
|
||||
Just an internal Helper function
|
||||
|
||||
.LINK
|
||||
https://learn-powershell.net/2013/08/03/quick-hits-set-the-default-property-display-in-powershell-on-custom-objects/
|
||||
.LINK
|
||||
http://stackoverflow.com/questions/1369542/can-you-set-an-objects-defaultdisplaypropertyset-in-a-powershell-v2-script/1891215#1891215
|
||||
|
||||
.INPUTS
|
||||
psobject, string
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
HelpMessage = 'The input object, must be a psobject.')]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[psobject]
|
||||
$InputObject,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('DefaultProperties')]
|
||||
[string[]]
|
||||
$Properties = $null
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
try
|
||||
{
|
||||
$defaultDisplayPropertySet = (New-Object -TypeName System.Management.Automation.PSPropertySet -ArgumentList ('DefaultDisplayPropertySet', [string[]]$Properties))
|
||||
$PSStandardMembers = ([Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet))
|
||||
$InputObject | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers -Force
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion HelperFunctions
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the UnifiedAuditLog Data, with the delete operations
|
||||
$Records = (Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Operations 'HardDelete', 'SoftDelete')
|
||||
|
||||
# Do we have a result
|
||||
if ($Records)
|
||||
{
|
||||
Write-Verbose -Message ('Processing ' + $Records.Count + ' audit records...')
|
||||
|
||||
# Create a new Object
|
||||
$Report = [Collections.Generic.List[Object]]::new()
|
||||
|
||||
foreach ($Rec in $Records)
|
||||
{
|
||||
$AuditData = (ConvertFrom-Json -InputObject $Rec.Auditdata)
|
||||
|
||||
if ($AuditData.ResultStatus -eq 'PartiallySucceeded')
|
||||
{
|
||||
$MessageSubject = '# Not fully deleted by' + $AuditData.ClientInfoString + ' #'
|
||||
}
|
||||
else
|
||||
{
|
||||
$MessageSubject = ($AuditData.AffectedItems.Subject -split '\n')[0]
|
||||
}
|
||||
|
||||
$ReportLine = [PSCustomObject] @{
|
||||
TimeStamp = (Get-Date -Date ($AuditData.CreationTime) -Format g)
|
||||
User = $AuditData.UserId
|
||||
Action = $AuditData.Operation
|
||||
Status = $AuditData.ResultStatus
|
||||
Mailbox = $AuditData.MailboxOwnerUPN
|
||||
MailboxGuid = $AuditData.MailboxGuid
|
||||
Subject = $MessageSubject
|
||||
MessageId = ($AuditData.AffectedItems.Id -split '\n')[0]
|
||||
InternetMessageId = ($AuditData.AffectedItems.InternetMessageId -split '\n')[0]
|
||||
Folder = $AuditData.Folder.Path.Split('\')[1]
|
||||
Client = $AuditData.ClientInfoString
|
||||
AppId = $AuditData.AppId
|
||||
ClientIP = $AuditData.ClientIP
|
||||
External = $AuditData.ExternalAccess
|
||||
SessionId = $AuditData.SessionId
|
||||
ExternalAccess = $AuditData.ExternalAccess
|
||||
InternalLogonType = $AuditData.InternalLogonType
|
||||
LogonType = $AuditData.LogonType
|
||||
OrganizationName = $AuditData.OrganizationName
|
||||
OrganizationId = $AuditData.OrganizationId
|
||||
OriginatingServer = $AuditData.OriginatingServer
|
||||
}
|
||||
|
||||
# Define the default properties and support Select-Object
|
||||
Get-StandardMembersFromPSObject -InputObject $ReportLine -Properties 'Timestamp', 'Action', 'User', 'Mailbox', 'Subject', 'Folder'
|
||||
|
||||
# Add to the reporting
|
||||
$Report.Add($ReportLine)
|
||||
}
|
||||
|
||||
$Records = $null
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output -InputObject 'No deletion records found.'
|
||||
break
|
||||
}
|
||||
|
||||
# Create a new array object
|
||||
$Output = @()
|
||||
|
||||
# Single or all ?
|
||||
switch ($PsCmdlet.ParameterSetName)
|
||||
{
|
||||
'Single'
|
||||
{
|
||||
$Output = ($Report | Where-Object -FilterScript {
|
||||
# You might want to tweak the filter to support Wildcards or more the one mailbox
|
||||
$_.Mailbox -eq $Mailbox
|
||||
})
|
||||
}
|
||||
'All'
|
||||
{
|
||||
$Output = ($Report | Sort-Object -Property Mailbox)
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$Report = $null
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Just dump the result to the terminal
|
||||
$Output
|
||||
|
||||
# Cleanup
|
||||
$Output = $null
|
||||
|
||||
# Garbage Collection
|
||||
[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
|
||||
@@ -0,0 +1,167 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Cleanup Microsoft Teams Client
|
||||
|
||||
.DESCRIPTION
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-MicrosoftTeamsClientCache.ps1
|
||||
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-MicrosoftTeamsClientCache.ps1 -Verbose
|
||||
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files, but be verbose while doing it
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-MicrosoftTeamsClientCache.ps1 -WhatIf
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files - Dry Run!!!
|
||||
|
||||
.NOTES
|
||||
Due to some issues, Windows is not supported at this time!
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
if ($IsMacOS -eq $true)
|
||||
{
|
||||
$AppDataBasePath = '~/Library/Application Support/Microsoft/Teams/'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'Due to some issues, Windows is not supported at this time!'
|
||||
|
||||
exit 1
|
||||
|
||||
$AppDataBasePath = ($env:APPDATA + '\Microsoft\teams\')
|
||||
}
|
||||
|
||||
#region BoundParameters
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$VerboseValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$VerboseValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$DebugValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$DebugValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['WhatIf']).IsPresent)
|
||||
{
|
||||
$WhatIfValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$WhatIfValue = $false
|
||||
}
|
||||
#endregion BoundParameters
|
||||
|
||||
#region
|
||||
$paramGetChildItem = @{
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
Recurse = $true
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
|
||||
$paramRemoveItem = @{
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
WhatIf = $WhatIfValue
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
Recurse = $true
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region
|
||||
if ($PSCmdlet.ShouldProcess('Microsoft Teams Client', 'Hard Kill'))
|
||||
{
|
||||
$null = (Get-Process -Name Teams -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue)
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
#endregion
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'blob_storage') @paramGetChildItem -Verbose -Debug | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem -WhatIf
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'databases') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'Cache') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'gpucache') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'IndexedDB') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName -Confirm:$false -Force -Recurse -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'Local Storage') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'tmp') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path $AppDataBasePath -Include 'old_logs_*.txt', 'logs.txt', 'in_progress_download_metadata_store' @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
if (Test-Path -Path ($AppDataBasePath + 'installTime.txt'))
|
||||
{
|
||||
$InstallDateInput = (Get-Content -Path ($AppDataBasePath + 'installTime.txt'))
|
||||
$Culture = (New-Object -TypeName System.Globalization.CultureInfo -ArgumentList ('de-DE'))
|
||||
$InstallDate = (Get-Date -Date $InstallDateInput -Format ($Culture.DateTimeFormat.ShortDatePattern))
|
||||
|
||||
Write-Output -InputObject ('Latest Version of Microsoft Teams from: {0}' -f $InstallDate)
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,535 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Microsoft Teams Client customization settings via PowerShell
|
||||
|
||||
.DESCRIPTION
|
||||
Microsoft Teams Client customization settings via PowerShell
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Default_MicrosoftTeams_DesktopConfig.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Default_MicrosoftTeams_DesktopConfig.ps1 -verbose
|
||||
|
||||
.NOTES
|
||||
Refactored and extended version of Desktop-Config-Json.ps1 by eshlomo1
|
||||
|
||||
.LINK
|
||||
https://github.com/eshlomo1/MS_Teams/blob/master/Desktop-Config-Json.ps1
|
||||
|
||||
.LINK
|
||||
https://www.eshlomo.us/microsoft-teams-client-personalization-with-powershell/
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
#region DefaultSettings
|
||||
$AppPrefSetOpenAsHidden = $false
|
||||
$AppPrefSetOpenAtLogin = $false
|
||||
$AppPrefSetRegisterAsIMProvider = $true
|
||||
$AppPrefSetRunningOnClose = $false
|
||||
$NotificationWindowOnClose = $true
|
||||
$OverrideOpenAsHiddenProperty = $true
|
||||
$IsAppFirstRun = $false
|
||||
$CurrentWebLanguage = 'en-us'
|
||||
#endregion DefaultSettings
|
||||
|
||||
#region Cleanup
|
||||
$ChangedConfig = $null
|
||||
$SourceConfigFile = $null
|
||||
$Teams = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region SetConfigPath
|
||||
if (($PSVersionTable.PSEdition -eq 'Core') + ($PSVersionTable.Platform -eq 'Unix') -and ($PSVersionTable.OS -like 'Darwin*'))
|
||||
{
|
||||
# OK, macOS is supported
|
||||
$SourceConfigFile = ($Env:HOME + '/Library/Application Support/Microsoft/Teams/desktop-config.json')
|
||||
}
|
||||
elseif (($PSVersionTable.PSEdition -eq 'Core') + ($PSVersionTable.Platform -eq 'Unix') -and ($PSVersionTable.OS -like 'Linux*'))
|
||||
{
|
||||
# Sorry, Linux is not supported...
|
||||
$paramWriteError = @{
|
||||
Message = 'Sorry, Linux is not supported...'
|
||||
Exception = 'Sorry, Linux is not supported!'
|
||||
Category = 'NotImplemented'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
{
|
||||
# Windows? Really??? OK, sure this is supported
|
||||
$SourceConfigFile = ($env:userprofile + '\AppData\Roaming\Microsoft\Teams\desktop-config.json')
|
||||
}
|
||||
#endregion SetConfigPath
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if (Test-Path -Path $SourceConfigFile -ErrorAction SilentlyContinue -WarningAction Continue)
|
||||
{
|
||||
#region GetConfig
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramGetContent = @{
|
||||
Path = $SourceConfigFile
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$Teams = (Get-Content @paramGetContent | ConvertFrom-Json -ErrorAction Stop)
|
||||
|
||||
# Cleanup
|
||||
$paramGetContent = $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
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
#endregion GetConfig
|
||||
|
||||
#region
|
||||
if ($Teams.appPreferenceSettings)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.openAsHidden)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.openAsHidden -ne $AppPrefSetOpenAsHidden)
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAsHidden will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.openAsHidden = $AppPrefSetOpenAsHidden
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of openAsHidden was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAsHidden is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter openAsHidden will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'openAsHidden'
|
||||
Value = $AppPrefSetOpenAsHidden
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter openAsHidden was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.appPreferenceSettings.openAtLogin)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.openAtLogin -ne $AppPrefSetOpenAtLogin)
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAtLogin will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.openAtLogin = $AppPrefSetOpenAtLogin
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of openAtLogin was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAtLogin is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter openAtLogin will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'openAtLogin'
|
||||
Value = $AppPrefSetOpenAtLogin
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter openAtLogin was created with the desired default value'
|
||||
}
|
||||
|
||||
if (($PSVersionTable.PSEdition -eq 'Core') + ($PSVersionTable.Platform -eq 'Unix') -and ($PSVersionTable.OS -like 'Darwin*') )
|
||||
{
|
||||
Write-Verbose -Message 'The setting registerAsIMProvider is not supported on macOS...'
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.registerAsIMProvider)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.registerAsIMProvider -ne $AppPrefSetRegisterAsIMProvider)
|
||||
{
|
||||
Write-Verbose -Message 'Value of registerAsIMProvider will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.registerAsIMProvider = $AppPrefSetRegisterAsIMProvider
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of registerAsIMProvider was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of registerAsIMProvider is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter registerAsIMProvider will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'registerAsIMProvider'
|
||||
Value = $AppPrefSetRegisterAsIMProvider
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter registerAsIMProvider was created with the desired default value'
|
||||
}
|
||||
}
|
||||
|
||||
if ($Teams.appPreferenceSettings.runningOnClose)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.runningOnClose -ne $AppPrefSetRunningOnClose)
|
||||
{
|
||||
Write-Verbose -Message 'Value of runningOnClose will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.runningOnClose = $AppPrefSetRunningOnClose
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of runningOnClose was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of runningOnClose is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter runningOnClose will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'runningOnClose'
|
||||
Value = $AppPrefSetRunningOnClose
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter runningOnClose was created with the desired default value'
|
||||
}
|
||||
}
|
||||
|
||||
if ($Teams.notificationWindowOnClose)
|
||||
{
|
||||
if ($Teams.notificationWindowOnClose -ne $NotificationWindowOnClose)
|
||||
{
|
||||
Write-Verbose -Message 'Value of notificationWindowOnClose will be changed to the desired default'
|
||||
|
||||
$Teams.notificationWindowOnClose = $NotificationWindowOnClose
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of notificationWindowOnClose was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of notificationWindowOnClose is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'notificationWindowOnClose'
|
||||
Value = $NotificationWindowOnClose
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.overrideOpenAsHiddenProperty)
|
||||
{
|
||||
if ($Teams.overrideOpenAsHiddenProperty -ne $OverrideOpenAsHiddenProperty)
|
||||
{
|
||||
Write-Verbose -Message 'Value of overrideOpenAsHiddenProperty will be changed to the desired default'
|
||||
|
||||
$Teams.overrideOpenAsHiddenProperty = $OverrideOpenAsHiddenProperty
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of overrideOpenAsHiddenProperty was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of overrideOpenAsHiddenProperty is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter overrideOpenAsHiddenProperty will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'overrideOpenAsHiddenProperty'
|
||||
Value = $OverrideOpenAsHiddenProperty
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter overrideOpenAsHiddenProperty was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.isAppFirstRun)
|
||||
{
|
||||
if ($Teams.isAppFirstRun -ne $IsAppFirstRun)
|
||||
{
|
||||
Write-Verbose -Message 'Value of isAppFirstRun will be changed to the desired default'
|
||||
|
||||
$Teams.isAppFirstRun = $IsAppFirstRun
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of isAppFirstRun was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of isAppFirstRun is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter isAppFirstRun will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'isAppFirstRun'
|
||||
Value = $false
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter isAppFirstRun was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.currentWebLanguage)
|
||||
{
|
||||
if ($Teams.currentWebLanguage -ne $CurrentWebLanguage)
|
||||
{
|
||||
Write-Verbose -Message 'Value of currentWebLanguage will be changed to the desired default'
|
||||
|
||||
$Teams.currentWebLanguage = $CurrentWebLanguage
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of currentWebLanguage was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of currentWebLanguage is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'currentWebLanguage'
|
||||
Value = $CurrentWebLanguage
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
#Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage was created with the desired default value'
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SaveNewConfig
|
||||
if ($ChangedConfig)
|
||||
{
|
||||
Write-Verbose -Message 'Changed configuration will be saved'
|
||||
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramConvertToJson = @{
|
||||
Compress = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
|
||||
$paramSetContent = @{
|
||||
Path = $SourceConfigFile
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
|
||||
$null = ($Teams | ConvertTo-Json @paramConvertToJson | Set-Content @paramSetContent)
|
||||
|
||||
# Cleanup
|
||||
$paramConvertToJson = $null
|
||||
$paramSetContent = $null
|
||||
$Teams = $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
|
||||
}
|
||||
|
||||
# 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 'Changed configuration was saved'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No changes made to the configuration'
|
||||
}
|
||||
#endregion SaveNewConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No Configuration File for Microsoft Teams was found.'
|
||||
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,65 @@
|
||||
#requires -Version 2.0 -Modules MicrosoftTeams
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a List of external Microsoft Teams Applications
|
||||
|
||||
.DESCRIPTION
|
||||
Get a List of external Microsoft Teams Applications for the tenant.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-AllExternalTeamsApps.ps1
|
||||
|
||||
Get a List of external Microsoft Teams Applications for the tenant.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-AllExternalTeamsApps.ps1 | Select-Object -Property DisplayName, DistributionMethod
|
||||
|
||||
Get a List of external Microsoft Teams Applications for the tenant.
|
||||
|
||||
.NOTES
|
||||
You need to use the Microsoft Teams Cmdlets module
|
||||
|
||||
If you don't have, install it from the gallery:
|
||||
Install-Module -Name MicrosoftTeams
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
<#
|
||||
Simple filter: External Apps will have the ExternalId field filled,
|
||||
where store apps (from the Microsoft Teams App Store) not.
|
||||
#>
|
||||
Get-TeamsApp | Where-Object -FilterScript {
|
||||
$_.ExternalId
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,717 @@
|
||||
#requires -Version 3.0 -Modules MicrosoftTeams
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Collects assigned phone numbers from Microsoft Teams
|
||||
|
||||
.DESCRIPTION
|
||||
This script queries Microsoft Teams for assigned numbers and displays in a formatted table with the option to export the report in several formats
|
||||
During processing LineURI's are run against a regex pattern to extract the DDI/DID and the extension to a separate column
|
||||
|
||||
This script collects Microsoft Teams objects including:
|
||||
Users, Meeting Rooms, Online Application Instances (Resource Accounts)
|
||||
|
||||
.PARAMETER OutputType
|
||||
Define the Script Output
|
||||
|
||||
Valid values are:
|
||||
CONSOLE - Dump a formatted list into the console
|
||||
HTML - Create a simple HTML report with Tables. Only here to be compatible to our older version
|
||||
XML - Create a simple Extensible Markup Language (XML) report
|
||||
YAML - Create a simple YAML Ain't Markup Language (YAML) report
|
||||
JSON - Create a simple JavaScript Object Notation (JSON) report. Handy if you need to upload the data via WebServices/APIs
|
||||
CSV - Create a simple comma-separated values (CSV) report. This is perfect for re-use within Excel, or other applications
|
||||
|
||||
If you leave it empty (this is the default), the object will be dumped to the console!
|
||||
This can become handy, if you use this script to generate the report and re-use it in the pipe or your own application
|
||||
|
||||
.PARAMETER Path
|
||||
Where to store the Report File
|
||||
|
||||
Default is 'C:\scripts\PowerShell\logs\'
|
||||
|
||||
.PARAMETER DateFormat
|
||||
Use the format for Get-Date
|
||||
|
||||
Default is 'yyyyMMdd-HHmmUTC'
|
||||
|
||||
.PARAMETER UTC
|
||||
Use ToUniversalTime for the Date Strings
|
||||
|
||||
Default is $true
|
||||
|
||||
.PARAMETER Report
|
||||
Define what to report.
|
||||
|
||||
Valid values are:
|
||||
Users - Report numbers assigned to users
|
||||
MeetingRooms - Report numbers assigned to Meetings Room accounts
|
||||
ResourceAccounts - Report numbers assigned to Applications. (Auto Attendants (AA) and/or Call Queues (CQ) are supported)
|
||||
All - All assigned numbers (all above merged into one report)
|
||||
|
||||
Default is 'All'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1
|
||||
|
||||
The Report will be dumped to the console (unformatted)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report MeetingRooms
|
||||
|
||||
Dump a formatted report for numbers assigned to Meeting Rooms into the console
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report ResourceAccounts
|
||||
|
||||
Dump a formatted report for numbers assigned to Resource Accounts into the console
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report Users
|
||||
|
||||
Dump a formatted report for numbers assigned to Resource Accounts into the console
|
||||
This will contain function users for Resource Accounts and Meeting Rooms, but they will be shown as user object!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report all
|
||||
|
||||
Dump a formatted report for every assigned number into the console
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType HTML
|
||||
|
||||
Create a simple HTML report with Tables.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType XML
|
||||
|
||||
Create a simple Extensible Markup Language (XML) report
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType YAML
|
||||
|
||||
Create a simple YAML Ain't Markup Language (YAML) report
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType JSON
|
||||
|
||||
Create a simple JavaScript Object Notation (JSON) report.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CSV
|
||||
|
||||
Create a simple comma-separated values (CSV) report.
|
||||
|
||||
.LINK
|
||||
https://github.com/ucgeek/Get-TeamsAssignedNumbers
|
||||
|
||||
.LINK
|
||||
https://github.com/ucgeek/Get-TeamsAssignedNumbers/blob/master/LICENSE
|
||||
|
||||
.NOTES
|
||||
Based on the work off Andrew Morpeth (@ucgeek and https://ucgeek.co/)
|
||||
Licensed under the GNU General Public License v3.0 terms (by @ucgeek)
|
||||
|
||||
REQUIREMENTS:
|
||||
If you haven't already, you will need to install the MicrosoftTeams PowerShell module
|
||||
The script assumes, you are connect to the Teams/Skype for Business Online Service of Microsoft Office 365
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowNull()]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[ValidateSet('CONSOLE', 'HTML', 'XML', 'YAML', 'JSON', 'CSV', IgnoreCase = $true)]
|
||||
[Alias('ReportFormat')]
|
||||
[string]
|
||||
$OutputType = $null,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowNull()]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[string]
|
||||
$Path = 'C:\scripts\PowerShell\logs',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowNull()]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[string]
|
||||
$DateFormat = 'yyyyMMdd-HHmmUTC',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('UseUTC')]
|
||||
[switch]
|
||||
$UTC,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[AllowNull()]
|
||||
[ValidateSet('Users', 'MeetingRooms', 'ResourceAccounts', 'All', IgnoreCase = $true)]
|
||||
[Alias('ReportType')]
|
||||
[string[]]
|
||||
$Report = 'All'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region BoundParameters
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$VerboseValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$VerboseValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$DebugValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$DebugValue = $false
|
||||
}
|
||||
#endregion BoundParameters
|
||||
|
||||
#region DateToUTC
|
||||
if (-not ($UTC))
|
||||
{
|
||||
$UTC = $true
|
||||
}
|
||||
#endregion DateToUTC
|
||||
|
||||
#region UseDateUTC
|
||||
if (($UTC -eq $true) -and ($DateFormat))
|
||||
{
|
||||
$FileName = ('MicrosoftTeamsAssignedNumbers_' + ((Get-Date).ToUniversalTime()).ToString($DateFormat))
|
||||
}
|
||||
#endregion UseDateUTC
|
||||
|
||||
#region UseDateFormat
|
||||
if ($DateFormat)
|
||||
{
|
||||
$FileName = ('MicrosoftTeamsAssignedNumbers_' + ((Get-Date).ToString($DateFormat)))
|
||||
}
|
||||
else
|
||||
{
|
||||
# This is the default
|
||||
$FileName = ('MicrosoftTeamsAssignedNumbers_' + (Get-Date -Format s).replace(':', '-'))
|
||||
}
|
||||
#endregion UseDateFormat
|
||||
|
||||
#region PathMangle
|
||||
if ($Path)
|
||||
{
|
||||
# Save to a given PATH
|
||||
$FilePath = ($Path + '\' + $FileName)
|
||||
}
|
||||
else
|
||||
{
|
||||
# Save here (where the script was started)
|
||||
$FilePath = ('.\' + $FileName)
|
||||
}
|
||||
#endregion PathMangle
|
||||
|
||||
#region Regex
|
||||
# Regex values
|
||||
$LineURIRegex = '^(?:tel:)?(?:\+)?(\d+)(?:;ext=(\d+))?(?:;([\w-]+))?$'
|
||||
#endregion Regex
|
||||
|
||||
#region ReportType
|
||||
if (-not ($Report))
|
||||
{
|
||||
$Report = 'All'
|
||||
}
|
||||
#endregion ReportType
|
||||
|
||||
# Cleanup
|
||||
$ReportData = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
#region Users
|
||||
if (($Report -eq 'Users') -or ($Report -eq 'All'))
|
||||
{
|
||||
# Get Users with LineURI
|
||||
$UsersLineURI = $null
|
||||
$paramGetCsOnlineUser = @{
|
||||
ResultSize = 30000
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
Filter = {
|
||||
(LineURI -ne $null)
|
||||
}
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramSelectObject = @{
|
||||
Property = 'UserPrincipalName', 'LineURI', 'DisplayName', 'FirstName', 'LastName', 'Enabled', 'SipAddress'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$UsersLineURI = (Get-CsOnlineUser @paramGetCsOnlineUser | Select-Object @paramSelectObject)
|
||||
|
||||
if ($UsersLineURI)
|
||||
{
|
||||
Write-Verbose -Message 'Processing User Numbers'
|
||||
|
||||
foreach ($ReportingItem in $UsersLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
|
||||
($ReportingItem.PhoneNumber -match $LineURIRegex | Out-Null)
|
||||
|
||||
$ReportingObject = (New-Object -TypeName System.Object)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'UserPrincipalName' -Value $ReportingItem.UserPrincipalName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LineURI' -Value $ReportingItem.LineURI)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DDI' -Value $Matches[1])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Ext' -Value $Matches[2])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $ReportingItem.DisplayName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'FirstName' -Value $ReportingItem.FirstName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LastName' -Value $ReportingItem.LastName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'SipAddress' -Value $($ReportingItem.SipAddress -replace 'sip:', ''))
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $ReportingItem.Enabled)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Type' -Value 'User')
|
||||
|
||||
# Add to array
|
||||
$null = ($ReportData += $ReportingObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Users
|
||||
|
||||
#region MeetingRooms
|
||||
if (($Report -eq 'MeetingRooms') -or ($Report -eq 'All'))
|
||||
{
|
||||
# Get meeting room numbers
|
||||
$MeetingRoomLineURI = $null
|
||||
|
||||
$paramGetCsMeetingRoom = @{
|
||||
ResultSize = 10000
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
Filter = {
|
||||
LineURI -ne $null
|
||||
}
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramSelectObject = @{
|
||||
Property = 'UserPrincipalName', 'LineURI', 'DisplayName', 'Enabled', 'SipAddress'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$MeetingRoomLineURI = (Get-CsMeetingRoom @paramGetCsMeetingRoom | Select-Object @paramSelectObject)
|
||||
|
||||
if ($MeetingRoomLineURI)
|
||||
{
|
||||
Write-Verbose -Message 'Processing Meeting Room Numbers'
|
||||
|
||||
foreach ($ReportingItem in $MeetingRoomLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
|
||||
($ReportingItem.PhoneNumber -match $LineURIRegex | Out-Null)
|
||||
|
||||
$ReportingObject = (New-Object -TypeName System.Object)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'UserPrincipalName' -Value $ReportingItem.UserPrincipalName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LineURI' -Value $ReportingItem.LineURI)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DDI' -Value $Matches[1])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Ext' -Value $Matches[2])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $ReportingItem.DisplayName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'SipAddress' -Value $($ReportingItem.SipAddress -replace 'sip:', ''))
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $ReportingItem.Enabled)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Type' -Value 'Meeting Room')
|
||||
|
||||
# Remove existing User entry (Rooms have an user object as well)
|
||||
if ($ReportData.UserPrincipalName -contains $ReportingItem.UserPrincipalName)
|
||||
{
|
||||
$ReportData = ($ReportData | Where-Object -FilterScript {
|
||||
($_.UserPrincipalName -ne $ReportingItem.UserPrincipalName)
|
||||
})
|
||||
}
|
||||
|
||||
# Add to array
|
||||
$null = ($ReportData += $ReportingObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion MeetingRooms
|
||||
|
||||
#region ResourceAccounts
|
||||
if (($Report -eq 'ResourceAccounts') -or ($Report -eq 'All'))
|
||||
{
|
||||
# Get online resource accounts
|
||||
$OnlineApplicationInstanceLineURI = $null
|
||||
|
||||
$paramGetCsOnlineApplicationInstance = @{
|
||||
Force = $true
|
||||
ResultSize = 10000
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramSelectObject = @{
|
||||
Property = 'UserPrincipalName', 'DisplayName', 'PhoneNumber', 'ApplicationId', 'Enabled'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$OnlineApplicationInstanceLineURI = (Get-CsOnlineApplicationInstance @paramGetCsOnlineApplicationInstance | Where-Object -FilterScript {
|
||||
($_.PhoneNumber -ne $null)
|
||||
} -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Select-Object @paramSelectObject)
|
||||
|
||||
if ($OnlineApplicationInstanceLineURI)
|
||||
{
|
||||
Write-Verbose -Message 'Processing Online Application Instances (Resource Accounts) Numbers'
|
||||
|
||||
foreach ($ReportingItem in $OnlineApplicationInstanceLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
|
||||
($ReportingItem.PhoneNumber -match $LineURIRegex | Out-Null)
|
||||
|
||||
<#
|
||||
Workaround:
|
||||
|
||||
Get-CsOnlineApplicationInstance does not return an "Enabled" and "SipAddress" field,
|
||||
so we try to re-use any existing object information
|
||||
|
||||
Will not work all the time, only if regular users are reported as well!
|
||||
#>
|
||||
if ($ReportData.UserPrincipalName -contains $ReportingItem.UserPrincipalName)
|
||||
{
|
||||
# Cleanup
|
||||
$WorkaroundInfo = $null
|
||||
|
||||
$WorkaroundInfo = ($ReportData | Where-Object -FilterScript {
|
||||
($_.UserPrincipalName -eq $ReportingItem.UserPrincipalName)
|
||||
} | Select-Object -Property 'Enabled', 'SipAddress')
|
||||
|
||||
if (($WorkaroundInfo).Enabled)
|
||||
{
|
||||
$isAppEnabled = (($WorkaroundInfo).Enabled)
|
||||
}
|
||||
else
|
||||
{
|
||||
$isAppEnabled = 'unknown'
|
||||
}
|
||||
|
||||
if (($WorkaroundInfo).SipAddress)
|
||||
{
|
||||
$isSipAddress = (($WorkaroundInfo).SipAddress)
|
||||
}
|
||||
else
|
||||
{
|
||||
$isSipAddress = 'unknown'
|
||||
}
|
||||
}
|
||||
|
||||
$ReportingObject = (New-Object -TypeName System.Object)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'UserPrincipalName' -Value $ReportingItem.UserPrincipalName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LineURI' -Value $ReportingItem.PhoneNumber)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DDI' -Value $Matches[1])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Ext' -Value $Matches[2])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $ReportingItem.DisplayName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'SipAddress' -Value $isSipAddress)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $isAppEnabled)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Type' -Value $(
|
||||
if ($ReportingItem.ApplicationId -eq 'ce933385-9390-45d1-9512-c8d228074e07')
|
||||
{
|
||||
'Auto Attendant Resource Account'
|
||||
}
|
||||
elseif ($ReportingItem.ApplicationId -eq '11cd3e2e-fccb-42ad-ad00-878b93575e07')
|
||||
{
|
||||
'Call Queue Resource Account'
|
||||
}
|
||||
else
|
||||
{
|
||||
'Unknown Resource Account'
|
||||
}
|
||||
))
|
||||
|
||||
# Remove existing User entry (Apps have an user object as well)
|
||||
if ($ReportData.UserPrincipalName -contains $ReportingItem.UserPrincipalName)
|
||||
{
|
||||
$ReportData = ($ReportData | Where-Object -FilterScript {
|
||||
($_.UserPrincipalName -ne $ReportingItem.UserPrincipalName)
|
||||
})
|
||||
}
|
||||
|
||||
# Add to array
|
||||
$null = ($ReportData += $ReportingObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion ResourceAccounts
|
||||
|
||||
# Sort the Array data, based on the LineURI object
|
||||
$paramSortObject = @{
|
||||
Property = 'LineURI'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$ReportData = ($ReportData | Sort-Object @paramSortObject)
|
||||
|
||||
#region Output
|
||||
switch ($OutputType)
|
||||
{
|
||||
CSV
|
||||
{
|
||||
$FilePath = ($FilePath + '.csv')
|
||||
|
||||
$paramConvertToCsv = @{
|
||||
Delimiter = ','
|
||||
NoTypeInformation = $true
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$PsCsv = ($ReportData | ConvertTo-Csv @paramConvertToCsv)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsCsv | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your CSV report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
JSON
|
||||
{
|
||||
$FilePath = ($FilePath + '.json')
|
||||
|
||||
$paramConvertToJson = @{
|
||||
Depth = 5
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsJson = @($ReportData | ConvertTo-Json @paramConvertToJson)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsJson | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your JSON report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
YAML
|
||||
{
|
||||
if (Get-Command -Name 'ConvertTo-Yaml' -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$FilePath = ($FilePath + '.yml')
|
||||
|
||||
<#
|
||||
Workaround for ConvertTo-Yaml
|
||||
#>
|
||||
$paramJsonWorkaround = @{
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$ReportData = @($ReportData | ConvertTo-Json @paramJsonWorkaround | ConvertFrom-Json @paramJsonWorkaround)
|
||||
|
||||
$paramConvertToYaml = @{
|
||||
Data = $ReportData
|
||||
Force = $true
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsYaml = (ConvertTo-Yaml @paramConvertToYaml)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsYaml | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your YAML report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
else
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Exception = 'The ConvertTo-Yaml command was not found'
|
||||
Message = 'Please ensure, that the ''powershell-yaml'' module is installed.'
|
||||
Category = 'NotInstalled'
|
||||
RecommendedAction = 'Please use ''Install-Module -Name powershell-yaml'' to install the required module!'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
XML
|
||||
{
|
||||
$FilePath = ($FilePath + '.xml')
|
||||
|
||||
$paramConvertToXml = @{
|
||||
As = 'Stream'
|
||||
InputObject = $ReportData
|
||||
NoTypeInformation = $true
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsXML = (ConvertTo-Xml @paramConvertToXml)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsXML | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your XML report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
HTML
|
||||
{
|
||||
$FilePath = ($FilePath + '.html')
|
||||
|
||||
$Header = @"
|
||||
<title>Microsoft Teams assigned phone number report</title>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<style>
|
||||
table {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
background-color: #6495ED;
|
||||
}
|
||||
|
||||
td {
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
}
|
||||
</style>
|
||||
"@
|
||||
|
||||
$htmlParams = @{
|
||||
Title = 'Microsoft Teams assigned phone number report'
|
||||
Head = $Header
|
||||
body = '<h3>Microsoft Teams assigned phone number report</h3>'
|
||||
PreContent = '<p>The following Phone numbers are assigned in Microsoft Teams:</p>'
|
||||
PostContent = '<p><i>Last updated: ' + ((Get-Date).ToUniversalTime()).ToString('HH:MM dd.MM.yyyy (UTC)') + '</i></p>'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsHtml = ($ReportData | ConvertTo-Html @htmlParams)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsHtml | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your HTML report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
CONSOLE
|
||||
{
|
||||
$paramFormatTable = @{
|
||||
AutoSize = $true
|
||||
Property = 'UserPrincipalName', 'LineURI', 'DDI', 'Ext', 'DisplayName', 'Type'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($ReportData | Format-Table @paramFormatTable)
|
||||
|
||||
Write-Verbose -Message 'Formated Object was dumped'
|
||||
}
|
||||
default
|
||||
{
|
||||
$ReportData
|
||||
|
||||
Write-Verbose -Message 'Unformated Object was dumped'
|
||||
}
|
||||
}
|
||||
#endregion Output
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Cleanup
|
||||
$ReportData = $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
|
||||
@@ -0,0 +1,276 @@
|
||||
function Get-TeamsServiceNumbers
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the Phone numbers assigned to Teams/SfB Services
|
||||
|
||||
.DESCRIPTION
|
||||
Get the Phone numbers assigned to Teams/SfB Services
|
||||
Supported are AutoAttendant and/or CallQueue
|
||||
|
||||
.PARAMETER AutoAttendant
|
||||
Get the numbers assigned to AutoAttendant(s)
|
||||
|
||||
.PARAMETER CallQueue
|
||||
Get the numbers assigned to CallQueue(s)
|
||||
|
||||
.PARAMETER All
|
||||
Get all Numbers, assignee to AutoAttendant(s) and CallQueue(s)
|
||||
|
||||
.PARAMETER LeaveTel
|
||||
Normally the function dumps phone numbers with a stripped tel:
|
||||
With this switch the function will dump it with the leading tel:
|
||||
|
||||
.PARAMETER Export
|
||||
Export the result to a CSV
|
||||
|
||||
.PARAMETER Path
|
||||
Path for the CSV Export
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and dump them to the terminal
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All -Export -Path '.\TeamsServiceNumbers.csv'
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and export them to the given CSV file '.\TeamsServiceNumbers.csv'
|
||||
TeamsServiceNumbers.csv is in the directory where the user is right now (and calls the function)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All -Export -Path 'c:\temp\TeamsServiceNumbers.csv'
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and export them to the given CSV file 'c:\temp\TeamsServiceNumbers.csv'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All -Export
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and export them to a CSV
|
||||
The funtion will ask for the Path to the CSV File
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -AutoAttendant
|
||||
|
||||
Get all AutoAttendant(s) Services numbers and dump them to the terminal
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -AA
|
||||
|
||||
Get all AutoAttendant(s) Services numbers and dump them to the terminal
|
||||
Same as above, but use the Alias (Shorter)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -CallQueue
|
||||
|
||||
Get all CallQueue(s) Services numbers and dump them to the terminal
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -CQ
|
||||
|
||||
Get all CallQueue(s) Services numbers and dump them to the terminal
|
||||
Same as above, but use the Alias (Shorter)
|
||||
|
||||
.NOTES
|
||||
Additional information about the function.
|
||||
#>
|
||||
|
||||
[CmdletBinding(DefaultParameterSetName = 'AllNumbers',
|
||||
ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param
|
||||
(
|
||||
[Parameter(ParameterSetName = 'AANumbers',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('AA')]
|
||||
[switch]
|
||||
$AutoAttendant = $null,
|
||||
[Parameter(ParameterSetName = 'CQNumbers',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('CQ')]
|
||||
[switch]
|
||||
$CallQueue = $null,
|
||||
[Parameter(ParameterSetName = 'AllNumbers',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('Any')]
|
||||
[switch]
|
||||
$All,
|
||||
[Parameter(ParameterSetName = '__AllParameterSets',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[switch]
|
||||
$LeaveTel = $null,
|
||||
[Parameter(ParameterSetName = '__AllParameterSets',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('ExportCsv', 'CSV')]
|
||||
[switch]
|
||||
$Export = $false
|
||||
)
|
||||
|
||||
dynamicparam
|
||||
{
|
||||
if ($PSBoundParameters['Export'])
|
||||
{
|
||||
# The PATH parameter is only needed if -Export is given
|
||||
$PathAttribute = New-Object System.Management.Automation.ParameterAttribute
|
||||
$PathAttribute.Mandatory = $true
|
||||
$PathAttribute.HelpMessage = "Path for the CSV Export:"
|
||||
$PathAttribute.ValueFromPipeline = $true
|
||||
$PathAttribute.ValueFromPipelineByPropertyName = $true
|
||||
$PathAttribute.ParameterSetName = '__AllParameterSets'
|
||||
$attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
|
||||
$attributeCollection.Add($PathAttribute)
|
||||
$PathParam = New-Object System.Management.Automation.RuntimeDefinedParameter('Path', [String], $attributeCollection)
|
||||
$paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
|
||||
$paramDictionary.Add('Path', $PathParam)
|
||||
$paramDictionary
|
||||
}
|
||||
}
|
||||
|
||||
begin
|
||||
{
|
||||
switch ($PsCmdlet.ParameterSetName)
|
||||
{
|
||||
'AANumbers'
|
||||
{
|
||||
$AutoAttendant = $true
|
||||
}
|
||||
'CQNumbers'
|
||||
{
|
||||
$CallQueue = $true
|
||||
}
|
||||
'AllNumbers'
|
||||
{
|
||||
$All = $true
|
||||
}
|
||||
default
|
||||
{
|
||||
$All = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.Path)
|
||||
{
|
||||
$Path = $PSBoundParameters.Path
|
||||
}
|
||||
|
||||
$NumberReport = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if (($AutoAttendant) -or ($All))
|
||||
{
|
||||
foreach ($AA in (Get-CsAutoAttendant -ErrorAction Continue))
|
||||
{
|
||||
foreach ($AppInstance in $AA.ApplicationInstances)
|
||||
{
|
||||
$AAName = $AA.Name
|
||||
$AppPhoneNum = $null
|
||||
|
||||
if ($LeaveTel)
|
||||
{
|
||||
$AppPhoneNum = ((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber)
|
||||
}
|
||||
else
|
||||
{
|
||||
$AppPhoneNum = (((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber).replace('tel:', ''))
|
||||
}
|
||||
|
||||
Write-Verbose ('AutoAttendant ' + $AA.Name + ' has ' + $AppPhoneNum + ' assigned')
|
||||
|
||||
$NewRow = $null
|
||||
$NewRow = [PSCustomObject][ordered]@{
|
||||
Name = ($AA.Name)
|
||||
Number = ($AppPhoneNum)
|
||||
Type = 'AutoAttendant'
|
||||
}
|
||||
|
||||
$NumberReport += $newrow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (($CallQueue) -or ($All))
|
||||
{
|
||||
foreach ($CQ in (Get-CsCallQueue -ErrorAction Continue))
|
||||
{
|
||||
foreach ($AppInstance in $CQ.ApplicationInstances)
|
||||
{
|
||||
$CQName = $null
|
||||
$CQName = $CQ.Name
|
||||
|
||||
$AppPhoneNum = $null
|
||||
|
||||
if ($LeaveTel)
|
||||
{
|
||||
$AppPhoneNum = ((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber)
|
||||
}
|
||||
else
|
||||
{
|
||||
$AppPhoneNum = (((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber).replace('tel:', ''))
|
||||
}
|
||||
|
||||
Write-Verbose ('CallQueue ' + $CQ.Name + ' has ' + $AppPhoneNum + ' assigned')
|
||||
|
||||
$NewRow = $null
|
||||
$NewRow = [PSCustomObject][ordered]@{
|
||||
Name = ($CQ.Name)
|
||||
Number = ($AppPhoneNum)
|
||||
Type = 'CallQueue'
|
||||
}
|
||||
|
||||
$NumberReport += $newrow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
if (($PSBoundParameters['Export']) -or ($Path))
|
||||
{
|
||||
$NumberReport | Export-Csv -Path $Path -NoTypeInformation -Encoding UTF8 -ErrorAction Stop -WarningAction Continue
|
||||
|
||||
Write-Verbose -Message $NumberReport
|
||||
}
|
||||
else
|
||||
{
|
||||
$NumberReport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,446 @@
|
||||
function Get-bdcMicrosoftTeamsReporting
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a Report for all Microsoft Teams Teams
|
||||
|
||||
.DESCRIPTION
|
||||
Get a Report for all Microsoft Teams Teams
|
||||
|
||||
.PARAMETER Connect
|
||||
Executes Connect-MicrosoftTeams for you
|
||||
|
||||
.PARAMETER Disconnect
|
||||
Executes Disconnect-MicrosoftTeams for you as soon as the report is generated
|
||||
|
||||
.PARAMETER GiphyDetails
|
||||
Include Giphy Details in the report
|
||||
|
||||
.PARAMETER MemesDetails
|
||||
Include Memes Details in the report
|
||||
|
||||
.PARAMETER GuestDetails
|
||||
Include Guest Details in the report
|
||||
|
||||
.PARAMETER Detailed
|
||||
Report some more Details about the Teams.
|
||||
|
||||
.PARAMETER AllDetails
|
||||
All of the Details are reported, might be a bit verbose for some.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting
|
||||
|
||||
Get a Report for all Microsoft Teams Teams
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
$_.owners -eq 0
|
||||
} | Select-Object -ExpandProperty DisplayName
|
||||
|
||||
Find all Teams without an owner.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
$_.owners -eq 1
|
||||
} | Select-Object -ExpandProperty DisplayName | ForEach-Object -Process {
|
||||
Write-Warning -Message "Looks like $_ is an orphaned objects, it has no owner!" -ErrorAction Continue
|
||||
}
|
||||
|
||||
Find all Teams without an owner. Teams without an owner are bad teams...
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
($_.Members -eq 0) -and ($_.Guests -eq 0)
|
||||
} | Select-Object -ExpandProperty DisplayName | ForEach-Object -Process {
|
||||
Write-Warning -Message "Looks like $_ has no members and guests!" -ErrorAction Continue
|
||||
}
|
||||
|
||||
Find Teams without members and guests, empty teams are boring and, more or less, useless
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
($_.Archived -eq $true) -and ($_.ShowInTeamsSearchAndSuggestions -eq $true)
|
||||
} | Select-Object -ExpandProperty DisplayName | ForEach-Object -Process {
|
||||
Write-Warning -Message "Looks like $_ is archived but searchable!" -ErrorAction Continue
|
||||
}
|
||||
|
||||
Find archived Teams that are still searchable, might not be a bad thing...
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -Connect -Disconnect
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, invokes the Connect-MicrosoftTeams and Disconnect-MicrosoftTeams for you
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -AllDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, with all the details (very verbose)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -GiphyDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Giphy Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -MemesDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Memes Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -GiphyDetails -MemesDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Giphy and Memes Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -GuestDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Guest Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -Detailed
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, with more details then the regular report
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -Detailed -GuestDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, with more details then the regular report and Guest Details
|
||||
|
||||
.NOTES
|
||||
Reworked function to deliver everything we need to have for our Office 365 reporting service.
|
||||
See the examples above and you will get an idea what you can do with filtering :-)
|
||||
|
||||
.LINK
|
||||
https://www.powershellgallery.com/packages/MicrosoftTeams/1.0.3
|
||||
|
||||
.LINK
|
||||
https://github.com/MicrosoftDocs/office-docs-powershell/tree/master/teams
|
||||
|
||||
.LINK
|
||||
Get-Team
|
||||
|
||||
.LINK
|
||||
Get-TeamUser
|
||||
|
||||
.LINK
|
||||
Get-TeamChannel
|
||||
|
||||
.LINK
|
||||
Connect-MicrosoftTeams
|
||||
|
||||
.LINK
|
||||
Disconnect-MicrosoftTeams
|
||||
|
||||
.LINK
|
||||
https://aka.ms/InstallModule
|
||||
|
||||
.LINK
|
||||
https://github.com/tomarbuthnot/Microsoft-Teams-PowerShell
|
||||
|
||||
.LINK
|
||||
https://opensource.org/licenses/BSD-3-Clause
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('DoConnect')]
|
||||
[switch]
|
||||
$Connect,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('DoDisconnect')]
|
||||
[switch]
|
||||
$Disconnect,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('IncludeGiphyDetails', 'Giphy')]
|
||||
[switch]
|
||||
$GiphyDetails,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('IncludeMemesDetails', 'Memes')]
|
||||
[switch]
|
||||
$MemesDetails,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('IncludeGuestDetails', 'Guest')]
|
||||
[switch]
|
||||
$GuestDetails,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('DetailedReport')]
|
||||
[switch]
|
||||
$Detailed,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('VerboseReport')]
|
||||
[switch]
|
||||
$AllDetails
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Connect
|
||||
if ($Connect)
|
||||
{
|
||||
# Logon
|
||||
$null = (Connect-MicrosoftTeams)
|
||||
}
|
||||
#endregion Connect
|
||||
|
||||
# Crete an empty Report variable
|
||||
$MicrosoftTeamsReport = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get all Microsoft Teams Teams and loop over them
|
||||
try
|
||||
{
|
||||
Get-Team -ErrorAction Stop | ForEach-Object -Process {
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Generate the Report for the Microsoft Teams Team {0}' -f $_.DisplayName)
|
||||
|
||||
# Cleanup
|
||||
$TeamUserDetails = $null
|
||||
|
||||
# Get the User information for the Microsoft Teams Team and save it for reuse
|
||||
$TeamUserDetails = $null
|
||||
$TeamUserDetails = (Get-TeamUser -GroupId $_.GroupID -ErrorAction Stop)
|
||||
|
||||
# Get the Channel information for the Microsoft Teams Team
|
||||
$TeamChannelDetails = $null
|
||||
$TeamChannelDetails = ((Get-TeamChannel -GroupId $_.GroupID -ErrorAction Stop).count)
|
||||
|
||||
# Put all details into an object
|
||||
$SingleTeamReport = (New-Object -TypeName PSobject)
|
||||
|
||||
#region FillSingleTeamReport
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $_.DisplayName
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Description' -Value $_.Description
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Visibility' -Value $_.Visibility
|
||||
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Archived' -Value $_.Archived
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'ShowInTeamsSearchAndSuggestions' -Value $_.ShowInTeamsSearchAndSuggestions
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Channels' -Value $TeamChannelDetails
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Owners' -Value (($TeamUserDetails | Where-Object -FilterScript {
|
||||
$_.Role -like 'owner'
|
||||
}).count)
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Members' -Value (($TeamUserDetails | Where-Object -FilterScript {
|
||||
$_.Role -like 'member'
|
||||
}).count)
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Guests' -Value (($TeamUserDetails | Where-Object -FilterScript {
|
||||
$_.Role -like 'guest'
|
||||
}).count)
|
||||
|
||||
#region GiphyDetails
|
||||
if ($GiphyDetails -or $AllDetails)
|
||||
{
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowGiphy' -Value $_.AllowGiphy
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'GiphyContentRating' -Value $_.GiphyContentRating
|
||||
}
|
||||
#endregion GiphyDetails
|
||||
|
||||
#region MemesDetails
|
||||
if ($MemesDetails -or $AllDetails)
|
||||
{
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowStickersAndMemes' -Value $_.AllowStickersAndMemes
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCustomMemes' -Value $_.AllowCustomMemes
|
||||
}
|
||||
#endregion MemesDetails
|
||||
|
||||
#region GuestDetails
|
||||
if ($GuestDetails -or $AllDetails)
|
||||
{
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowGuestCreateUpdateChannels' -Value $_.AllowGuestCreateUpdateChannels
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowGuestDeleteChannels' -Value $_.AllowGuestDeleteChannels
|
||||
}
|
||||
#endregion GuestDetails
|
||||
|
||||
#region DetailedReport
|
||||
if ($Detailed -or $AllDetails)
|
||||
{
|
||||
# Based on the idea of Tom Arbuthnot (https://github.com/tomarbuthnot/Microsoft-Teams-PowerShell)
|
||||
$DescriptionWordCount = (($_.Description | Out-String | Measure-Object -Word).words)
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'DescriptionWordCount' -Value $DescriptionWordCount
|
||||
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'DescriptionScore' -Value $(if ($DescriptionWordCount -eq 0)
|
||||
{
|
||||
'Terrible'
|
||||
}
|
||||
elseif ($DescriptionWordCount -le 2)
|
||||
{
|
||||
'Poor'
|
||||
}
|
||||
elseif ($DescriptionWordCount -le 5)
|
||||
{
|
||||
'OK'
|
||||
}
|
||||
elseif ($DescriptionWordCount -ge 6)
|
||||
{
|
||||
'Good'
|
||||
}
|
||||
else
|
||||
{
|
||||
'Unknown'
|
||||
}
|
||||
)
|
||||
|
||||
# As requested by Peter Duda
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Classification' -Value $(if ($_.Classification)
|
||||
{
|
||||
$_.Classification
|
||||
}
|
||||
else
|
||||
{
|
||||
'None'
|
||||
}
|
||||
)
|
||||
|
||||
# New since 2020/01
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'MailNickName' -Value $(if ($_.MailNickName)
|
||||
{
|
||||
$_.MailNickName
|
||||
}
|
||||
else
|
||||
{
|
||||
'None'
|
||||
}
|
||||
)
|
||||
|
||||
# Verbose reporting
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCreateUpdateChannels' -Value $_.AllowCreateUpdateChannels
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowDeleteChannels' -Value $_.AllowDeleteChannels
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowAddRemoveApps' -Value $_.AllowAddRemoveApps
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCreateUpdateRemoveTabs' -Value $_.AllowCreateUpdateRemoveTabs
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCreateUpdateRemoveConnectors' -Value $_.AllowCreateUpdateRemoveConnectors
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowUserEditMessages' -Value $_.AllowUserEditMessages
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowUserDeleteMessages' -Value $_.AllowUserDeleteMessages
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowOwnerDeleteMessages' -Value $_.AllowOwnerDeleteMessages
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowTeamMentions' -Value $_.AllowTeamMentions
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowChannelMentions' -Value $_.AllowChannelMentions
|
||||
}
|
||||
#endregion DetailedReport
|
||||
|
||||
#region FinalValue
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'GroupId' -Value $_.GroupId
|
||||
#endregion FinalValue
|
||||
#endregion FillSingleTeamReport
|
||||
|
||||
# Append to the Report
|
||||
$MicrosoftTeamsReport += $SingleTeamReport
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region WarningHandler
|
||||
# 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
|
||||
|
||||
$paramWriteWarning = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
Write-Warning @paramWriteWarning
|
||||
#region WarningHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Just in case
|
||||
Exit 1
|
||||
#region ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region Disconnect
|
||||
if ($Disconnect)
|
||||
{
|
||||
# Logoff
|
||||
$null = (Disconnect-MicrosoftTeams -Confirm:$false)
|
||||
}
|
||||
#endregion Disconnect
|
||||
|
||||
#region ShowReport
|
||||
# Dump the Report
|
||||
$MicrosoftTeamsReport
|
||||
#endregion ShowReport
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,300 @@
|
||||
#requires -Version 3.0 -Modules BitsTransfer -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Download, install, and Tweak System and Apps for Terminal Server use
|
||||
|
||||
.DESCRIPTION
|
||||
Download, install, and Tweak System and Apps for Terminal Server (WVD/VDI/WDS) use
|
||||
|
||||
.NOTES
|
||||
Early testing release - Future releases might get some parameters
|
||||
|
||||
Changelog:
|
||||
1.0.0: Initial Release
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
.LINK
|
||||
http://enatec.io
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
Write-Output -InputObject 'Download, install, and Tweak System and Apps for Terminal Server use'
|
||||
|
||||
# Default URL (Assume we use 64Bit)
|
||||
[string]$FSLogixUrl = 'https://aka.ms/fslogix_download'
|
||||
|
||||
#region PossibleParameters
|
||||
# Where to Store it
|
||||
[string]$Target = ($env:Temp)
|
||||
|
||||
# File Name
|
||||
[string]$TargetName = 'fslogix.zip'
|
||||
|
||||
# Install Switch
|
||||
[string]$Arguments = '/install /quiet /norestart'
|
||||
#endregion PossibleParameters
|
||||
|
||||
#region Defaults
|
||||
# Set the full path of the downloaded installer
|
||||
[string]$InstallerPackage = ($Target + '\' + $TargetName)
|
||||
|
||||
[string]$InstallerDestination = (($InstallerPackage).Replace('.zip', ''))
|
||||
[string]$InstallerExecutable = ($InstallerDestination + '\x64\Release\FSLogixAppsSetup.exe')
|
||||
$SCT = 'SilentlyContinue'
|
||||
$STP = 'Stop'
|
||||
#endregion Defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
Write-Verbose -Message ('Downloading {0} to {1}' -f $TargetName, $InstallerPackage)
|
||||
|
||||
# Use BitsTransfer to download the latest installer
|
||||
$paramStartBitsTransfer = @{
|
||||
Source = $FSLogixUrl
|
||||
Destination = $InstallerPackage
|
||||
Priority = 'High'
|
||||
TransferPolicy = 'Always'
|
||||
ErrorAction = $STP
|
||||
}
|
||||
$null = (Start-BitsTransfer @paramStartBitsTransfer)
|
||||
|
||||
# Expand FSLogix Installer
|
||||
$paramTestPath = @{
|
||||
Path = $InstallerPackage
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (Test-Path @paramTestPath)
|
||||
{
|
||||
$paramTestPath = @{
|
||||
Path = $InstallerDestination
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (-not (Test-Path @paramTestPath))
|
||||
{
|
||||
$paramNewItem = @{
|
||||
Path = $InstallerDestination
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ItemType = 'Directory'
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
# Expand-Archive is to buggy!
|
||||
$null = (Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction $STP)
|
||||
$null = ([IO.Compression.ZipFile]::ExtractToDirectory($InstallerPackage, $InstallerDestination))
|
||||
}
|
||||
catch
|
||||
{
|
||||
# OK! That is crappy, but it still works well as a fallback.
|
||||
$shellApp = (New-Object -ComObject Shell.Application -ErrorAction $STP)
|
||||
$shellZip = $shellApp.NameSpace([String]$InstallerPackage)
|
||||
$shellDest = $shellApp.NameSpace($InstallerDestination)
|
||||
$shellDest.CopyHere($shellZip.items())
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# 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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = $STP
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# We are done
|
||||
break
|
||||
}
|
||||
|
||||
# Install FSLogix
|
||||
$paramTestPath = @{
|
||||
Path = $InstallerExecutable
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (Test-Path @paramTestPath)
|
||||
{
|
||||
$paramGetItemProperty = @{
|
||||
Path = $InstallerExecutable
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$InstallerVersion = ((Get-ItemProperty @paramGetItemProperty).VersionInfo.ProductVersion)
|
||||
|
||||
Write-Verbose -Message ('Running FSLogix installer version {0}' -f $InstallerVersion)
|
||||
|
||||
$paramStartProcess = @{
|
||||
FilePath = $InstallerExecutable
|
||||
ArgumentList = $Arguments
|
||||
Wait = $true
|
||||
PassThru = $true
|
||||
ErrorAction = $STP
|
||||
}
|
||||
$InstallerProcess = (Start-Process @paramStartProcess)
|
||||
|
||||
if (($InstallerProcess | Select-Object -ExpandProperty ExitCode) -eq 0)
|
||||
{
|
||||
Write-Verbose -Message ('Installed FSLogix version {0}' -f $InstallerVersion)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('Installer exit code {0}.' -f $InstallerProcess.ExitCode)
|
||||
}
|
||||
|
||||
Write-Verbose -Message ('Removing file: {0}' -f $InstallerPackage)
|
||||
|
||||
# Remove the downloaded Installaer Package
|
||||
$paramRemoveItem = @{
|
||||
Path = $InstallerPackage
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Remove-Item @paramRemoveItem)
|
||||
|
||||
# Install the expanded stuff
|
||||
$paramRemoveItem = @{
|
||||
Path = $InstallerDestination
|
||||
Recurse = $true
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Remove-Item @paramRemoveItem)
|
||||
|
||||
# Legacy HKLM Path for WVD/VDI/WDS Environment
|
||||
$paramNewItem = @{
|
||||
Path = 'HKLM:\SOFTWARE\Citrix\PortICA'
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
|
||||
# Ensure that the registry path exists
|
||||
$paramNewItem = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Teams'
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
|
||||
# Tell Microsoft Teams that it runs in an WVD/VDI/WDS Environment
|
||||
# Source: https://docs.microsoft.com/en-us/azure/virtual-desktop/teams-on-wvd
|
||||
$paramNewItemProperty = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Teams'
|
||||
Name = 'IsWVDEnvironment'
|
||||
PropertyType = 'DWORD'
|
||||
Value = 1
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-ItemProperty @paramNewItemProperty)
|
||||
|
||||
# Ensure that the registry path exists
|
||||
$paramNewItem = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run32'
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
|
||||
# Do not start Microsoft Teams after Login
|
||||
$paramNewItemProperty = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run32'
|
||||
Name = 'Teams'
|
||||
PropertyType = 'Binary'
|
||||
Value = ([byte[]](0x01, 0x00, 0x00, 0x00, 0x1a, 0x19, 0xc3, 0xb9, 0x62, 0x69, 0xd5, 0x01))
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-ItemProperty @paramNewItemProperty)
|
||||
}
|
||||
else
|
||||
{
|
||||
# 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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = $STP
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# We are done
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,137 @@
|
||||
#requires -Version 3.0 -Modules NetSecurity -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Tweak the Firewall Rules for Microsoft Teams clients
|
||||
|
||||
.DESCRIPTION
|
||||
Tweak the Firewall Rules for Microsoft Teams clients for all users that have it installed
|
||||
|
||||
.NOTES
|
||||
Early testing release
|
||||
|
||||
Changelog:
|
||||
1.0.0: Initial Release
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
.LINK
|
||||
http://enatec.io
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
Write-Output -InputObject 'Tweak the Firewall Rules for Microsoft Teams clients for all users that have it installed'
|
||||
|
||||
#region Defaults
|
||||
$SCT = 'SilentlyContinue'
|
||||
#endregion Defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Creates firewall rules for Microsoft Teams
|
||||
$AllUsers = $null
|
||||
|
||||
$paramJoinPath = @{
|
||||
Path = $env:SystemDrive
|
||||
ChildPath = 'Users'
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$paramGetChildItem = @{
|
||||
Path = (Join-Path @paramJoinPath)
|
||||
ErrorAction = $SCT
|
||||
Exclude = 'Public', 'ADMINI~*'
|
||||
}
|
||||
$AllUsers = (Get-ChildItem @paramGetChildItem)
|
||||
|
||||
if ($null -ne $AllUsers)
|
||||
{
|
||||
foreach ($SingleUser in $AllUsers)
|
||||
{
|
||||
# Cleanup
|
||||
$FullTeamsPath = $null
|
||||
|
||||
# get the Executable
|
||||
$paramJoinPath = @{
|
||||
Path = $SingleUser.FullName
|
||||
ChildPath = 'AppData\Local\Microsoft\Teams\Current\Teams.exe'
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$FullTeamsPath = (Join-Path @paramJoinPath)
|
||||
|
||||
$paramTestPath = @{
|
||||
Path = $FullTeamsPath
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (Test-Path @paramTestPath)
|
||||
{
|
||||
$paramGetNetFirewallApplicationFilter = @{
|
||||
Program = $FullTeamsPath
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetFirewallApplicationFilter @paramGetNetFirewallApplicationFilter))
|
||||
{
|
||||
# Cleanup
|
||||
$NetFirewallRuleName = $null
|
||||
|
||||
# Apply the Rulename
|
||||
$NetFirewallRuleName = ('Teams.exe for user {0}' -f $SingleUser.Name)
|
||||
|
||||
'UDP', 'TCP' | ForEach-Object -Process {
|
||||
$paramNewNetFirewallRule = @{
|
||||
DisplayName = $NetFirewallRuleName
|
||||
Direction = 'Inbound'
|
||||
Profile = 'Any'
|
||||
Program = $FullTeamsPath
|
||||
Action = 'Allow'
|
||||
Protocol = $_
|
||||
Enabled = 'True'
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-NetFirewallRule @paramNewNetFirewallRule)
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$NetFirewallRuleName = $null
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$FullTeamsPath = $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
|
||||
@@ -0,0 +1,184 @@
|
||||
function Invoke-mtrDisableModernAuthentication
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Disable Modern Authentication for a Microsoft Teams Room Device Account
|
||||
|
||||
.DESCRIPTION
|
||||
Disable Modern Authentication for a Microsoft Teams Room Device Account
|
||||
It dsables it in Exchange Online and Skype for Business Online. It also configures the tenant to do so, if needed.
|
||||
|
||||
.PARAMETER Identity
|
||||
The Microsoft Teams Rooms (MTR) Account Search String
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-mtrDisableModernAuthentication.ps1 -Identity 'MyTeamRoom'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-mtrDisableModernAuthentication.ps1 -Identity 'TeamRoom@contoso.com'
|
||||
|
||||
.NOTES
|
||||
Just a quick and dirty tool to do the job, nothing fancy and without a real error handling!
|
||||
-> Use at your own risk!
|
||||
|
||||
You need to be a tenant admin to configure all the things
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory, HelpMessage = 'The Microsoft Teams Rooms (MTR) Account Search String',
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('SearchString', 'mtrAccount')]
|
||||
[string]
|
||||
$Identity
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$STP = 'Stop'
|
||||
$SCT = 'SilentlyContinue'
|
||||
#endregion Defaults
|
||||
|
||||
#region GeneralParameters
|
||||
$RemovePSSessionDefaultParams = @{
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
|
||||
$RemoveModuleDefaultParams = @{
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
#endregion GeneralParameters
|
||||
|
||||
Write-Verbose -Message 'Message'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
#region ConnectAzureAD
|
||||
$null = (Connect-AzureAD)
|
||||
#endregion ConnectAzureAD
|
||||
|
||||
#region ConnectSkypeForBusinessOnline
|
||||
# We use a crappy workaround, because the Modern Auth window never shows up to querry the admin UPN, and I do NOT trust the command to querry it
|
||||
$SkypeForBusinessSession = (New-CsOnlineSession -UserName (Read-Host -Prompt 'Please enter the admin principal name (ex. admin@contoso.com)'))
|
||||
$paramImportPSSession = @{
|
||||
Session = $SkypeForBusinessSession
|
||||
DisableNameChecking = $true
|
||||
AllowClobber = $true
|
||||
}
|
||||
$null = (Import-PSSession @paramImportPSSession)
|
||||
#endregion ConnectSkypeForBusinessOnline
|
||||
|
||||
#region ConnectExchangeOnline
|
||||
# We use the ExchangeOnlineShell Module from the Gallery
|
||||
if (-not (Get-Command -Name Get-Mailbox -ErrorAction $SCT))
|
||||
{
|
||||
$paramConnectExchangeOnlineShell = @{
|
||||
Confirm = $false
|
||||
WarningAction = $SCT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
$null = (Connect-ExchangeOnlineShell @paramConnectExchangeOnlineShell)
|
||||
}
|
||||
#endregion ConnectExchangeOnline
|
||||
|
||||
#region CheckModernAuth
|
||||
# Do we have Modern Auth enabled Global?
|
||||
if ((Get-OrganizationConfig | Select-Object -ExpandProperty OAuth2ClientProfileEnabled) -eq $true)
|
||||
{
|
||||
# Disconnect Modern Authentication (For a single user) - In this case the MTR
|
||||
$paramRevokeAzureADUserAllRefreshToken = @{
|
||||
ObjectId = (Get-AzureADUser -SearchString $Identity | Select-Object -ExpandProperty objectId)
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Revoke-AzureADUserAllRefreshToken @paramRevokeAzureADUserAllRefreshToken)
|
||||
$null = (Revoke-AzureADUserAllRefreshToken @paramRevokeAzureADUserAllRefreshToken)
|
||||
|
||||
# Allow non Modern Auth in Skype for Business
|
||||
if ((Get-CsOAuthConfiguration -ErrorAction $SCT | Select-Object -ExpandProperty ClientAdalAuthOverride) -ne 'Allowed')
|
||||
{
|
||||
$paramSetCsOAuthConfiguration = @{
|
||||
ClientAdalAuthOverride = 'Allowed'
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Set-CsOAuthConfiguration @paramSetCsOAuthConfiguration)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Shame on you!
|
||||
Write-Warning -Message 'Looks like Modern Auth is not enabled for this tenant!' -WarningAction $STP
|
||||
}
|
||||
#endregion CheckModernAuth
|
||||
|
||||
#region DisconnectAzureAD
|
||||
$null = (Disconnect-AzureAD -Confirm:$false -ErrorAction $SCT)
|
||||
#endregion DisconnectAzureAD
|
||||
|
||||
#region DisconnectSkypeForBusiness
|
||||
$paramRemoveModule = @{
|
||||
Name = (Get-Command -Name Set-CsOAuthConfiguration -ErrorAction $SCT | Select-Object -ExpandProperty Source)
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
|
||||
$null = (Remove-Module @paramRemoveModule)
|
||||
$null = ($SkypeForBusinessSession.Id | Remove-PSSession @RemovePSSessionDefaultParams)
|
||||
#endregion DisconnectSkypeForBusiness
|
||||
|
||||
#region DisconnectExchangeOnline
|
||||
$ExchangeSessionID = (Get-PSSession | Where-Object {
|
||||
$_.ComputerName -eq 'outlook.office365.com'
|
||||
} | Select-Object -ExpandProperty Id)
|
||||
|
||||
if ($ExchangeSessionID)
|
||||
{
|
||||
$paramDisconnectExchangeOnlineShell = @{
|
||||
SessionID = $ExchangeSessionID
|
||||
Confirm = $false
|
||||
}
|
||||
$null = (Disconnect-ExchangeOnlineShell @paramDisconnectExchangeOnlineShell)
|
||||
}
|
||||
|
||||
# Will be removed soon (Disconnect-ExchangeOnlineShell will handle this for us!)
|
||||
$RemoveModuleName = (Get-Command -Name Get-OrganizationConfig -ErrorAction $SCT | Select-Object -ExpandProperty Source)
|
||||
|
||||
if ($RemoveModuleName)
|
||||
{
|
||||
$paramRemoveModule = @{
|
||||
Name = $RemoveModuleName
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Remove-Module @RemoveModuleDefaultParams)
|
||||
}
|
||||
#endregion DisconnectExchangeOnline
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region FinalCleanup
|
||||
# Just in case: We remove all sessions that might still be around
|
||||
$null = ((Get-PSSession -ErrorAction $SCT | Where-Object {
|
||||
$_.ComputerName -eq 'outlook.office365.com'
|
||||
}) | Remove-PSSession @RemovePSSessionDefaultParams)
|
||||
|
||||
$null = ((Get-PSSession -ErrorAction $SCT | Where-Object {
|
||||
$_.ComputerName -like 'admin*.online.lync.com'
|
||||
}) | Remove-PSSession @RemovePSSessionDefaultParams)
|
||||
|
||||
# Remove the Modules (Here just in case we missed something above)
|
||||
$null = (Remove-Module -Name (Get-Command -Name Connect-ExchangeOnlineShell -ErrorAction $SCT | Select-Object -ExpandProperty Source) @RemoveModuleDefaultParams)
|
||||
$null = (Remove-Module -Name (Get-Command -Name Disconnect-AzureAD -ErrorAction $SCT | Select-Object -ExpandProperty Source) @RemoveModuleDefaultParams)
|
||||
$null = (Remove-Module -Name (Get-Command -Name New-CsOnlineSession -ErrorAction $SCT | Select-Object -ExpandProperty Source) @RemoveModuleDefaultParams)
|
||||
#endregion FinalCleanup
|
||||
}
|
||||
}
|
||||
29
Powershell/PowerShell-collection/MicrosoftTeams/LICENSE
Normal file
29
Powershell/PowerShell-collection/MicrosoftTeams/LICENSE
Normal 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.
|
||||
@@ -0,0 +1,448 @@
|
||||
#requires -Version 3.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates a new Microsoft Teams team with the MicrosoftTeams Module.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a new Microsoft Teams team with the MicrosoftTeams Module.
|
||||
The new team will be backed by a newly created unified group and SharePoint Online Site.
|
||||
|
||||
The script depends on Microsoft's Version 0.9.6 of the MicrosoftTeams Module.
|
||||
Please note: Not all authentications methods of the latest MicrosoftTeams Module are supported!
|
||||
|
||||
.PARAMETER msTeamsCreds
|
||||
Specifies a PSCredential object. For more information about the PSCredential object, type Get-Help Get-Credential.
|
||||
The PSCredential object provides the user ID and password for organizational ID credentials.
|
||||
|
||||
.PARAMETER mfa
|
||||
Use the web based authentication. Supports MFA and prevents issues in non ADFS implementations.
|
||||
|
||||
.PARAMETER DisplayName
|
||||
Todeam display name. Team Name Characters Limit is 256.
|
||||
|
||||
.PARAMETER Alias
|
||||
Same as displayName without any spaces. Team Alias Characters Limit is 64
|
||||
|
||||
.PARAMETER Description
|
||||
Team description. Team Description Characters Limit is 1024.
|
||||
|
||||
.PARAMETER AccessType
|
||||
Team access type. Valid values are "Private" and "Public". Default is "Private". (This parameter has the same meaning as -AccessType in New-UnifiedGroup.)
|
||||
|
||||
.PARAMETER AddCreatorAsMember
|
||||
This setting lets you decide if you will be added as a member of the team. The default is false.
|
||||
|
||||
.PARAMETER Owner
|
||||
UPN/Mail of the Teams Owner, multiple values are supported!
|
||||
|
||||
.PARAMETER User
|
||||
member Users for the Group, Please use UPN or Mail.
|
||||
Multiple values are supported.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -mfa -DisplayName 'Contoso Support'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support'. Uses Weblog (supports MFA)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -msTeamsCreds $O365 -DisplayName 'Contoso Support'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support'. Uses existing credentials stored in the variable $O365 to authenticate.
|
||||
This might be the perfect way for automation, but use stored credentials might also be insecure.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Support'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Support' -Alias 'AITSupport'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support' with an Alias 'AITSupport'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Info-pool' -AccessType 'public'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Info-pool', public mean open to join for every member of the organization.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Development' -Description 'Contoso IT Development Team' -Owner 'john.doe@acontoso.com'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Development', sets a description and add 'john.doe@contoso.com' as Owner.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Core Dev' -AddCreatorAsMember $true
|
||||
|
||||
Creates the Microsoft Team 'Contoso Core Dev' and adds the creator to the new Team.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Install-Module -Name MicrosoftTeams
|
||||
|
||||
Install the dependency Module from Microsoft via PowerShellGet.
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.3 2019-04-26: Fix Module Statement to use the correct version (0.9.6) to avoid issues with our workaround.
|
||||
1.0.2 2019-02-05: Reintroduce the -MFA switch to support the web based authentication. Prevent issues in non ADFS implementations.
|
||||
1.0.1 2019-02-04: Add workaround for AddCreatorAsMember Bug (Creator is added as owner all the time)
|
||||
1.0.0 2018-12-31: Internal 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.
|
||||
|
||||
Dependencies:
|
||||
The script depends on Microsoft's Version 0.9.6 of the MicrosoftTeams PowerShell Module.
|
||||
The MicrosoftTeams PowerShell Module GA Version (1.0.0) is not yet tested!
|
||||
|
||||
Install it with PowerShellGet:
|
||||
PS C:\> Install-Module -Name MicrosoftTeams -RequiredVersion 0.9.6
|
||||
|
||||
.LINK
|
||||
https://www.powershellgallery.com/packages/MicrosoftTeams/0.9.6
|
||||
|
||||
.LINK
|
||||
https://aka.ms/InstallModule
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName = 'MFA',
|
||||
ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ParameterSetName = 'Credentials',
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[System.Management.Automation.Credential()]
|
||||
[Alias('TeamsCredentials', 'TeamsAdminCredentials', 'Office365creds')]
|
||||
[pscredential]
|
||||
$msTeamsCreds,
|
||||
[Parameter(ParameterSetName = 'MFA',
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[Alias('UseMFA')]
|
||||
[switch]
|
||||
$mfa,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Team display name.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('TeamsDisplayName')]
|
||||
[string]
|
||||
$DisplayName,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[Alias('TeamsAlias')]
|
||||
[string]
|
||||
$Alias,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[Alias('TeamsDescription')]
|
||||
[string]
|
||||
$Description,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 4)]
|
||||
[ValidateSet('HiddenMembership', 'Private', 'Public', IgnoreCase = $true)]
|
||||
[Alias('TeamsAccessType')]
|
||||
[string]
|
||||
$AccessType = 'Private',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 5)]
|
||||
[Alias('AddCreatorAsTeamsMember')]
|
||||
[switch]
|
||||
$AddCreatorAsMember = $false,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 6)]
|
||||
[Alias('TeamsOwner')]
|
||||
[string[]]
|
||||
$Owner,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 7)]
|
||||
[Alias('TeamsUser', 'TeamsMember')]
|
||||
[string[]]
|
||||
$User
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region VersionRequirement
|
||||
try
|
||||
{
|
||||
$paramRemoveModule = @{
|
||||
Name = 'MicrosoftTeams'
|
||||
Force = $true
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Remove-Module @paramRemoveModule)
|
||||
|
||||
$paramImportModule = @{
|
||||
Name = 'MicrosoftTeams'
|
||||
MaximumVersion = '0.9.6'
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Import-Module @paramImportModule)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = 'Microsoft´s Version 0.9.6 of the MicrosoftTeams PowerShell Module'
|
||||
ErrorAction = 'Stop'
|
||||
Category = 'NotInstalled'
|
||||
Exception = 'Required Module not found'
|
||||
RecommendedAction = 'Please install Version 0.9.6 of the MicrosoftTeams PowerShell Module via Install-Module -Name MicrosoftTeams -RequiredVersion 0.9.6'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
}
|
||||
#endregion VersionRequirement
|
||||
|
||||
#region AuthChecker
|
||||
if (($msTeamsCreds) -and ($mfa))
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = 'You have selected muliple authentication methods. This is not valid'
|
||||
Exception = 'Muliple authentication methods selected'
|
||||
Category = 'AuthenticationError'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
}
|
||||
#endregion AuthChecker
|
||||
|
||||
#region Defaults
|
||||
#region AccessType
|
||||
if (-not ($AccessType))
|
||||
{
|
||||
$AccessType = 'Private'
|
||||
}
|
||||
#endregion AccessType
|
||||
|
||||
#region AddCreatorAsMember
|
||||
if (-not ($AddCreatorAsMember))
|
||||
{
|
||||
$AddCreatorAsMember = $false
|
||||
}
|
||||
#endregion AddCreatorAsMember
|
||||
#endregion defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($DisplayName, 'Create'))
|
||||
{
|
||||
try
|
||||
{
|
||||
#region Authentication
|
||||
if (-not ($mfa))
|
||||
{
|
||||
#region CredentialHandler
|
||||
if (-not ($msTeamsCreds))
|
||||
{
|
||||
# Get the credentials / Use it within the script only
|
||||
$script:msTeamsCreds = (Get-Credential -Message 'Please use credentials with Teams Admin capabilities.')
|
||||
}
|
||||
#endregion CredentialHandler
|
||||
|
||||
#region ConnectMicrosoftTeams
|
||||
$paramConnectMicrosoftTeams = @{
|
||||
Credential = $msTeamsCreds
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Connect-MicrosoftTeams @paramConnectMicrosoftTeams)
|
||||
#endregion ConnectMicrosoftTeams
|
||||
}
|
||||
else
|
||||
{
|
||||
#region ConnectMicrosoftTeams
|
||||
# Use the Web login
|
||||
$paramConnectMicrosoftTeams = @{
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Connect-MicrosoftTeams @paramConnectMicrosoftTeams)
|
||||
#endregion ConnectMicrosoftTeams
|
||||
}
|
||||
#endregion Authentication
|
||||
|
||||
#region NewTeam
|
||||
#region SplatDefaults
|
||||
$paramNewTeam = @{
|
||||
DisplayName = $DisplayName
|
||||
Visibility = $AccessType
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
#endregion SplatDefaults
|
||||
|
||||
#region Optionals
|
||||
if (($msTeamsCreds.UserName) -and ($AddCreatorAsMember -eq $true))
|
||||
{
|
||||
$paramNewTeam | Add-Member -MemberType NoteProperty -Name Owner -Value $msTeamsCreds.UserName
|
||||
}
|
||||
|
||||
if ($Alias)
|
||||
{
|
||||
$paramNewTeam | Add-Member -MemberType NoteProperty -Name Alias -Value $Alias
|
||||
}
|
||||
|
||||
if ($Description)
|
||||
{
|
||||
$paramNewTeam | Add-Member -MemberType NoteProperty -Name Description -Value $Description
|
||||
}
|
||||
#region Optionals
|
||||
|
||||
#region CreateTeam
|
||||
$NewTeam = (New-Team @paramNewTeam)
|
||||
#endregion CreateTeam
|
||||
|
||||
if (-not ($NewTeam.GroupId))
|
||||
{
|
||||
Write-Error -Message ('Error while try to create {0}' -f $DisplayName)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message "The new Team id is $($NewTeam.GroupId)"
|
||||
|
||||
#region BugWorkAround
|
||||
#BUG: There is a bug in the AddCreatorAsMember implemntation of Microsoft
|
||||
if ($AddCreatorAsMember -eq $false)
|
||||
{
|
||||
Write-Verbose -Message 'Workaround: Workaround for the AddCreatorAsMember of the Microsoft MicrosoftTeams Module'
|
||||
Remove-TeamUser -GroupId $NewTeam.GroupId -User $msTeamsCreds.UserName -ErrorAction SilentlyContinue
|
||||
}
|
||||
#endregion BugWorkAround
|
||||
|
||||
#region SetOwner
|
||||
if ($Owner)
|
||||
{
|
||||
foreach ($Admin in $Owner)
|
||||
{
|
||||
try
|
||||
{
|
||||
$paramAddTeamUser = @{
|
||||
GroupId = $NewTeam.GroupId
|
||||
User = $Admin
|
||||
Role = 'Owner'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-TeamUser @paramAddTeamUser)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to add {0} as owner to the Team {1}' -f $Admin, $DisplayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('The Team {0} has no owner!' -f $DisplayName)
|
||||
}
|
||||
#endregion SetOwner
|
||||
|
||||
#region Setmember
|
||||
if ($User)
|
||||
{
|
||||
foreach ($Member in $User)
|
||||
{
|
||||
try
|
||||
{
|
||||
$paramAddTeamUser = @{
|
||||
GroupId = $NewTeam.GroupId
|
||||
User = $Member
|
||||
Role = 'Member'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-TeamUser @paramAddTeamUser)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to add {0} as member to the Team {1}' -f $Member, $DisplayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Setmember
|
||||
}
|
||||
#endregion NewTeam
|
||||
}
|
||||
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
|
||||
}
|
||||
finally
|
||||
{
|
||||
#region Cleanup
|
||||
$null = (Disconnect-MicrosoftTeams -Confirm:$false)
|
||||
#endregion Cleanup
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message ('Created the Team {0}' -f $DisplayName)
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,719 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create a Project team in Teams with folder structure in files tab
|
||||
|
||||
.TeamsDescription
|
||||
Create a Project team in Teams with folder structure in files tab
|
||||
Based on Alexander Holmeset's version.
|
||||
|
||||
.DESCRIPTION
|
||||
A detailed description of the file.
|
||||
|
||||
.PARAMETER TeamName
|
||||
Name of the Microsoft Teams team
|
||||
|
||||
.PARAMETER TeamsOwner
|
||||
TeamsOwner of the new Microsoft Teams team
|
||||
|
||||
.PARAMETER privatepublic
|
||||
Os it a private or Public team?
|
||||
|
||||
.PARAMETER TeamsDescription
|
||||
The TeamsDescription for the new team
|
||||
|
||||
.PARAMETER ClientId
|
||||
Azure AD Application (client) ID
|
||||
|
||||
.PARAMETER TenantId
|
||||
Azure AD Tenant ID
|
||||
|
||||
.PARAMETER ClientSecret
|
||||
Azure AD secret
|
||||
|
||||
.PARAMETER TenantName
|
||||
Office 365 Tenant Name (e.g. contoso for https://contoso.sharepoint.com)
|
||||
|
||||
.PARAMETER DocumentLibrary
|
||||
Document Library Folder, default is /shared documents
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\ProjectTeamStructure.ps1 -TeamName 'Value1' -TeamsOwner 'Value2'
|
||||
|
||||
.NOTES
|
||||
Original found in Alexander Holmeset's Blog
|
||||
My version starts to make it a bit more flexible (e.g. more parameters)
|
||||
I might update this to be more configurable in the future
|
||||
|
||||
.LINK
|
||||
https://alexholmeset.blog/2019/05/01/project-team-in-teams-with-folder-structure-in-files-tab/
|
||||
|
||||
.LINK
|
||||
https://gist.githubusercontent.com/AlexanderHolmeset/d447cd7c24dd91c3275ad17a5091f0ed/raw/79478f1e789ab36a9236f21a3161685091b12e62/ProjectTeamStructure.ps1
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Name of the Microsoft Teams team')]
|
||||
[Parameter (Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Name')]
|
||||
[String]
|
||||
$TeamName,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Owner of the new Microsoft Teams team')]
|
||||
[Parameter (Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Owner')]
|
||||
[String]
|
||||
$TeamsOwner,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[Parameter (Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$privatepublic = 'Public',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[Parameter (Mandatory)]
|
||||
[Alias('description')]
|
||||
[String]
|
||||
$TeamsDescription,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 4)]
|
||||
[Alias('OAuthClientId')]
|
||||
[string]
|
||||
$ClientId,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 5)]
|
||||
[Alias('OAuthTenantId')]
|
||||
[string]
|
||||
$TenantId,
|
||||
[Parameter(Position = 6)]
|
||||
[Alias('OAuthClientSecret')]
|
||||
[string]
|
||||
$ClientSecret,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 7)]
|
||||
[string]
|
||||
$TenantName = 'contoso',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 8)]
|
||||
[string]
|
||||
$DocumentLibrary = '/shared documents'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
<#
|
||||
# Azure AD OAuth Application Token for Graph API
|
||||
# Get OAuth token for a AAD Application (returned as $token)
|
||||
# Application (client) ID, tenant ID and secret
|
||||
$ClientId = 'xxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
$TenantId = 'xxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
$ClientSecret = 'xxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
#>
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the credentials to use
|
||||
$Cred = (Get-Credential)
|
||||
|
||||
# Connect to Exchange Online
|
||||
$paramNewPSSession = @{
|
||||
ConfigurationName = 'Microsoft.Exchange'
|
||||
ConnectionUri = 'https://outlook.office365.com/powershell-liveid'
|
||||
Credential = $Cred
|
||||
Authentication = 'Basic'
|
||||
AllowRedirection = $true
|
||||
}
|
||||
|
||||
$Session = (New-PSSession @paramNewPSSession)
|
||||
$paramImportPSSession = @{
|
||||
Session = $Session
|
||||
DisableNameChecking = $true
|
||||
AllowClobber = $true
|
||||
}
|
||||
|
||||
$null = (Import-PSSession @paramImportPSSession)
|
||||
|
||||
# Connect to Microsoft Teams
|
||||
$null = (Connect-MicrosoftTeams -Credential $Cred)
|
||||
|
||||
# Contruct URI
|
||||
$uri = 'https://login.microsoftonline.com/' + $TenantId + '/oauth2/v2.0/token'
|
||||
|
||||
# Construct the JSON Body
|
||||
$body1 = @{
|
||||
client_id = $ClientId
|
||||
scope = 'https://graph.microsoft.com/.default'
|
||||
client_secret = $ClientSecret
|
||||
grant_type = 'client_credentials'
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
# Get OAuth 2.0 Token
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = 'Post'
|
||||
Uri = $uri
|
||||
ContentType = 'application/x-www-form-urlencoded'
|
||||
Body = $body1
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$tokenRequest = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Token
|
||||
$token = (($tokenRequest.Content | ConvertFrom-Json).access_token)
|
||||
|
||||
# Get ID of team requester and set as owner.
|
||||
$uri = 'https://graph.microsoft.com/beta/users/' + $TeamsOwner + '?$select=id'
|
||||
$method = 'GET'
|
||||
|
||||
try
|
||||
{
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = $method
|
||||
Uri = $uri
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$query = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the ID
|
||||
$ownerID = (($query.content | ConvertFrom-Json).id)
|
||||
|
||||
# Specify the URI to call and method
|
||||
$uri = 'https://graph.microsoft.com/beta/teams'
|
||||
$method = 'Post'
|
||||
|
||||
# Construct the JSON Body
|
||||
<#
|
||||
Please review this defaults,
|
||||
these settings are applied to the new Microsoft Teams team!
|
||||
#>
|
||||
$body = @"
|
||||
{
|
||||
"template@odata.bind": "https://graph.microsoft.com/beta/teamsTemplates/standard",
|
||||
"displayName": "$TeamName",
|
||||
"description": "$TeamsDescription",
|
||||
"channels": [
|
||||
{
|
||||
"displayName": "01-Management",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "Description"
|
||||
},
|
||||
{
|
||||
"displayName": "02-Developement",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "DEscription"
|
||||
},
|
||||
{
|
||||
"displayName": "03-Marketing",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "Description"
|
||||
},
|
||||
{
|
||||
"displayName": "04-Finance",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "Description"
|
||||
}
|
||||
],
|
||||
"memberSettings": {
|
||||
"allowCreateUpdateChannels": true,
|
||||
"allowDeleteChannels": false,
|
||||
"allowAddRemoveApps": true,
|
||||
"allowCreateUpdateRemoveTabs": true,
|
||||
"allowCreateUpdateRemoveConnectors": true
|
||||
},
|
||||
"guestSettings": {
|
||||
"allowCreateUpdateChannels": false,
|
||||
"allowDeleteChannels": false
|
||||
},
|
||||
"funSettings": {
|
||||
"allowGiphy": true,
|
||||
"giphyContentRating": "Moderate",
|
||||
"allowStickersAndMemes": true,
|
||||
"allowCustomMemes": true
|
||||
},
|
||||
"messagingSettings": {
|
||||
"allowUserEditMessages": true,
|
||||
"allowUserDeleteMessages": true,
|
||||
"allowOwnerDeleteMessages": true,
|
||||
"allowTeamMentions": true,
|
||||
"allowChannelMentions": true
|
||||
},
|
||||
"visibility": "$Private",
|
||||
"owners@odata.bind": [
|
||||
"https://graph.microsoft.com/beta/users('$ownerID')"
|
||||
]
|
||||
}
|
||||
"@
|
||||
|
||||
try
|
||||
{
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = $method
|
||||
Uri = $uri
|
||||
ContentType = 'application/json'
|
||||
Body = $body
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$query = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Data
|
||||
$location = ($query.Headers).Location
|
||||
$GroupID = $location.Substring(8, 36)
|
||||
|
||||
# Wait a minute to setup the stuff
|
||||
Start-Sleep -Seconds 60
|
||||
|
||||
# Get the Mail info about the new team
|
||||
$TeamSiteName = ((Get-Team -groupid $GroupID).MailNickName)
|
||||
|
||||
# Set some defaults
|
||||
$SiteURL = 'https://' + $TenantName + '.sharepoint.com/sites/' + $TeamSiteName
|
||||
$DocumentLibrary = '/shared documents'
|
||||
|
||||
# Channels
|
||||
# Config Variables
|
||||
$FolderNames = '01-Management', '02-Developement', '03-Marketing', '04-Finance'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
#sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 01-Management
|
||||
# Config Variables
|
||||
$FolderNames = 'Meetings', 'Presentations'
|
||||
$RelativeURL = $DocumentLibrary + '/01-management' #Relative URL of the Parent Folder
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 02-Developement
|
||||
# Config Variables
|
||||
$FolderNames = 'Design', 'Specs', 'Labeling'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/02-Developement'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Subfolder
|
||||
$FolderNames = 'Sketches', 'Requirements'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/02-Developement/Design'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 03-Marketing
|
||||
# Config Variables
|
||||
$FolderNames = 'Communication Brief', 'Competitor Review', 'Consumer Insights', 'Product FAQ', 'Product Information', 'Product Strategy'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/03-Marketing'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 04-Finance
|
||||
# Config Variables
|
||||
$FolderNames = 'Budget', 'Presentations'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/04-Finance'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
300
Powershell/PowerShell-collection/MicrosoftTeams/RemoveWiki.ps1
Normal file
300
Powershell/PowerShell-collection/MicrosoftTeams/RemoveWiki.ps1
Normal file
@@ -0,0 +1,300 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remove the Wiki tab on Microsoft Teams teams
|
||||
|
||||
.DESCRIPTION
|
||||
Remove the Wiki tab on Microsoft Teams teams
|
||||
I like Teams, but I never use the Wiki within Teams.
|
||||
Alexander Holmeset figured out a smart way to get rid of the Wiki tab.
|
||||
|
||||
.PARAMETER ClientId
|
||||
Azure AD Application (client) ID
|
||||
|
||||
.PARAMETER TenantId
|
||||
Azure AD Tenant ID
|
||||
|
||||
.PARAMETER ClientSecret
|
||||
Azure AD secret
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\RemoveWiki.ps1 -ClientId 'Value1' -TenantId 'Value2' -ClientSecret 'Value3'
|
||||
|
||||
.NOTES
|
||||
Original found in Alexander Holmeset's Blog
|
||||
My version starts to make it a bit more flexible (e.g. more parameters)
|
||||
|
||||
.LINK
|
||||
https://alexholmeset.blog/2019/05/10/remove-the-wiki-tab/
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/AlexanderHolmeset/e40c7e9297ae9cc01cb832871a9ff770
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Azure AD Application (client) ID')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('OAuthClientId')]
|
||||
[string]
|
||||
$ClientId,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Azure AD Tenant ID')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('OAuthTenantId')]
|
||||
[string]
|
||||
$TenantId,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2,
|
||||
HelpMessage = 'Azure AD secret')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('OAuthClientSecret')]
|
||||
[string]
|
||||
$ClientSecret
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
# Contruct URI
|
||||
$uri = 'https://login.microsoftonline.com/' + $TenantId + '/oauth2/v2.0/token'
|
||||
|
||||
try
|
||||
{
|
||||
# Construct Body
|
||||
$body1 = @{
|
||||
client_id = $ClientId
|
||||
scope = 'https://graph.microsoft.com/.default'
|
||||
client_secret = $ClientSecret
|
||||
grant_type = 'client_credentials'
|
||||
}
|
||||
|
||||
# Get OAuth 2.0 Token
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = 'Post'
|
||||
Uri = $uri
|
||||
ContentType = 'application/x-www-form-urlencoded'
|
||||
Body = $body1
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$tokenRequest = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Token
|
||||
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
|
||||
|
||||
# Just in case
|
||||
Write-Verbose -Message $token
|
||||
|
||||
try
|
||||
{
|
||||
# URI to call
|
||||
$uri = 'https://graph.microsoft.com/v1.0/groups'
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'GET'
|
||||
Uri = $uri
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$query = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Value
|
||||
$groups = $query.value
|
||||
|
||||
foreach ($group in $groups)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ($group.resourceProvisioningOptions -contains 'Team')
|
||||
{
|
||||
# Extract the ID
|
||||
$id = $group.id
|
||||
|
||||
# Build the URI
|
||||
$uri2 = 'https://graph.microsoft.com/v1.0/teams/' + $id + '/channels'
|
||||
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'Get'
|
||||
Uri = $uri2
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
}
|
||||
$query2 = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
|
||||
# Extract the Value
|
||||
$Channels = $query2.value
|
||||
|
||||
foreach ($Channel in $Channels)
|
||||
{
|
||||
$id2 = $Channel.id
|
||||
$uri3 = 'https://graph.microsoft.com/v1.0/teams/' + $id + '/channels/' + $id2 + '/tabs'
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'Get'
|
||||
Uri = $uri3
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
}
|
||||
$query3 = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
|
||||
# Extract the Value
|
||||
$tabs = $query3.value
|
||||
|
||||
# Find the Wiki Tab
|
||||
$WikiTabs = ($tabs | Where-Object -FilterScript {
|
||||
$_.displayname -eq 'Wiki'
|
||||
})
|
||||
|
||||
if ($WikiTabs)
|
||||
{
|
||||
foreach ($wikitab in $WikiTabs)
|
||||
{
|
||||
# Extract the ID
|
||||
$wikitabID = $wikitab.id
|
||||
|
||||
# Build the URI
|
||||
$uri4 = 'https://graph.microsoft.com/v1.0/teams/' + $id + '/channels/' + $id2 + '/tabs/' + $wikitabID
|
||||
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'DELETE'
|
||||
Uri = $uri4
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
}
|
||||
$query4 = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
|
||||
Write-Verbose -Message $query4
|
||||
|
||||
Write-Output -InputObject 'wikitab removed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,131 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Replace the Domain for all UnifiedGroups (and Microsoft Teams) Primary SMTP Address
|
||||
|
||||
.DESCRIPTION
|
||||
Replace the Domain for all UnifiedGroups (and Microsoft Teams) Primary SMTP Address
|
||||
|
||||
.PARAMETER OldDomain
|
||||
The old Domain (e.g. contoso.com)
|
||||
|
||||
.PARAMETER NewDomain
|
||||
The new Domain (e.g. contoso.net)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\ReplaceDomainForAllUnifiedGroups.ps1 -OldDomain 'contoso.com' -NewDomain 'contoso.net'
|
||||
|
||||
Replace the Primary SMTP Addresses for all UnifiedGroups (and Microsoft Teams) that are in the domain 'contoso.com' with the someone in the Domain 'contoso.net'
|
||||
e.g. if an old address was myTeam@contoso.com would end up as myTeam@contoso.new
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps
|
||||
|
||||
.LINK
|
||||
http://hochwald.net
|
||||
|
||||
.NOTES
|
||||
Quick and dirty approach, without any real Error handling.
|
||||
A friend asked me for a solution after a merger to replace all Primary SMTP Addresses and get rid of the old domain (legal requirement in this case)
|
||||
|
||||
You need be be connected to an Exchange Online Session (NOT part of this script).
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess = $true)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true,
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('DomainToReplace')]
|
||||
[string]
|
||||
$OldDomain,
|
||||
[Parameter(Mandatory = $true,
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$NewDomain
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$OldMailFilter = ('@' + $OldDomain)
|
||||
|
||||
# Cleanup
|
||||
$AllUnifiedGroups = $null
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$AllUnifiedGroups = (Get-UnifiedGroup | Where-Object -FilterScript {
|
||||
$_.PrimarySmtpAddress -like ('*' + $OldMailFilter)
|
||||
} | Select-Object -Property Identity, DisplayName, PrimarySmtpAddress)
|
||||
|
||||
if ($AllUnifiedGroups)
|
||||
{
|
||||
foreach ($item in $AllUnifiedGroups)
|
||||
{
|
||||
if ($item.PrimarySmtpAddress -like ('*' + $OldMailFilter))
|
||||
{
|
||||
$OldMailAddress = $null
|
||||
$OldMailAddress = (($item).PrimarySmtpAddress)
|
||||
|
||||
$NewMailAddress = $null
|
||||
$NewMailAddress = ($OldMailAddress.Replace($OldMailFilter, ('@' + $NewDomain)))
|
||||
Write-Verbose -Message ('Replace: {0} with: {1}' -f $OldMailAddress, $NewMailAddress)
|
||||
|
||||
# Add the new Address
|
||||
$null = (Set-UnifiedGroup -Identity (($item).Identity) -EmailAddresses: @{
|
||||
Add = $NewMailAddress
|
||||
} -Confirm:$false)
|
||||
|
||||
# Make new Address the primary SMTP address
|
||||
$null = (Set-UnifiedGroup -Identity (($item).Identity) -PrimarySmtpAddress $NewMailAddress -Confirm:$false)
|
||||
|
||||
# Remove the old SMTP Address
|
||||
$null = (Set-UnifiedGroup -Identity (($item).Identity) -EmailAddresses: @{
|
||||
Remove = $OldMailAddress
|
||||
} -Confirm:$false)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('Sorry, the PrimarySmtpAddress of {0} is not in {1}' -f $item.DisplayName, $OldDomain)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output -InputObject 'Nothing to do!!!'
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,210 @@
|
||||
#requires -Version 3.0 -Modules NetQos -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Apply QoS Settings for Microsoft Teams
|
||||
|
||||
.DESCRIPTION
|
||||
Apply Network Quality of Service (QoS) settings for Microsoft Teams.
|
||||
|
||||
.PARAMETER AppPathNameMatchCondition
|
||||
Specifies the name by which an application is run, such as application.exe or %ProgramFiles%\application.exe application.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeams.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeamsRoom.ps1 -AppPathNameMatchCondition 'Teams.exe'
|
||||
|
||||
.NOTES
|
||||
Changelog:
|
||||
1.0.0: Initial Release (Adopted from Set-QoSForMicrosoftTeamsRoomDevices.ps1)
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
.LINK
|
||||
Get-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
New-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/microsoftteams/qos-in-teams-clients
|
||||
|
||||
.LINK
|
||||
http://enatec.io
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('AppName')]
|
||||
[string]
|
||||
$AppPathNameMatchCondition = 'Teams.exe'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
Write-Output -InputObject 'Apply Network Quality of Service (QoS) settings for Microsoft Teams'
|
||||
|
||||
#region Defaults
|
||||
$CNT = 'Continue'
|
||||
$STP = 'Stop'
|
||||
$SCT = 'SilentlyContinue'
|
||||
|
||||
[string]$AppSharingPolicy = 'Microsoft Teams AppSharing'
|
||||
[string]$VideoPolicy = 'Microsoft Teams Video'
|
||||
[string]$AudioPoliy = 'Microsoft Teams Audio'
|
||||
#endregion Defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('QoS-Settings', 'Apply'))
|
||||
{
|
||||
#region Audio
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AudioPoliy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50000
|
||||
IPSrcPortEndMatchCondition = 50019
|
||||
DSCPAction = 46
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AudioPoliy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AudioPoliy)
|
||||
}
|
||||
}
|
||||
#endregion Audio
|
||||
|
||||
#region Video
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $VideoPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50020
|
||||
IPSrcPortEndMatchCondition = 50039
|
||||
DSCPAction = 34
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $VideoPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $VideoPolicy)
|
||||
}
|
||||
}
|
||||
#endregion Video
|
||||
|
||||
#region AppSharing
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AppSharingPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50040
|
||||
IPSrcPortEndMatchCondition = 50059
|
||||
DSCPAction = 28
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AppSharingPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AppSharingPolicy)
|
||||
}
|
||||
}
|
||||
#endregion AppSharing
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,203 @@
|
||||
#requires -Version 3.0 -Modules NetQos -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Apply QoS Settings for Microsoft Teams Room Devices
|
||||
|
||||
.DESCRIPTION
|
||||
Apply Network Quality of Service (QoS) settings for Microsoft Teams Room Devices.
|
||||
I use this script to deploy the QoS settings to MTR devices via Intune.
|
||||
|
||||
.PARAMETER AppPathNameMatchCondition
|
||||
Specifies the name by which an application is run, such as application.exe or %ProgramFiles%\application.exe application.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeamsRoomDevices.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeamsRoomDevices.ps1 -AppPathNameMatchCondition 'Teams.exe'
|
||||
|
||||
.NOTES
|
||||
Idea based on a Twitter chat with @StaleHansen
|
||||
|
||||
Please ensure to check the Ports!
|
||||
They must match you Teams Admin Centr (TAC) settings.
|
||||
|
||||
.LINK
|
||||
Get-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
New-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/microsoftteams/qos-in-teams-clients
|
||||
|
||||
.LINK
|
||||
https://twitter.com/StaleHansen/status/1294341225647083522
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('AppName')]
|
||||
[string]
|
||||
$AppPathNameMatchCondition = $null
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$AppSharingPolicy = 'MTR AppSharing'
|
||||
$VideoPolicy = 'MTR Video'
|
||||
$AudioPoliy = 'MTR Audio'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('QoS-Settings', 'Apply'))
|
||||
{
|
||||
#region Audio
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AudioPoliy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50000
|
||||
IPSrcPortEndMatchCondition = 50019
|
||||
DSCPAction = 46
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AudioPoliy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AudioPoliy)
|
||||
}
|
||||
}
|
||||
#endregion Audio
|
||||
|
||||
#region Video
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $VideoPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50020
|
||||
IPSrcPortEndMatchCondition = 50039
|
||||
DSCPAction = 34
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $VideoPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $VideoPolicy)
|
||||
}
|
||||
}
|
||||
#endregion Video
|
||||
|
||||
#region AppSharing
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AppSharingPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50040
|
||||
IPSrcPortEndMatchCondition = 50059
|
||||
DSCPAction = 28
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AppSharingPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AppSharingPolicy)
|
||||
}
|
||||
}
|
||||
#endregion AppSharing
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,128 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create a Microsoft Teams Room Device in Office 365
|
||||
|
||||
.DESCRIPTION
|
||||
Create and setup a Microsoft Teams Room Device in Microsoft Office 365
|
||||
|
||||
.NOTES
|
||||
Review the variable here.
|
||||
|
||||
You must be connected to the following Services:
|
||||
- Exchange Online
|
||||
- MSOL (Not AzureAD!)
|
||||
- Skype for Business Online (Not Teams!)
|
||||
|
||||
.LINK
|
||||
https://hochwald.net/microsoft-teams-room-device-1-2/
|
||||
|
||||
.LINK
|
||||
https://hochwald.net/microsoft-teams-room-device-2-2/
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param ()
|
||||
|
||||
# Display Name of the Room
|
||||
$RoomName = 'Your-Teams-Room'
|
||||
|
||||
# Alias of the Room (For the UPN, SMTP, and SIP Address)
|
||||
$RoomAlias = 'YourTeamsRoom'
|
||||
|
||||
# Keep this safe
|
||||
$RoomPassword = 'YourSuperSecretRoomPassword'
|
||||
<#
|
||||
At the moment, the password for a room/resource will never expire!
|
||||
So keep this in a safe place. And there is no second factor (MFA).
|
||||
#>
|
||||
|
||||
# The Domain for the UPN, and the SMTP address
|
||||
$RoomDomain = 'contoso.com'
|
||||
|
||||
# The Response text for meeting requests
|
||||
$RoomAdditionalResponse = 'This is a Microsoft Teams Team Room'
|
||||
<#
|
||||
Basic HTML is supported here!
|
||||
This text will be in the meeting respoinse mail, so use it as a info or teaser
|
||||
#>
|
||||
|
||||
# The ALIAS of the license to apply.
|
||||
# In this case it is the MEETING_ROOM License in the tenant with the name contoso
|
||||
$RoomLicence = 'contoso:MEETING_ROOM'
|
||||
<#
|
||||
The license must be availible (Buy it before create the room)
|
||||
#>
|
||||
|
||||
# We need one User that we use to find the SIP Registrar Pool (For Skype for Business and Teams SIP handling)
|
||||
$CsOnlineUser = 'john.doe'
|
||||
|
||||
#region AutomatedStrings
|
||||
# Build some strings
|
||||
$RoomUserPrincipalName = ($RoomAlias + '@' + $RoomDomain)
|
||||
$CsOnlineUserTemplate = ($CsOnlineUser + '@' + $RoomDomain)
|
||||
<#
|
||||
I use the same domain for the UPN and the SMTP/SIP address,
|
||||
and I highly recommend you to do the same!
|
||||
#>
|
||||
#endregion AutomatedStrings
|
||||
|
||||
#region NewMailbox
|
||||
# Create the Mailbox
|
||||
$paramNewMailbox = @{
|
||||
Name = $RoomName
|
||||
Alias = $RoomAlias
|
||||
Room = $true
|
||||
EnableRoomMailboxAccount = $true
|
||||
MicrosoftOnlineServicesID = $RoomUserPrincipalName
|
||||
RoomMailboxPassword = (ConvertTo-SecureString -String $RoomPassword -AsPlainText -Force)
|
||||
}
|
||||
New-Mailbox @paramNewMailbox
|
||||
#endregion NewMailbox
|
||||
|
||||
#region SetCalendarProcessing
|
||||
# Tweak Calendar settings
|
||||
$paramSetCalendarProcessing = @{
|
||||
Identity = $RoomName
|
||||
AutomateProcessing = 'AutoAccept'
|
||||
AddOrganizerToSubject = $false
|
||||
DeleteComments = $false
|
||||
DeleteSubject = $false
|
||||
RemovePrivateProperty = $false
|
||||
AddAdditionalResponse = $true
|
||||
AdditionalResponse = $RoomAdditionalResponse
|
||||
}
|
||||
Set-CalendarProcessing @paramSetCalendarProcessing
|
||||
<#
|
||||
Please review the parameters above!
|
||||
They might not match your taste or requirements
|
||||
You can add more: Use 'Get-Help Set-CalendarProcessing -details' to see all supported paramaters
|
||||
#>
|
||||
#endregion SetCalendarProcessing
|
||||
|
||||
#region SetMsolUser
|
||||
# Usage location and password tweak
|
||||
$paramSetMsolUser = @{
|
||||
UserPrincipalName = $RoomUserPrincipalName
|
||||
PasswordNeverExpires = $true
|
||||
UsageLocation = 'DE'
|
||||
}
|
||||
Set-MsolUser @paramSetMsolUser
|
||||
#endregion SetMsolUser
|
||||
|
||||
#region SetMsolUserLicense
|
||||
# Apply the license
|
||||
$paramSetMsolUserLicense = @{
|
||||
UserPrincipalName = $RoomUserPrincipalName
|
||||
AddLicenses = $RoomLicence
|
||||
}
|
||||
Set-MsolUserLicense @paramSetMsolUserLicense
|
||||
#endregion SetMsolUserLicense
|
||||
|
||||
#region EnableCsMeetingRoom
|
||||
# Enable SIP (Skype for Business/Teams)
|
||||
$paramEnableCsMeetingRoom = @{
|
||||
Identity = $RoomUserPrincipalName
|
||||
RegistrarPool = (Get-CsOnlineUser -Identity $CsOnlineUserTemplate | Select-Object -ExpandProperty RegistrarPool)
|
||||
SipAddressType = 'EmailAddress'
|
||||
}
|
||||
Enable-CsMeetingRoom @paramEnableCsMeetingRoom
|
||||
#endregion EnableCsMeetingRoom
|
||||
@@ -0,0 +1,227 @@
|
||||
function Update-UnifiedGroupsToTeams
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Converts all Microsoft Office 365 Groups into a new Microsoft Teams Team
|
||||
|
||||
.DESCRIPTION
|
||||
Converts all Microsoft Office 365 Groups into a new Microsoft Teams Team
|
||||
Microsoft Office 365 Groups are also known as Unified Office 365 Groups
|
||||
|
||||
.PARAMETER ReportOnly
|
||||
Shows a list of Microsoft Office 365 Groups that would be migrated to a new Microsoft Teams Team.
|
||||
This is a DryRun only!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Update-UnifiedGroupsToTeams
|
||||
|
||||
Converting all Microsoft Office 365 Groups into a new Microsoft Teams Team
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Update-UnifiedGroupsToTeams -ReportOnly
|
||||
|
||||
Do a DryRun (Just get a List of Unified Groups that do NOT have a Microsoft Teams Team)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Compare-Object -ReferenceObject ((Get-Team | Select-Object -ExpandProperty GroupId)) -DifferenceObject ((Get-UnifiedGroup -ResultSize Unlimited | Select-Object -ExpandProperty ExternalDirectoryObjectId)) -PassThru
|
||||
|
||||
Get a short difference list (this function is not required to do so)
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.1 2019-04-21: Add a bit more error handling
|
||||
1.0.0 2018-04-14: Internal 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.
|
||||
|
||||
Dependencies:
|
||||
The script depends on Microsoft's Version 0.9.6, or newer, of the MicrosoftTeams PowerShell Module
|
||||
|
||||
Install it with PowerShellGet:
|
||||
PS C:\> Install-Module MicrosoftTeams
|
||||
|
||||
You need to be connected to Office 365 (Exchange Online). The function will check that.
|
||||
|
||||
.LINK
|
||||
https://www.powershellgallery.com/packages/MicrosoftTeams/0.9.6
|
||||
|
||||
.LINK
|
||||
https://aka.ms/InstallModule
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[Alias('DryRun')]
|
||||
[switch]
|
||||
$ReportOnly
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$CNT = 'Continue'
|
||||
$STP = 'Stop'
|
||||
#endregion Defaults
|
||||
|
||||
try
|
||||
{
|
||||
#region ConnectionCheck
|
||||
if (-not (Get-Command -Name Get-UnifiedGroup -ErrorAction SilentlyContinue))
|
||||
{
|
||||
$ErrorParameter = @{
|
||||
Message = 'Please connect to Office 365/Exchange Online before using this function!'
|
||||
Category = 'ResourceUnavailable'
|
||||
RecommendedAction = 'Connect to Office 365/Exchange Online before using this function'
|
||||
ErrorAction = $STP
|
||||
}
|
||||
Write-Error @ErrorParameter
|
||||
}
|
||||
#endregion ConnectionCheck
|
||||
|
||||
#region GetUnifiedGroups
|
||||
$GetUnifiedGroupParameter = @{
|
||||
ResultSize = 'Unlimited'
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$AllOffice365UnifiedGroups = (Get-UnifiedGroup @GetUnifiedGroupParameter | Select-Object -Property DisplayName, ExternalDirectoryObjectId)
|
||||
#endregion GetUnifiedGroups
|
||||
|
||||
#region GetMicrosoftTeams
|
||||
$GetTeamParameter = @{
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$AllMicrosoftTeams = (Get-Team @GetTeamParameter | Select-Object -ExpandProperty GroupId)
|
||||
#endregion GetMicrosoftTeams
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# Dump the FULL error record
|
||||
Write-Warning -Message ($info | Out-String)
|
||||
|
||||
Write-Error -Message $info.Exception -Exception $info.Exception -ErrorAction $STP
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($AllOffice365UnifiedGroups)
|
||||
{
|
||||
#region Loop
|
||||
foreach ($Office365UnifiedGroup in $AllOffice365UnifiedGroups)
|
||||
{
|
||||
if (-not ($AllMicrosoftTeams -match $Office365UnifiedGroup.ExternalDirectoryObjectId))
|
||||
{
|
||||
if ($ReportOnly)
|
||||
{
|
||||
#region ReportOnly
|
||||
$SingleOffice365UnifiedGroup = $Office365UnifiedGroup.DisplayName
|
||||
Write-Output -InputObject ('Microsoft Teams for Unified Group {0} is missing' -f $SingleOffice365UnifiedGroup)
|
||||
#endregion ReportOnly
|
||||
}
|
||||
else
|
||||
{
|
||||
#region CreateMissingTeam
|
||||
Write-Verbose -Message ('Create Microsoft Teams Team for Unified Group {0}' -f $SingleOffice365UnifiedGroup)
|
||||
|
||||
try
|
||||
{
|
||||
$NewTeamParameter = @{
|
||||
Group = $Office365UnifiedGroup
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$NewTeam = (New-Team @NewTeamParameter)
|
||||
|
||||
Write-Debug -Message $NewTeam
|
||||
|
||||
Write-Verbose -Message ('Created Microsoft Teams Team for Unified Group {0}' -f $SingleOffice365UnifiedGroup)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
$TheException = $info.Exception
|
||||
|
||||
Write-Warning -Message ('Microsoft Teams creation for {0} failed with {1} ' -f $SingleOffice365UnifiedGroup, $TheException)
|
||||
|
||||
# Dump the FULL error record
|
||||
Write-Verbose -Message ($info | Out-String)
|
||||
}
|
||||
#endregion CreateMissingTeam
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Loop
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No Unified Groups found in your Tenant...'
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message 'Done.'
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,23 @@
|
||||
# Use the latest Microsoft Teams PowerShell Module to connect
|
||||
# Not the Skype for Business Online Module (outdated)
|
||||
|
||||
# Get all Teams Meeting Policies
|
||||
Get-CsTeamsMeetingPolicy | Select-Object -ExpandProperty Identity
|
||||
|
||||
# Get all Teams Meeting Policies, exclude all TAG Policies (You can not modify them with Get-CsTeamsMeetingPolicy)
|
||||
Get-CsTeamsMeetingPolicy | Where-Object -FilterScript {
|
||||
$_.Identity -notlike 'Tag:*'
|
||||
} | Select-Object -ExpandProperty Identity
|
||||
|
||||
# Modify the Global Policy
|
||||
Set-CsTeamsMeetingPolicy -Identity Global -AllowEngagementReport Enabled
|
||||
|
||||
# Modify any Policy by name
|
||||
Set-CsTeamsMeetingPolicy -Identity 'Meetings' | Set-CsTeamsMeetingPolicy -AllowEngagementReport Enabled
|
||||
|
||||
# Modify all Policies (exclude the TAG Policies, because you can not modify them with Get-CsTeamsMeetingPolicy)
|
||||
Get-CsTeamsMeetingPolicy | Where-Object -FilterScript {
|
||||
$_.Identity -notlike 'Tag:*'
|
||||
} | ForEach-Object -Process {
|
||||
Set-CsTeamsMeetingPolicy -Identity $_.Identity -AllowEngagementReport Enabled -ErrorAction Continue
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
RuleID,RuleDescription,RuleAction
|
||||
75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84, Block Office applications from injecting into other processes, Enabled
|
||||
3B576869-A4EC-4529-8536-B80A7769E899, Block Office applications from creating executable content, Enabled
|
||||
D4F940AB-401B-4EfC-AADC-AD5F3C50688A, Block Office applications from creating child processes, Enabled
|
||||
D3E037E1-3EB8-44C8-A917-57927947596D, Impede JavaScript and VBScript to launch executables, Enabled
|
||||
5BEB7EFE-FD9A-4556-801D-275E5FFC04CC, Block execution of potentially obfuscated script, Enabled
|
||||
BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550, Block executable content from email client and webmail, Enabled
|
||||
92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B, Block Win32 imports from Macro code in Office, Enabled
|
||||
c1db55ab-c21a-4637-bb3f-a12568109d35, Use advanced protection against ransomware, Enabled
|
||||
9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2, Block credential stealing from the Windows local security authority subsystem (lsass.exe), Enabled
|
||||
d1e49aac-8f56-4280-b9ba-993a6d77406c, Block process creations originating from PSExec and WMI commands, Enabled
|
||||
b2b3f03d-6a65-4f7b-a9c7-1c7ef74a9ba4, Block untrusted and unsigned processes that run from USB, Enabled
|
||||
26190899-1602-49e8-8b27-eb1d0a1ce869, Block Office communication applications from creating child processes, AuditMode
|
||||
7674ba52-37eb-4a4f-a9a1-f0f9a1619a2c, Block Adobe Reader from creating child processes, Enabled
|
||||
e6db77e5-3df2-4cf1-b95a-636979351e5b, Block persistence through WMI event subscription, Enabled
|
||||
01443614-cd74-433a-b99e-2ecdc07bfc25, Block executable files from running unless they meet a prevalence age or trusted list criteria, AuditMode
|
||||
|
@@ -0,0 +1,676 @@
|
||||
#requires -Version 3.0 -Modules ConfigDefender, NetSecurity
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Bootstrap Microsoft Defender configuration
|
||||
|
||||
.DESCRIPTION
|
||||
Bootstrap Microsoft Defender configuration, optimize and tweak Windows 10 protection and security
|
||||
|
||||
.PARAMETER CsvPath
|
||||
The CSV with the configuration.
|
||||
This is optional. Defaults are in the Script.
|
||||
|
||||
.PARAMETER Force
|
||||
Enforce to apply the customize attack surface reduction rules
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Bootstrap-MicrosoftDefenderConfiguration.ps1
|
||||
|
||||
Bootstrap Microsoft Defender configuration, optimize and tweak Windows 10 Protection
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Bootstrap-MicrosoftDefenderConfiguration.ps1 -Verbose -Force
|
||||
|
||||
Bootstrap Microsoft Defender configuration, optimize and tweak Windows 10 Protection
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Bootstrap-MicrosoftDefenderConfiguration.ps1 -Verbose
|
||||
|
||||
Bootstrap Microsoft Defender configuration, optimize and tweak Windows 10 Protection
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/defender/index?view=win10-ps
|
||||
|
||||
.LINK
|
||||
https://github.com/jhochwald/PowerShell-collection/blob/master/Misc/Optimize-MicrosoftDefenderExclusions.ps1
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/enable-exploit-protection
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=win10-ps
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/customize-attack-surface-reduction
|
||||
|
||||
.LINK
|
||||
https://support.microsoft.com/en-us/help/822158/virus-scanning-recommendations-for-enterprise-computers-that-are-runni
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-antivirus/enable-cloud-protection-windows-defender-antivirus
|
||||
|
||||
.LINK
|
||||
https://demo.wd.microsoft.com/?ocid=cx-wddocs-testground
|
||||
|
||||
.NOTES
|
||||
Please review the settings, please tweak the rules file (or modify the default rule set here)
|
||||
|
||||
You need to run this in an elevated PowerShell!
|
||||
|
||||
I use this during the bootstrap process of Windows systems.
|
||||
Most of the settings here is also enforced by some of our Group Policies and we also have a lot of it configured via MDM CSPs (InTune).
|
||||
|
||||
This script is only a quick hack to harden (and secure) any new system, even if it is not managed afterwords.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('RulesCsv')]
|
||||
[string]
|
||||
$CsvPath = '.\Bootstrap-MicrosoftDefenderConfiguration.csv',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('EnforceRule')]
|
||||
[switch]
|
||||
$Force = $null
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Create a new Mail Object
|
||||
$AttackSurfaceReductionRuleList = @()
|
||||
|
||||
#region CsvHandler
|
||||
if (Test-Path -Path $CsvPath -ErrorAction SilentlyContinue)
|
||||
{
|
||||
#region ImportCsv
|
||||
Write-Verbose -Message ('Import the attack surface reduction settings from ' + $CsvPath)
|
||||
$AttackSurfaceReductionRuleList = (Import-Csv -Path $CsvPath -Delimiter ',' -Encoding UTF8)
|
||||
#endregion ImportCsv
|
||||
}
|
||||
else
|
||||
{
|
||||
#region DefaultCsv
|
||||
Write-Verbose -Message 'Use the attack surface reduction default settings'
|
||||
|
||||
# Create a virtual CSV File (Quick hack: To keep it plain and simple to maintain)
|
||||
$RuleDefaults = 'RuleID,RuleDescription,RuleAction
|
||||
75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84, Block Office applications from injecting into other processes, Enabled
|
||||
3B576869-A4EC-4529-8536-B80A7769E899, Block Office applications from creating executable content, Enabled
|
||||
D4F940AB-401B-4EfC-AADC-AD5F3C50688A, Block Office applications from creating child processes, Enabled
|
||||
D3E037E1-3EB8-44C8-A917-57927947596D, Impede JavaScript and VBScript to launch executable, Enabled
|
||||
5BEB7EFE-FD9A-4556-801D-275E5FFC04CC, Block execution of potentially obfuscated script, Enabled
|
||||
BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550, Block executable content from email client and webmail, Enabled
|
||||
92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B, Block Win32 imports from Macro code in Office, Enabled
|
||||
c1db55ab-c21a-4637-bb3f-a12568109d35, Use advanced protection against ransomware, Enabled
|
||||
9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2, Block credential stealing from the Windows local security authority subsystem (lsass.exe), Enabled
|
||||
d1e49aac-8f56-4280-b9ba-993a6d77406c, Block process creations originating from PSExec and WMI commands, Enabled
|
||||
b2b3f03d-6a65-4f7b-a9c7-1c7ef74a9ba4, Block untrusted and unsigned processes that run from USB, Enabled
|
||||
26190899-1602-49e8-8b27-eb1d0a1ce869, Block Office communication applications from creating child processes, AuditMode
|
||||
7674ba52-37eb-4a4f-a9a1-f0f9a1619a2c, Block Adobe Reader from creating child processes, Enabled
|
||||
e6db77e5-3df2-4cf1-b95a-636979351e5b, Block persistence through WMI event subscription, Enabled
|
||||
01443614-cd74-433a-b99e-2ecdc07bfc25, Block executable files from running unless they meet a prevalence age or trusted list criteria, AuditMode'
|
||||
|
||||
# Import the virtual CSV File
|
||||
$AttackSurfaceReductionRuleList = (ConvertFrom-Csv -InputObject $RuleDefaults -Delimiter ',')
|
||||
#endregion DefaultCsv
|
||||
}
|
||||
#endregion CsvHandler
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
#region SetMpPreference
|
||||
#region EnableNetworkProtection
|
||||
Write-Verbose -Message 'Network protection helps to prevent employees from using any application to access dangerous domains that may host phishing scams, exploits, and other malicious content on the Internet'
|
||||
$null = (Set-MpPreference -EnableNetworkProtection Enabled -Force -ErrorAction Continue)
|
||||
#endregion EnableNetworkProtection
|
||||
|
||||
#region EnableControlledFolderAccess
|
||||
Write-Verbose -Message 'Controlled folder access helps you protect valuable data from malicious apps and threats, such as ransomware'
|
||||
$null = (Set-MpPreference -EnableControlledFolderAccess Enabled -Force -ErrorAction Continue)
|
||||
#endregion EnableControlledFolderAccess
|
||||
|
||||
#region SignatureScheduleDay
|
||||
Write-Verbose -Message 'Specifies the day of the week on which to check for definition updates'
|
||||
$null = (Set-MpPreference -SignatureScheduleDay Everyday -Force -ErrorAction Continue)
|
||||
#endregion SignatureScheduleDay
|
||||
|
||||
#region SignatureScheduleTime
|
||||
Write-Verbose -Message 'Specifies the time of day, as the number of minutes after midnight, to check for definition updates'
|
||||
$null = (Set-MpPreference -SignatureScheduleTime 320 -Force -ErrorAction Continue)
|
||||
#endregion SignatureScheduleTime
|
||||
|
||||
#region DisableArchiveScanning
|
||||
Write-Verbose -Message 'Indicates whether to scan archive files for malicious and unwanted software'
|
||||
$null = (Set-MpPreference -DisableArchiveScanning $true -Force -ErrorAction Continue)
|
||||
#endregion DisableArchiveScanning
|
||||
|
||||
#region DisableAutoExclusions
|
||||
Write-Verbose -Message 'Indicates whether to disable the Automatic Exclusions feature for the server'
|
||||
$null = (Set-MpPreference -DisableAutoExclusions $false -Force -ErrorAction Continue)
|
||||
#endregion DisableAutoExclusions
|
||||
|
||||
#region DisableBehaviorMonitoring
|
||||
Write-Verbose -Message 'Indicates whether to enable behavior monitoring'
|
||||
$null = (Set-MpPreference -DisableBehaviorMonitoring $true -Force -ErrorAction Continue)
|
||||
#endregion DisableBehaviorMonitoring
|
||||
|
||||
#region DisableBlockAtFirstSeen
|
||||
Write-Verbose -Message 'Indicates whether to enable block at first seen'
|
||||
$null = (Set-MpPreference -DisableBlockAtFirstSeen $true -Force -ErrorAction Continue)
|
||||
#endregion DisableBlockAtFirstSeen
|
||||
|
||||
#region DisableCatchupFullScan
|
||||
Write-Verbose -Message 'Indicates whether Windows Defender runs catch-up scans for scheduled full scans'
|
||||
$null = (Set-MpPreference -DisableCatchupFullScan $true -Force -ErrorAction Continue)
|
||||
#endregion DisableCatchupFullScan
|
||||
|
||||
#region DisableCatchupQuickScan
|
||||
Write-Verbose -Message 'Indicates whether Windows Defender runs catch-up scans for scheduled quick scans'
|
||||
$null = (Set-MpPreference -DisableCatchupQuickScan $true -Force -ErrorAction Continue)
|
||||
#endregion DisableCatchupQuickScan
|
||||
|
||||
#region DisableEmailScanning
|
||||
Write-Verbose -Message 'Indicates whether Windows Defender parses the mailbox and mail files, according to their specific format, in order to analyze mail bodies and attachments'
|
||||
$null = (Set-MpPreference -DisableEmailScanning $false -Force -ErrorAction Continue)
|
||||
#endregion DisableEmailScanning
|
||||
|
||||
#region DisableIOAVProtection
|
||||
Write-Verbose -Message 'Indicates whether Windows Defender scans all downloaded files and attachments (e.g. Downloads)'
|
||||
$null = (Set-MpPreference -DisableIOAVProtection $true -Force -ErrorAction Continue)
|
||||
#endregion DisableIOAVProtection
|
||||
|
||||
#region DisableIntrusionPreventionSystem
|
||||
Write-Verbose -Message 'Indicates whether to configure network protection against exploitation of known vulnerabilities'
|
||||
$null = (Set-MpPreference -DisableIntrusionPreventionSystem $false -Force -ErrorAction Continue)
|
||||
#endregion DisableIntrusionPreventionSystem
|
||||
|
||||
#region DisablePrivacyMode
|
||||
Write-Verbose -Message 'Indicates whether to disable privacy mode. Privacy mode prevents users, other than administrators, from displaying threat history'
|
||||
$null = (Set-MpPreference -DisablePrivacyMode $false -Force -ErrorAction Continue)
|
||||
#endregion DisablePrivacyMode
|
||||
|
||||
#region DisableRealtimeMonitoring
|
||||
Write-Verbose -Message 'Indicates whether to use real-time protection'
|
||||
$null = (Set-MpPreference -DisableRealtimeMonitoring $false -Force -ErrorAction Continue)
|
||||
#endregion DisableRealtimeMonitoring
|
||||
|
||||
#region CheckForSignaturesBeforeRunningScan
|
||||
Write-Verbose -Message 'Enable checking signatures before scanning'
|
||||
$null = (Set-MpPreference -CheckForSignaturesBeforeRunningScan 1 -Force -ErrorAction Continue)
|
||||
#endregion CheckForSignaturesBeforeRunningScan
|
||||
|
||||
#region DisableRemovableDriveScanning
|
||||
Write-Verbose -Message 'Indicates whether to scan for malicious and unwanted software in removable drives, such as flash drives, during a full scan'
|
||||
$null = (Set-MpPreference -DisableRemovableDriveScanning $true -Force -ErrorAction Continue)
|
||||
#endregion DisableRemovableDriveScanning
|
||||
|
||||
#region DisableRestorePoint
|
||||
Write-Verbose -Message 'Indicates whether to disable scanning of restore points'
|
||||
$null = (Set-MpPreference -DisableRestorePoint $true -Force -ErrorAction Continue)
|
||||
#endregion DisableRestorePoint
|
||||
|
||||
#region DisableScanningMappedNetworkDrivesForFullScan
|
||||
Write-Verbose -Message 'Indicates whether to scan mapped network drives'
|
||||
$null = (Set-MpPreference -DisableScanningMappedNetworkDrivesForFullScan $true -Force -ErrorAction Continue)
|
||||
#endregion DisableScanningMappedNetworkDrivesForFullScan
|
||||
|
||||
#region DisableScanningNetworkFiles
|
||||
Write-Verbose -Message 'Indicates whether to scan for network files'
|
||||
$null = (Set-MpPreference -DisableScanningNetworkFiles $false -Force -ErrorAction Continue)
|
||||
#endregion DisableScanningNetworkFiles
|
||||
|
||||
#region DisableScriptScanning
|
||||
Write-Verbose -Message 'Specifies whether to disable the scanning of scripts during malware scans'
|
||||
$null = (Set-MpPreference -DisableScriptScanning $false -Force -ErrorAction Continue)
|
||||
#endregion DisableScriptScanning
|
||||
|
||||
#region HighThreatDefaultAction
|
||||
Write-Verbose -Message 'Specifies which automatic remediation action to take for a high level threat'
|
||||
$null = (Set-MpPreference -HighThreatDefaultAction Quarantine -Force -ErrorAction Continue)
|
||||
#endregion HighThreatDefaultAction
|
||||
|
||||
#region LowThreatDefaultAction
|
||||
Write-Verbose -Message 'Specifies which automatic remediation action to take for a low level threat'
|
||||
$null = (Set-MpPreference -LowThreatDefaultAction Block -Force -ErrorAction Continue)
|
||||
#endregion LowThreatDefaultAction
|
||||
|
||||
#region ModerateThreatDefaultAction
|
||||
Write-Verbose -Message 'Specifies which automatic remediation action to take for a moderate level threat'
|
||||
$null = (Set-MpPreference -ModerateThreatDefaultAction Quarantine -Force -ErrorAction Continue)
|
||||
#endregion ModerateThreatDefaultAction
|
||||
|
||||
#region PUAProtection
|
||||
Write-Verbose -Message 'Disable PUA Protection'
|
||||
$null = (Set-MpPreference -PUAProtection Enabled -Force -ErrorAction Continue)
|
||||
#endregion PUAProtection
|
||||
|
||||
#region QuarantinePurgeItemsAfterDelay
|
||||
Write-Verbose -Message 'Specifies the number of days to keep items in the Quarantine folder'
|
||||
$null = (Set-MpPreference -QuarantinePurgeItemsAfterDelay 30 -Force -ErrorAction Continue)
|
||||
#endregion QuarantinePurgeItemsAfterDelay
|
||||
|
||||
#region RandomizeScheduleTaskTimes
|
||||
Write-Verbose -Message 'Indicates whether to select a random time for the scheduled start and scheduled update for definitions'
|
||||
$null = (Set-MpPreference -RandomizeScheduleTaskTimes $true -Force -ErrorAction Continue)
|
||||
#endregion RandomizeScheduleTaskTimes
|
||||
|
||||
#region RealTimeScanDirection
|
||||
Write-Verbose -Message 'Specifies scanning configuration for incoming and outgoing files on NTFS volumes'
|
||||
$null = (Set-MpPreference -RealTimeScanDirection 0 -Force -ErrorAction Continue)
|
||||
#endregion RealTimeScanDirection
|
||||
|
||||
#region RemediationScheduleDay
|
||||
Write-Verbose -Message 'Specifies the day of the week on which to perform a scheduled full scan in order to complete remediation'
|
||||
$null = (Set-MpPreference -RemediationScheduleDay Everyday -Force -ErrorAction Continue)
|
||||
#endregion
|
||||
|
||||
#region RemediationScheduleTime
|
||||
Write-Verbose -Message 'Specifies the time of day, as the number of minutes after midnight, to perform a scheduled scan'
|
||||
$null = (Set-MpPreference -RemediationScheduleTime 120 -Force -ErrorAction Continue)
|
||||
#endregion RemediationScheduleDay
|
||||
|
||||
#region ReportingAdditionalActionTimeOut
|
||||
Write-Verbose -Message 'Specifies the number of minutes before a detection in the additional action state changes to the cleared state'
|
||||
$null = (Set-MpPreference -ReportingAdditionalActionTimeOut 10080 -Force -ErrorAction Continue)
|
||||
#endregion ReportingAdditionalActionTimeOut
|
||||
|
||||
#region ReportingCriticalFailureTimeOut
|
||||
Write-Verbose -Message 'Specifies the number of minutes before a detection in the critically failed state changes to either the additional action state or the cleared state'
|
||||
$null = (Set-MpPreference -ReportingCriticalFailureTimeOut 10080 -Force -ErrorAction Continue)
|
||||
#endregion ReportingCriticalFailureTimeOut
|
||||
|
||||
#region ReportingNonCriticalTimeOut
|
||||
Write-Verbose -Message 'Specifies the number of minutes before a detection in the non-critically failed state changes to the cleared state'
|
||||
$null = (Set-MpPreference -ReportingNonCriticalTimeOut 11440 -Force -ErrorAction Continue)
|
||||
#endregion ReportingNonCriticalTimeOut
|
||||
|
||||
#region ScanAvgCPULoadFactor
|
||||
Write-Verbose -Message 'Specifies the maximum percentage CPU usage for a scan'
|
||||
$null = (Set-MpPreference -ScanAvgCPULoadFactor 50 -Force -ErrorAction Continue)
|
||||
#endregion ScanAvgCPULoadFactor
|
||||
|
||||
#region ScanOnlyIfIdleEnabled
|
||||
Write-Verbose -Message 'Indicates whether to start scheduled scans only when the computer is not in use'
|
||||
$null = (Set-MpPreference -ScanOnlyIfIdleEnabled $true -Force -ErrorAction Continue)
|
||||
#endregion ScanOnlyIfIdleEnabled
|
||||
|
||||
#region ScanParameters
|
||||
Write-Verbose -Message 'Specifies the scan type to use during a scheduled scan'
|
||||
$null = (Set-MpPreference -ScanParameters 1 -Force -ErrorAction Continue)
|
||||
#endregion ScanParameters
|
||||
|
||||
#region ScanPurgeItemsAfterDelay
|
||||
Write-Verbose -Message 'Specifies the number of days to keep items in the scan history folder'
|
||||
$null = (Set-MpPreference -ScanPurgeItemsAfterDelay 15 -Force -ErrorAction Continue)
|
||||
#endregion ScanPurgeItemsAfterDelay
|
||||
|
||||
#region ScanScheduleDay
|
||||
Write-Verbose -Message 'Specifies the day of the week on which to perform a scheduled scan'
|
||||
$null = (Set-MpPreference -ScanScheduleDay Everyday -Force -ErrorAction Continue)
|
||||
#endregion ScanScheduleDay
|
||||
|
||||
#region ScanScheduleQuickScanTime
|
||||
Write-Verbose -Message 'Specifies the time of day, as the number of minutes after midnight, to perform a scheduled quick scan'
|
||||
$null = (Set-MpPreference -ScanScheduleQuickScanTime 0 -Force -ErrorAction Continue)
|
||||
#endregion ScanScheduleQuickScanTime
|
||||
|
||||
#region ScanScheduleTime
|
||||
Write-Verbose -Message 'Specifies the time of day, as the number of minutes after midnight, to perform a scheduled scan'
|
||||
$null = (Set-MpPreference -ScanScheduleTime 120 -Force -ErrorAction Continue)
|
||||
#endregion ScanScheduleTime
|
||||
|
||||
#region SevereThreatDefaultAction
|
||||
Write-Verbose -Message 'Specifies which automatic remediation action to take for a severe level threat'
|
||||
$null = (Set-MpPreference -SevereThreatDefaultAction Quarantine -Force -ErrorAction Continue)
|
||||
#endregion SevereThreatDefaultAction
|
||||
|
||||
#region SignatureAuGracePeriod
|
||||
Write-Verbose -Message 'Specifies a grace period, in minutes, for the definition'
|
||||
$null = (Set-MpPreference -SignatureAuGracePeriod 0 -Force -ErrorAction Continue)
|
||||
#endregion SignatureAuGracePeriod
|
||||
|
||||
#region SignatureDisableUpdateOnStartupWithoutEngine
|
||||
Write-Verbose -Message 'Indicates whether to initiate definition updates even if no antimalware engine is present'
|
||||
$null = (Set-MpPreference -SignatureDisableUpdateOnStartupWithoutEngine $false -Force -ErrorAction Continue)
|
||||
#endregion SignatureDisableUpdateOnStartupWithoutEngine
|
||||
|
||||
#region SignatureFirstAuGracePeriod
|
||||
Write-Verbose -Message 'Specifies a grace period, in minutes, for the definition. If a definition successfully updates within this period, Windows Defender abandons any service initiated updates'
|
||||
$null = (Set-MpPreference -SignatureFirstAuGracePeriod 120 -Force -ErrorAction Continue)
|
||||
#endregion SignatureFirstAuGracePeriod
|
||||
|
||||
#region SignatureScheduleDay
|
||||
Write-Verbose -Message 'Specifies the day of the week on which to check for definition updates'
|
||||
$null = (Set-MpPreference -SignatureScheduleDay Everyday -Force -ErrorAction Continue)
|
||||
#endregion SignatureScheduleDay
|
||||
|
||||
#region SignatureScheduleTime
|
||||
Write-Verbose -Message 'Specifies the time of day, as the number of minutes after midnight, to check for definition updates'
|
||||
$null = (Set-MpPreference -SignatureScheduleTime 165 -Force -ErrorAction Continue)
|
||||
#endregion SignatureScheduleTime
|
||||
|
||||
#region SignatureUpdateCatchupInterval
|
||||
Write-Verbose -Message 'Specifies the number of days after which Windows Defender requires a catch-up definition update'
|
||||
$null = (Set-MpPreference -SignatureUpdateCatchupInterval 1 -Force -ErrorAction Continue)
|
||||
#endregion SignatureUpdateCatchupInterval
|
||||
|
||||
#region SignatureUpdateInterval
|
||||
Write-Verbose -Message 'Specifies the interval, in hours, at which to check for definition updates'
|
||||
$null = (Set-MpPreference -SignatureUpdateInterval 12 -Force -ErrorAction Continue)
|
||||
#endregion SignatureUpdateInterval
|
||||
|
||||
#region SubmitSamplesConsent
|
||||
Write-Verbose -Message 'Specifies how Windows Defender checks for user consent for certain samples'
|
||||
$null = (Set-MpPreference -SubmitSamplesConsent AlwaysPrompt -Force -ErrorAction Continue)
|
||||
#endregion SubmitSamplesConsent
|
||||
|
||||
#region MAPSReporting MAPSReporting
|
||||
Write-Verbose -Message 'Membership in Microsoft Active Protection Service Enable'
|
||||
$null = (Set-MpPreference -MAPSReporting Advanced -Force -ErrorAction Continue)
|
||||
#endregion MAPSReporting MAPSReporting
|
||||
|
||||
#region ThrottleLimit
|
||||
Write-Verbose -Message 'Specifies the maximum number of concurrent operations that can be established to run the cmdlet'
|
||||
$null = (Set-MpPreference -ThrottleLimit 0 -Force -ErrorAction Continue)
|
||||
#endregion ThrottleLimit
|
||||
|
||||
#region UILockdown
|
||||
Write-Verbose -Message 'Indicates whether to disable UI lock down mode'
|
||||
$null = (Set-MpPreference -UILockdown $false -Force -ErrorAction Continue)
|
||||
#endregion UILockdown
|
||||
|
||||
#region UnknownThreatDefaultAction
|
||||
Write-Verbose -Message 'Specifies which automatic remediation action to take for an unknown level threat'
|
||||
$null = (Set-MpPreference -UnknownThreatDefaultAction Block -Force -ErrorAction Continue)
|
||||
#endregion UnknownThreatDefaultAction
|
||||
|
||||
#region SignatureFallbackOrder
|
||||
Write-Verbose -Message 'Specifies the order in which to contact different definition update sources.'
|
||||
$null = (Set-MpPreference -SignatureFallbackOrder 'MicrosoftUpdateServer | MMPC' -Force -ErrorAction Continue)
|
||||
#endregion SignatureFallbackOrder
|
||||
|
||||
#region ControlledFolderAccessAllowedApplications
|
||||
Write-Verbose -Message 'Setup the Controlled Folder Access Allowed Applications'
|
||||
|
||||
# Define a list of Applications to exclude - Fully Qualified
|
||||
<#
|
||||
I like to keep this list as short as possible
|
||||
#>
|
||||
$NewControlledFolderAccessAllowedApplications = @(
|
||||
"$env:windir\System32\taskhostw.exe"
|
||||
)
|
||||
|
||||
# Create a new Object
|
||||
$AllControlledFolderAccessAllowedApplications = (New-Object -TypeName System.Collections.Generic.List[System.Object])
|
||||
|
||||
# Get the existing exclusions
|
||||
$AllControlledFolderAccessAllowedApplications.Add((Get-MpPreference -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ControlledFolderAccessAllowedApplications))
|
||||
|
||||
#region NewControlledFolderAccessAllowedApplicationsLoop
|
||||
foreach ($NewControlledFolderAccessAllowedApplication in $NewControlledFolderAccessAllowedApplications)
|
||||
{
|
||||
if ($AllControlledFolderAccessAllowedApplications -notcontains $NewControlledFolderAccessAllowedApplication)
|
||||
{
|
||||
Write-Verbose -Message ('Add ' + $NewControlledFolderAccessAllowedApplication + ' to the Controlled Folder Access Allowed Applications list')
|
||||
|
||||
$AllControlledFolderAccessAllowedApplications.Add($NewControlledFolderAccessAllowedApplication)
|
||||
}
|
||||
}
|
||||
#endregion NewControlledFolderAccessAllowedApplicationsLoop
|
||||
|
||||
# Make sure we have nothing doubled
|
||||
$AllControlledFolderAccessAllowedApplications = ($AllControlledFolderAccessAllowedApplications | Sort-Object -Unique)
|
||||
|
||||
# Apply the new exclusion list. This will replace the complete list.
|
||||
Write-Verbose -Message 'Apply the new Controlled Folder Access Allowed Applications list'
|
||||
|
||||
$null = (Set-MpPreference -ControlledFolderAccessAllowedApplications $AllControlledFolderAccessAllowedApplications -Force -ErrorAction Continue)
|
||||
#endregion ControlledFolderAccessAllowedApplications
|
||||
|
||||
#region ExclusionPath
|
||||
# Define a list of Applications to exclude - Fully Qualified
|
||||
$NewExclusionPathList = @(
|
||||
"$env:windir\SoftwareDistribution\DataStore\Datastore.edb",
|
||||
"$env:windir\SoftwareDistribution\DataStore\Logs\Edb*.jrs",
|
||||
"$env:windir\SoftwareDistribution\DataStore\Logs\Edb.chk",
|
||||
"$env:windir\SoftwareDistribution\DataStore\Logs\Tmp.edb",
|
||||
"$env:windir\Security\Database\*.edb",
|
||||
"$env:windir\Security\Database\*.sdb",
|
||||
"$env:windir\Security\Database\*.log",
|
||||
"$env:windir\Security\Database\*.chk",
|
||||
"$env:windir\Security\Database\*.jrs",
|
||||
"$env:windir\Security\Database\*.xml",
|
||||
"$env:windir\Security\Database\*.csv",
|
||||
"$env:windir\Security\Database\*.cmtx",
|
||||
"$env:ProgramData\ntuser.pol",
|
||||
"$env:windir\System32\GroupPolicy\Machine\Registry.pol",
|
||||
"$env:windir\System32\GroupPolicy\Machine\Registry.tmp",
|
||||
"$env:windir\System32\GroupPolicy\User\Registry.pol",
|
||||
"$env:windir\System32\GroupPolicy\User\Registry.tmp"
|
||||
)
|
||||
|
||||
# Create a new Object
|
||||
$AllExclusionPath = (New-Object -TypeName System.Collections.Generic.List[System.Object])
|
||||
|
||||
# Get the existing exclusions
|
||||
$AllExclusionPath.Add((Get-MpPreference -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ExclusionPath))
|
||||
|
||||
#region NewExclusionPathLoop
|
||||
foreach ($NewExclusionPath in $NewExclusionPathList)
|
||||
{
|
||||
if ($AllExclusionPath -notcontains $NewExclusionPath)
|
||||
{
|
||||
Write-Verbose -Message ('Add ' + $NewExclusionPath + ' as path to exclude')
|
||||
|
||||
$AllExclusionPath.Add($NewExclusionPath)
|
||||
}
|
||||
}
|
||||
#endregion NewExclusionPathLoop
|
||||
|
||||
# Make sure we have nothing doubled
|
||||
$AllExclusionPath = ($AllExclusionPath | Sort-Object -Unique)
|
||||
|
||||
# Apply the new exclusion list. This will replace the complete list.
|
||||
Write-Verbose -Message 'Apply the new Path to exclude list'
|
||||
|
||||
$null = (Set-MpPreference -ExclusionPath $AllExclusionPath -Force -ErrorAction Continue)
|
||||
#endregion ExclusionPath
|
||||
|
||||
#region ExclusionProcess
|
||||
# Define a list of Applications to exclude - Fully Qualified
|
||||
$NewExclusionProcessList = @(
|
||||
"$env:windir\System32\svchost.exe",
|
||||
"$env:windir\System32\wuauclt.exe"
|
||||
)
|
||||
|
||||
# Create a new Object
|
||||
$AllExclusionProcess = (New-Object -TypeName System.Collections.Generic.List[System.Object])
|
||||
|
||||
# Get the existing exclusions
|
||||
$AllExclusionProcess.Add((Get-MpPreference -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ExclusionProcess))
|
||||
|
||||
#region NewExclusionProcessLoop
|
||||
foreach ($NewExclusionProcess in $NewExclusionProcessList)
|
||||
{
|
||||
if ($AllExclusionProcess -notcontains $NewExclusionProcess)
|
||||
{
|
||||
Write-Verbose -Message ('Add ' + $NewExclusionProcess + ' as process to exclude')
|
||||
|
||||
$AllExclusionProcess.Add($NewExclusionProcess)
|
||||
}
|
||||
}
|
||||
#endregion NewExclusionProcessLoop
|
||||
|
||||
# Make sure we have nothing doubled
|
||||
$AllExclusionProcess = ($AllExclusionProcess | Sort-Object -Unique)
|
||||
|
||||
# Apply the new exclusion list. This will replace the complete list.
|
||||
Write-Verbose -Message 'Apply the new Process to exclude list'
|
||||
|
||||
$null = (Set-MpPreference -ExclusionProcess $AllExclusionProcess -Force -ErrorAction Continue)
|
||||
#endregion ExclusionProcess
|
||||
#endregion SetMpPreference
|
||||
|
||||
#region ProcessMitigation
|
||||
# Local Process Mitigation file
|
||||
$ProcessMitigationFile = '.\ProcessMitigation.xml'
|
||||
|
||||
# Check if we have a local Process Mitigation file
|
||||
if (-not (Test-Path -Path $ProcessMitigationFile -ErrorAction SilentlyContinue))
|
||||
{
|
||||
# Where to download the XML File?
|
||||
$ProcessMitigationUri = 'https://demo.wd.microsoft.com/Content/ProcessMitigation.xml'
|
||||
|
||||
Write-Verbose -Message ('Downloading Process Mitigation file from ' + $ProcessMitigationUri)
|
||||
|
||||
# Download
|
||||
$paramInvokeWebRequest = @{
|
||||
Uri = $ProcessMitigationUri
|
||||
OutFile = $ProcessMitigationFile
|
||||
Method = 'Get'
|
||||
ContentType = 'text/xml'
|
||||
ErrorAction = 'Continue'
|
||||
}
|
||||
$null = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
|
||||
if (Test-Path -Path $ProcessMitigationFile -ErrorAction SilentlyContinue)
|
||||
{
|
||||
Write-Verbose -Message 'Enabling Exploit Protection'
|
||||
|
||||
# Apply the File
|
||||
$null = (Set-ProcessMitigation -PolicyFilePath $ProcessMitigationFile -ErrorAction Continue)
|
||||
|
||||
# Cleanup
|
||||
$paramRemoveItem = @{
|
||||
Path = $ProcessMitigationFile
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Continue'
|
||||
}
|
||||
$null = (Remove-Item @paramRemoveItem)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('The local Process Mitigation file (' + $ProcessMitigationFile + ') is missing! Not enabling Exploit Protection.')
|
||||
}
|
||||
#endregion ProcessMitigation
|
||||
|
||||
#region WindowsDefenderSandbox
|
||||
Write-Verbose -Message 'Turn on Windows Defender Sandbox'
|
||||
$null = ([Environment]::SetEnvironmentVariable('MP_FORCE_USE_SANDBOX', 1, 'Machine'))
|
||||
#endregion WindowsDefenderSandbox
|
||||
|
||||
#region AttackSurfaceReduction
|
||||
#region GetAttackSurfaceReductionRulesIds
|
||||
$AttackSurfaceReductionRulesIds = (Get-MpPreference -ErrorAction SilentlyContinue | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids)
|
||||
#endregion GetAttackSurfaceReductionRulesIds
|
||||
|
||||
Write-Verbose -Message 'Enabling Attack Surface Reduction rules'
|
||||
|
||||
#region SetMpPreferenceDefaults
|
||||
$AddMpPreferenceParameters = @{
|
||||
ErrorAction = 'Stop'
|
||||
Force = $true
|
||||
}
|
||||
#endregion SetMpPreferenceDefaults
|
||||
|
||||
#region RuleLoop
|
||||
foreach ($AttackSurfaceReductionRule in $AttackSurfaceReductionRuleList)
|
||||
{
|
||||
#region SingleLoop
|
||||
try
|
||||
{
|
||||
if (($Force) -or ($AttackSurfaceReductionRulesIds -notcontains $AttackSurfaceReductionRule.RuleID))
|
||||
{
|
||||
#region AppleTheRuleValue
|
||||
Write-Verbose -Message ('Set ' + $AttackSurfaceReductionRule.RuleDescription + ' to ' + $AttackSurfaceReductionRule.RuleAction)
|
||||
|
||||
# Add some values
|
||||
$AddMpPreferenceParameters.AttackSurfaceReductionRules_Ids = $AttackSurfaceReductionRule.RuleID
|
||||
$AddMpPreferenceParameters.AttackSurfaceReductionRules_Actions = $AttackSurfaceReductionRule.RuleAction
|
||||
|
||||
# Apply the Rule
|
||||
$null = (Add-MpPreference @AddMpPreferenceParameters)
|
||||
#endregion AppleTheRuleValue
|
||||
}
|
||||
}
|
||||
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-Warning -Message ('Unable to enable to Rule: ' + $AttackSurfaceReductionRule.RuleID + ' (' + $AttackSurfaceReductionRule.RuleDescription + ')')
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
#endregion SingleLoop
|
||||
}
|
||||
#endregion RuleLoop
|
||||
#endregion AttackSurfaceReduction
|
||||
|
||||
#region ReloadRegistry
|
||||
& "$env:windir\system32\rundll32.exe" USER32.DLL, UpdatePerUserSystemParameters , 1 , True
|
||||
#endregion ReloadRegistry
|
||||
|
||||
#region EnableFirewall
|
||||
Write-Verbose -Message 'Enable the Windows Firewall for all Profiles - Set the default to block everything'
|
||||
$null = (Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled True -DefaultInboundAction Block -LogBlocked True -Confirm:$false -ErrorAction Continue)
|
||||
#endregion EnableFirewall
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region UpdateSignature
|
||||
Write-Verbose -Message 'Update Defender'
|
||||
$null = (Update-MpSignature)
|
||||
#endregion UpdateSignature
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -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.
|
||||
@@ -0,0 +1,476 @@
|
||||
# Bootstrap Microsoft Defender configuration
|
||||
|
||||
Bootstrap Microsoft Defender configuration, optimize and tweak Windows 10 protection and security
|
||||
|
||||
## What it does
|
||||
|
||||
Several Microsoft Defender settings are configured.
|
||||
|
||||
### EnableNetworkProtection
|
||||
|
||||
Network protection helps to prevent employees from using any application to access dangerous domains that may host phishing scams, exploits, and other malicious content on the Internet
|
||||
|
||||
Set to: `Enabled`
|
||||
|
||||
### EnableControlledFolderAccess
|
||||
|
||||
Controlled folder access helps you protect valuable data from malicious apps and threats, such as ransomware
|
||||
|
||||
Set to: `Enabled`
|
||||
|
||||
### SignatureScheduleDay
|
||||
|
||||
Specifies the day of the week on which to check for definition updates.
|
||||
|
||||
Set to: `Everyday`
|
||||
|
||||
### SignatureScheduleTime
|
||||
|
||||
Specifies the time of day, as the number of minutes after midnight, to check for definition updates
|
||||
|
||||
Set to: `320`
|
||||
|
||||
### DisableArchiveScanning
|
||||
|
||||
Indicates whether to scan archive files for malicious and unwanted software
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableAutoExclusions
|
||||
|
||||
Indicates whether to disable the Automatic Exclusions feature for the server
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### DisableBehaviorMonitoring
|
||||
|
||||
Indicates whether to enable behavior monitoring
|
||||
|
||||
Set to: `true`
|
||||
|
||||
Something I enable on a few systems only.
|
||||
|
||||
### DisableBlockAtFirstSeen
|
||||
|
||||
Indicates whether to enable block at first seen
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableCatchupFullScan
|
||||
|
||||
Indicates whether Windows Defender runs catch-up scans for scheduled full scans
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableCatchupQuickScan
|
||||
|
||||
Indicates whether Windows Defender runs catch-up scans for scheduled quick scans
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableEmailScanning
|
||||
|
||||
Indicates whether Windows Defender parses the mailbox and mail files, according to their specific format, in order to analyze mail bodies and attachments
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### DisableIOAVProtection
|
||||
|
||||
Indicates whether Windows Defender scans all downloaded files and attachments (e.g. Downloads)
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableIntrusionPreventionSystem
|
||||
|
||||
Indicates whether to configure network protection against exploitation of known vulnerabilities
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### DisablePrivacyMode
|
||||
|
||||
Indicates whether to disable privacy mode. Privacy mode prevents users, other than administrators, from displaying threat history
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### DisableRealtimeMonitoring
|
||||
|
||||
Indicates whether to use real-time protection
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### CheckForSignaturesBeforeRunningScan
|
||||
|
||||
Set to: `1`
|
||||
|
||||
### DisableRemovableDriveScanning
|
||||
|
||||
Indicates whether to scan for malicious and unwanted software in removable drives, such as flash drives, during a full scan
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableRestorePoint
|
||||
|
||||
Indicates whether to disable scanning of restore points
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableScanningMappedNetworkDrivesForFullScan
|
||||
|
||||
Indicates whether to scan mapped network drives
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### DisableScanningNetworkFiles
|
||||
|
||||
Indicates whether to scan for network files
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### DisableScriptScanning
|
||||
|
||||
Specifies whether to disable the scanning of scripts during malware scans
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### HighThreatDefaultAction
|
||||
|
||||
Specifies which automatic remediation action to take for a high level threat
|
||||
|
||||
Set to: `Quarantine`
|
||||
|
||||
### LowThreatDefaultAction
|
||||
|
||||
Specifies which automatic remediation action to take for a low level threat
|
||||
|
||||
Set to: `Block`
|
||||
|
||||
### ModerateThreatDefaultAction
|
||||
|
||||
Specifies which automatic remediation action to take for a moderate level threat
|
||||
|
||||
Set to: `Quarantine`
|
||||
|
||||
### PUAProtection
|
||||
|
||||
Disable PUA Protection
|
||||
|
||||
Set to: `Enabled`
|
||||
|
||||
### QuarantinePurgeItemsAfterDelay
|
||||
|
||||
Specifies the number of days to keep items in the Quarantine folder
|
||||
|
||||
Set to: `30`
|
||||
|
||||
### RandomizeScheduleTaskTimes
|
||||
|
||||
Indicates whether to select a random time for the scheduled start and scheduled update for definitions
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### RealTimeScanDirection
|
||||
|
||||
Specifies scanning configuration for incoming and outgoing files on NTFS volumes
|
||||
|
||||
Set to: `0`
|
||||
|
||||
### RemediationScheduleDay
|
||||
|
||||
Specifies the day of the week on which to perform a scheduled full scan in order to complete remediation
|
||||
|
||||
Set to: `Everyday`
|
||||
|
||||
### RemediationScheduleTime
|
||||
|
||||
Specifies the time of day, as the number of minutes after midnight, to perform a scheduled scan
|
||||
|
||||
Set to: `120`
|
||||
|
||||
### ReportingAdditionalActionTimeOut
|
||||
|
||||
Specifies the number of minutes before a detection in the additional action state changes to the cleared state
|
||||
|
||||
Set to: `10080`
|
||||
|
||||
### ReportingCriticalFailureTimeOut
|
||||
|
||||
Specifies the number of minutes before a detection in the critically failed state changes to either the additional action state or the cleared state
|
||||
|
||||
Set to: `10080`
|
||||
|
||||
### ReportingNonCriticalTimeOut
|
||||
|
||||
Specifies the number of minutes before a detection in the non-critically failed state changes to the cleared state
|
||||
|
||||
Set to: `11440`
|
||||
|
||||
### ScanAvgCPULoadFactor
|
||||
|
||||
Specifies the maximum percentage CPU usage for a scan
|
||||
|
||||
Set to: `50`
|
||||
|
||||
### ScanOnlyIfIdleEnabled
|
||||
|
||||
Indicates whether to start scheduled scans only when the computer is not in use
|
||||
|
||||
Set to: `true`
|
||||
|
||||
### ScanParameters
|
||||
|
||||
Specifies the scan type to use during a scheduled scan
|
||||
|
||||
Set to: `1`
|
||||
|
||||
### ScanPurgeItemsAfterDelay
|
||||
|
||||
Specifies the number of days to keep items in the scan history folder
|
||||
|
||||
Set to: `15`
|
||||
|
||||
### ScanScheduleDay
|
||||
|
||||
Specifies the day of the week on which to perform a scheduled scan
|
||||
|
||||
Set to: `Everyday`
|
||||
|
||||
### ScanScheduleQuickScanTime
|
||||
|
||||
Specifies the time of day, as the number of minutes after midnight, to perform a scheduled quick scan
|
||||
|
||||
Set to: `0`
|
||||
|
||||
### ScanScheduleTime
|
||||
|
||||
Specifies the time of day, as the number of minutes after midnight, to perform a scheduled scan
|
||||
|
||||
Set to: `120`
|
||||
|
||||
### SevereThreatDefaultAction
|
||||
|
||||
Specifies which automatic remediation action to take for a severe level threat
|
||||
|
||||
Set to: `Quarantine`
|
||||
|
||||
### SignatureAuGracePeriod
|
||||
|
||||
Specifies a grace period, in minutes, for the definition
|
||||
|
||||
Set to: `0`
|
||||
|
||||
### SignatureDisableUpdateOnStartupWithoutEngine
|
||||
|
||||
Indicates whether to initiate definition updates even if no antimalware engine is present
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### SignatureFirstAuGracePeriod
|
||||
|
||||
Specifies a grace period, in minutes, for the definition. If a definition successfully updates within this period, Windows Defender abandons any service initiated updates
|
||||
|
||||
Set to: `120`
|
||||
|
||||
### SignatureScheduleDay
|
||||
|
||||
Specifies the day of the week on which to check for definition updates
|
||||
|
||||
Set to: `Everyday`
|
||||
|
||||
### SignatureScheduleTime
|
||||
|
||||
Specifies the time of day, as the number of minutes after midnight, to check for definition updates
|
||||
|
||||
Set to: `165`
|
||||
|
||||
### SignatureUpdateCatchupInterval
|
||||
|
||||
Specifies the number of days after which Windows Defender requires a catch-up definition update
|
||||
|
||||
Set to: `1`
|
||||
|
||||
### SignatureUpdateInterval
|
||||
|
||||
Specifies the interval, in hours, at which to check for definition updates
|
||||
|
||||
Set to: `12`
|
||||
|
||||
### SubmitSamplesConsent
|
||||
|
||||
Specifies how Windows Defender checks for user consent for certain samples
|
||||
|
||||
Set to: `AlwaysPrompt`
|
||||
|
||||
### MAPSReporting
|
||||
|
||||
Membership in Microsoft Active Protection Service Enable
|
||||
|
||||
Set to: `Advanced`
|
||||
|
||||
### ThrottleLimit
|
||||
|
||||
Specifies the maximum number of concurrent operations that can be established to run the cmdlet
|
||||
|
||||
Set to: `0`
|
||||
|
||||
### UILockdown
|
||||
|
||||
Indicates whether to disable UI lock down mode
|
||||
|
||||
Set to: `false`
|
||||
|
||||
### UnknownThreatDefaultAction
|
||||
|
||||
Specifies which automatic remediation action to take for an unknown level threat
|
||||
|
||||
Set to: `Block`
|
||||
|
||||
### SignatureFallbackOrder
|
||||
|
||||
Specifies the order in which to contact different definition update sources. Specify the types of update sources in the order in which you want Windows Defender to contact them, enclosed in braces and separated by the pipeline symbol
|
||||
|
||||
Set to: `MicrosoftUpdateServer | MMPC`
|
||||
|
||||
### ControlledFolderAccessAllowedApplications
|
||||
|
||||
We exclude the following Files by default: `$env:windir\System32\taskhostw.exe`
|
||||
|
||||
Any exclusions previously configured stay intact!
|
||||
|
||||
### ExclusionPath
|
||||
|
||||
The following Files/Folders are excluded from the scan:
|
||||
|
||||
`windir\SoftwareDistribution\DataStore\Datastore.edb`
|
||||
`windir\SoftwareDistribution\DataStore\Logs\Edb*.jrs`
|
||||
`windir\SoftwareDistribution\DataStore\Logs\Edb.chk`
|
||||
`windir\SoftwareDistribution\DataStore\Logs\Tmp.edb`
|
||||
`windir\Security\Database\*.edb`
|
||||
`windir\Security\Database\*.sdb`
|
||||
`windir\Security\Database\*.log`
|
||||
`windir\Security\Database\*.chk`
|
||||
`windir\Security\Database\*.jrs`
|
||||
`windir\Security\Database\*.xml`
|
||||
`windir\Security\Database\*.csv`
|
||||
`windir\Security\Database\*.cmtx`
|
||||
`ProgramData\ntuser.pol`
|
||||
`windir\System32\GroupPolicy\Machine\Registry.pol`
|
||||
`windir\System32\GroupPolicy\Machine\Registry.tmp`
|
||||
`windir\System32\GroupPolicy\User\Registry.pol`
|
||||
`windir\System32\GroupPolicy\User\Registry.tmp`
|
||||
|
||||
Any exclusions previously configured stay intact!
|
||||
|
||||
More Info: [https://support.microsoft.com/en-us/help/822158/virus-scanning-recommendations-for-enterprise-computers-that-are-runni](https://support.microsoft.com/en-us/help/822158/virus-scanning-recommendations-for-enterprise-computers-that-are-runni)
|
||||
|
||||
### ExclusionProcess
|
||||
|
||||
The following processes are excluded from the scan:
|
||||
|
||||
`$env:windir\System32\svchost.exe`
|
||||
`$env:windir\System32\wuauclt.exe`
|
||||
|
||||
Any exclusions previously configured stay intact!
|
||||
|
||||
More Info: [https://support.microsoft.com/en-us/help/822158/virus-scanning-recommendations-for-enterprise-computers-that-are-runni](https://support.microsoft.com/en-us/help/822158/virus-scanning-recommendations-for-enterprise-computers-that-are-runni)
|
||||
|
||||
### Process Mitigation and Exploit Protection
|
||||
|
||||
Microsoft provides a XML file (`ProcessMitigation.xml`) that provides a configuration best practice to mitigate the attack surface and provide Exploit Protection.
|
||||
|
||||
You can provide your own File, otherwise (if missing) we will download the latest version from Microsoft.
|
||||
|
||||
More Info: [https://demo.wd.microsoft.com/Page/EP](https://demo.wd.microsoft.com/Page/EP)
|
||||
|
||||
### WindowsDefenderSandbox
|
||||
|
||||
We tuen on Windows Defender Sandbox
|
||||
|
||||
### AttackSurfaceReduction
|
||||
|
||||
Attack Surface Reduction (ASR) is comprised of a number of rules, each of which target specific behaviors that are typically used by malware and malicious apps to infect machines, such as:
|
||||
|
||||
- Executable files and scripts used in Office apps or web mail that attempt to download or run files
|
||||
- Scripts that are obfuscated or otherwise suspicious
|
||||
- Behaviors that apps undertake that are not usually initiated during normal day-to-day work
|
||||
|
||||
More Info: [https://demo.wd.microsoft.com/Page/ASR](https://demo.wd.microsoft.com/Page/ASR)
|
||||
|
||||
### ReloadRegistry
|
||||
|
||||
We then reload the registry to ensure that the new configuration is activated
|
||||
|
||||
### EnableFirewall
|
||||
|
||||
Enable the Windows Firewall for all Profiles - Set the default to block everything
|
||||
|
||||
We enable the Windows Firewall for the following Network-Profiles:
|
||||
|
||||
- Domain
|
||||
- Public
|
||||
- Private
|
||||
|
||||
We block all inbound connections by default and we log all block-events!
|
||||
|
||||
### UpdateSignature
|
||||
|
||||
As a final touch: We update the Windows Defender signatures.
|
||||
|
||||
## Why this?
|
||||
|
||||
I use this during the bootstrap process of Windows systems.
|
||||
Most of the settings here is also enforced by some of our Group Policies and we also have a lot of it configured via MDM CSPs (InTune).
|
||||
|
||||
This script is only a quick hack to harden (and secure) any new system, even if it is not managed afterwords.
|
||||
|
||||
## Content
|
||||
|
||||
There are two files:
|
||||
|
||||
### Bootstrap-MicrosoftDefenderConfiguration.ps1
|
||||
|
||||
The PowerShell Script itself
|
||||
|
||||
### Bootstrap-MicrosoftDefenderConfiguration.csv
|
||||
|
||||
A CSV File that contains the configuration of the attack surface reduction rules.
|
||||
|
||||
## Configuration
|
||||
|
||||
Please review the `Bootstrap-MicrosoftDefenderConfiguration.csv` where you configure the attack surface reduction rules. Please also review the `Bootstrap-MicrosoftDefenderConfiguration.ps1` file. There is no configuration file, at least not yet!
|
||||
|
||||
## Further Information
|
||||
|
||||
[https://docs.microsoft.com/en-us/powershell/module/defender/index?view=win10-ps](https://docs.microsoft.com/en-us/powershell/module/defender/index?view=win10-ps)
|
||||
|
||||
[https://github.com/jhochwald/PowerShell-collection/blob/master/Misc/Optimize-MicrosoftDefenderExclusions.ps1](https://github.com/jhochwald/PowerShell-collection/blob/master/Misc/Optimize-MicrosoftDefenderExclusions.ps1)
|
||||
|
||||
[https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/enable-exploit-protection](https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/enable-exploit-protection
|
||||
)
|
||||
|
||||
[https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=win10-ps](https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=win10-ps)
|
||||
|
||||
[https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/customize-attack-surface-reduction](https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=win10-ps)
|
||||
|
||||
[https://support.microsoft.com/en-us/help/822158/virus-scanning-recommendations-for-enterprise-computers-that-are-runni](https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=win10-ps)
|
||||
|
||||
[https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-antivirus/enable-cloud-protection-windows-defender-antivirus](https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=win10-ps)
|
||||
|
||||
[https://demo.wd.microsoft.com/?ocid=cx-wddocs-testground](https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=win10-ps)
|
||||
|
||||
## License
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020, Joerg Hochwald
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
158
Powershell/PowerShell-collection/Misc/Check-ServiceMonitor.ps1
Normal file
158
Powershell/PowerShell-collection/Misc/Check-ServiceMonitor.ps1
Normal file
@@ -0,0 +1,158 @@
|
||||
#requires -Version 3.0 -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Quick an dirty Windows Service Monitor
|
||||
|
||||
.DESCRIPTION
|
||||
I came across the the problem, that one of the services I depend one was not started after the system reboots.
|
||||
That happens after a .NET update. So I decided to create this real simple monitor to make sure, that this service is running.
|
||||
If not, the script tries to restart it.
|
||||
|
||||
.PARAMETER MonService
|
||||
The Service we would like to check. Default is RoyalServer
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Check-ServiceMonitor.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Check-ServiceMonitor.ps1 -MonService 'myservice'
|
||||
|
||||
.NOTES
|
||||
The script itself have some basic error handling,
|
||||
nothing to complex or fancy.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
Position = 1)]
|
||||
[Alias('ServiceToMonitor')]
|
||||
[string]
|
||||
$MonService = 'RoyalServer'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
[string]$SC = 'SilentlyContinue'
|
||||
[string]$STP = 'Stop'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the Status
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Get the Status of {0}' -f $MonService)
|
||||
|
||||
$paramGetService = @{
|
||||
Name = $MonService
|
||||
ErrorAction = $STP
|
||||
WarningAction = $SC
|
||||
}
|
||||
|
||||
[string]$MonServiceStatus = ((Get-Service @paramGetService).Status)
|
||||
|
||||
Write-Verbose -Message ('We have the Status of {0}' -f $MonService)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Error -Message ('Looks like the Service {0} is not installed!' -f $MonService) -ErrorAction $STP
|
||||
|
||||
# Point of no return (Should never be reached)
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
# Do the check
|
||||
if ($MonServiceStatus -ne 'Running')
|
||||
{
|
||||
Write-Warning -Message ('Sorry, but {0} is not running ' -f $MonService)
|
||||
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Try to restart {0}' -f $MonService)
|
||||
|
||||
$MonParam = @{
|
||||
Name = $MonService
|
||||
Confirm = $false
|
||||
ErrorAction = $STP
|
||||
WarningAction = $SC
|
||||
}
|
||||
|
||||
$null = (Restart-Service @MonParam)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Whooooops! Try it again... Let us try to stop the services
|
||||
|
||||
Write-Verbose -Message ('Try to stop {0}' -f $MonService)
|
||||
$null = (Stop-Service @MonParam)
|
||||
|
||||
# Wait a second
|
||||
$null = (Start-Sleep -Seconds 1)
|
||||
|
||||
# Try to stop it again...
|
||||
$null = (Stop-Service @MonParam)
|
||||
|
||||
# Wait a second
|
||||
$null = (Start-Sleep -Seconds 1)
|
||||
|
||||
# Try to kill it, again!
|
||||
$null = (Stop-Service @MonParam)
|
||||
|
||||
# Wait two seconds to cool down
|
||||
Write-Verbose -Message ('Try to start {0}' -f $MonService)
|
||||
|
||||
$null = (Start-Sleep -Seconds 2)
|
||||
|
||||
try
|
||||
{
|
||||
# Now let us try to start the service
|
||||
Write-Verbose -Message ('Try to start {0} again!' -f $MonService)
|
||||
|
||||
$null = (Start-Service @MonParam)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Dude, this is bad! And I mean real bad!!!
|
||||
Write-Error -Message ('We where not able to start {0} - Might be a good idea to reboot this system' -f $MonService)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Looks good so far
|
||||
Write-Verbose -Message ('Looks like {0} is doing great...' -f $MonService)
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,84 @@
|
||||
function Clear-EnAllEventLogs
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
AllEventLlogs
|
||||
|
||||
.DESCRIPTION
|
||||
AllEventLlogs
|
||||
|
||||
.PARAMETER ComputerName
|
||||
Computer Name
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogs
|
||||
|
||||
.NOTES
|
||||
N.N.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[string[]]
|
||||
$ComputerName = "$env:COMPUTERNAME"
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
|
||||
foreach ($SingleComputerName in $ComputerName)
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($SingleComputerName, 'Cleanup All EventLogs'))
|
||||
{
|
||||
$paramGetEventLog = @{
|
||||
ComputerName = $SingleComputerName
|
||||
List = $true
|
||||
}
|
||||
$null = (Get-EventLog @paramGetEventLog | ForEach-Object -Process {
|
||||
if ($_.Entries)
|
||||
{
|
||||
$paramClearEventLog = @{
|
||||
LogName = $_.Log
|
||||
Confirm = $false
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Clear-EventLog @paramClearEventLog)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,373 @@
|
||||
#requires -Version 4.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Compare a old and a refactored function to get any Performace differences
|
||||
|
||||
.DESCRIPTION
|
||||
This script compares a simple function (That deletes all Windows Eventlog Entries) with an refacored one.
|
||||
The request came up during a workshop: I was asked why I use pipes so much and if there is another way, without pipes.
|
||||
|
||||
The refactored version was created during the workshop as a prototype.
|
||||
And to make it easier to compare them, I created this test script.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-EnAllEventLogs_TESTS.ps1
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.0 2019-07-24 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:
|
||||
NONE
|
||||
|
||||
.LINK
|
||||
https://www.enatec.io
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param ()
|
||||
|
||||
#region VersionOfJosh
|
||||
function Clear-EnAllEventLogs
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Delete all Windows event log entries
|
||||
|
||||
.DESCRIPTION
|
||||
Delete all Windows event log entries, without any further interaction.
|
||||
I use this only after I do some tests on a virtual machine.
|
||||
|
||||
Please Note:
|
||||
It Might be dangerous! It might delete more than you like.
|
||||
|
||||
Warning:
|
||||
All security related will also be removed completely.
|
||||
If there were any issues, you might never find any information about it!
|
||||
|
||||
.PARAMETER ComputerName
|
||||
Computer Name as String. Multi Value is possible
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogs
|
||||
|
||||
Delete all Windows EventLog Entries on the local Computer.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogs -ComputerName FRADC01
|
||||
|
||||
Delete all Windows EventLog Entries on the Computer with the name FRADC01.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogs -ComputerName 'FRADC01', 'FRADC02'
|
||||
|
||||
Delete all Windows EventLog Entries on the Computers with the names FRADC01 and FRADC02.
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
|
||||
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:
|
||||
TNONE
|
||||
|
||||
.LINK
|
||||
https://www.enatec.io
|
||||
|
||||
.LINK
|
||||
about_foreach
|
||||
|
||||
.LINK
|
||||
Foreach-Object
|
||||
|
||||
.LINK
|
||||
Get-EventLog
|
||||
|
||||
.LINK
|
||||
Clear-EventLog
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[string[]]
|
||||
$ComputerName = "$env:COMPUTERNAME"
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
|
||||
foreach ($SingleComputerName in $ComputerName)
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($SingleComputerName, 'Cleanup All EventLogs'))
|
||||
{
|
||||
$paramGetEventLog = @{
|
||||
ComputerName = $SingleComputerName
|
||||
List = $true
|
||||
}
|
||||
$null = (Get-EventLog @paramGetEventLog | ForEach-Object -Process {
|
||||
if ($_.Entries)
|
||||
{
|
||||
$paramClearEventLog = @{
|
||||
LogName = $_.Log
|
||||
Confirm = $false
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Clear-EventLog @paramClearEventLog)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion VersionOfJosh
|
||||
|
||||
#region RefactoredVersion
|
||||
function Clear-EnAllEventLogsv2
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Delete all Windows event log entries
|
||||
|
||||
.DESCRIPTION
|
||||
Delete all Windows event log entries, without any further interaction.
|
||||
I use this only after I do some tests on a virtual machine.
|
||||
|
||||
Please Note:
|
||||
It Might be dangerous! It might delete more than you like.
|
||||
|
||||
Warning:
|
||||
All security related will also be removed completely.
|
||||
If there were any issues, you might never find any information about it!
|
||||
|
||||
.PARAMETER ComputerName
|
||||
Computer Name as String. Multi Value is possible
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogsv2
|
||||
|
||||
Delete all Windows EventLog Entries on the local Computer.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogsv2 -ComputerName FRADC01
|
||||
|
||||
Delete all Windows EventLog Entries on the Computer with the name FRADC01.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogsv2 -ComputerName 'FRADC01', 'FRADC02'
|
||||
|
||||
Delete all Windows EventLog Entries on the Computers with the names FRADC01 and FRADC02.
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
2.0.0 2019-07-23: Refactored 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:
|
||||
NONE
|
||||
|
||||
.LINK
|
||||
https://www.enatec.io
|
||||
|
||||
.LINK
|
||||
about_foreach
|
||||
|
||||
.LINK
|
||||
Foreach-Object
|
||||
|
||||
.LINK
|
||||
Get-EventLog
|
||||
|
||||
.LINK
|
||||
Clear-EventLog
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[string[]]
|
||||
$ComputerName = "$env:COMPUTERNAME"
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
|
||||
foreach ($SingleComputerName in $ComputerName)
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($SingleComputerName, 'Cleanup All EventLogs'))
|
||||
{
|
||||
$paramGetEventLog = @{
|
||||
ComputerName = $SingleComputerName
|
||||
List = $true
|
||||
}
|
||||
$null = ((Get-EventLog @paramGetEventLog).Where( {
|
||||
if ($_.Entries)
|
||||
{
|
||||
$_
|
||||
}
|
||||
}).ForEach( {
|
||||
$paramClearEventLog = @{
|
||||
LogName = $_.Log
|
||||
Confirm = $false
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Clear-EventLog @paramClearEventLog)
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion RefactoredVersion
|
||||
|
||||
#region CreateTestData
|
||||
function Invoke-CreateTestData
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create 10.000 dummy entries
|
||||
|
||||
.DESCRIPTION
|
||||
Create 10.000 dummy entries
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-CreateTestData
|
||||
|
||||
.NOTES
|
||||
Internal Helper Function to create some useless Test Data
|
||||
|
||||
Releasenotes:
|
||||
1.0.1 2019-07-23: Splat the parameters for better radability
|
||||
1.0.0 2019-07-23: 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:
|
||||
NONE
|
||||
|
||||
.LINK
|
||||
https://www.enatec.io
|
||||
|
||||
.LINK
|
||||
Write-EventLog
|
||||
|
||||
.LINK
|
||||
about_foreach
|
||||
|
||||
.LINK
|
||||
Foreach-Object
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramWriteEventLog = @{
|
||||
LogName = 'Application'
|
||||
EventId = 2001
|
||||
EntryType = 'Information'
|
||||
Source = 'HAL9000'
|
||||
Message = 'I think you know what the problem is just as well as I do.'
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Change the number to fit your needs
|
||||
1 .. 1000 | ForEach-Object -Process {
|
||||
$null = (Write-EventLog @paramWriteEventLog)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion CreateTestData
|
||||
|
||||
# Initial Cleanup
|
||||
$null = (Clear-EnAllEventLogs -ErrorAction SilentlyContinue)
|
||||
|
||||
# Create a few new objects
|
||||
$OldWayAverage = @()
|
||||
$OldWaySum = @()
|
||||
$NewWayAverage = @()
|
||||
$NewWaySum = @()
|
||||
|
||||
# Create the new Eventlog
|
||||
$null = (New-EventLog -LogName Application -Source 'HAL9000' -ErrorAction SilentlyContinue)
|
||||
|
||||
#region OldWay
|
||||
$null = (1..10 | ForEach-Object {
|
||||
# Create some Test Data
|
||||
$null = (Invoke-CreateTestData -ErrorAction SilentlyContinue)
|
||||
|
||||
#region OldWaySingle
|
||||
$OldWaySingle = (Measure-Command -Expression {
|
||||
$null = (Clear-EnAllEventLogs -ErrorAction SilentlyContinue)
|
||||
})
|
||||
#endregion OldWaySingle
|
||||
$OldWaySum += $OldWaySingle
|
||||
})
|
||||
$OldWayAverage = (($OldWaySum | Measure-Object -Property TotalMilliseconds -Average).Average)
|
||||
#endregion OldWay
|
||||
|
||||
#region NewWay
|
||||
$null = (1..10 | ForEach-Object {
|
||||
# Create some Test Data
|
||||
$null = (Invoke-CreateTestData -ErrorAction SilentlyContinue)
|
||||
|
||||
#region NewWaySingle
|
||||
$NewWaySingle = (Measure-Command -Expression {
|
||||
$null = (Clear-EnAllEventLogsv2 -ErrorAction SilentlyContinue)
|
||||
})
|
||||
#endregion NewWaySingle
|
||||
$NewWaySum += $NewWaySingle
|
||||
})
|
||||
$NewWayAverage = (($NewWaySum | Measure-Object -Property TotalMilliseconds -Average).Average)
|
||||
#endregion NewWay
|
||||
|
||||
#Region DumpData
|
||||
Write-Verbose -Message 'Time measured in milliseconds' -Verbose
|
||||
|
||||
[pscustomobject]@{
|
||||
OldWay = $OldWayAverage
|
||||
NewWay = $NewWayAverage
|
||||
}
|
||||
#endregion DumpData
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,85 @@
|
||||
function Clear-EnAllEventLogsv2
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
AllEventLlogs
|
||||
|
||||
.DESCRIPTION
|
||||
AllEventLlogs
|
||||
|
||||
.PARAMETER ComputerName
|
||||
Computer Name
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Clear-EnAllEventLogsv2
|
||||
|
||||
.NOTES
|
||||
N.N.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[string[]]
|
||||
$ComputerName = "$env:COMPUTERNAME"
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
foreach ($SingleComputerName in $ComputerName)
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($SingleComputerName, 'Cleanup All EventLogs'))
|
||||
{
|
||||
$paramGetEventLog = @{
|
||||
ComputerName = $SingleComputerName
|
||||
List = $true
|
||||
}
|
||||
$null = ((Get-EventLog @paramGetEventLog).Where( {
|
||||
if ($_.Entries)
|
||||
{
|
||||
$_
|
||||
}
|
||||
}).ForEach( {
|
||||
$paramClearEventLog = @{
|
||||
LogName = $_.Log
|
||||
Confirm = $false
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Clear-EventLog @paramClearEventLog)
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,6 @@
|
||||
# Disable the .NET Telemetry on production servers and critical workstations
|
||||
[Environment]::SetEnvironmentVariable('DOTNET_CLI_TELEMETRY_OPTOUT', '1', 'Machine')
|
||||
[Environment]::SetEnvironmentVariable('MLDOTNET_CLI_TELEMETRY_OPTOUT', '1', 'Machine')
|
||||
|
||||
# Tweak the 1st run experience
|
||||
[Environment]::SetEnvironmentVariable('DOTNET_SKIP_FIRST_TIME_EXPERIENCE', '1', 'Machine')
|
||||
272
Powershell/PowerShell-collection/Misc/Enable-DNSOverHTTPS.ps1
Normal file
272
Powershell/PowerShell-collection/Misc/Enable-DNSOverHTTPS.ps1
Normal file
@@ -0,0 +1,272 @@
|
||||
#requires -Version 3.0 -Modules CimCmdlets, DnsClient, NetAdapter, NetTCPIP -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Enable DNS-over-HTTPS (DoH) if device is not domain-joined
|
||||
|
||||
.DESCRIPTION
|
||||
Enable DNS-over-HTTPS (DoH) if device is not domain-joined
|
||||
|
||||
It enables the Cloudflare DNS Servers, even if DoH is not working yet.
|
||||
|
||||
IPv6 Support is optional.
|
||||
|
||||
.PARAMETER IPv6
|
||||
Enable IPv6 Support, IPv6 Servers will be added to the serverlist
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Enable-DNSOverHTTPS.ps1
|
||||
|
||||
Enable DNS-over-HTTPS (DoH) if device is not domain-joined for IPv4 only
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Enable-DNSOverHTTPS.ps1 -IPv6
|
||||
|
||||
Enable DNS-over-HTTPS (DoH) if device is not domain-joined for IPv4 and IPv6
|
||||
|
||||
.NOTES
|
||||
Only the Insider Build of Windows 10 supports DoH!
|
||||
But we configure it anyway!
|
||||
|
||||
The Cloudflare servers are used for regular DNS resolution and as soon as DoH is supported,
|
||||
we can configure and use it anyway.
|
||||
|
||||
A future version of this script might support additional parameters, like DohFlags
|
||||
|
||||
You can also change the servers below to any service you like, e.g. Google DNS or Quad9 from IBM.
|
||||
|
||||
The Bool as return was requested by a customer, and the exit code (0 or 1) is implemented for our bootstrap setup
|
||||
|
||||
.LINK
|
||||
https://1.1.1.1/dns/
|
||||
|
||||
.LINK
|
||||
https://techcommunity.microsoft.com/t5/networking-blog/windows-insiders-can-now-test-dns-over-https/ba-p/1381282
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([bool])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('IP6', '6')]
|
||||
[switch]
|
||||
$IPv6
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$SCT = 'SilentlyContinue'
|
||||
$STP = 'Stop'
|
||||
$CNT = 'Continue'
|
||||
|
||||
# Save the infos from the switches
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$IsVerbose = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$IsVerbose = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$IsDebug = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$IsDebug = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['WhatIf']).IsPresent)
|
||||
{
|
||||
$IsWhatIf = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$IsWhatIf = $false
|
||||
}
|
||||
#endregion Defaults
|
||||
|
||||
#region ServerAddresses
|
||||
# Create an Empty Object
|
||||
$ServerAddresses = @()
|
||||
|
||||
# IPv4 DNS Servers to use
|
||||
$ServerAddressesIPv4 = @(
|
||||
'1.1.1.1'
|
||||
'1.0.0.1'
|
||||
)
|
||||
|
||||
# Add the IPv4 Servers to the Object
|
||||
$ServerAddresses += $ServerAddressesIPv4
|
||||
|
||||
if ((($PSCmdlet.MyInvocation.BoundParameters['IPv6']).IsPresent) -eq $true)
|
||||
{
|
||||
Write-Verbose -Message 'IPv6 Servers will be added to the serverlist'
|
||||
# IPv6 DNS Servers to use
|
||||
$ServerAddressesIPv6 = @(
|
||||
'2606:4700:4700::1111'
|
||||
'2606:4700:4700::1001'
|
||||
)
|
||||
|
||||
# Add the IPv6 Servers to the Object
|
||||
$ServerAddresses += $ServerAddressesIPv6
|
||||
}
|
||||
#endregion ServerAddresses
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
#region DoH
|
||||
# Enable DNS-over-HTTPS for IPv4 if device is not domain-joined
|
||||
$paramGetCimInstance = @{
|
||||
ClassName = 'CIM_ComputerSystem'
|
||||
Verbose = $IsVerbose
|
||||
Debug = $IsDebug
|
||||
ErrorAction = $STP
|
||||
}
|
||||
if (((Get-CimInstance @paramGetCimInstance).PartOfDomain) -eq $false)
|
||||
{
|
||||
try
|
||||
{
|
||||
# Temporarily key
|
||||
$paramNewItemProperty = @{
|
||||
Path = 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters'
|
||||
Name = 'EnableAutoDoh'
|
||||
Value = 2
|
||||
PropertyType = 'DWord'
|
||||
Force = $true
|
||||
WhatIf = $IsWhatIf
|
||||
Verbose = $IsVerbose
|
||||
Debug = $IsDebug
|
||||
ErrorAction = $CNT
|
||||
}
|
||||
$null = (New-ItemProperty @paramNewItemProperty)
|
||||
|
||||
$paramGetNetAdapter = @{
|
||||
Verbose = $IsVerbose
|
||||
Debug = $IsDebug
|
||||
Physical = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$MACAddress = ((Get-NetAdapter @paramGetNetAdapter).MacAddress)
|
||||
|
||||
$paramGetNetIPConfiguration = @{
|
||||
Verbose = $IsVerbose
|
||||
Debug = $IsDebug
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$IpConfig = (Get-NetIPConfiguration @paramGetNetIPConfiguration | Where-Object -FilterScript {
|
||||
$MACAddress -eq $_.NetAdapter.MacAddress
|
||||
})
|
||||
|
||||
$paramSetDnsClientServerAddress = @{
|
||||
ServerAddresses = $ServerAddresses
|
||||
Verbose = $IsVerbose
|
||||
Debug = $IsDebug
|
||||
ErrorAction = $CNT
|
||||
}
|
||||
$null = ($IpConfig | Set-DnsClientServerAddress @paramSetDnsClientServerAddress)
|
||||
|
||||
$paramClearDnsClientCache = @{
|
||||
Verbose = $IsVerbose
|
||||
Debug = $IsDebug
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Clear-DnsClientCache @paramClearDnsClientCache)
|
||||
|
||||
$paramRegisterDnsClient = @{
|
||||
Verbose = $IsVerbose
|
||||
Debug = $IsDebug
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Register-DnsClient @paramRegisterDnsClient)
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = $CNT
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = 'Sorry, this computer seems to be part of a Active Directory domain!'
|
||||
Exception = 'Active Directory Domain Members are not supported'
|
||||
Category = 'NotEnabled'
|
||||
TargetObject = $env:COMPUTERNAME
|
||||
ErrorAction = $CNT
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Return the Bool
|
||||
Write-Output -InputObject $false
|
||||
|
||||
# Unclean exit
|
||||
exit 1
|
||||
}
|
||||
#endregion DoH
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Return the Bool
|
||||
Write-Output -InputObject $true
|
||||
|
||||
# Clean exit
|
||||
exit 0
|
||||
}
|
||||
|
||||
#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
|
||||
56
Powershell/PowerShell-collection/Misc/ForceTimeResync.ps1
Normal file
56
Powershell/PowerShell-collection/Misc/ForceTimeResync.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
#requires -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Force Time re-sync with PowerShell
|
||||
|
||||
.DESCRIPTION
|
||||
Force Time re-sync as a PowerShell script
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\ForceTimeResync.ps1
|
||||
|
||||
Force Time Resync as a PowerShell script (Wrapper for w32tm.exe). Most be executed in an elevated shell)
|
||||
|
||||
.NOTES
|
||||
One of my VM's did a view time travels in the past. This little script runs every hour (Task).
|
||||
I still try to find the cause for the time travels (It jumps 2 hours forward, from time to time) and a better PowerShell way to do it.
|
||||
For now, this quick and dirty solution works just fine.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
process
|
||||
{
|
||||
$null = (& "$env:windir\system32\w32tm.exe" /resync /force)
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,114 @@
|
||||
function Get-AllCookiesFromWebRequestSession
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get all cookies stored in the WebRequestSession variable from any Invoke-RestMethod and/or Invoke-WebRequest request
|
||||
|
||||
.DESCRIPTION
|
||||
Get all cookies stored in the WebRequestSession variable from any Invoke-RestMethod and/or Invoke-WebRequest request
|
||||
The WebRequestSession stores useful info and it has something that some my know as CookieJar or http.cookiejar.
|
||||
|
||||
.PARAMETER WebRequestSession
|
||||
Specifies a variable where Invoke-RestMethod and/or Invoke-WebRequest saves values.
|
||||
Must be a valid [Microsoft.PowerShell.Commands.WebRequestSession] object!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> $null = Invoke-WebRequest -UseBasicParsing -Uri 'http://jhochwald.com' -Method Get -SessionVariable WebSession -ErrorAction SilentlyContinue
|
||||
PS C:\> $WebSession | Get-AllCookiesFromWebRequestSession
|
||||
|
||||
Get all cookies stored in the $WebSession variable from the request above.
|
||||
This page doesn't use or set any cookies, but the (awesome) CloudFlare service does.
|
||||
|
||||
.EXAMPLE
|
||||
$null = Invoke-RestMethod -UseBasicParsing -Uri 'https://jsonplaceholder.typicode.com/todos/1' -Method Get -SessionVariable RestSession -ErrorAction SilentlyContinue
|
||||
$RestSession | Get-AllCookiesFromWebRequestSession
|
||||
|
||||
Get all cookies stored in the $RestSession variable from the request above.
|
||||
Please do not abuse the free API service above!
|
||||
|
||||
.NOTES
|
||||
I used something I had stolen from Chrissy LeMaire's TechNet Gallery entry a (very) long time ago.
|
||||
But I needed something more generic, independent from the URL! This can become handy, to find any cookie from a 3rd party site or another host.
|
||||
|
||||
.LINK
|
||||
https://docs.python.org/3/library/http.cookiejar.html
|
||||
|
||||
.LINK
|
||||
https://en.wikipedia.org/wiki/HTTP_cookie
|
||||
|
||||
.LINK
|
||||
https://gallery.technet.microsoft.com/scriptcenter/Getting-Cookies-using-3c373c7e
|
||||
|
||||
.LINK
|
||||
Invoke-RestMethod
|
||||
|
||||
.LINK
|
||||
Invoke-WebRequest
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Specifies a variable where Invoke-RestMethod and/or Invoke-WebRequest saves values.')]
|
||||
[ValidateNotNull()]
|
||||
[Alias('Session', 'InputObject')]
|
||||
[Microsoft.PowerShell.Commands.WebRequestSession]
|
||||
$WebRequestSession
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Do the housekeeping
|
||||
$CookieInfoObject = $null
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
try
|
||||
{
|
||||
# I know, this look very crappy, but it just work fine!
|
||||
[pscustomobject]$CookieInfoObject = ((($WebRequestSession).Cookies).GetType().InvokeMember('m_domainTable', [Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::GetField -bor [Reflection.BindingFlags]::Instance, $null, (($WebRequestSession).Cookies), @()))
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
exit 1
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Dump the Cookies to the Console
|
||||
((($CookieInfoObject).Values).Values)
|
||||
}
|
||||
}
|
||||
134
Powershell/PowerShell-collection/Misc/Get-DirectorySize.ps1
Normal file
134
Powershell/PowerShell-collection/Misc/Get-DirectorySize.ps1
Normal file
@@ -0,0 +1,134 @@
|
||||
function Get-DirectorySize
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the size of a given folder in a human readable format
|
||||
|
||||
.DESCRIPTION
|
||||
Get the size of a given folder in a human readable format
|
||||
|
||||
.PARAMETER Path
|
||||
Folder to check
|
||||
|
||||
.PARAMETER Type
|
||||
Type of the Return,
|
||||
Valid values are: GB, MB, KB, B
|
||||
The default is MB (Megabyte)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-DirectorySize -Path 'C:\scripts'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-DirectorySize -Path 'C:\scripts' -Type GB
|
||||
|
||||
.NOTES
|
||||
PowerShell function to emulate the wel known Linux DU command
|
||||
|
||||
Releasenotes:
|
||||
1.0.0 2019-05-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.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([string])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Directory', 'Folder')]
|
||||
[string]
|
||||
$Path = '.',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateSet('GB', 'MB', 'KB', 'B', IgnoreCase = $true)]
|
||||
[Alias('InType')]
|
||||
[string]
|
||||
$Type = 'MB'
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
try
|
||||
{
|
||||
$AllFolderItems = (Get-ChildItem -Path $Path -Recurse -ErrorAction Stop | Measure-Object -Property length -Sum)
|
||||
|
||||
switch ($Type)
|
||||
{
|
||||
'GB'
|
||||
{
|
||||
$FolderSize = '{0:N2}' -f ($AllFolderItems.sum / 1GB) + ' GB'
|
||||
}
|
||||
'MB'
|
||||
{
|
||||
$FolderSize = '{0:N2}' -f ($AllFolderItems.sum / 1MB) + ' MB'
|
||||
}
|
||||
'KB'
|
||||
{
|
||||
$FolderSize = '{0:N2}' -f ($AllFolderItems.sum / 1KB) + ' KB'
|
||||
}
|
||||
'B'
|
||||
{
|
||||
$FolderSize = '{0:N2}' -f ($AllFolderItems.sum) + ' B'
|
||||
}
|
||||
Default
|
||||
{
|
||||
$FolderSize = '{0:N2}' -f ($AllFolderItems.sum) + ' MB'
|
||||
}
|
||||
}
|
||||
|
||||
return $FolderSize
|
||||
}
|
||||
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 Continue -Exception $e.Exception -TargetObject $e.CategoryInfo.TargetName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
463
Powershell/PowerShell-collection/Misc/Get-FritzBoxEvents.ps1
Normal file
463
Powershell/PowerShell-collection/Misc/Get-FritzBoxEvents.ps1
Normal file
@@ -0,0 +1,463 @@
|
||||
function Get-FritzBoxEvents
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the Events from a FritzBox router
|
||||
|
||||
.DESCRIPTION
|
||||
Get the Events from a FritzBox router
|
||||
|
||||
.PARAMETER FritzBoxUser
|
||||
Username to use for the FritzBox login
|
||||
|
||||
.PARAMETER FritzBoxPassword
|
||||
FritzBox Password in plain text (might be changed to a secure string soon)
|
||||
|
||||
.PARAMETER FritzBoxHost
|
||||
The URI that contains the FQDN or IP of your FritzBox,
|
||||
e.g. http://fritz.box or http://192.168.178.1
|
||||
|
||||
.PARAMETER Hours
|
||||
Hours to get, e.g. 24
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' -Hours 24 | Where-Object {(($_.ipv4 -ne $null) -or ($_.ipv6 -ne $null))}
|
||||
|
||||
Get only entries with IPv4 or IPv6 values, of the last 24 hours
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' -Hours 48 | Where-Object {($_.ipv6 -ne $null)}
|
||||
|
||||
Get only entries with IPv6 values, of the last 48 hours
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like 'Die Systemzeit wurde erfolgreich aktualisiert von Zeitserver*')}
|
||||
|
||||
Get all events where the time was set via a time server, no time limit
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like 'Die Systemzeit wurde erfolgreich aktualisiert von Zeitserver*')} | Select-Object -ExpandProperty IPv4
|
||||
|
||||
Get all events where the time was set via a time server, only return the IPv4 addresses, no time limit
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> ((Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like 'Die Systemzeit wurde erfolgreich aktualisiert von Zeitserver*')})[0] | Select-Object -ExpandProperty IPv4)
|
||||
|
||||
Get all events where the time was set via a time server, only return the IPv4 address of the latest (youngest) event
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like '*main-repeater*')}
|
||||
|
||||
Only return events from a repeater with the name main-repeater, no time limit
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> (Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like '*main-repeater*')})[0]
|
||||
|
||||
Only return the latest (youngest) events from a repeater with the name main-repeater, no time limit
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like '*Zeitserver * antwortet nicht.')}
|
||||
|
||||
Only return events where the Timeserver does NOT answer, no time limit
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like '*verschlüsselten DNS-Servern*')}
|
||||
|
||||
All events related to encrypted DNS, no time limit
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' -Hours 24 | Where-Object {($_.Message -like '*Authentifizierungsfehler*')}
|
||||
|
||||
Only events with authentication errors, of the last 24 hours
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> ((Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like '*(verfügbare Bitrate)*')})[0] | Select-Object -ExpandProperty Message)
|
||||
|
||||
The latest (youngest) event that has the bitrate info (capacity)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> ((Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like 'Internetverbindung wurde erfolgreich hergestellt.*')})[0] | Select-Object -ExpandProperty IPv4)
|
||||
|
||||
Get the public IPv4 address
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> ((Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {($_.Message -like 'Internetverbindung IPv6 wurde erfolgreich hergestellt.*')})[0] | Select-Object -ExpandProperty IPv6)
|
||||
|
||||
Get the public IPv6 address
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> ((Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {(($_.Message -like '*IPv6-Präfix wurde erfolgreich bezogen.*') -and ($_.ipv6 -ne $null))})[0] | Select-Object -ExpandProperty IPv6)
|
||||
|
||||
Get the latest public IPv6 prefix (CIDR)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> ((Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {(($_.Message -like 'Freigabe als Exposed Host auf * (*) hinzugefügt.') -and ($_.ipv4 -ne $null))})[0] | Select-Object -ExpandProperty IPv4)
|
||||
|
||||
get the exposed host IPv4
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> $IPv6TMP = (Get-FritzBoxEvents -FritzBoxUser 'myFritz' -FritzBoxPassword 'ThePassw0rd' -FritzBoxHost 'http://myfritz.box' | Where-Object {(($_.Message -like 'Freigabe als Exposed Host auf * (*) hinzugefügt.') -and ($_.ipv4 -eq $null))} | Select-Object -ExpandProperty Message)
|
||||
PS C:\> $regex = [regex]'(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'
|
||||
PS C:\> $regex.Matches($IPv6TMP) | ForEach-Object{ $_.value }
|
||||
|
||||
Get the exposed host IPv6 address and/or IPv6 CIDR (of exists)
|
||||
|
||||
.LINK
|
||||
https://github.com/jangeisbauer/FritzBox2Sentinel
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/joasch/e48738417ec1efcc963a96bbb3f34cba
|
||||
|
||||
.LINK
|
||||
https://www.ip-phone-forum.de/threads/ereignisprotokoll-der-fritz-box-auf-linux-server-sichern.280328/page-5
|
||||
|
||||
.NOTES
|
||||
All tests in the examples are only valid if your FritzBox has a german UI!
|
||||
For other languages, dump all events and search for the matches in your own language
|
||||
|
||||
If you have issues with german umlauts, use the following before stating the command:
|
||||
[console]::OutputEncoding = [System.Text.Encoding]::GetEncoding(1252)
|
||||
|
||||
I had issues on macOS and Linux with german umlauts, never happened on Windows!
|
||||
|
||||
Idea is stolen from https://github.com/jangeisbauer/FritzBox2Sentinel (No license was applied)
|
||||
So, @jangeisbauer is considered as a contributor
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([array])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('FBUser', 'user')]
|
||||
[string]
|
||||
$FritzBoxUser = $null,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Password', 'fbpassword')]
|
||||
[string]
|
||||
$FritzBoxPassword = $null,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('fbhost', 'host', 'fritzbox')]
|
||||
[string]
|
||||
$FritzBoxHost = 'http://fritz.box',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[int]
|
||||
$Hours = $null
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Garbage Collection
|
||||
[GC]::Collect()
|
||||
|
||||
#region Helper
|
||||
function Get-MD5Hash
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Return a MD5 hash of a given String
|
||||
|
||||
.DESCRIPTION
|
||||
Return a MD5 hash of a given String
|
||||
|
||||
.PARAMETER Text
|
||||
String to convert
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-MD5Hash -Text 'Value1'
|
||||
|
||||
.LINK
|
||||
https://github.com/jangeisbauer/FritzBox2Sentinel
|
||||
|
||||
.NOTES
|
||||
Cheap internal helper
|
||||
|
||||
Stolen from https://github.com/jangeisbauer/FritzBox2Sentinel (No license was applied)
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([string])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
HelpMessage = 'String to convert')]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Text
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$md5 = (New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider)
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$md5.ComputeHash([Text.Encoding]::utf8.getbytes($Text)) | ForEach-Object -Process {
|
||||
$HC = ''
|
||||
} {
|
||||
$HC += $_.tostring('x2')
|
||||
} {
|
||||
$HC
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Helper
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
try
|
||||
{
|
||||
# Convert the plain text password to a secure string
|
||||
$FritzBoxSecurePassword = ($FritzBoxPassword | ConvertTo-SecureString -AsPlainText -Force -ErrorAction Stop)
|
||||
|
||||
# FritzBox Pages to get
|
||||
$FritzBoxLoginPage = '/login_sid.lua'
|
||||
$FritzBoxEventPage = '/query.lua?mq_log=logger:status/log&sid='
|
||||
|
||||
# Secret handler
|
||||
$SecureStringToBSTR = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($FritzBoxSecurePassword)
|
||||
$PtrToStringAuto = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($SecureStringToBSTR)
|
||||
|
||||
# Get the challenge from the FritzBox Login Page
|
||||
$ChallengeRequest = (Invoke-WebRequest -Uri ($FritzBoxHost + $FritzBoxLoginPage) -UseBasicParsing -ErrorAction Stop)
|
||||
|
||||
# Save the recived challenge
|
||||
$Challenge = ([xml]$ChallengeRequest).sessioninfo.challenge
|
||||
|
||||
# Create the input for the HEX code
|
||||
$Code1 = ($Challenge + '-' + $PtrToStringAuto)
|
||||
|
||||
# Create the HEX data string
|
||||
$Code2 = ([char[]]$Code1 | ForEach-Object -Process {
|
||||
$Code2 = ''
|
||||
} {
|
||||
$Code2 += $_ + [Char]0
|
||||
} {
|
||||
$Code2
|
||||
})
|
||||
|
||||
# Create the body part for the next request (includes the MD5 hash of the HEX from above)
|
||||
$SIDRequestBody = ('response=' + $Challenge + '-' + $(Get-MD5Hash -text ($Code2)) + '&username=' + $FritzBoxUser)
|
||||
|
||||
# Do the real Login
|
||||
$SIDRequest = (Invoke-WebRequest -Uri ($FritzBoxHost + $FritzBoxLoginPage) -Method Post -Body $SIDRequestBody -ErrorAction Stop)
|
||||
|
||||
# Extract the SID from the Login request
|
||||
$SID = ((([xml]($SIDRequest.Content)).ChildNodes).sid)
|
||||
|
||||
# Get the Events
|
||||
|
||||
$FritzBoxEvents = (Invoke-WebRequest -Uri ($FritzBoxHost + $FritzBoxEventPage + $SID) -UseBasicParsing -ErrorAction Stop)
|
||||
|
||||
# Do we have a time limit?
|
||||
if ($Hours -ne 0)
|
||||
{
|
||||
# Create a filter
|
||||
$Filterhours = ((Get-Date).AddHours(-$Hours))
|
||||
}
|
||||
else
|
||||
{
|
||||
# No filter needed
|
||||
$Filterhours = $null
|
||||
}
|
||||
|
||||
# Create a new Array
|
||||
$FritzEvents = @()
|
||||
|
||||
# loop over the events we have (and extract the JSON return that contains all events)
|
||||
foreach ($FritzBoxEvent in ($FritzBoxEvents.Content | ConvertFrom-Json -ErrorAction Stop).mq_log)
|
||||
{
|
||||
try
|
||||
{
|
||||
# Cleanup
|
||||
$EventDate = $null
|
||||
$IPv6 = $null
|
||||
$IPv4 = $null
|
||||
$EventEntry = $null
|
||||
|
||||
# Transform the Data
|
||||
$EventDate = [regex]::Matches($FritzBoxEvent, '\d\d\.\d\d\.\d\d \d\d:\d\d:\d\d')[0].Value
|
||||
|
||||
# This REGEX should match IPv6 and IPv6 CIDR
|
||||
$IPv6 = [regex]::Matches($FritzBoxEvent[0], '((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$')[0].Value
|
||||
|
||||
# Simple IPv4 REGEX
|
||||
$IPv4 = [regex]::Matches($FritzBoxEvent[0], '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)')[0].Value
|
||||
|
||||
# Do we have a DATE in the event?
|
||||
if ($EventDate -ne '')
|
||||
{
|
||||
# Transform the Event DATE
|
||||
$EventEntry = $FritzBoxEvent[0].replace($EventDate, '')
|
||||
|
||||
# Ensure we have the correct format, just in case
|
||||
#$EventDate = (Get-Date -Date $EventDate)
|
||||
}
|
||||
|
||||
# Apply the Limit, if needed
|
||||
if (($Filterhours) -and ($EventDate -ge $Filterhours))
|
||||
{
|
||||
# Cleanup the event message (remove leading or trailing whitespaces)
|
||||
$EventEntry = $EventEntry.trim()
|
||||
|
||||
# Add the Event to the list
|
||||
$FritzEvents += [PSCustomObject]@{
|
||||
Date = $EventDate
|
||||
Message = $EventEntry
|
||||
IPv4 = $IPv4
|
||||
IPv6 = $IPv6
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$EventDate = $null
|
||||
$IPv6 = $null
|
||||
$IPv4 = $null
|
||||
$EventEntry = $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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
Write-Warning -Message $e.Exception.Message -WarningAction Continue
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Cleanup
|
||||
$FritzEvents = $null
|
||||
$FritzBoxSecurePassword = $null
|
||||
$FritzBoxLoginPage = $null
|
||||
$FritzBoxEventPage = $null
|
||||
$SecureStringToBSTR = $null
|
||||
$PtrToStringAuto = $null
|
||||
$ChallengeRequest = $null
|
||||
$Challenge = $null
|
||||
$Code1 = $null
|
||||
$Code2 = $null
|
||||
$SIDRequestBody = $null
|
||||
$SIDRequest = $null
|
||||
$SID = $null
|
||||
$FritzBoxEvents = $null
|
||||
$Hours = $null
|
||||
$Filterhours = $null
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
exit 1
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
finally
|
||||
{
|
||||
# Garbage Collection
|
||||
[GC]::Collect()
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Dump to the Terminal
|
||||
$FritzEvents
|
||||
|
||||
# Cleanup
|
||||
$FritzEvents = $null
|
||||
$FritzBoxSecurePassword = $null
|
||||
$FritzBoxLoginPage = $null
|
||||
$FritzBoxEventPage = $null
|
||||
$SecureStringToBSTR = $null
|
||||
$PtrToStringAuto = $null
|
||||
$ChallengeRequest = $null
|
||||
$Challenge = $null
|
||||
$Code1 = $null
|
||||
$Code2 = $null
|
||||
$SIDRequestBody = $null
|
||||
$SIDRequest = $null
|
||||
$SID = $null
|
||||
$FritzBoxEvents = $null
|
||||
$Hours = $null
|
||||
$Filterhours = $null
|
||||
|
||||
# Garbage Collection
|
||||
[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
|
||||
188
Powershell/PowerShell-collection/Misc/Get-IPv6InWindows.ps1
Normal file
188
Powershell/PowerShell-collection/Misc/Get-IPv6InWindows.ps1
Normal file
@@ -0,0 +1,188 @@
|
||||
function Get-IPv6InWindows
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the configured IPv6 value from the registry
|
||||
|
||||
.DESCRIPTION
|
||||
Get the configured IPv6 value from the registry
|
||||
Transforms the Registry value into human understandable values
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-IPv6InWindows
|
||||
All IPv6 components are enabled (0)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-IPv6InWindows -verbose
|
||||
Prefer IPv4 over IPv6 (32)
|
||||
|
||||
Get the configured IPv6 value from the registry, with verbose output
|
||||
|
||||
.LINK
|
||||
Set-IPv6InWindows
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/troubleshoot/windows-server/networking/configure-ipv6-in-windows
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/troubleshoot/windows-server/networking/configure-ipv6-in-windows#reference
|
||||
|
||||
.NOTES
|
||||
Just a wrapper to make the values more human readable.
|
||||
This is just a quick and dirty initial version!
|
||||
|
||||
If you find any further values (other then the supported), please let me know!
|
||||
|
||||
Want to modify your IPv6 configuration? Use its companion Set-IPv6InWindows
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([string])]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
# Cleanup
|
||||
$ComponentValue = $null
|
||||
$ComponentValueText = $null
|
||||
|
||||
#region BoundParameters
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$IsVerbose = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$IsVerbose = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$IsDebug = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$IsDebug = $false
|
||||
}
|
||||
#endregion BoundParameters
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the Value from the registry
|
||||
try
|
||||
{
|
||||
$paramGetItemProperty = @{
|
||||
Path = 'HKLM:\SYSTEM\CurrentControlSet\Services\tcpip6\Parameters'
|
||||
Name = 'DisabledComponents'
|
||||
Debug = $IsDebug
|
||||
Verbose = $IsVerbose
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$ComponentValue = (Get-ItemProperty @paramGetItemProperty | Select-Object -ExpandProperty DisabledComponents -ErrorAction Stop -WarningAction Continue)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
Write-Verbose -Message $info
|
||||
|
||||
Write-Error -Message ($info.Exception) -ErrorAction Stop
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
exit 1
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
|
||||
switch ($ComponentValue)
|
||||
{
|
||||
0
|
||||
{
|
||||
$ComponentValueText = ('All IPv6 components are enabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
255
|
||||
{
|
||||
$ComponentValueText = ('All IPv6 components are disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
2
|
||||
{
|
||||
$ComponentValueText = ('6to4 is disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
4
|
||||
{
|
||||
$ComponentValueText = ('ISATAP is disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
8
|
||||
{
|
||||
$ComponentValueText = ('Teredo is disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
10
|
||||
{
|
||||
$ComponentValueText = ('Teredo and 6to4 is disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
1
|
||||
{
|
||||
$ComponentValueText = ('All tunnel interfaces are disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
16
|
||||
{
|
||||
$ComponentValueText = ('All LAN and PPP interfaces are disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
17
|
||||
{
|
||||
$ComponentValueText = ('All LAN, PPP and tunnel interfaces are disabled ({0})' -f $ComponentValue)
|
||||
}
|
||||
32
|
||||
{
|
||||
$ComponentValueText = ('Prefer IPv4 over IPv6 ({0})' -f $ComponentValue)
|
||||
}
|
||||
default
|
||||
{
|
||||
$ComponentValueText = ('Unknown value found: {0}' -f $ComponentValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Dump the info
|
||||
$ComponentValueText
|
||||
}
|
||||
}
|
||||
#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
|
||||
75
Powershell/PowerShell-collection/Misc/Get-IpInfo.ps1
Normal file
75
Powershell/PowerShell-collection/Misc/Get-IpInfo.ps1
Normal file
@@ -0,0 +1,75 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get all local IP addresses
|
||||
|
||||
.DESCRIPTION
|
||||
Get all local IP addresses, just the addresses
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-IpInfo.ps1
|
||||
|
||||
Get all local IP addresses, just the addresses
|
||||
|
||||
.NOTES
|
||||
Quick an dirty function that uses Net.DNS to gather the information about the IP Addresses
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
#Cleanup
|
||||
$IpAddressInfo = $null
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the Info using Net.Dns
|
||||
$IpAddressInfo = @(
|
||||
(([Net.DNS]::GetHostAddresses([Net.Dns]::GetHostByName(($env:COMPUTERNAME)).HostName) | Where-Object -FilterScript {
|
||||
$_.IsIPv6LinkLocal -eq $false
|
||||
}).IPAddressToString | Where-Object -FilterScript {
|
||||
$_ -ne '::1'
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Dump the Info
|
||||
$IpAddressInfo
|
||||
|
||||
#Cleanup
|
||||
$IpAddressInfo = $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
|
||||
@@ -0,0 +1,106 @@
|
||||
function Get-LocalGroupMembership
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get all local Groups a given User is a Member of
|
||||
|
||||
.DESCRIPTION
|
||||
The the the membership of all local Groups for a given User.
|
||||
The Given User could be a local User (COMPUTER\USER) or a Domain User (DOMAIN\USER).
|
||||
|
||||
.PARAMETER UserName
|
||||
Given User could be a local User (COMPUTER\USER) or a Domain User (DOMAIN\USER).
|
||||
Default is the user that executes the function.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-LocalGroupMembership
|
||||
|
||||
Dump the Group Membership for the User that executes the function
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-LocalGroupMembership -UserName 'CONTOSO\John.Doe'
|
||||
|
||||
Dump the Group Membership for the User John.Doe in the Domain CONTOSO
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-LocalGroupMembership -UserName "$env:COMPUTERNAME\John.Doe"
|
||||
|
||||
Dump the Group Membership for the User John.Doe on the local computer
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-LocalGroupMembership -UserName 'CONTOSO\John.Doe' | Foreach-Object { Add-LocalGroupMember -Group $_ -Member "$env:COMPUTERNAME\John.Doe" -ErrorAction SilentlyContinue }
|
||||
|
||||
Clone the Group Membership from User John.Doe in the Domain CONTOSO to User John.Doe on the local computer
|
||||
|
||||
.NOTES
|
||||
This is just a quick and dirty solution for a problem I faced. (See last example)
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('User')]
|
||||
[string]
|
||||
$UserName = ("$env:USERDOMAIN" + '\' + "$env:USERNAME")
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Create a new Object
|
||||
$LocalGroupMembership = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$AllGroups = (Get-LocalGroup -Name *)
|
||||
|
||||
foreach ($LocalGroup in $AllGroups)
|
||||
{
|
||||
if (Get-LocalGroupMember -Group $LocalGroup.Name -ErrorAction SilentlyContinue | Where-Object -FilterScript {
|
||||
$_.name -eq $UserName
|
||||
})
|
||||
{
|
||||
$LocalGroupMembership += $LocalGroup.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
{
|
||||
# Dump the object to the console
|
||||
$LocalGroupMembership
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,95 @@
|
||||
function Get-LocalIpAddresses
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Print a string with all IP addresses
|
||||
|
||||
.DESCRIPTION
|
||||
Print a string with all IP addresses. Supports IPv4 and IPv6.
|
||||
It filters IPv6 Link Local only addresses by default.
|
||||
|
||||
.PARAMETER TargetName
|
||||
Specifies the computers to test. Type the computer names or type IP addresses in IPv4 or IPv6 format. Wildcard characters are not permitted. The default is localhost.
|
||||
|
||||
.PARAMETER IPv6LinkLocal
|
||||
Retuns IPv6 Link Local only addresses? Off by default.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-LocalIpAddresses
|
||||
Print a string with all local IP addresses
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-LocalIpAddresses -TargetName 'mycomputer'
|
||||
Print a string with all IP addresses for the computer 'mycomputer'
|
||||
|
||||
.NOTES
|
||||
TODO: Remove the -TargetName in the next release! Makes no sense (only IPv4 is returned)
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([string])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$TargetName = $env:COMPUTERNAME,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[Alias('IsIPv6LinkLocal')]
|
||||
[switch]
|
||||
$IPv6LinkLocal
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$IpInfo = $null
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$IpInfo = ($TargetName | ForEach-Object -Process {
|
||||
(([Net.DNS]::GetHostAddresses([Net.Dns]::GetHostByName($_).HostName) | Where-Object -FilterScript {
|
||||
$_.IsIPv6LinkLocal -eq $IPv6LinkLocal
|
||||
}).IPAddressToString)
|
||||
})
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Dump to the Console
|
||||
$IpInfo
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,158 @@
|
||||
function Get-etLatestNuGetRelease
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the latest published version of a given Module from a NuGet Repository
|
||||
|
||||
.DESCRIPTION
|
||||
Get the latest published version of a given PowerShell Module from a NuGet Repository
|
||||
|
||||
.PARAMETER Project
|
||||
Name of the Project, e.g. et.Office365
|
||||
|
||||
.PARAMETER Repository
|
||||
NuGet Repository, default is the PowerShell Gallery
|
||||
|
||||
.PARAMETER Version
|
||||
Return a PowerShell Version String instead of a String
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-etLatestNuGetRelease -Project 'et.Office365'
|
||||
|
||||
Get the latest published version of a given Module from a NuGet Repository
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-etLatestNuGetRelease -Project 'et.Office365' -version
|
||||
|
||||
Get the latest published version of a given Module from a NuGet Repository, but as Version instead of a String
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> 'et.Office365' | Get-etLatestNuGetRelease
|
||||
|
||||
Get the latest published version of a given Module from a NuGet Repository
|
||||
|
||||
.NOTES
|
||||
enabling Technology internal Build helper function
|
||||
|
||||
.LINK
|
||||
Get-etModuleVersion
|
||||
|
||||
.LINK
|
||||
Compare-enModuleVersions
|
||||
|
||||
.LINK
|
||||
Find-Module
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([string])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Name of the Project, e.g. et.Office365')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('etProject')]
|
||||
[string]
|
||||
$Project,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('etRepository', 'Gallery', 'NuGetGallery')]
|
||||
[string]
|
||||
$Repository = 'PSGallery',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[Alias('enVersion')]
|
||||
[switch]
|
||||
$Version = $false
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$LatestNuGetRelease = $null
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
try
|
||||
{
|
||||
$paramFindModule = @{
|
||||
Name = $Project
|
||||
Repository = $Repository
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$LatestNuGetRelease = (Find-Module @paramFindModule | Select-Object -ExpandProperty Version)
|
||||
}
|
||||
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 ($info.Exception) -TargetObject ($info.Target) -ErrorAction Stop
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
if ($Version)
|
||||
{
|
||||
[version]$LatestNuGetRelease = $LatestNuGetRelease
|
||||
}
|
||||
else
|
||||
{
|
||||
[string]$LatestNuGetRelease = $LatestNuGetRelease
|
||||
}
|
||||
|
||||
# Dump to the console
|
||||
$LatestNuGetRelease
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
131
Powershell/PowerShell-collection/Misc/Grant-LogOnAsService.ps1
Normal file
131
Powershell/PowerShell-collection/Misc/Grant-LogOnAsService.ps1
Normal file
@@ -0,0 +1,131 @@
|
||||
function Grant-LogOnAsService
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Grant user log on as a service right in PowerShell
|
||||
|
||||
.DESCRIPTION
|
||||
Grant user log on as a service right in PowerShell
|
||||
|
||||
.PARAMETER Users
|
||||
The User that should get the grant
|
||||
|
||||
.INPUTS
|
||||
String, Multi Value is OK here
|
||||
|
||||
.OUTPUTS
|
||||
None
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Grant-LogOnAsService -Users 'johndoe'
|
||||
|
||||
Grant user log on as a service right in PowerShell
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/ned1313/9143039
|
||||
|
||||
.NOTES
|
||||
Just a minor refactoring of the original
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'The User that should get the grant')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string[]]
|
||||
$Users
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('Apply login as a service', "$Users"))
|
||||
{
|
||||
# Get list of currently used SIDs
|
||||
& "$env:windir\system32\secedit.exe" /export /cfg tempexport.inf
|
||||
$curSIDs = (Select-String -Path .\tempexport.inf -Pattern 'SeServiceLogonRight')
|
||||
$Sids = $curSIDs.line
|
||||
$sidstring = ''
|
||||
|
||||
foreach ($user in $Users)
|
||||
{
|
||||
$objUser = (New-Object -TypeName System.Security.Principal.NTAccount -ArgumentList ($user))
|
||||
$strSID = $objUser.Translate([Security.Principal.SecurityIdentifier])
|
||||
|
||||
if (!$Sids.Contains($strSID) -and !$Sids.Contains($user))
|
||||
{
|
||||
$sidstring += ",*$strSID"
|
||||
}
|
||||
}
|
||||
|
||||
if ($sidstring)
|
||||
{
|
||||
$newSids = $Sids + $sidstring
|
||||
|
||||
Write-Output -InputObject ('New Sids: {0}' -f $newSids)
|
||||
$tempinf = (Get-Content -Path tempexport.inf)
|
||||
$tempinf = $tempinf.Replace($Sids, $newSids)
|
||||
$null = (Add-Content -Path tempimport.inf -Value $tempinf -Force -Confirm:$false)
|
||||
|
||||
& "$env:windir\system32\secedit.exe" /import /db secedit.sdb /cfg '.\tempimport.inf'
|
||||
& "$env:windir\system32\secedit.exe" /configure /db secedit.sdb
|
||||
& "$env:windir\system32\gpupdate.exe" /force
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output -InputObject 'No new sids'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('Cleanup', 'Tempfiles'))
|
||||
{
|
||||
# Splat the Defaults
|
||||
$paramRemoveItem = @{
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
|
||||
$null = (Remove-Item -Path '.\tempimport.inf' @paramRemoveItem)
|
||||
$null = (Remove-Item -Path '.\secedit.sdb' @paramRemoveItem)
|
||||
$null = (Remove-Item -Path '.\tempexport.inf' @paramRemoveItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
439
Powershell/PowerShell-collection/Misc/Hosts_helper.ps1
Normal file
439
Powershell/PowerShell-collection/Misc/Hosts_helper.ps1
Normal file
@@ -0,0 +1,439 @@
|
||||
function Add-HostsEntry
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Add a single Hosts Entry to the HOSTS File
|
||||
|
||||
.DESCRIPTION
|
||||
Add a single Hosts Entry to the HOSTS File, multiple are not supported yet!
|
||||
|
||||
.PARAMETER Path
|
||||
The path to the hosts file where the entry should be set. Defaults to the local computer's hosts file.
|
||||
|
||||
.PARAMETER Address
|
||||
The Address address for the hosts entry.
|
||||
|
||||
.PARAMETER HostName
|
||||
The hostname for the hosts entry.
|
||||
|
||||
.PARAMETER force
|
||||
Force (replace)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Add-HostsEntry -Address '0.0.0.0' -HostName 'badhost'
|
||||
|
||||
Add the host 'badhost' with the Adress '0.0.0.0' (blackhole) wo the Hosts.
|
||||
If an Entry for 'badhost' exists, the new one will be appended anyway (You end up with two entries)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Add-HostsEntry -Address '0.0.0.0' -HostName 'badhost' -force
|
||||
|
||||
Add the host 'badhost' with the Adress '0.0.0.0' (blackhole) wo the Hosts.
|
||||
If an Entry for 'badhost' exists, the new one will replace the existing one.
|
||||
|
||||
.NOTES
|
||||
Internal Helper, inspired by an old GIST I found
|
||||
|
||||
.LINK
|
||||
Get-HostsFile
|
||||
|
||||
.LINK
|
||||
Remove-HostsEntry
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/markembling/173887/1824b370be3fe468faceaed5f39b12bad010a417
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
Position = 0,
|
||||
HelpMessage = 'The IP address for the hosts entry.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('ipaddress', 'ip')]
|
||||
[string]
|
||||
$Address,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'The hostname for the hosts entry.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Host', 'Name')]
|
||||
[string]
|
||||
$HostName,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[switch]
|
||||
$force = $false,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('filename', 'Hosts', 'hostsfile', 'file')]
|
||||
[string]
|
||||
$Path = "$env:windir\System32\drivers\etc\hosts"
|
||||
)
|
||||
begin
|
||||
{
|
||||
Write-Verbose -Message 'Start'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($force)
|
||||
{
|
||||
try
|
||||
{
|
||||
$null = (Remove-HostsEntry -HostName $HostName -Path $Path -ErrorAction SilentlyContinue -WarningAction SilentlyContinue)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Verbose -Message 'Looks like the entry was not there before'
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('Target', 'Operation'))
|
||||
{
|
||||
# Get a clean (end of) file
|
||||
$paramGetContent = @{
|
||||
Path = $Path
|
||||
Raw = $true
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$HostsFileContent = (((Get-Content @paramGetContent ).TrimEnd()).ToString())
|
||||
|
||||
$NewValue = "`n" + $Address + "`t`t" + $HostName
|
||||
$NewHostsFileContent = $HostsFileContent + $NewValue
|
||||
|
||||
$paramSetContent = @{
|
||||
Path = $Path
|
||||
Value = $NewHostsFileContent
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
Encoding = 'UTF8'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Set-Content @paramSetContent)
|
||||
}
|
||||
}
|
||||
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 ($info.Exception) -ErrorAction Stop
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message 'Done'
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-HostsEntry
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes a single Hosts Entry from the HOSTS File
|
||||
|
||||
.DESCRIPTION
|
||||
Removes a single Hosts Entry from the HOSTS File, multiple are not supported yet!
|
||||
|
||||
.PARAMETER Path
|
||||
The path to the hosts file where the entry should be set. Defaults to the local computer's hosts file.
|
||||
|
||||
.PARAMETER HostName
|
||||
The hostname for the hosts entry.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-HostsEntry -HostName 'Dummy'
|
||||
|
||||
Remove the entry for the host 'Dummy' from the HOSTS File
|
||||
|
||||
.NOTES
|
||||
Internal Helper, inspired by an old GIST I found
|
||||
|
||||
.LINK
|
||||
Get-HostsFile
|
||||
|
||||
.LINK
|
||||
Add-HostsEntry
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/markembling/173887/1824b370be3fe468faceaed5f39b12bad010a417
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'The hostname for the hosts entry.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Host', 'Name')]
|
||||
[string]
|
||||
$HostName,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Hosts', 'hostsfile', 'file', 'Filename')]
|
||||
[string]
|
||||
$Path = "$env:windir\System32\drivers\etc\hosts"
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
Write-Verbose -Message 'Start'
|
||||
|
||||
try
|
||||
{
|
||||
$paramGetContent = @{
|
||||
Path = $Path
|
||||
Raw = $true
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$HostsFileContent = (((Get-Content @paramGetContent ).TrimEnd()).ToString())
|
||||
}
|
||||
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 ($info.Exception) -ErrorAction Stop
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
}
|
||||
|
||||
$newLines = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
foreach ($line in $HostsFileContent)
|
||||
{
|
||||
$bits = [regex]::Split($line, '\t+')
|
||||
if ($bits.count -eq 2)
|
||||
{
|
||||
if ($bits[1] -ne $HostName)
|
||||
{
|
||||
$newLines += $line
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$newLines += $line
|
||||
}
|
||||
}
|
||||
|
||||
# Write file
|
||||
try
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('Target', 'Operation'))
|
||||
{
|
||||
$paramClearContent = @{
|
||||
Path = $Path
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Clear-Content @paramClearContent)
|
||||
|
||||
$paramSetContent = @{
|
||||
Path = $Path
|
||||
Value = $newLines
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
Encoding = 'UTF8'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Set-Content @paramSetContent)
|
||||
}
|
||||
}
|
||||
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 ($info.Exception) -ErrorAction Stop
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message 'Done'
|
||||
}
|
||||
}
|
||||
|
||||
function Get-HostsFile
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Print the HOSTS File in a more clean format
|
||||
|
||||
.DESCRIPTION
|
||||
Print the HOSTS File in a more clean format
|
||||
|
||||
.PARAMETER Path
|
||||
The path to the hosts file where the entry should be set. Defaults to the local computer's hosts file.
|
||||
|
||||
.PARAMETER raw
|
||||
Print raw Hosts File
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-HostsFile
|
||||
|
||||
Print the HOSTS File in a more clean format
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-HostsFile -raw
|
||||
|
||||
Print the HOSTS File in the regular format
|
||||
|
||||
.NOTES
|
||||
Internal Helper, inspired by an old GIST I found
|
||||
|
||||
.LINK
|
||||
Add-HostsEntry
|
||||
|
||||
.LINK
|
||||
Remove-HostsEntry
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/markembling/173887/1824b370be3fe468faceaed5f39b12bad010a417
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Hosts', 'hostsfile', 'file', 'filename')]
|
||||
[string]
|
||||
$Path = "$env:windir\System32\drivers\etc\hosts",
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1)]
|
||||
[Alias('plain')]
|
||||
[switch]
|
||||
$raw = $false
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$HostsFileContent = Get-Content -Path $Path
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
foreach ($line in $HostsFileContent)
|
||||
{
|
||||
if ($raw)
|
||||
{
|
||||
Write-Output -InputObject $line
|
||||
}
|
||||
else
|
||||
{
|
||||
$bits = [regex]::Split($line, '\t+')
|
||||
if ($bits.count -eq 2)
|
||||
{
|
||||
[string]$HostsFileLine = $bits
|
||||
|
||||
if (-not ($HostsFileLine.StartsWith('#')))
|
||||
{
|
||||
Write-Output -InputObject $HostsFileLine
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
183
Powershell/PowerShell-collection/Misc/Install-DSCResourceKit.ps1
Normal file
183
Powershell/PowerShell-collection/Misc/Install-DSCResourceKit.ps1
Normal file
@@ -0,0 +1,183 @@
|
||||
function Install-DSCResourceKit
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Install the complete PowerShell DSCResourceKit
|
||||
|
||||
.DESCRIPTION
|
||||
Install the complete PowerShell DSCResourceKit from the PowerShell Gallery.
|
||||
It only installs the missing resources.
|
||||
|
||||
.PARAMETER Scope
|
||||
Specifies the installation scope of the module. The acceptable values for this parameter are: AllUsers and CurrentUser.
|
||||
|
||||
The AllUsers scope lets modules be installed in a location that is accessible to all users of the computer, that is, %systemdrive%:\ProgramFiles\WindowsPowerShell\Modules.
|
||||
|
||||
The CurrentUser scope lets modules be installed only to $home\Documents\WindowsPowerShell\Modules, so that the module is available only to the current user.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Install-DSCResourceKit
|
||||
|
||||
Install the complete PowerShell DSCResourceKit
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Install-DSCResourceKit -verbose
|
||||
|
||||
Install the complete PowerShell DSCResourceKit
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.0 2019-04-10: Internal 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.
|
||||
|
||||
Dependencies:
|
||||
PowerShellGet
|
||||
|
||||
.LINK
|
||||
https://aka.ms/InstallModule
|
||||
|
||||
.LINK
|
||||
https://www.powershellgallery.com
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[ValidateSet('AllUsers', 'CurrentUser', IgnoreCase = $true)]
|
||||
[Alias('ModuleScope')]
|
||||
[String]
|
||||
$Scope = 'AllUsers'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
try
|
||||
{
|
||||
if (-not ($Scope))
|
||||
{
|
||||
$Scope = 'AllUsers'
|
||||
}
|
||||
|
||||
$AllReSources = ((Find-Module -Tag DSCResourceKit).name)
|
||||
$AllInstall = ((Get-Module -ListAvailable).Name)
|
||||
}
|
||||
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
|
||||
|
||||
# Whoops
|
||||
Write-Error -Message $info.Exception -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('DSCResourceKit', 'Install'))
|
||||
{
|
||||
foreach ($DSCResource in $AllReSources)
|
||||
{
|
||||
if (-not ($AllInstall.Contains($DSCResource)))
|
||||
{
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Try to install {0}' -f $DSCResource)
|
||||
|
||||
$paramInstallModule = @{
|
||||
Name = $DSCResource
|
||||
Scope = $Scope
|
||||
AllowClobber = $true
|
||||
SkipPublisherCheck = $true
|
||||
Repository = 'PSGallery'
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Install-Module @paramInstallModule)
|
||||
|
||||
Write-Verbose -Message ('Installed {0}' -f $DSCResource)
|
||||
}
|
||||
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 ('Unable to install {0}' -f $DSCResource) -ErrorAction Continue -WarningAction Continue
|
||||
|
||||
# Cleanup
|
||||
$e = $null
|
||||
$info = $null
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message ('{0} is already installed' -f $DSCResource)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Cleanup
|
||||
$AllReSources = $null
|
||||
$AllInstall = $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
|
||||
@@ -0,0 +1,360 @@
|
||||
function Invoke-CheckPowerShellModules
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Check if one or more given modules are installed.
|
||||
|
||||
.DESCRIPTION
|
||||
Check if one or more given modules are installed.
|
||||
Any missing modules can be installed (optional) and updated to the latest version available on the PowerShell Gallery can be applied (optional).
|
||||
|
||||
.PARAMETER Module
|
||||
One or more modules to check, update, install.
|
||||
|
||||
.PARAMETER Install
|
||||
Install any missing modules from the PowerShell Gallery?
|
||||
|
||||
.PARAMETER Update
|
||||
Updated to the latest PowerShell Gallery Version of the module, if available?
|
||||
|
||||
.PARAMETER Scope
|
||||
Specifies the installation scope of the module.
|
||||
The acceptable values for this parameter are: AllUsers and CurrentUser.
|
||||
The default is CurrentUser.
|
||||
|
||||
The AllUsers scope lets modules be installed in a location that is accessible to all users of the computer,
|
||||
that is, %systemdrive%:\ProgramFiles\WindowsPowerShell\Modules. Elevated Shell required!
|
||||
|
||||
The CurrentUser scope lets modules be installed only to $home\Documents\WindowsPowerShell\Modules,
|
||||
so that the module is available only to the current user.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-CheckPowerShellModules -Module 'MSOnline', 'azuread', 'AzureADPreview', 'Microsoft.Online.SharePoint.PowerShell', 'MicrosoftTeams', 'Microsoft.PowerApps.PowerShell', 'Microsoft.PowerApps.Administration.PowerShell', 'SharePointPnPPowerShellOnline', 'credentialmanager' -Install
|
||||
|
||||
Check if all the Office 365 related PowerShell Modules are installed.
|
||||
This will not install anything missing; it just runs a check!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-CheckPowerShellModules -Module 'MSOnline', 'azuread', 'AzureADPreview', 'Microsoft.Online.SharePoint.PowerShell', 'MicrosoftTeams', 'Microsoft.PowerApps.PowerShell', 'Microsoft.PowerApps.Administration.PowerShell', 'SharePointPnPPowerShellOnline', 'credentialmanager' -Install
|
||||
|
||||
Install all the Office 365 related PowerShell Modules if anything is missing.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-CheckPowerShellModules -Module 'MSOnline', 'azuread', 'AzureADPreview', 'Microsoft.Online.SharePoint.PowerShell', 'MicrosoftTeams', 'Microsoft.PowerApps.PowerShell', 'Microsoft.PowerApps.Administration.PowerShell', 'SharePointPnPPowerShellOnline', 'credentialmanager' -Scope AllUsers
|
||||
|
||||
Install all the Office 365 related PowerShell Modules if anything is missing (system wide).
|
||||
This required to runn in an elevated Shell!!!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-CheckPowerShellModules -Module 'MSOnline', 'azuread', 'AzureADPreview', 'Microsoft.Online.SharePoint.PowerShell', 'MicrosoftTeams', 'Microsoft.PowerApps.PowerShell', 'Microsoft.PowerApps.Administration.PowerShell', 'SharePointPnPPowerShellOnline', 'credentialmanager' -Update
|
||||
|
||||
Install all the Office 365 related PowerShell Modules if missing, automatically updates the latest version (if there is any update available)
|
||||
|
||||
.NOTES
|
||||
For now, only the PowerShell Gallery is supported as Repository!
|
||||
The next version might bring the check for an elevated shell if the scope is set to 'AllUsers'.
|
||||
|
||||
Releasenotes:
|
||||
1.0.1 2019-05-24: Make it a bit more robust and add some examples (intial public release)
|
||||
1.0.0 2019-05-15: Initial Release (internal)
|
||||
|
||||
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.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'One or more Modules to check.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string[]]
|
||||
$Module,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1)]
|
||||
[Alias('AutoInstall', 'InstallMissing')]
|
||||
[switch]
|
||||
$Install = $null,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[Alias('AutoUpdate')]
|
||||
[switch]
|
||||
$Update = $null,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateSet('AllUsers', 'CurrentUser', IgnoreCase = $true)]
|
||||
[Alias('InstallScope', 'ModuleScope')]
|
||||
[string]
|
||||
$Scope = 'CurrentUser'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# The default scope is the current user (if not given)
|
||||
if (-not $Scope)
|
||||
{
|
||||
$Scope = 'CurrentUser'
|
||||
}
|
||||
|
||||
# Mandatory PowerShell Modules for Office 365 administration.
|
||||
if (-not $Module)
|
||||
{
|
||||
$Module = 'MSOnline', 'azuread', 'AzureADPreview', 'Microsoft.Online.SharePoint.PowerShell', 'MicrosoftTeams', 'Microsoft.PowerApps.PowerShell', 'Microsoft.PowerApps.Administration.PowerShell'
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
foreach ($PowerShellModule in $Module)
|
||||
{
|
||||
# Cleanup
|
||||
$InstalledModuleVersion = $null
|
||||
$LatestModuleVersion = $null
|
||||
$UpdateVersion = $null
|
||||
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Start processing for {0}' -f $PowerShellModule)
|
||||
|
||||
# Cleanup
|
||||
$InstalledModuleVersion = $null
|
||||
|
||||
# In some cases, we might have different versions installed.
|
||||
# We just want to have the latest and greatest one.
|
||||
$paramGetModule = @{
|
||||
Name = $PowerShellModule
|
||||
ListAvailable = $true
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$InstalledModuleVersion = (Get-Module @paramGetModule | Select-Object -Property Name, Version, repositorysourcelocation | Sort-Object -Property Version -Descending | Select-Object -First 1)
|
||||
|
||||
if (-not $InstalledModuleVersion)
|
||||
{
|
||||
if ($Install)
|
||||
{
|
||||
Write-Verbose -Message ('Start the installation of {0}' -f $PowerShellModule)
|
||||
|
||||
try
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($PowerShellModule, 'Install'))
|
||||
{
|
||||
$paramInstallModule = @{
|
||||
Name = $PowerShellModule
|
||||
Repository = 'PSGallery'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
Scope = $Scope
|
||||
Force = $true
|
||||
AllowClobber = $true
|
||||
}
|
||||
$null = (Install-Module @paramInstallModule)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# Build the Info object
|
||||
$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
|
||||
}
|
||||
|
||||
# Do some verbose things
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
Write-Verbose -Message ('Finished the installation of {0}' -f $PowerShellModule)
|
||||
}
|
||||
else
|
||||
{
|
||||
# Error message
|
||||
Write-Error -Message ('{0} was not found...' -f $PowerShellModule) -Category NotInstalled -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($InstalledModuleVersion.RepositorySourceLocation.Authority -ne 'www.powershellgallery.com')
|
||||
{
|
||||
Write-Error -Message ('Sorry, but only modules from the PowerShell Gallery are supported and {0} is not installed from there.' -f $PowerShellModule) -Category InvalidType -ErrorAction Stop
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Get the latest PowerShell Gallery version for {0}' -f $PowerShellModule)
|
||||
|
||||
$paramFindModule = @{
|
||||
Name = $PowerShellModule
|
||||
Repository = 'PSGallery'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$LatestModuleVersion = (Find-Module @paramFindModule | Select-Object -Property Name, Version)
|
||||
|
||||
$UpdateVersion = $LatestModuleVersion.Version
|
||||
|
||||
Write-Verbose -Message ('Found version {0} of {1} in the PowerShell Gallery' -f $UpdateVersion, $PowerShellModule)
|
||||
|
||||
if ($InstalledModuleVersion.Version -ilt $UpdateVersion)
|
||||
{
|
||||
Write-Verbose -Message ('Version {0} for {1} is availible in the PowerShell Galery' -f $UpdateVersion, $PowerShellModule)
|
||||
|
||||
if ($Update)
|
||||
{
|
||||
Write-Verbose -Message ('Start the update for {0} to version {1}' -f $PowerShellModule, $UpdateVersion)
|
||||
|
||||
try
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($PowerShellModule, 'Update'))
|
||||
{
|
||||
$paramInstallModule = @{
|
||||
Name = $PowerShellModule
|
||||
Repository = 'PSGallery'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
Scope = $Scope
|
||||
Force = $true
|
||||
AllowClobber = $true
|
||||
}
|
||||
$null = (Install-Module @paramInstallModule)
|
||||
}
|
||||
|
||||
Write-Verbose -Message ('Installed version {0} for {1}' -f $UpdateVersion, $PowerShellModule)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# Create the Info Object
|
||||
$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
|
||||
}
|
||||
|
||||
# Do some verbose stuff
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
Write-Warning -Message $e.Exception.Message
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('Version {0} for {1} is availible on the PowerShell Galery' -f $UpdateVersion, $PowerShellModule)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message ('No update found for {0}' -f $PowerShellModule)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# Create the Info Object
|
||||
$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
|
||||
}
|
||||
|
||||
# Do some verbose stuff
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
Write-Warning -Message $e.Exception.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# Create the Info Object
|
||||
$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
|
||||
}
|
||||
|
||||
# Do some verbose stuff
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message 'Done'
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,269 @@
|
||||
#requires -Version 3.0 -Modules @{ ModuleName="PowerShellGet"; ModuleVersion="2.0.0" } -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remove older versions of a installed PowerShell module
|
||||
|
||||
.DESCRIPTION
|
||||
Remove older versions of a installed PowerShell module
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-CleanupOldGalleryModuleVersions.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-CleanupOldGalleryModuleVersions.ps1 -Verbose
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-CleanupOldGalleryModuleVersions.ps1 -Verbose
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-CleanupOldGalleryModuleVersions.ps1 -debug
|
||||
|
||||
.NOTES
|
||||
This is a replacement for some older functions
|
||||
|
||||
.LINK
|
||||
Invoke-UpdateAllGalleryModules.ps1
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$STP = 'Stop'
|
||||
$CNT = 'Continue'
|
||||
$SCT = 'SilentlyContinue'
|
||||
#endregion Defaults
|
||||
|
||||
#region Cleanup
|
||||
$AllModules = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region BoundParameters
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$VerboseValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$VerboseValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$DebugValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$DebugValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['WhatIf']).IsPresent)
|
||||
{
|
||||
$WhatIfValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$WhatIfValue = $false
|
||||
}
|
||||
#endregion BoundParameters
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the Module information
|
||||
$paramGetModule = @{
|
||||
ListAvailable = $true
|
||||
Refresh = $true
|
||||
ErrorAction = $CNT
|
||||
WarningAction = $CNT
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$AllModules = (Get-Module @paramGetModule | Where-Object -FilterScript {
|
||||
$_.RepositorySourceLocation -like '*powershellgallery*'
|
||||
} | Select-Object -ExpandProperty Name)
|
||||
|
||||
$AllModules = ($AllModules | Sort-Object -Unique)
|
||||
|
||||
foreach ($ModuleName in $AllModules)
|
||||
{
|
||||
Write-Verbose -Message ('Get all existing versions of {0}' -f $ModuleName)
|
||||
|
||||
$AllModuleVersions = $null
|
||||
$AllModuleVersions = (Get-InstalledModule -Name $ModuleName -AllVersions -ErrorAction $SCT -WarningAction $CNT)
|
||||
|
||||
if (((($AllModuleVersions).Version).count) -gt 1)
|
||||
{
|
||||
$LatestModuleVersion = $null
|
||||
|
||||
$LatestModuleVersion = (($AllModuleVersions | Sort-Object -Property $AllModuleVersions.Version)[1])
|
||||
|
||||
try
|
||||
{
|
||||
$output = $null
|
||||
$output = ($AllModuleVersions | Where-Object {
|
||||
(($_.Version) -lt ($LatestModuleVersion.Version))
|
||||
} | ForEach-Object -Process {
|
||||
Write-Verbose -Message ('Start to process {0}' -f ($_).Name)
|
||||
|
||||
try
|
||||
{
|
||||
$paramUninstallModule = @{
|
||||
Name = $_
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
WhatIf = $WhatIfValue
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
Uninstall-Module @paramUninstallModule
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = $CNT
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Test-Path -Path $_.InstalledLocation -ErrorAction $SCT -WarningAction $SCT)
|
||||
{
|
||||
Write-Verbose -Message ('Try to remove {0}' -f ($_).InstalledLocation)
|
||||
|
||||
try
|
||||
{
|
||||
$paramRemoveItem = @{
|
||||
Path = $_.InstalledLocation
|
||||
Recurse = $true
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
WhatIf = $WhatIfValue
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
Remove-Item @paramRemoveItem
|
||||
|
||||
Write-Verbose -Message ('Removed {0}' -f ($_).InstalledLocation)
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = $STP
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose -Message ('Removed old versions off {0}' -f ($_).Name)
|
||||
})
|
||||
$output
|
||||
}
|
||||
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-Warning -Message ('Failed to process {0}' -f ($_).Name)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message ('Skip {0}' -f ($AllModuleVersions).Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
$AllModules = $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
|
||||
@@ -0,0 +1,302 @@
|
||||
#requires -Version 3.0 -Modules DnsClient
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Update CloudFlare DNS A Record if needed
|
||||
|
||||
.DESCRIPTION
|
||||
Update CloudFlare DNS A Record if needed
|
||||
|
||||
The prevent to much API calls, we use a regular DNS query first.
|
||||
Only if this query spot a difference, we ensure if an update is needed by ask the Cloudflare API for the latest published info.
|
||||
If there is stiff a difference, the cmdlet will update the entry for you.
|
||||
|
||||
If you use a new/unknown hostname in the CF_HOSTNAME parameter, the cmdlet will create a new entry for the given host!
|
||||
|
||||
.PARAMETER CF_TOKEN
|
||||
CloudFlare API Token
|
||||
|
||||
Hint: You can find your API key at: https://dash.cloudflare.com/profile/api-tokens
|
||||
|
||||
Create a dedicated Token just for this cmdlet and give it a name that indicate the purpose of it
|
||||
|
||||
The Token needs a least the following permission: Zone.Zone, Zone.DNS
|
||||
The token needs access to at least the Zone you want to update (Resources), or use 'All zones'
|
||||
|
||||
.PARAMETER CF_DOMAIN
|
||||
The CloudFlare DNS zone you want to modify
|
||||
|
||||
Example: contoso.com (this is also the default)
|
||||
|
||||
.PARAMETER CF_HOSTNAME
|
||||
This is the A record you'd like to update or add
|
||||
|
||||
Example: homelab (this is also the default)
|
||||
|
||||
Please Note: We support A Records only at this time!
|
||||
|
||||
.PARAMETER DNSServer
|
||||
Resolves hostname using DNS instead of checking CloudFlare.
|
||||
It is recommended to use the CloudFlare DNS Servers, e.g. 1.1.1.1
|
||||
You can use any other server, but mind that you might not see the changed IP until the Cache TTL expired on this Server!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-CloudFlareDDNSUpdate.ps1 -CF_TOKEN '<TOKEN>' -CF_DOMAIN 'contoso.com' -CF_HOSTNAME 'homelab'
|
||||
|
||||
Check and updates the host 'homelab' in the DNS Zone 'contoso.com'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-CloudFlareDDNSUpdate.ps1 -CF_TOKEN '<TOKEN>' -CF_DOMAIN 'contoso.com' -CF_HOSTNAME 'homelab' -Verbose
|
||||
|
||||
Check and updates the host 'homelab' in the DNS Zone 'contoso.com', but run in verbose mode
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-CloudFlareDDNSUpdate.ps1 -CF_TOKEN '<TOKEN>' -CF_DOMAIN 'contoso.com' -CF_HOSTNAME 'homelab' -DNSServer 1.0.0.1
|
||||
|
||||
Check and updates the host 'homelab' in the DNS Zone 'contoso.com', uses the backup CloudFlare DNS to get the published info
|
||||
|
||||
.LINK
|
||||
https://1.1.1.1/dns/
|
||||
|
||||
.NOTES
|
||||
We use a regular (cheap) DNS call to reduce the number of calls to CloudFlare (they allow 200 reqs/minute but why ask an API first?)
|
||||
|
||||
There is no output by the cmdlet, makes it easier if run a a service or schedules task. use the -Verbose switch to see what the cmdlet is doing
|
||||
|
||||
Please Note: We support A Records only at this time! We are already testing IPv6 (AAAA) and a few others.
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('CLOUDFLARE_TOKEN', 'CFAPIKey', 'Token')]
|
||||
[string]
|
||||
$CF_TOKEN = '<Your_Super_Secret_Token_Here>',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('CLOUDFLARE_Domain', 'CLOUDFLARE_DomainName', 'CFDomainName', 'Zone')]
|
||||
[string]
|
||||
$CF_DOMAIN = 'contoso.com',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('CFARecord', 'CLOUDFLARE_HOST', 'CLOUDFLARE_HOSTNAME')]
|
||||
[string]
|
||||
$CF_HOSTNAME = 'homelab',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('DNSToUse')]
|
||||
[string]
|
||||
$DNSServer = '1.1.1.1'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Cleanup
|
||||
$CF_KnownIP = $null
|
||||
$CF_ExternalIP = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region CheapRequests
|
||||
if (Get-Command -Name Resolve-DnsName -ErrorAction SilentlyContinue)
|
||||
{
|
||||
# Get the A record from the CloudFlare DNS (cheap request)
|
||||
$paramResolveDnsName = @{
|
||||
Name = ($CF_HOSTNAME + '.' + $CF_DOMAIN)
|
||||
Type = 'A'
|
||||
Server = $DNSServer
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
[string]$CF_KnownIP = (((Resolve-DnsName @paramResolveDnsName) | Select-Object -ExpandProperty IPAddress).Trim())
|
||||
}
|
||||
elseif (Get-Command -Name dig -ErrorAction SilentlyContinue)
|
||||
{
|
||||
# This is the Fallback on macOS, due to the missing DnsClient module on PowerShell core here
|
||||
[string]$CF_KnownIP = (((dig A ($CF_HOSTNAME + '.' + $CF_DOMAIN) ('@' + $DNSServer) +short)).Trim())
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'Unable to lookup the DNS entry, we try to use the CloudFlare API' -WarningAction Continue
|
||||
|
||||
# Set a dummy (to prevent any null pointer exception during the compare)
|
||||
[string]$CF_KnownIP = '0.0.0.0'
|
||||
}
|
||||
|
||||
# Get the external IP via Web Request from our own service (cheap request)
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'Get'
|
||||
UseBasicParsing = $true
|
||||
Uri = 'https://ip.enatec.net'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
[string]$CF_ExternalIP = ((Invoke-RestMethod @paramInvokeRestMethod).Trim())
|
||||
#endregion CheapRequests
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Compare the two values
|
||||
if ($CF_ExternalIP -ne $CF_KnownIP)
|
||||
{
|
||||
# Looks like there is a Difference
|
||||
|
||||
# Only the V4 API is supported by the cmdlet yet!
|
||||
$CF_API_ENDPOINT = $null
|
||||
$CF_API_ENDPOINT = 'https://api.cloudflare.com/client/v4'
|
||||
|
||||
$CF_Headers = $null
|
||||
$CF_Headers = @{
|
||||
'Authorization' = ('Bearer ' + $CF_TOKEN)
|
||||
'Content-Type' = 'application/json'
|
||||
}
|
||||
|
||||
$CF_ZoneURI = $null
|
||||
$CF_ZoneURI = ($CF_API_ENDPOINT + '/zones?name=' + $CF_DOMAIN)
|
||||
|
||||
Write-Verbose -Message ('Getting DNS-Zone ID for ' + $($CF_DOMAIN) + ' via ' + $CF_ZoneURI)
|
||||
|
||||
# Let us get the Zone Info directly from CloudFlare (API Request)
|
||||
$CF_ZoneId = $null
|
||||
$paramInvokeRestMethod = @{
|
||||
Uri = $CF_ZoneURI
|
||||
ContentType = 'application/json'
|
||||
Headers = $CF_Headers
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$CF_ZoneId = (((Invoke-RestMethod @paramInvokeRestMethod).result).id)
|
||||
|
||||
$CF_DNSURI = $null
|
||||
$CF_DNSURI = ($CF_API_ENDPOINT + '/zones/' + $CF_ZoneId + '/dns_records?type=A&name=' + $CF_HOSTNAME + '.' + $CF_DOMAIN)
|
||||
|
||||
Write-Verbose -Message ('Getting DNS data for ' + $($CF_HOSTNAME).$($CF_DOMAIN) + ' via ' + $CF_DNSURI)
|
||||
|
||||
# Let us get the host Info directly from CloudFlare (API Request)
|
||||
$CF_DNSData = $null
|
||||
$paramInvokeRestMethod = @{
|
||||
Uri = $CF_DNSURI
|
||||
ContentType = 'application/json'
|
||||
Headers = $CF_Headers
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$CF_DNSData = ((Invoke-RestMethod @paramInvokeRestMethod).result)
|
||||
|
||||
# Compare again (Double check)
|
||||
if ($CF_ExternalIP -ne $CF_DNSData.content)
|
||||
{
|
||||
# OK, we are sure that there is a new IP!
|
||||
Write-Verbose -Message 'IP address change detected, we will try to update the CloudFlare DNS'
|
||||
|
||||
try
|
||||
{
|
||||
$CF_Body = $null
|
||||
$CF_Body = @{
|
||||
'type' = 'A'
|
||||
'name' = ($CF_HOSTNAME + '.' + $CF_DOMAIN)
|
||||
'content' = $CF_ExternalIP
|
||||
'ttl' = '1'
|
||||
}
|
||||
|
||||
$URI_Update = $null
|
||||
$URI_Update = ($CF_API_ENDPOINT + '/zones/' + $CF_ZoneId + '/dns_records/' + $($CF_DNSData.id))
|
||||
|
||||
# Apply the new IP address to the CloudFlare DNS
|
||||
$CF_Result = $null
|
||||
$paramInvokeRestMethod = @{
|
||||
Uri = $URI_Update
|
||||
Method = 'Put'
|
||||
ContentType = 'application/json'
|
||||
Headers = $CF_Headers
|
||||
Body = $
|
||||
WebSession = ($CF_Body | ConvertTo-Json)
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$CF_Result = ((Invoke-RestMethod @paramInvokeRestMethod).result)
|
||||
|
||||
if ($CF_Result.content -eq $CF_ExternalIP)
|
||||
{
|
||||
Write-Verbose -Message 'SUCCESS: CloudFlare DNS was successfully updated'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'FAILED: CloudFlare DNS was not successfully updated'
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Just in case
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'CloudFlare: No update is needed'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'DNS: No update is needed'
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,159 @@
|
||||
function Invoke-DSCPerfReqConfigCheck
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Perform Required Configuration Checks and suppress all outputs.
|
||||
|
||||
.DESCRIPTION
|
||||
Run the DSCLocalConfigurationManager method PerformRequiredConfigurationChecks.
|
||||
|
||||
.PARAMETER Silent
|
||||
The progress bar will be suppressed. this is not the case by default.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-DSCPerfReqConfigCheck
|
||||
True
|
||||
|
||||
# Run without any error
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-DSCPerfReqConfigCheck -Silent
|
||||
True
|
||||
|
||||
# Run without any error. Suppress the progress bar.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-DSCPerfReqConfigCheck
|
||||
False
|
||||
|
||||
# The run had errors.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Invoke-DSCPerfReqConfigCheck -Silent
|
||||
False
|
||||
|
||||
# The run had errors. Suppress the progress bar.
|
||||
|
||||
.NOTES
|
||||
I do a lot of testing with several DSC configurations.
|
||||
I just want a TRUE or FALSE as return to see if its working, or not.
|
||||
You may guess why: I use this in a CI chain :-)
|
||||
|
||||
You may want to have separated EventLog entries for DSC (useful for the log-Resource):
|
||||
& "$env:windir\system32\wevtutil.exe" set-log 'Microsoft-Windows-Dsc/Analytic' /q:true /e:true
|
||||
& "$env:windir\system32\wevtutil.exe" set-log 'Microsoft-Windows-Dsc/Debug' /q:True /e:true
|
||||
|
||||
I dedicate any and all copyright interest in this software to the public domain.
|
||||
I make this dedication for the benefit of the public at large and to the detriment of my heirs and successors.
|
||||
I intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
|
||||
|
||||
.LINK
|
||||
Author http://jhochwald.com
|
||||
|
||||
.LINK
|
||||
LICENSE http://unlicense.org
|
||||
|
||||
.LINK
|
||||
Invoke-CimMethod
|
||||
Write-Verbose
|
||||
Get-WinEvent
|
||||
#>
|
||||
[OutputType([bool])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
Position = 1)]
|
||||
[switch]
|
||||
$Silent = $null
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$SC = 'SilentlyContinue'
|
||||
|
||||
if ($Silent)
|
||||
{
|
||||
$ProgressPreference = $SC
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$InvokeCimMethodParams = @{
|
||||
Namespace = 'root/Microsoft/Windows/DesiredStateConfiguration'
|
||||
ClassName = 'MSFT_DSCLocalConfigurationManager'
|
||||
MethodName = 'PerformRequiredConfigurationChecks'
|
||||
Arguments = @{
|
||||
Flags = [uint32] 1
|
||||
}
|
||||
ErrorAction = $SC
|
||||
WarningAction = $SC
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$null = (Invoke-CimMethod @InvokeCimMethodParams)
|
||||
|
||||
if ($Silent)
|
||||
{
|
||||
$ProgressPreference = $null
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
$paramWriteVerbose = @{
|
||||
Message = "$_.Exception.Message - Line Number: $_.InvocationInfo.ScriptLineNumber"
|
||||
ErrorAction = $SC
|
||||
WarningAction = $SC
|
||||
}
|
||||
Write-Verbose @paramWriteVerbose
|
||||
}
|
||||
|
||||
$GetWinEventParams = @{
|
||||
LogName = 'Microsoft-Windows-Dsc/*'
|
||||
ErrorAction = $SC
|
||||
WarningAction = $SC
|
||||
Oldest = $true
|
||||
}
|
||||
|
||||
# TODO: That is fast, but the code looks bad!
|
||||
$SuccessResult = (Get-WinEvent @GetWinEventParams | Group-Object -Property {
|
||||
$_.Properties[0].value
|
||||
}).Group.LevelDisplayName -notcontains 'Error'
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
return $SuccessResult
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,315 @@
|
||||
#requires -Version 3.0 -Modules @{ ModuleName="PowerShellGet"; ModuleVersion="2.0.0" } -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Update all PowerShell Modules to the latest PowerShell Gallery version
|
||||
|
||||
.DESCRIPTION
|
||||
Update all PowerShell Modules to the latest PowerShell Gallery version
|
||||
|
||||
.PARAMETER Silent
|
||||
Hide the PowerShell Progress Bars
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-UpdateAllGalleryModules.ps1
|
||||
Update all PowerShell Modules to the latest PowerShell Gallery version
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-UpdateAllGalleryModules.ps1 -Silent
|
||||
|
||||
Update all PowerShell Modules to the latest PowerShell Gallery version and hide the PowerShell Progress Bars
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-UpdateAllGalleryModules.ps1 -WhatIf
|
||||
|
||||
Dry run the update all PowerShell Modules to the latest PowerShell Gallery version
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-UpdateAllGalleryModules.ps1 -verbose
|
||||
|
||||
Update all PowerShell Modules to the latest PowerShell Gallery version in verbose mode
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-UpdateAllGalleryModules.ps1 -verbose
|
||||
|
||||
Update all PowerShell Modules to the latest PowerShell Gallery version in debug mode
|
||||
|
||||
.NOTES
|
||||
This is a replacement for some older functions
|
||||
|
||||
.LINK
|
||||
Invoke-CleanupOldGalleryModuleVersions.ps1
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('NoProgressBars')]
|
||||
[switch]
|
||||
$Silent
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$STP = 'Stop'
|
||||
$CNT = 'Continue'
|
||||
$SCT = 'SilentlyContinue'
|
||||
#endregion Defaults
|
||||
|
||||
#region Cleanup
|
||||
$OriginalProgressPreference = $null
|
||||
$AllModules = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region BoundParameters
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$VerboseValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$VerboseValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$DebugValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$DebugValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['WhatIf']).IsPresent)
|
||||
{
|
||||
$WhatIfValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$WhatIfValue = $false
|
||||
}
|
||||
#endregion BoundParameters
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Silent']).IsPresent)
|
||||
{
|
||||
# Save the original value
|
||||
$OriginalProgressPreference = $ProgressPreference
|
||||
|
||||
# Silence is golden...
|
||||
$ProgressPreference = $SCT
|
||||
}
|
||||
|
||||
# Get the Module information
|
||||
$paramGetModule = @{
|
||||
ListAvailable = $true
|
||||
Refresh = $true
|
||||
ErrorAction = $CNT
|
||||
WarningAction = $CNT
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$AllModules = (Get-Module @paramGetModule | Where-Object -FilterScript {
|
||||
$_.RepositorySourceLocation -like '*powershellgallery*'
|
||||
} | Select-Object -Property Name, Version, Path)
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
foreach ($SingleModule in $AllModules)
|
||||
{
|
||||
# Cleanup
|
||||
$RepositoryInfo = $null
|
||||
|
||||
<#
|
||||
The AllowPrerelease is needed here
|
||||
Find-Module ignored the ErrorAction setting, try/catch will not work
|
||||
#>
|
||||
$paramFindModule = @{
|
||||
Name = (($SingleModule).Name)
|
||||
Repository = 'PSGallery'
|
||||
AllowPrerelease = $true
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $CNT
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$RepositoryInfo = (Find-Module @paramFindModule | Select-Object -Property Name, Version)
|
||||
|
||||
#region CleanVersions
|
||||
<#
|
||||
Remove everything from the version string that violates the System.Version class
|
||||
https://docs.microsoft.com/en-us/dotnet/api/system.version
|
||||
|
||||
e.g. -beta4 or -preview
|
||||
#>
|
||||
# Character that we use as a slipt
|
||||
$SlipPointer = '-'
|
||||
|
||||
# Create the Wildcard to search for
|
||||
$SplitSearch = ('*' + $SlipPointer + '*')
|
||||
|
||||
if (($SingleModule.Version) -like $SplitSearch)
|
||||
{
|
||||
$SingleModule.Version = (($SingleModule.Version).split($SlipPointer)[0])
|
||||
}
|
||||
|
||||
if (($RepositoryInfo.Version) -like $SplitSearch)
|
||||
{
|
||||
$RepositoryInfo.Version = (($RepositoryInfo.Version).split($SlipPointer)[0])
|
||||
}
|
||||
#endregion CleanVersions
|
||||
|
||||
# Is the online version newer?
|
||||
if ((($SingleModule).Version) -lt (($RepositoryInfo).Version))
|
||||
{
|
||||
# Cleanup
|
||||
$ModuleScope = $null
|
||||
|
||||
# try to figure out the scope
|
||||
if ((($SingleModule).Path) -like ($env:ProgramW6432 + '\*'))
|
||||
{
|
||||
$ModuleScope = 'AllUsers'
|
||||
}
|
||||
else
|
||||
{
|
||||
$ModuleScope = 'CurrentUser'
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Try to update {0}' -f ($SingleModule).Name)
|
||||
|
||||
# Cleanup
|
||||
$paramUpdateModule = $null
|
||||
|
||||
# Try the Update
|
||||
$paramUpdateModule = @{
|
||||
Name = (($SingleModule).Name)
|
||||
Scope = $ModuleScope
|
||||
Force = $true
|
||||
AcceptLicense = $true
|
||||
Confirm = $false
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
WhatIf = $WhatIfValue
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$null = (Update-Module @paramUpdateModule)
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
# 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-Verbose -Message ('Retry to update {0}' -f ($SingleModule).Name)
|
||||
|
||||
# Cleanup
|
||||
$paramUpdateModule = $null
|
||||
|
||||
# Re-Try the update by allowing prereleases
|
||||
$paramUpdateModule = @{
|
||||
Name = (($SingleModule).Name)
|
||||
AllowPrerelease = $true
|
||||
Scope = $ModuleScope
|
||||
Force = $true
|
||||
AcceptLicense = $true
|
||||
Confirm = $false
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
WhatIf = $WhatIfValue
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$null = (Update-Module @paramUpdateModule)
|
||||
}
|
||||
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-Warning -Message ('Update of {0} failed' -f ($SingleModule).Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message ('No update for {0} found' -f ($SingleModule).Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
if ($OriginalProgressPreference)
|
||||
{
|
||||
# Restore the old value
|
||||
$ProgressPreference = $OriginalProgressPreference
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$AllModules = $null
|
||||
|
||||
# Have a great day!
|
||||
}
|
||||
|
||||
#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
|
||||
29
Powershell/PowerShell-collection/Misc/LICENSE
Normal file
29
Powershell/PowerShell-collection/Misc/LICENSE
Normal 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.
|
||||
@@ -0,0 +1,311 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Apply the Defender exclusions based on recommendations by Microsoft
|
||||
|
||||
.DESCRIPTION
|
||||
Apply the Defender exclusions based on recommendations by Microsoft
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Optimize-MicrosoftDefenderExclusions.ps1
|
||||
|
||||
.NOTES
|
||||
Do not just use set-mppreference here, this might remove any existing exclusions.
|
||||
Might be the right thing to do, but with add-mppreference you append to the list (if exists).
|
||||
|
||||
.LINK
|
||||
https://support.microsoft.com/en-ie/help/822158/virus-scanning-recommendations-for-enterprise-computers-that-are-runni
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/defender/add-mppreference
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
#region DefaultExclusions
|
||||
$ExcludePathList = @(
|
||||
"$env:windir\SoftwareDistribution\DataStore\Datastore.edb",
|
||||
"$env:windir\SoftwareDistribution\DataStore\Logs\Edb*.jrs",
|
||||
"$env:windir\SoftwareDistribution\DataStore\Logs\Edb.chk",
|
||||
"$env:windir\SoftwareDistribution\DataStore\Logs\Tmp.edb",
|
||||
"$env:windir\Security\Database\*.edb",
|
||||
"$env:windir\Security\Database\*.sdb",
|
||||
"$env:windir\Security\Database\*.log",
|
||||
"$env:windir\Security\Database\*.chk",
|
||||
"$env:windir\Security\Database\*.jrs",
|
||||
"$env:windir\Security\Database\*.xml",
|
||||
"$env:windir\Security\Database\*.csv",
|
||||
"$env:windir\Security\Database\*.cmtx",
|
||||
"$env:ProgramData\ntuser.pol",
|
||||
"$env:windir\System32\GroupPolicy\Machine\Registry.pol",
|
||||
"$env:windir\System32\GroupPolicy\Machine\Registry.tmp",
|
||||
"$env:windir\System32\GroupPolicy\User\Registry.pol",
|
||||
"$env:windir\System32\GroupPolicy\User\Registry.tmp"
|
||||
)
|
||||
#endregion DefaultExclusions
|
||||
|
||||
#region AdExclusions
|
||||
# Turn off scanning of Active Directory and Active Directory-related files
|
||||
|
||||
# Exclude the Main NTDS database files.
|
||||
$DSADatabaseFile = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters'
|
||||
$DSADatabaseFilePath = ('Registry::' + $DSADatabaseFile)
|
||||
if (Test-Path -Path $DSADatabaseFilePath)
|
||||
{
|
||||
$DSADatabaseFileValue = (Get-ItemProperty -Path $DSADatabaseFilePath | Select-Object -ExpandProperty 'DSA Database file' -ErrorAction SilentlyContinue)
|
||||
if ($DSADatabaseFileValue)
|
||||
{
|
||||
$ExcludePathList += ($DSADatabaseFileValue)
|
||||
$ExcludePathList += ($DSADatabaseFileValue).Replace('.dit', '.pat')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No NTDS database files to exclude'
|
||||
}
|
||||
|
||||
# Exclude the Active Directory transaction log files.
|
||||
$DatabaseLogFiles = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters'
|
||||
$DatabaseLogFilesPath = ('Registry::' + $DatabaseLogFiles)
|
||||
if (Test-Path -Path $DatabaseLogFilesPath)
|
||||
{
|
||||
$DatabaseLogFilesPathValue = (Get-ItemProperty -Path $DatabaseLogFilesPath | Select-Object -ExpandProperty 'Database Log Files Path' -ErrorAction SilentlyContinue)
|
||||
if ($DatabaseLogFilesPathValue)
|
||||
{
|
||||
$ExcludePathList += ($DatabaseLogFilesPathValue + '\EDB*.log')
|
||||
$ExcludePathList += ($DatabaseLogFilesPathValue + '\Res*.log')
|
||||
$ExcludePathList += ($DatabaseLogFilesPathValue + '\Edb*.jrs')
|
||||
$ExcludePathList += ($DatabaseLogFilesPathValue + '\Ntds.pat')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No Active Directory transaction log files to exclude'
|
||||
}
|
||||
|
||||
# Exclude the files in the NTDS Working folder
|
||||
$DSAWorkingDir = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters'
|
||||
$DSAWorkingDirPath = ('Registry::' + $DSAWorkingDir)
|
||||
if (Test-Path -Path $DSAWorkingDirPath)
|
||||
{
|
||||
$DSAWorkingDirValue = (Get-ItemProperty -Path $DSAWorkingDirPath | Select-Object -ExpandProperty 'DSA Working Directory' -ErrorAction SilentlyContinue)
|
||||
if ($DSAWorkingDirValue)
|
||||
{
|
||||
$ExcludePathList += ($DSAWorkingDirValue + '\Temp.edb')
|
||||
$ExcludePathList += ($DSAWorkingDirValue + '\Edb.chk')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No NTDS Working folder to exclude'
|
||||
}
|
||||
#endregion AdExclusions
|
||||
|
||||
#region SysVolExclusions
|
||||
# Turn off scanning of SYSVOL files
|
||||
|
||||
# Turn off scanning of files in the File Replication Service (FRS) Working folder
|
||||
$SysVolWorkingDir = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NtFrs\Parameters'
|
||||
$SysVolWorkingDirPath = ('Registry::' + $SysVolWorkingDir)
|
||||
if (Test-Path -Path $SysVolWorkingDirPath)
|
||||
{
|
||||
$SysVolWorkingDirValue = (Get-ItemProperty -Path $SysVolWorkingDirPath | Select-Object -ExpandProperty 'Working Directory' -ErrorAction SilentlyContinue)
|
||||
if ($SysVolWorkingDirValue)
|
||||
{
|
||||
$ExcludePathList += ($SysVolWorkingDirValue + '\jet\sys\edb.chk')
|
||||
$ExcludePathList += ($SysVolWorkingDirValue + '\jet\Ntfrs.jdb')
|
||||
$ExcludePathList += ($SysVolWorkingDirValue + '\jet\log\*.log')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No File Replication Service Working folder to exclude'
|
||||
}
|
||||
|
||||
# Turn off scanning of files in the File Replication Service Database Log files
|
||||
$SysVolDBLogFileDir = 'HKEY_LOCAL_MACHINE\SYSTEM\Currentcontrolset\Services\Ntfrs\Parameters'
|
||||
$SysVolDBLogFileDirPath = ('Registry::' + $SysVolDBLogFileDir)
|
||||
if (Test-Path -Path $SysVolDBLogFileDirPath)
|
||||
{
|
||||
$SysVolDBLogFileDirValue = (Get-ItemProperty -Path $SysVolWorkingDirPath | Select-Object -ExpandProperty 'Working Directory' -ErrorAction SilentlyContinue)
|
||||
if ($SysVolDBLogFileDirValue)
|
||||
{
|
||||
$ExcludePathList += ($SysVolDBLogFileDirValue + '\Jet\Log\Edb*.jrs')
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($SysVolWorkingDirValue)
|
||||
{
|
||||
$ExcludePathList += ($SysVolWorkingDirValue + '\jet\Log\Edb*.log')
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No File Replication Service Database Log files to exclude'
|
||||
}
|
||||
#endregion SysVolExclusions
|
||||
|
||||
#region DhcpExclusions
|
||||
# Turn off scanning of DHCP files
|
||||
$DhcpFiles = 'HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\DHCPServer\Parameters'
|
||||
$DhcpFilesPath = ('Registry::' + $DhcpFiles)
|
||||
if (Test-Path -Path $DhcpFilesPath)
|
||||
{
|
||||
$DhcpDatabasePathValue = (Get-ItemProperty -Path $DhcpFilesPath | Select-Object -ExpandProperty 'DatabasePath' -ErrorAction SilentlyContinue)
|
||||
if ($DhcpDatabasePathValue)
|
||||
{
|
||||
$ExcludePathList += ($DhcpDatabasePathValue + '\*.mdb')
|
||||
$ExcludePathList += ($DhcpDatabasePathValue + '\*.pat')
|
||||
$ExcludePathList += ($DhcpDatabasePathValue + '\*.chk')
|
||||
$ExcludePathList += ($DhcpDatabasePathValue + '\*.edb')
|
||||
}
|
||||
|
||||
$DhcpLogFilePathValue = (Get-ItemProperty -Path $DhcpFilesPath | Select-Object -ExpandProperty 'DhcpLogFilePath' -ErrorAction SilentlyContinue)
|
||||
if (($DhcpLogFilePathValue) -and ($DhcpLogFilePathValue -ne $DhcpDatabasePathValue))
|
||||
{
|
||||
$ExcludePathList += ($DhcpLogFilePathValue + '\*.log')
|
||||
}
|
||||
else
|
||||
{
|
||||
$ExcludePathList += ($DhcpDatabasePathValue + '\*.log')
|
||||
}
|
||||
|
||||
$DhcpBackupDatabasePathValue = (Get-ItemProperty -Path $DhcpFilesPath | Select-Object -ExpandProperty 'BackupDatabasePath' -ErrorAction SilentlyContinue)
|
||||
if ($DhcpBackupDatabasePathValue)
|
||||
{
|
||||
$ExcludePathList += ($DhcpBackupDatabasePathValue + '\new\*.mdb')
|
||||
$ExcludePathList += ($DhcpBackupDatabasePathValue + '\new\*.pat')
|
||||
$ExcludePathList += ($DhcpBackupDatabasePathValue + '\new\*.chk')
|
||||
$ExcludePathList += ($DhcpBackupDatabasePathValue + '\new\*.edb')
|
||||
$ExcludePathList += ($DhcpBackupDatabasePathValue + '\new\*.log')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No DHCP Server Directory found'
|
||||
}
|
||||
#endregion DhcpExclusions
|
||||
|
||||
#region DnsExclusions
|
||||
$DnsServerDir = "$env:windir\System32\dns"
|
||||
if (Test-Path -Path $DnsServerDir -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$ExcludePathList += ($DnsServerDir + '\*.log')
|
||||
$ExcludePathList += ($DnsServerDir + '\*.dns')
|
||||
$ExcludePathList += ($DnsServerDir + '\BOOT')
|
||||
|
||||
$DnsBackupServerDir = ($DnsServerDir + '\backup')
|
||||
if (Test-Path -Path $DnsBackupServerDir -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$ExcludePathList += ($DnsBackupServerDir + '\*.log')
|
||||
$ExcludePathList += ($DnsBackupServerDir + '\*.dns')
|
||||
$ExcludePathList += ($DnsBackupServerDir + '\BOOT')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No DNS Server Directory found'
|
||||
}
|
||||
#endregion DnsExclusions
|
||||
|
||||
#region WinsExclusions
|
||||
$WinsServerDir = "$env:windir\System32\Wins"
|
||||
if (Test-Path -Path $WinsServerDir -ErrorAction SilentlyContinue)
|
||||
{
|
||||
Write-Warning -Message 'WINS is still installed on this system!' -WarningAction Continue
|
||||
|
||||
$ExcludePathList += ($WinsServerDir + '\*.chk')
|
||||
$ExcludePathList += ($WinsServerDir + '\*.log')
|
||||
$ExcludePathList += ($WinsServerDir + '\*.mdb')
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No WINS Server Directory found'
|
||||
}
|
||||
#endregion WinsExclusions
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($ExcludePathList, 'Exclude from Microsoft Defender Scanning'))
|
||||
{
|
||||
# Loop over the list we created
|
||||
foreach ($ExcludePath in $ExcludePathList)
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters for Add-MpPreference
|
||||
$SplatAddMpPreference = @{
|
||||
ExclusionPath = $ExcludePath
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$null = (Add-MpPreference @SplatAddMpPreference)
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# Error Stack
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
# Just display the info on continue with the rest of the list
|
||||
Write-Warning -Message ($info.Exception) -ErrorAction Continue -WarningAction Continue
|
||||
|
||||
# Cleanup
|
||||
$info = $null
|
||||
$e = $null
|
||||
#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
|
||||
@@ -0,0 +1,133 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Add Defender Antivirus Exclusions for the Teams Desktop Client for a given User
|
||||
|
||||
.DESCRIPTION
|
||||
Add Defender Antivirus Exclusions for the Teams Desktop Client for a given User
|
||||
|
||||
.PARAMETER Username
|
||||
Username to apply the exclusion to.
|
||||
Please Note: The user 'john.doe' in the domain 'CONTOSO' will have the username 'john.doe.CONTOSO'. This is the case to have the connect Directory (Windows naming convention).
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Optimize-MicrosoftDefenderExclusionsForMicrosoftTeams.ps1 -Username 'john.doe.CONTOSO'
|
||||
|
||||
Apply the Defender Antivirus Exclusions for the user 'john.doe' in the domain 'CONTOSO'.
|
||||
In this case, the $env:USERPROFILE Directory will be 'C:\Users\john.doe.CONTOSO'
|
||||
|
||||
.NOTES
|
||||
This is a more flexible version of Add-DefenderExclusionsForMicrosoftteams.ps1 that brings username as a parameter.
|
||||
I crerated this because my user does NOT have Admin permissions on my local windows boxes and with this version, I can apply it with my admin account, biut for my regular user (or any other user on the local system)
|
||||
|
||||
Do not just use set-mppreference here, this might remove any existing exclusions.
|
||||
Might be the right thing to do, but with add-mppreference you append to the list (if exists).
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/jhochwald/866ce1c5ac894397979f38fa9720b8ff
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/defender/add-mppreference
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Username to apply the exclusion to.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('User', 'Name')]
|
||||
[string]
|
||||
$Username
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$ExcludePathList = @(
|
||||
('C:\Users\' + $Username + '\Microsoft\Teams\Update.exe'),
|
||||
('C:\Users\' + $Username + '\Microsoft\Teams\current\Teams.exe'),
|
||||
('C:\Users\' + $Username + '\Microsoft\Teams\'),
|
||||
('C:\Users\' + $Username + '\Microsoft\Teams\')
|
||||
)
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Loop over the list we created
|
||||
foreach ($ExcludePath in $ExcludePathList)
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters for Add-MpPreference
|
||||
$SplatAddMpPreference = @{
|
||||
ExclusionPath = $ExcludePath
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$null = (Add-MpPreference @SplatAddMpPreference)
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = @{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# Error Stack
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
# Just display the info on continue with the rest of the list
|
||||
Write-Warning -Message ($info.Exception) -ErrorAction Continue -WarningAction Continue
|
||||
|
||||
# Cleanup
|
||||
$info = $null
|
||||
$e = $null
|
||||
#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
|
||||
229
Powershell/PowerShell-collection/Misc/Out-ZipArchive.ps1
Normal file
229
Powershell/PowerShell-collection/Misc/Out-ZipArchive.ps1
Normal file
@@ -0,0 +1,229 @@
|
||||
function Out-ZipArchive
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates a ZIP Archive
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a ZIP Archive with all given Files (and subdirectories)
|
||||
|
||||
.PARAMETER Path
|
||||
Input Path
|
||||
|
||||
.PARAMETER ArchiveName
|
||||
Name of the archive to create.
|
||||
|
||||
.PARAMETER force
|
||||
Enforce overwrite?
|
||||
|
||||
.PARAMETER fallback
|
||||
Use Microsoft .NET Framework API instead of Compress-Archive (Bundled with PowerShell 5.0, or later)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Out-ZipArchive -Path 'Value1' -ArchiveName 'Value2'
|
||||
|
||||
Creates a ZIP Archive with all given Files (and subdirectories)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Out-ZipArchive -Path 'Value1' -ArchiveName 'Value2' -fallback
|
||||
|
||||
Creates a ZIP Archive with all given Files (and subdirectories) - Use .NET Framework API instead of Compress-Archive internal
|
||||
|
||||
.NOTES
|
||||
We now use Compress-Archive by default. It is build upon the Microsoft .NET Framework API System.IO.Compression.ZipArchive and has the same limitation.
|
||||
|
||||
.LINK
|
||||
Compress-Archive
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/compress-archive
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true,
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
Position = 0,
|
||||
HelpMessage = 'Input Path')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Directory')]
|
||||
[string]
|
||||
$Path,
|
||||
[Parameter(Mandatory = $true,
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
Position = 1,
|
||||
HelpMessage = 'Name of the archive to create')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('FileName')]
|
||||
[string]
|
||||
$ArchiveName,
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
Position = 2)]
|
||||
[Alias('overwrite')]
|
||||
[switch]
|
||||
$force,
|
||||
[Parameter(ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
Position = 3)]
|
||||
[Alias('dotnet')]
|
||||
[switch]
|
||||
$fallback = $false
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$null = (Add-Type -AssemblyName System.IO.Compression.FileSystem)
|
||||
|
||||
$compressionLevel = [IO.Compression.CompressionLevel]::Optimal
|
||||
|
||||
Write-Verbose -Message "Compression level for $ArchiveName is $compressionLevel"
|
||||
|
||||
# Safe ProgressPreference and Setup SilentlyContinue for the function
|
||||
$ExistingProgressPreference = ($ProgressPreference)
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
|
||||
if (-not $ArchiveName.EndsWith('.zip'))
|
||||
{
|
||||
Write-Verbose -Message "Bad filename detected $ArchiveName"
|
||||
|
||||
$ArchiveName += '.zip'
|
||||
|
||||
Write-Verbose -Message "Corrected filename is $ArchiveName"
|
||||
}
|
||||
|
||||
if ($force)
|
||||
{
|
||||
if (Test-Path -Path $ArchiveName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue)
|
||||
{
|
||||
Write-Verbose -Message "Overwrite old archive $ArchiveName"
|
||||
|
||||
try
|
||||
{
|
||||
$paramRemoveItem = @{
|
||||
Path = $ArchiveName
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$null = (Remove-Item @paramRemoveItem)
|
||||
}
|
||||
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 ($info.Exception) -TargetObject ($info.Target) -ErrorAction Stop
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message "Try to create archive $ArchiveName"
|
||||
|
||||
if ($fallback)
|
||||
{
|
||||
Write-Verbose -Message 'Run in fallback mode and using System.IO.Compression.ZipArchive instead of Compress-Archive'
|
||||
$zip = ([IO.Compression.ZipFile]::CreateFromDirectory($Path, $ArchiveName, $compressionLevel, $false))
|
||||
# And always make sure to close the locks on that file
|
||||
$zip.Dispose()
|
||||
}
|
||||
else
|
||||
{
|
||||
$paramCompressArchive = @{
|
||||
Path = $Path
|
||||
CompressionLevel = $compressionLevel
|
||||
DestinationPath = $ArchiveName
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Compress-Archive @paramCompressArchive)
|
||||
}
|
||||
|
||||
Write-Verbose -Message "Archive $ArchiveName was created"
|
||||
}
|
||||
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 ($info.Exception) -TargetObject ($info.Target) -ErrorAction Stop
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Restore ProgressPreference
|
||||
$ProgressPreference = $ExistingProgressPreference
|
||||
|
||||
Write-Verbose -Message 'Out-ZipArchive done'
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,245 @@
|
||||
function Publish-BitbucketDownload
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Upload given file to BitBucket cloud service downloads section.
|
||||
|
||||
.DESCRIPTION
|
||||
Upload given file to BitBucket cloud service downloads section.
|
||||
I use this to upload build artifacts to the BitBucket Download section.
|
||||
|
||||
The code might not be perfect, and we still use the AUTH Header instead of OAuth yet,
|
||||
but I needed a quick and dirty solution to get things going.
|
||||
|
||||
I might change a few things soon, but for now; this function is doing what it should.
|
||||
|
||||
.PARAMETER username
|
||||
BitBucket cloud username, as plain text
|
||||
|
||||
.PARAMETER password
|
||||
BitBucket cloud password, as plain text
|
||||
|
||||
.PARAMETER FilePath
|
||||
File to upload, full path needed
|
||||
|
||||
.PARAMETER team
|
||||
BitBucket cloud team aka username (Might not be the login username!!!)
|
||||
|
||||
.PARAMETER Project
|
||||
BitBucket cloud project name
|
||||
|
||||
.EXAMPLE
|
||||
PS ~> Publish-BitbucketDownload -username 'MyUsername' -password 'MySectretPassword' -FilePath 'Y:\dev\release\myproject-current.zip' -team 'dummyTeam' -Project 'myproject'
|
||||
|
||||
# Upload the artifact 'Y:\dev\release\myproject-current.zip' to the Download sections of the 'myproject' project of the 'dummyTeam', It uses User name and password (Both in plain ASC) to authenticate. However, both are converted to base64 to prevent any clear text header transfers.
|
||||
|
||||
.EXAMPLE
|
||||
PS ~> Publish-BitbucketDownload -username 'MyUsername' -password 'MySectretPassword' -FilePath 'Y:\dev\release\myproject.nuget' -team 'dummyTeam' -Project 'myproject'
|
||||
|
||||
# Upload the artifact 'Y:\dev\release\myproject.nuget' to the Download sections of the 'myproject' project of the 'dummyTeam', It uses Username and password (Both in plain ASC) to authenticate. However, both are converted to base64 to prevent any clear text header transfers.
|
||||
|
||||
.NOTES
|
||||
I created this because I did not have CURL installed on my build system.
|
||||
|
||||
With Curl this is an absolute no brainer:
|
||||
curl -X POST "https://MyUsername:MySectretPassword@api.bitbucket.org/2.0/repositories/dummyTeam/myproject/downloads" --form files=@"/home/dev/release\myproject-current.zip"
|
||||
|
||||
INFO: Max. CPU: 16 % Max. Memory: 28.48 MB
|
||||
|
||||
TODO: Convert the request to use OAuth ASAP
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
HelpMessage = 'BitBucket cloud username, as plain text')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('user')]
|
||||
[string]
|
||||
$username,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
HelpMessage = 'BitBucket cloud password, as plain text')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('pass')]
|
||||
[string]
|
||||
$password,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
HelpMessage = 'File to upload, full path needed')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$FilePath,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
HelpMessage = 'BitBucket cloud team name')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$team,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
HelpMessage = 'BitBucket cloud project name')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('ProjectName')]
|
||||
[string]
|
||||
$Project
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
# Build the URI for our request
|
||||
$URI = 'https://api.bitbucket.org/2.0/repositories/' + $team + '/' + $Project + '/downloads'
|
||||
|
||||
# Create our authentication header
|
||||
# TODO: Migrate to OAUTH
|
||||
$pair = ($username + ':' + $password)
|
||||
$encodedCreds = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($pair))
|
||||
$basicAuthValue = ('Basic {0}' -f $encodedCreds)
|
||||
$Headers = @{
|
||||
Authorization = $basicAuthValue
|
||||
}
|
||||
|
||||
# Cleanup the plain text stuff
|
||||
$pair = $null
|
||||
$encodedCreds = $null
|
||||
|
||||
# The boundary is essential - Trust me, very essential
|
||||
$boundary = [Guid]::NewGuid().ToString()
|
||||
|
||||
<#
|
||||
This is the crappy part: Build a body for a multipart request with PowerShell
|
||||
|
||||
This is something that should be changed in PowerShell ASAP (I mean it is really crappy and really bad).
|
||||
|
||||
It is an absolute no brainer with Curl.
|
||||
#>
|
||||
$bodyStart = @"
|
||||
--$boundary
|
||||
Content-Disposition: form-data; name="token"
|
||||
|
||||
--$boundary
|
||||
Content-Disposition: form-data; name="files"; filename="$(Split-Path -Leaf -Path $FilePath)"
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
|
||||
"@
|
||||
|
||||
# Generate the end of the request body to finish it.
|
||||
$bodyEnd = @"
|
||||
|
||||
--$boundary--
|
||||
"@
|
||||
|
||||
# Now we create a temp file (Another crappy/bad thing)
|
||||
$requestInFile = (Join-Path -Path $env:TEMP -ChildPath ([IO.Path]::GetRandomFileName()))
|
||||
|
||||
try
|
||||
{
|
||||
# Create a new object for the brand new temporary file
|
||||
$fileStream = (New-Object -TypeName 'System.IO.FileStream' -ArgumentList ($requestInFile, [IO.FileMode]'Create', [IO.FileAccess]'Write'))
|
||||
|
||||
try
|
||||
{
|
||||
# The Body start
|
||||
$bytes = [Text.Encoding]::UTF8.GetBytes($bodyStart)
|
||||
$fileStream.Write($bytes, 0, $bytes.Length)
|
||||
|
||||
# The original File
|
||||
$bytes = [IO.File]::ReadAllBytes($FilePath)
|
||||
$fileStream.Write($bytes, 0, $bytes.Length)
|
||||
|
||||
# Append the end of the body part
|
||||
$bytes = [Text.Encoding]::UTF8.GetBytes($bodyEnd)
|
||||
$fileStream.Write($bytes, 0, $bytes.Length)
|
||||
}
|
||||
finally
|
||||
{
|
||||
# End the Stream to close the file
|
||||
$fileStream.Close()
|
||||
|
||||
# Cleanup
|
||||
$fileStream = $null
|
||||
|
||||
# PowerShell garbage collector
|
||||
[GC]::Collect()
|
||||
}
|
||||
|
||||
# Make it multipart, this is the magic part...
|
||||
$contentType = 'multipart/form-data; boundary={0}' -f $boundary
|
||||
|
||||
<#
|
||||
The request itself is simple and easy, also works fine with Invoke-WebRequest instead of Invoke-RestMethod
|
||||
|
||||
I use Microsoft.PowerShell.Utility\Invoke-RestMethod to make sure the build in (Windows PowerShell native) function is used.
|
||||
If PowerShell Core is installed or any Module provides a tweaked version... Just in case!
|
||||
#>
|
||||
try
|
||||
{
|
||||
$null = (Microsoft.PowerShell.Utility\Invoke-RestMethod -Uri $URI -Method Post -InFile $requestInFile -ContentType $contentType -Headers $Headers -ErrorAction Stop -WarningAction SilentlyContinue)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Remove the temp file
|
||||
$null = (Remove-Item -Path $requestInFile -Force -Confirm:$false)
|
||||
|
||||
# Cleanup
|
||||
$contentType = $null
|
||||
|
||||
# PowerShell garbage collector
|
||||
[GC]::Collect()
|
||||
|
||||
# For the Build logs (will not break the build)
|
||||
Write-Warning -Message 'StatusCode:' $_.Exception.Response.StatusCode.value__
|
||||
Write-Warning -Message 'StatusDescription:' $_.Exception.Response.StatusDescription
|
||||
|
||||
# Saved in the verbose logs for this build
|
||||
Write-Verbose -Message $_
|
||||
|
||||
# Inform the build and terminate (Will break the build)
|
||||
Write-Error -Message 'We were unable to upload your file to the BitBucket downloads section, please check the build logs for further information.' -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
# Remove the temp file
|
||||
$null = (Remove-Item -Path $requestInFile -Force -Confirm:$false)
|
||||
|
||||
# Cleanup
|
||||
$contentType = $null
|
||||
|
||||
# PowerShell garbage collector
|
||||
[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
|
||||
@@ -0,0 +1,211 @@
|
||||
function Remove-FileEndingBlankLines
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Strip white space/blank lines from end of file or path
|
||||
|
||||
.DESCRIPTION
|
||||
Strip white space/blank lines from end of file or path
|
||||
|
||||
.PARAMETER Path
|
||||
Single File or Path you want to unclutter. (Mandatory)
|
||||
|
||||
.PARAMETER Recurse
|
||||
Recurse through all subdirectories of the path provided. The default is not work recursively (Optional)
|
||||
|
||||
.PARAMETER noNewLine
|
||||
No new (blank) line at the end of a file.
|
||||
|
||||
.PARAMETER SafeFilesOnly
|
||||
Only safe files were processed. This is the default! This will prevent any issues with Binary Files or any other non safe to process files. If you like to process all files (can be dangerous) just negate this by using -SafeFilesOnly:$false
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-FileEndingBlankLines -Path 'C:\Temp\Export-DistributionGroup2Cloud.ps1'
|
||||
|
||||
Strip white space/blank lines from end of 'C:\Temp\Export-DistributionGroup2Cloud.ps1'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-FileEndingBlankLines -Path 'C:\Temp\Export-DistributionGroup2Cloud.ps1'
|
||||
|
||||
Strip white space/blank lines from end of 'C:\Temp\Export-DistributionGroup2Cloud.ps1' without ending a final blank line at the end.
|
||||
NOTE: Set-Content adds a final blank line by default. this switch prevents this!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-FileEndingBlankLines -Path 'C:\Temp' -Recurse
|
||||
|
||||
Strip white space/blank lines from end of files found in 'C:\Temp' and below (recursively).
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-FileEndingBlankLines -Path 'C:\Temp' -Recurse -SafeFilesOnly:$false
|
||||
|
||||
Strip white space/blank lines from end of all files found in 'C:\Temp' and below (recursively).
|
||||
This might be risky and/or even dangerous! If you process any binary files, they might be corrupt afterwards.
|
||||
|
||||
.NOTES
|
||||
I created this helper function to unclutter the file ends and white space/blank lines from files during my build process.
|
||||
|
||||
I prefer the way that Set-Content handles it: Add a single blank line at the end of each file. This is use to the fact, that I concatenate several files during a build process.
|
||||
|
||||
I also added a switch (noNewLine) to prevent this.
|
||||
|
||||
By default only PowerShell and Markdown Files are processed by this function
|
||||
|
||||
.LINK
|
||||
Set-Content
|
||||
|
||||
.LINK
|
||||
Get-Content
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Single File or Path you want to unclutter.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('FilePath')]
|
||||
[string]
|
||||
$Path,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[switch]
|
||||
$Recurse = $false,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[switch]
|
||||
$noNewLine = $false,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 4)]
|
||||
[switch]
|
||||
$SafeFilesOnly = $true
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$paramGetChildItem = @{
|
||||
Path = $Path
|
||||
File = $true
|
||||
}
|
||||
|
||||
if ($SafeFilesOnly)
|
||||
{
|
||||
Write-Verbose -Message 'Only safe files are processed'
|
||||
$paramGetChildItem.Include = '*.psm1', '*.ps1', '*.psd1', '*.ps1xml', '*.md'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'All are processed - Might be a bad idea!!!'
|
||||
}
|
||||
|
||||
if ($Recurse)
|
||||
{
|
||||
Write-Verbose -Message 'Read the info recursively'
|
||||
$paramGetChildItem.Recurse = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Read the info'
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Make sure only files are processed and get the minimal info
|
||||
(Get-ChildItem @paramGetChildItem | Where-Object -FilterScript {
|
||||
-not $_.PSIsContainer
|
||||
} | Select-Object -ExpandProperty FullName) | ForEach-Object -Process {
|
||||
Write-Verbose -Message ('Try to unclutter {0}' -f $_)
|
||||
|
||||
$UnclutteredText = (((Get-Content -Path $_ -Raw).TrimEnd()).ToString())
|
||||
|
||||
try
|
||||
{
|
||||
if ($noNewLine)
|
||||
{
|
||||
Write-Verbose -Message ('Try to unclutter {0} (no final new line)' -f $_)
|
||||
|
||||
$null = ([io.file]::WriteAllText($_.FullName, $UnclutteredText))
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message ('Try to unclutter {0}' -f $_)
|
||||
|
||||
$paramSetContent = @{
|
||||
Path = $_
|
||||
Value = $UnclutteredText
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
Encoding = 'UTF8'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$null = (Set-Content @paramSetContent)
|
||||
}
|
||||
|
||||
Write-Verbose -Message ('Uncluttered {0}' -f $_)
|
||||
}
|
||||
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 ($info.Exception) -TargetObject ($info.Target) -ErrorAction Stop
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message 'Clear-FileEnding Done'
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
188
Powershell/PowerShell-collection/Misc/Remove-Signature.ps1
Normal file
188
Powershell/PowerShell-collection/Misc/Remove-Signature.ps1
Normal file
@@ -0,0 +1,188 @@
|
||||
function Remove-Signature
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Finds all signed PowerShell files removes any digital signatures attached to them.
|
||||
|
||||
.DESCRIPTION
|
||||
Finds all signed PowerShell files removes any digital signatures attached to them.
|
||||
Supported Filetypes are: psm1, ps1, psd1, and ps1xml - All other Files are ignored!
|
||||
|
||||
.PARAMETER Path
|
||||
Single File or Path you want to parse for digital signatures. (Mandatory)
|
||||
|
||||
.PARAMETER Recurse
|
||||
Recurse through all subdirectories of the path provided. The default is not work recursively (Optional)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-Signature -Path 'C:\Temp\Export-DistributionGroup2Cloud.ps1'
|
||||
|
||||
Removes all digital signatures from 'C:\Temp\Export-DistributionGroup2Cloud.ps1'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Remove-Signature -Path 'C:\Temp' -Recurse
|
||||
|
||||
Removes all digital signatures from psm1, ps1, psd1, and ps1xml files found in 'C:\Temp' and below (recursively).
|
||||
|
||||
.NOTES
|
||||
Based on the ideas and work of the original Authors: Adrian Rodriguez and Zachary Loeber
|
||||
|
||||
.LINK
|
||||
http://www.the-little-things.net
|
||||
|
||||
.LINK
|
||||
https://psrdrgz.github.io/RemoveAuthenticodeSignature/
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Single File or Path you want to parse for digital signatures.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('FilePath')]
|
||||
[string]
|
||||
$Path,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[switch]
|
||||
$Recurse = $false
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$paramGetChildItem = @{
|
||||
Path = $Path
|
||||
File = $true
|
||||
Include = '*.psm1', '*.ps1', '*.psd1', '*.ps1xml'
|
||||
}
|
||||
|
||||
if ($Recurse)
|
||||
{
|
||||
Write-Verbose -Message 'Work recursively'
|
||||
$paramGetChildItem.Recurse = $true
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
|
||||
$FilesToProcess = (Get-ChildItem @paramGetChildItem)
|
||||
|
||||
$FilesToProcess | ForEach-Object -Process {
|
||||
$SignatureStatus = (Get-AuthenticodeSignature -FilePath $_).Status
|
||||
$ScriptFileFullName = $_.FullName
|
||||
|
||||
if ($SignatureStatus -ne 'NotSigned')
|
||||
{
|
||||
try
|
||||
{
|
||||
$paramGetContent = @{
|
||||
Path = $ScriptFileFullName
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$Content = (Get-Content @paramGetContent)
|
||||
|
||||
$paramNewObject = @{
|
||||
TypeName = 'System.Text.StringBuilder'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$StringBuilder = (New-Object @paramNewObject)
|
||||
|
||||
foreach ($Line in $Content)
|
||||
{
|
||||
if ($Line -match '^# SIG # Begin signature block|^<!-- SIG # Begin signature block -->')
|
||||
{
|
||||
break
|
||||
}
|
||||
else
|
||||
{
|
||||
$null = $StringBuilder.AppendLine($Line)
|
||||
}
|
||||
}
|
||||
if ($pscmdlet.ShouldProcess("$ScriptFileFullName"))
|
||||
{
|
||||
$paramSetContent = @{
|
||||
Path = $ScriptFileFullName
|
||||
Value = $StringBuilder.ToString()
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
Encoding = 'UTF8'
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$null = (Set-Content @paramSetContent)
|
||||
|
||||
Write-Verbose -Message ('Removed signature from {0}' -f $ScriptFileFullName)
|
||||
}
|
||||
}
|
||||
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 ($info.Exception) -TargetObject ($info.Target) -ErrorAction Stop
|
||||
break
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message ('No signature found in {0}' -f $ScriptFileFullName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message 'Remove-Signature Done'
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
118
Powershell/PowerShell-collection/Misc/Resolve-DNSHost.ps1
Normal file
118
Powershell/PowerShell-collection/Misc/Resolve-DNSHost.ps1
Normal file
@@ -0,0 +1,118 @@
|
||||
function Resolve-DNSHost
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Resolve DNS hostname to IP and reverse
|
||||
|
||||
.DESCRIPTION
|
||||
This function resolves DNS hostname to IP and the other way around (reverse)
|
||||
|
||||
.PARAMETER HostEntry
|
||||
Hostname (Single, or multiple) to test.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Resolve-DNSHost -HostEntry www.hochwald.net
|
||||
|
||||
HostName IPAddress
|
||||
-------- ---------
|
||||
www.hochwald.net {104.28.0.64, 104.28.1.64, 2606:4700:30::681c:140, 2606:4700:30::681c:40}
|
||||
|
||||
This function resolves DNS hostname to IP and the other way around (reverse)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Resolve-DNSHost -HostEntry 'www.hochwald.net','autodiscover.hochwald.net'
|
||||
|
||||
HostName IPAddress
|
||||
-------- ---------
|
||||
www.hochwald.net {104.28.0.64, 104.28.1.64, 2606:4700:30::681c:140, 2606:4700:30::681c:40}
|
||||
autodiscover.hochwald.net {40.101.88.8, 40.101.88.184, 52.97.151.104, 40.101.60.24...}
|
||||
|
||||
This function resolves DNS hostname to IP and the other way around (reverse)
|
||||
|
||||
.OUTPUTS
|
||||
psobject
|
||||
|
||||
.NOTES
|
||||
Refactored of Resolve-Host.Ps1 by @PrateekKumarSingh
|
||||
|
||||
.LINK
|
||||
Original:
|
||||
https://gist.github.com/PrateekKumarSingh/586f2d3d43f7e8cb07ce
|
||||
|
||||
.LINK
|
||||
Dns Class (system.net.dns):
|
||||
https://docs.microsoft.com/de-de/dotnet/api/system.net.dns
|
||||
|
||||
.INPUTS
|
||||
String
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Hostname (Single, or multiple) to test.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String[]]
|
||||
$HostEntry
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Cleanup
|
||||
$Obj = @()
|
||||
$Object = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$HostEntry | ForEach-Object -Process {
|
||||
$Obj += New-Object -TypeName psobject -Property @{
|
||||
HostName = $_
|
||||
IPAddress = $([Net.Dns]::gethostentry($_).AddressList.IPAddressToString)
|
||||
}
|
||||
}
|
||||
|
||||
# Append
|
||||
$Object = ($Obj | Select-Object -Property Hostname, IPAddress)
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Dump to the console
|
||||
$Object
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,133 @@
|
||||
#requires -Version 3.0 -Modules NetSecurity -RunAsAdministrator
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Enable inbound ICMP (Ping) and Remote Desktop (RDP)
|
||||
|
||||
.DESCRIPTION
|
||||
Enable inbound ICMP (Ping) and Remote Desktop (RDP).
|
||||
Ping will be enabled for IPv4 and IPv6.
|
||||
|
||||
.PARAMETER RDPGroup
|
||||
Enable the complete RDP Groups in the Windows Firewall?
|
||||
This will enable more then just the basic requirements, use with care!!!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-AllowPingAndRemoteDesktop.ps1
|
||||
|
||||
Enable inbound ICMP (Ping) and Remote Desktop (RDP)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-AllowPingAndRemoteDesktop.ps1 -verbose
|
||||
|
||||
Enable inbound ICMP (Ping) and Remote Desktop (RDP) - verbose run
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-AllowPingAndRemoteDesktop.ps1 -WhatIf
|
||||
|
||||
Enable inbound ICMP (Ping) and Remote Desktop (RDP) - Dry run
|
||||
|
||||
.NOTES
|
||||
Helper script I use to bootstrap servers
|
||||
Run this elevated!!!
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline)]
|
||||
[switch]
|
||||
$RDPGroup
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
# Splat the Set-ItemProperty parameters
|
||||
$paramSetItemProperty = @{
|
||||
Path = 'HKLM:\System\CurrentControlSet\Control\Terminal Server'
|
||||
Name = 'fDenyTSConnections'
|
||||
Value = 0
|
||||
ErrorAction = 'Continue'
|
||||
}
|
||||
|
||||
# Splat the Enable-NetFirewallRule parameters
|
||||
$paramEnableNetFirewallRule = @{
|
||||
Confirm = $false
|
||||
ErrorAction = 'Continue'
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Support WhatIf (SupportsShouldProcess)
|
||||
if ($pscmdlet.ShouldProcess('Registry Terminal Server', 'Modify'))
|
||||
{
|
||||
# Tweak the Registry for Remote Desktop connections
|
||||
$null = (Set-ItemProperty @paramSetItemProperty)
|
||||
}
|
||||
|
||||
# We avoid using $RDPGroup.IsPresent
|
||||
if ($PSBoundParameters.ContainsKey('RDPGroup'))
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('Firewall Group for Remote Desktop', 'Enable'))
|
||||
{
|
||||
# Allow Remote Desktop (The Group)
|
||||
$null = (Get-NetFirewallRule -DisplayGroup 'Remote Desktop' -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.Enabled -ne $true
|
||||
} | Enable-NetFirewallRule @paramEnableNetFirewallRule)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('Firewall Rules for Remote Desktop', 'Enable'))
|
||||
{
|
||||
# Alternative Approach: Enable the minimum, not the Group
|
||||
Get-NetFirewallRule -Name 'RemoteDesktop-UserMode-In-TCP' -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.Enabled -ne $true
|
||||
} | Enable-NetFirewallRule @paramEnableNetFirewallRule
|
||||
|
||||
Get-NetFirewallRule -DisplayName 'Remote Desktop - User Mode (TCP-In)' -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.Enabled -ne $true
|
||||
} | Enable-NetFirewallRule @paramEnableNetFirewallRule
|
||||
}
|
||||
}
|
||||
|
||||
if ($pscmdlet.ShouldProcess('Ping', 'Enable'))
|
||||
{
|
||||
# Allow Ping for IPv4 and IPv6
|
||||
# NOTE: The wildcard (ICMPv?) will select both. Replace it with 4 or 6 to use just one of them
|
||||
Get-NetFirewallRule -DisplayName 'File and Printer Sharing (Echo Request - ICMPv?-In)' -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.Enabled -ne $true
|
||||
} | Enable-NetFirewallRule @paramEnableNetFirewallRule
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user