├── ADMX
├── ActivClient
│ ├── AutoConfigEFS.xml
│ ├── HidePublishToGal.xml
│ ├── TimeOutToClearCache.xml
│ ├── UnlockCardContactTelephoneNumber.xml
│ ├── PINCachingExcludeList.xml
│ ├── ReaderBlackList.xml
│ ├── HIDGlobal.Logging.admx
│ ├── HIDGlobal.AdvancedDiagnostics.admx
│ ├── Readme.md
│ ├── HIDGlobal.ActivClient1.admx
│ └── HIDGlobal.ActivClient0.admx
├── Firefox
│ ├── ImportEnterpriseRoots.xml
│ ├── DisableBuiltinPDFViewer.xml
│ ├── ExtensionSettings.xml
│ └── README.md
├── MSIP
│ ├── CloudEnvType.xml
│ ├── MIP_Cloud.adml
│ ├── MIP_Cloud.admx
│ └── Readme.md
└── Google Chrome
│ ├── chrome.admx
│ ├── MicrosoftExtensions.xml
│ └── Readme.md
├── Automations
└── AzureFunctions
│ ├── Automated M365 Licenses
│ ├── WorkflowOverview.PNG
│ ├── Instructions.md
│ └── Automated-M365-Licenses.ps1
│ ├── Dependencies
│ ├── GeneralSettings.md
│ └── ApplicationSettings.md
│ ├── Remove Licenses from Disabled Accounts
│ └── Remove-InactiveLicensedGroupMembers.ps1
│ ├── Revoke EXO PS Access for Users
│ └── Revoke-ExoPsAccess.ps1
│ ├── Onboard Employees
│ └── Send-EmployeeOnboardingMessages.ps1
│ └── Onboard Contractors
│ └── Onboard-ContractorAccount.ps1
├── scripts
└── powershell
│ ├── cyber
│ └── readme.md
│ ├── readme.md
│ ├── WindowsServer
│ ├── Activate-Windows.ps1
│ ├── Set-RdpCertificate.ps1
│ ├── Set-WinRmSecureListener.ps1
│ ├── New-ServerCsr.ps1
│ └── New-KdcCsr.ps1
│ ├── Office-365
│ ├── Exchange
│ │ └── List-Exchange-Connected-Devices.ps1
│ └── group-creators
│ │ ├── GroupCreators.ps1
│ │ └── README.md
│ └── PKI
│ └── Set-AzureKeyVaultSignature.ps1
├── README.md
└── LICENSE
/ADMX/ActivClient/AutoConfigEFS.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/HidePublishToGal.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ADMX/Firefox/ImportEnterpriseRoots.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ADMX/Firefox/DisableBuiltinPDFViewer.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ADMX/MSIP/CloudEnvType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/TimeOutToClearCache.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ADMX/Google Chrome/chrome.admx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cooeycomrades/cooey-tools/HEAD/ADMX/Google Chrome/chrome.admx
--------------------------------------------------------------------------------
/ADMX/ActivClient/UnlockCardContactTelephoneNumber.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/PINCachingExcludeList.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/ReaderBlackList.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Automated M365 Licenses/WorkflowOverview.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cooeycomrades/cooey-tools/HEAD/Automations/AzureFunctions/Automated M365 Licenses/WorkflowOverview.PNG
--------------------------------------------------------------------------------
/scripts/powershell/cyber/readme.md:
--------------------------------------------------------------------------------
1 | # Cyber
2 |
3 | ## Links / Honorable Mentions
4 |
5 | **Azure & Office 365 Assesment**
6 |
7 | Crowdstrike's CRT tool modified for Azure Gov:
8 |
9 | https://github.com/sentinelblue/CRTgov/
10 |
11 | https://github.com/hbwheat/CRT
--------------------------------------------------------------------------------
/ADMX/Google Chrome/MicrosoftExtensions.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/powershell/readme.md:
--------------------------------------------------------------------------------
1 | # powershell
2 |
3 | Here we have our powershell scripts. However, they don't all live in this castle.
4 |
5 | ## Links
6 |
7 | List of great repositories that are maintained and owned elsewhere.
8 |
9 | ### Cyber
10 |
11 | Cybersecurity powershell things...
12 |
13 | ### Office-365
14 |
15 | Office 365 related scripts...
16 |
--------------------------------------------------------------------------------
/scripts/powershell/WindowsServer/Activate-Windows.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Purpose:
3 | Used to activate windows using motherboard installed license key when Windows fails to automatically
4 |
5 | Usage:
6 | Run as administrator
7 |
8 | Author: @garrett-wood
9 | #>
10 |
11 | # Retrieves License Key from BIOS/UEFI
12 | $LicenseKey = (Get-WmiObject SoftwareLicensingService).OA3xOriginalProductKey
13 |
14 | # Installs Product Key
15 | slmgr.vbs /ipk $LicenseKey
16 |
17 | # Activates Windows
18 | slmgr.vbs /ato
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cooey-tools
2 | Tools by cooey comrades for cooey comrades.
3 |
4 | ## Contributions
5 |
6 | Contribute in a couple of ways...
7 |
8 | By pull request...
9 |
10 | 1. Fork this repository
11 | 2. Add anything you want
12 | 3. Open a pull request
13 | 4. Detail the additions or changes
14 |
15 | By issuse..
16 |
17 | 1. Open an issues regarding an item
18 | 2. Someone will take a look
19 | 3. Profit
20 |
21 | Remember this is a community driven project. Your contributions make us complete.
22 |
23 | ## Scripts
24 |
25 | These aren't long lived programs, just short snippets.
26 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Dependencies/GeneralSettings.md:
--------------------------------------------------------------------------------
1 | | Setting | Value |
2 | |-----------------------------|-----------------|
3 | | Stack | PowerShell Core |
4 | | PowerShell Core Version | PowerShell 7.0 |
5 | | Platform | 64 Bit |
6 | | Managed pipeline version | Integrated |
7 | | FTP State | FTPS only |
8 | | HTTP version | 1.1 |
9 | | Web sockets | Off |
10 | | Always on | On |
11 | | ARR affinity | Off |
12 | | Remote debugging | Off |
13 | | Client Certificate mode | Allow |
14 | | Certificate exclusion paths | |
15 |
--------------------------------------------------------------------------------
/ADMX/Firefox/ExtensionSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
29 |
--------------------------------------------------------------------------------
/scripts/powershell/WindowsServer/Set-RdpCertificate.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Author: @garrett-wood
3 | Purpose: Registers a custom Certificate to be served up by the RDP Client. Often used if you don't use AD CS as your CA.
4 | Requirements: A valid service auth certificate
5 | Usage: Run this script and it should automatically identify the cert installed by your specified issuer with the latest expiration date.
6 | Be sure to change the Issuer to match the Issuer DN of your CA.
7 | #>
8 |
9 | # Gets the Cert issued for the hostname for SSLServerAuthentication
10 | $pkiCert = (Get-ChildItem Cert:\LocalMachine\My\ `
11 | -SSLServerAuthentication `
12 | -DnsName ([System.Net.Dns]::GetHostByName(($env:computerName)).HostName) `
13 | | Where-Object Issuer -eq "CN=Your Org Issuing CA, OU=Certification Authorities, O=Your Org, C=US" `
14 | | Sort-Object NotAfter -Descending)[0]
15 |
16 | # Sets RDP to use that certificate for authentication
17 | wmic /namespace:\\root\cimv2\TerminalServices PATH Win32_TSGeneralSetting Set SSLCertificateSHA1Hash=$($pkiCert.Thumbprint)
18 |
--------------------------------------------------------------------------------
/ADMX/MSIP/MIP_Cloud.adml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Microsoft Information Protection
8 | AIP apps configuration for the unified labeling client
9 | Relevant for: The AIP unified labeling client only. If your tenant is in the Microsoft 365 Commercial environment, you do not need to set this policy.
10 | Microsoft 365 Commercial
11 | Microsoft 365 GCC
12 | Microsoft 365 GCC High
13 | Microsoft 365 DoD
14 |
15 |
16 | Cloud Environment Type
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/scripts/powershell/Office-365/Exchange/List-Exchange-Connected-Devices.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | List Exchange Connected Devices.
4 |
5 | .DESCRIPTION
6 | This was designed to show you all of the devices that are connected to your M365 Exchange environment which aren't listed in the MDM\MAM web portals.
7 | Includes Outlook mobile apps, 3rd party mail apps, basic auth, and the like. You want to be aware of these devices and how policy changes will affect them.
8 |
9 | .NOTES
10 | Author : Adam Kauffman https://github.com/A9G-Data-Droid
11 |
12 | .COMPONENT
13 | ExchangeOnlineManagement is required and imported automatically.
14 |
15 | .LINK
16 | https://github.com/A9G-Data-Droid/cooey-tools/tree/main/scripts/powershell/Office-365/Exchange
17 | #>
18 |
19 |
20 |
21 | function Connect-Exchange-Stateful {
22 | if (!(Get-PSSession | Where-Object {$_.Name -match 'ExchangeOnline' -and $_.Availability -eq 'Available'})) {
23 | Connect-ExchangeOnline -ExchangeEnvironmentName O365USGovGCCHigh -ShowBanner:$False
24 | }
25 | }
26 |
27 | #Requires -Modules ExchangeOnlineManagement
28 | #Requires -Version 5
29 |
30 | Connect-Exchange-Stateful
31 | Get-MobileDevice | Format-Table -Auto Identity, FriendlyName, DeviceOS, DeviceId
32 |
33 | # How to remove them:
34 | Write-Output "Cleanup old devices with the command: Remove-MobileDevice `"Identity`""
35 |
--------------------------------------------------------------------------------
/scripts/powershell/WindowsServer/Set-WinRmSecureListener.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Author: @garrett-wood
3 | Purpose: Registers a custom Certificate to be served up by the WinRM Server. Often used if you don't use AD CS as your CA.
4 | Requirements: A valid TLS Server certificate
5 | Usage: Run this script and it should automatically identify the cert installed by your specified issuer with the latest expiration date.
6 | #>
7 |
8 | # Be sure to change the Issuer to match the Issuer DN of your CA.
9 | $IssuerDistinguishedName = "CN=Contoso Issuing CA, OU=Certification Authorities, O=Contoso, C=US"
10 |
11 | # Gets the Computers name and domain name through WMI. We only care about the FQDN
12 | $computerSystemWmi = Get-WmiObject Win32_ComputerSystem
13 | $computerCertificateFqdn = [String]::Concat($computerSystemWmi.name,'.',$computerSystemWmi.domain)
14 |
15 | # Gets the Cert issued for the hostname for SSLServerAuthentication. Uses the last one to expire that's valid for SSL authentication by that issuer
16 | $pkiCert = (Get-ChildItem Cert:\LocalMachine\My\ `
17 | -SSLServerAuthentication `
18 | -DnsName $computerCertificateFqdn `
19 | | Where-Object Issuer -eq $IssuerDistinguishedName `
20 | | Sort-Object NotAfter -Descending)[0]
21 |
22 | # Builds lists of arguments to call with WinRM. This was the least likely to cause errors after testing.
23 | $winrmArgs = [String]::Concat('create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="',$computerCertificateFqdn,'";CertificateThumbprint="',$pkiCert.Thumbprint,'"}')
24 |
25 | # Starts a seperate process with proper encoding
26 | Start-Process winrm -ArgumentList $winrmArgs
27 |
28 | # Verifies the listener was successfully created
29 | winrm enumerate winrm/config/listener
30 |
--------------------------------------------------------------------------------
/scripts/powershell/Office-365/group-creators/GroupCreators.ps1:
--------------------------------------------------------------------------------
1 | #################################################################################################################
2 | #
3 | # Author: Matt Carson
4 | # Contact: https://github.com/mattco593
5 | # Title: Office 365 Group Creators
6 | # Purpose: Limit the amount of users that are able to create Microsoft/Office 365 groups without any oversight.
7 | #
8 | #
9 | ################################################################################################################
10 |
11 | $GroupName = "Office 365 Group Creators"
12 | $AllowGroupCreation = "False"
13 |
14 | Connect-AzureAD -AzureEnvironmentName AzureUSGovernment
15 |
16 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id
17 | if(!$settingsObjectID)
18 | {
19 | $template = Get-AzureADDirectorySettingTemplate | Where-object {$_.displayname -eq "group.unified"}
20 | $settingsCopy = $template.CreateDirectorySetting()
21 | New-AzureADDirectorySetting -DirectorySetting $settingsCopy
22 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id
23 | }
24 |
25 | $settingsCopy = Get-AzureADDirectorySetting -Id $settingsObjectID
26 | $settingsCopy["EnableGroupCreation"] = $AllowGroupCreation
27 |
28 | if($GroupName)
29 | {
30 | $settingsCopy["GroupCreationAllowedGroupId"] = (Get-AzureADGroup -SearchString $GroupName).objectid
31 | }
32 | else {
33 | $settingsCopy["GroupCreationAllowedGroupId"] = $GroupName
34 | }
35 | Set-AzureADDirectorySetting -Id $settingsObjectID -DirectorySetting $settingsCopy
36 |
37 | (Get-AzureADDirectorySetting -Id $settingsObjectID).Values
38 |
--------------------------------------------------------------------------------
/scripts/powershell/WindowsServer/New-ServerCsr.ps1:
--------------------------------------------------------------------------------
1 |
2 | <#
3 | Author: @garrett-wood
4 | Purpose: Registers a custom Certificate to be served up by the RDP Client. Often used if you don't use AD CS as your CA.
5 | Requirements: A valid service auth certificate
6 | Usage: This script will automatically request a certificate using your FQDN with the Client and Server Auth EKUs. If you need custom OID's, add them.
7 | The output in the PS Windows will be the CSR. Give that to your PKI team, or submit to the CA yourself as org policies require.
8 | #>
9 |
10 | $CertName = ([System.Net.Dns]::GetHostByName(($env:computerName)).HostName)
11 | $CSRPath = [environment]::getfolderpath("desktop") + "\" + $CertName + ".csr.txt"
12 | $INFPath = [environment]::getfolderpath("desktop") + "\" + $CertName + ".inf"
13 | $Signature = '$Windows NT$'
14 |
15 |
16 | $INF =
17 | @"
18 | [Version]
19 | Signature= "$Signature"
20 |
21 | [NewRequest]
22 | Subject = "CN=$CertName"
23 | KeySpec = 1
24 | KeyLength = 2048
25 | Exportable = TRUE
26 | MachineKeySet = TRUE
27 | SMIME = False
28 | PrivateKeyArchive = FALSE
29 | UserProtected = FALSE
30 | UseExistingKeySet = FALSE
31 | ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
32 | ProviderType = 12
33 | RequestType = PKCS10
34 | KeyUsage = 0xa0
35 |
36 | [EnhancedKeyUsageExtension]
37 |
38 | OID=1.3.6.1.5.5.7.3.1
39 | OID=1.3.6.1.5.5.7.3.2
40 |
41 | [Extensions]
42 | 2.5.29.17 = "{text}" ; SAN - Subject Alternative Name
43 | _continue_ = "dns=$CertName&"
44 | "@
45 |
46 | $INF | out-file -filepath $INFPath -force
47 | certreq -new $INFPath $CSRPath
48 |
49 | Write-Host "CSR Content Below:"
50 | Write-Host " "
51 | Get-Content $CSRPath
52 | Write-Host " "
53 |
54 | Remove-Item $INFPath
55 | Remove-Item $CSRPath
56 |
--------------------------------------------------------------------------------
/ADMX/MSIP/MIP_Cloud.admx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | -
21 |
22 |
23 |
24 |
25 | -
26 |
27 |
28 |
29 |
30 | -
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ADMX/Firefox/README.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | The Firefox policies are extremely well documented and also located in Github. Please reference those for the latest information. See
4 |
5 | https://github.com/mozilla/policy-templates
6 |
7 | # Process
8 |
9 | 1. Import the ADMX Files into Intune using the standard process as shown in the table below. The files are in this folder in the repo.
10 |
11 | | Name | OMA-URI | Data type |
12 | |------------------------------------|---------------------------------------------------------------------------------------------------------|-----------|
13 | | firefox.admx | `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/Firefox/Policy/FirefoxAdmx` | String |
14 |
15 | 2. From here, you should stop and apply the policy to some devices. Verify you succeed, and see the values in the Registry before you continue.
16 |
17 | 3. Add the policies you need to. The below are a few examples. You would need to copy the value of the appropriate .xml file in this folder to the Value of the OMA-URI setting for the change to take affect. Again, it's highly recommended to consult Mozilla's documentation on this subject.
18 |
19 | | Name | OMA-URI | Data type |
20 | |----------------------------------|----------------------------------------------------------------------------------------------------------------------|-----------|
21 | | DisableBuiltinPDFViewer | `./Device/Vendor/MSFT/Policy/Config/Firefox~Policy~firefox/DisableBuiltinPDFViewer` | String |
22 | | ImportEnterpriseRoots | `./Device/Vendor/MSFT/Policy/Config/Firefox~Policy~firefox~Certificates/Certificates_ImportEnterpriseRoots` | String |
23 | | ExtensionSettings | `./Device/Vendor/MSFT/Policy/Config/Firefox~Policy~firefox~Extensions/ExtensionSettings` | String |
24 |
--------------------------------------------------------------------------------
/scripts/powershell/WindowsServer/New-KdcCsr.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Author: @garrett-wood
3 | Purpose: Registers a custom Certificate to be used for KDC functions including RDP, LDAPS, and Kerberos
4 | Requirements: A valid service auth certificate
5 | Usage: This script will automatically request a certificate using your FQDN with the Client and Server Auth EKUs as well ad KDC, DNS Signing, and SCL.
6 | If you need custom OID's, add them. The output in the PS Windows will be the CSR. Give that to your PKI team, or submit to the CA yourself as org policies require.
7 | #>
8 |
9 | $CertName = ([System.Net.Dns]::GetHostByName(($env:computerName)).HostName)
10 | $DomainFqdn = (Get-WmiObject Win32_NTDomain).DnsForestName
11 | $CSRPath = [environment]::getfolderpath("desktop") + "\" + $CertName + ".csr.txt"
12 | $INFPath = [environment]::getfolderpath("desktop") + "\" + $CertName + ".inf"
13 | $Signature = '$Windows NT$'
14 |
15 |
16 | $INF =
17 | @"
18 | [Version]
19 | Signature= "$Signature"
20 |
21 | [NewRequest]
22 | Subject = "CN=$CertName"
23 | KeySpec = 1
24 | KeyLength = 2048
25 | Exportable = TRUE
26 | MachineKeySet = TRUE
27 | SMIME = False
28 | PrivateKeyArchive = FALSE
29 | UserProtected = FALSE
30 | UseExistingKeySet = FALSE
31 | ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
32 | ProviderType = 12
33 | RequestType = PKCS10
34 | KeyUsage = 0xa0
35 |
36 | [EnhancedKeyUsageExtension]
37 | OID=1.3.6.1.5.5.7.3.1 ; this is for Server Authentication
38 | OID=1.3.6.1.5.5.7.3.2 ; this is for Client Authentication
39 | OID=1.3.6.1.5.2.3.5 ; this is for KDC Authentication
40 | OID=1.3.6.1.4.1.311.20.2.2 ; this is for Smart Card Logon
41 | OID=1.3.6.1.4.1.311.64.1.1 ; DNS Zone Signing
42 |
43 |
44 | [Extensions]
45 | 2.5.29.17 = "{text}" ; SAN - Subject Alternative Name
46 | _continue_ = "dns=$CertName&"
47 | _continue_ = "dns=$DomainFqdn&"
48 | _continue_ = "dns=ldap.$DomainFqdn&"
49 | "@
50 |
51 | $INF | out-file -filepath $INFPath -force
52 | certreq -new $INFPath $CSRPath
53 |
54 | Write-Host "CSR Content Below:"
55 | Write-Host " "
56 | Get-Content $CSRPath
57 | Write-Host " "
58 |
59 | Remove-Item $INFPath
60 | Remove-Item $CSRPath
61 |
--------------------------------------------------------------------------------
/ADMX/MSIP/Readme.md:
--------------------------------------------------------------------------------
1 | # Purpose
2 | Sets the value for the MSIP/AIP client using Intune, with full compliance visibility
3 |
4 | # Usage
5 | Both of these files must be uploaded to Microsoft Intune using a Custom policy, which will allow you to directly reference an OMA-URI. You can use the same Custom policy to deploy both settings. Name it what you wish. This has been updated so only the 'new' Unified Client Registry value can be changed. If you're still using the older version of this, please update.
6 |
7 | ## Intune
8 |
9 | 1. Create a new Custom Policy in Intune.
10 | 2. Create a new OMA-URI Setting. I named mine `MSIP.admx`
11 | 3. for the OMA-URI, type: `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/MSIP/Policy/MSIP.Admx`
12 | 4. For the Value, paste in the contents of the MSIP.admx file as a String. Set the description if desired.
13 | 5. Add a second new OMA-URI Setting called `CloudEnvType`
14 | 6. For the OMA-URI, type: `./Device/Vendor/MSFT/Policy/Config/MSIP~Policy~CloudEnvironment/CloudEnvType`
15 | 7. For the Value, paste in the Contents of the CloudEnvType.xml file, and substitute another value for the '2' if you aren't in GCCH.
16 | 8. Save all settings and deploy to your test group, then to prod.
17 |
18 | ## Group Policy
19 | 1. Download and save the `MIP_Cloud.admx` and `MIP_Cloud.adml`files onto your local workstation
20 | 2. Copy those file to wherever you copy PolicyDefinitions to your domain, with the .adml file going under the en-US subdirectory
21 | 3. Open Group Policy Management on a machine that can reference the policy store that has those files propagated.
22 | 4. Find the value under "Microsoft Information Protection" and set the Cloud Environment Type to your assigned tenant type.
23 | 5. Test the Policy in a test forest, domain, OU, or security group then send to protection.
24 |
25 | # Author
26 | @garrett-wood
27 |
28 | # References
29 | https://somedownti.me/2020/06/02/import-administrative-templates-admx-into-intune/
30 | https://docs.microsoft.com/en-us/enterprise-mobility-security/solutions/ems-aip-premium-govt-service-description
31 | https://4sysops.com/archives/how-to-create-an-admx-template/#admx-template-structure
32 |
--------------------------------------------------------------------------------
/scripts/powershell/Office-365/group-creators/README.md:
--------------------------------------------------------------------------------
1 | # Office 365 Scripts
2 |
3 | ## Group Creators Script:
4 | This script was originally on Microsoft's website. I just modifed one line to make it work with GCC High
5 |
6 | ### Features:
7 | Prevents anyone except members of the groups listed below or members of the specified security group within the script to create Microsoft 365 Groups. This will allow prevent user's outside of this group from creating Teams or SharePoint sites.
8 |
9 | #### Users in the following groups will still be able to create Microsoft/Office 365 Groups even after the script has been run:
10 | - Exchange Administrator: Exchange Admin center, Azure AD
11 | - Global Admins: Exchange Admin center, Azure AD, Teams Admin center, SharePoint Admin center
12 | - Partner Tier 1 Support: Microsoft 365 Admin center, Exchange Admin center, Azure AD
13 | - Partner Tier 2 Support: Microsoft 365 Admin center, Exchange Admin center, Azure AD
14 | - Directory Writers: Azure AD
15 | - SharePoint Administrator: SharePoint Admin center, Azure AD
16 | - Teams Service Administrator: Teams Admin center, Azure AD
17 | - User Management Administrator: Microsoft 365 Admin center, Azure AD
18 |
19 | ### Instructions
20 | 1. Open PowerShell on a Windows workstation
21 | 2. Install the Azure Active Directory Preview module by running Install-Module AzureADPreview
22 | 3. Open the GroupCreators.ps1 file in a text editor and modify the value for $GroupName to be the name of the security group you created.
23 | 4. Within PowerShell navigate to the directory where the script is saved and run it.
24 | 5. Test group creation with a user that should not have the privileges and see if the script worked.
25 |
26 | ### Bugs:
27 | I have noticed one bug within my tenant after running this script which is you are no longer able to preperly create Teams from within the Teams Admin Center Web Portal. When a Team gets created it does not show up for the users added to it and is not searchable. You will either need to create your Team from within the Teams Desktop or Web Application or create the Team using PowerShell.
28 |
29 | Link to original Microsoft Article: https://docs.microsoft.com/en-us/microsoft-365/solutions/manage-creation-of-groups?view=o365-worldwide
30 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Remove Licenses from Disabled Accounts/Remove-InactiveLicensedGroupMembers.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Author: @garrett-wood
3 | Purpose: To be run in a PowerShell Azure Function to remove unnecessarily assigned licenses without wasting admin time.
4 | Usage: Intended to be loaded in Azure Function. You wild need to create a custom Service Principal with the right API permissions
5 | on the MS Graph (out of scope for this guide)
6 | #>
7 |
8 | # In this example, all licenses are assigned with groups, and credentials are passed through the Azure Function using Application Settings.
9 | # In the example environment, the naming convention for these groups is "License-$licensename" and the E3 and E5 groups are not handled here.
10 |
11 | # Input bindings are passed in via param block.
12 | param($Timer)
13 |
14 | # Get the current universal time in the default string format.
15 | $currentUTCtime = (Get-Date).ToUniversalTime()
16 |
17 | # The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
18 | if ($Timer.IsPastDue) {
19 | Write-Host "PowerShell timer is running late!"
20 | }
21 |
22 | # Imports Module for Azure AD
23 | Import-Module 'AzureADPreview' -UseWindowsPowerShell
24 |
25 | # Connects to Azure AD using AAD and MS Graph Tokens
26 | Connect-AzureAD `
27 | -AzureEnvironmentName AzureUSGovernment `
28 | -TenantId $env:MsGraphTenantId `
29 | -ApplicationId $env:MsGraphClientId `
30 | -CertificateThumbprint $env:MsGraphClientCertificate
31 |
32 | # List user users with disabled access
33 | $DisabledUsers = Get-AzureADUser -all $true | Where-Object AccountEnabled -eq $false
34 |
35 | # List of all groups that assign licenses aside from the Base Office Suite. These are seperate because E3 is dynamic and E5 should be done manually.
36 | $LicenseGroups = Get-AzureADGroup -SearchString License- | Where-Object DisplayName -NotLike "*Microsoft 365 E*"
37 |
38 | ForEach ($User in $DisabledUsers)
39 | {
40 | #Creates List
41 | $UserLicensedGroups = Get-AzureAdUserMembership -ObjectId $User.ObjectId | Where-Object ObjectId -in $LicenseGroups.ObjectId
42 | ForEach ($Group in $UserLicensedGroups)
43 | {
44 | Remove-AzureAdGroupMember -ObjectId $Group.ObjectId -MemberId $User.ObjectId -Verbose
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Revoke EXO PS Access for Users/Revoke-ExoPsAccess.ps1:
--------------------------------------------------------------------------------
1 |
2 | <#
3 | Author: @garrett-wood
4 | Purpose: To be run on a cron timer to disable access to powershell for users that don't need it as that's occaisitonally used as an attack vector and there's no way
5 | to do so with Conditional Access policies
6 | #>
7 |
8 | # Ensure you swap the Environment (if needed) and VERIFY your admin account(s) are excempted.
9 | # Note that you will NEED to grant your application manageAsApp permissions to do this. This involves editing the manifest.
10 | # See: https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps
11 |
12 | # Input bindings are passed in via param block.
13 | param($Timer)
14 |
15 | # Get the current universal time in the default string format.
16 | $currentUTCtime = (Get-Date).ToUniversalTime()
17 |
18 | # The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
19 | if ($Timer.IsPastDue) {
20 | Write-Host "PowerShell timer is running late!"
21 | }
22 |
23 | # Connects to Exchange Online - Swap a different value if you're not in GCCH
24 | Write-Host "Connecting to EXO..."
25 | Connect-ExchangeOnline `
26 | -ExchangeEnvironmentName O365USGovGCCHigh `
27 | -AppId $env:MsGraphClientId `
28 | -CertificateThumbprint $env:MsGraphClientCertificate `
29 | -Organization $env:ExchangeOrganizationName
30 |
31 | # Gets list of non admin and non service account users according to naming convention. Change this to fit yours, or don't. I'm a comment, not a cop.
32 | $UnprivilegedUsers = Get-User -ResultSize unlimited -Filter `
33 | "(UserPrincipalName -notlike 'a-*') `
34 | -and (UserPrincipalName -notlike 'ga-*') `
35 | -and (UserPrincipalName -notlike 'svc-*') `
36 | -and (RemotePowerShellEnabled -eq 'true')"
37 | Write-Host "$($UnprivilegedUsers.Count) users in need of disabling were found!"
38 |
39 | # Sets users as unable to user remote powershell
40 | if ($UnprivilegedUsers)
41 | {
42 | $UnprivilegedUsers | foreach {
43 | Set-User -Identity $_.DistinguishedName -RemotePowerShellEnabled $false
44 | Write-Host "Disabled Remote PowerShell for $($_.Name)"
45 | }
46 | }
47 | # If no users were found, report.
48 | Else
49 | {Write-Host "All in-scope accounts already have Remote PowerShell disabled."}
50 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/HIDGlobal.Logging.admx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/HIDGlobal.AdvancedDiagnostics.admx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/scripts/powershell/PKI/Set-AzureKeyVaultSignature.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Author: @garrett-wood
3 |
4 | Purpose:
5 | This script can be used to sign code procedurally. It uses the Az module to aquire an identity with permissions in Azure, then gets
6 | the access token that's used by the Sign Tool. It is currently setup to be agnostic to cloud location eg. US Gov vs Commercial
7 |
8 | Requirements:
9 | Az PowerShell Module (https://www.powershellgallery.com/packages/Az/6.0.0)
10 | AzureSignTool Nuget Package (https://www.nuget.org/packages/AzureSignTool/)
11 | .NET Framework 2.1.0 (https://aka.ms/dotnet-core-applaunch?framework=Microsoft.NETCore.App&framework_version=2.1.0&arch=x64&rid=win10-x64)
12 |
13 | Instructions:
14 | Take the two variables immediately below this description and fill them with the right values for your key vault. Once you've done so, I
15 | strongly recommend you test this by signing this script itself. You can swap out the timestamp authority to your choice, it doesn't matter
16 | as long as it has RFC 3161 compliance. Note that you will need to assign permissions into the key vault in order to use this. I recommend
17 | that you visit the github page for Azure Key Vault to determine what is necessary.
18 | #>
19 |
20 | # This is the name of your keyvault. Recommend all lower case.
21 | $VaultName = 'contoso-codesigning-kv'
22 | # This is the name of the cert within your vault.
23 | $VaultCert = 'Contoso-EV-CodeSignging-Cert'
24 | # This is the authority you use for timestamping. Always timestamp your code unless you have a known, specific reason to not do so.
25 | $Timestamp = 'http://timestamp.entrust.net/rfc3161ts2'
26 |
27 |
28 | # Creates dialog box to select file
29 | $initialDirectory = [environment]::getfolderpath("Desktop")
30 | [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
31 | $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
32 | $OpenFileDialog.initialDirectory = $initialDirectory
33 | $OpenFileDialog.filter = "Executable Files|*.ps1;*.dll;*.msi;*.exe;*.appx;*.appxbundle"
34 | $OpenFileDialog.ShowDialog() | Out-Null
35 | $FilePath = $OpenFileDialog.FileName
36 |
37 | # Connects to Azure with said credential, and uses authentication session to obtain key vault token
38 | $TenantId = (Get-ItemProperty (Get-ChildItem "HKLM:/SYSTEM/CurrentControlSet/Control/CloudDomainJoin/JoinInfo").Name.Replace("HKEY_LOCAL_MACHINE","HKLM:")).TenantId
39 | $WellKnown = Invoke-RestMethod "https://login.microsoftonline.com/$TenantId/v2.0/.well-known/openid-configuration"
40 | $AzEnvironment = Get-AzEnvironment | Where-Object ActiveDirectoryAuthority -like "*$($WellKnown.cloud_instance_name)*"
41 | $KeyVaultSuffix = $AzEnvironment.AzureKeyVaultServiceEndpointResourceId.Split('//')[2]
42 | Connect-AzAccount -Environment $AzEnvironment.Name
43 | $Token = Get-AzAccessToken -ResourceTypeName KeyVault
44 | Disconnect-AzAccount
45 |
46 | # Signs Binaries
47 | AzureSignTool.exe sign `
48 | --azure-key-vault-url ("https://" + $VaultName + ".$KeyVaultSuffix/") `
49 | --azure-key-vault-accesstoken $Token.Token `
50 | --azure-key-vault-certificate $VaultCert `
51 | --timestamp-rfc3161 $Timestamp `
52 | --verbose `
53 | $FilePath
54 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Automated M365 Licenses/Instructions.md:
--------------------------------------------------------------------------------
1 | # Custom Object
2 |
3 | Creating your records in Freshservice is an essential part of making this automation work. The first step is creating the service catalog items, which you can reference the Freshservice KB's on. From here, create a custom object with the following object fields:
4 |
5 |
6 | | Field Name | Field Type | Data Source | Dropdown Field | Required |
7 | |-------------|------------|---------------|----------------|----------|
8 | | LicenseType | Lookup | Service Items | - | Yes |
9 | | Group GUID | Text | - | - | Yes |
10 | | Sku GUID | Text | - | - | Yes |
11 |
12 | I've populated mine with the following records, but depending on what licenses you're offering as addons you may have different needs. Note these are the GCC High Sku ID's. You might need something else if you're in GCC or Commercial. Well, no might about it. Check the Graph API or PowerShell on this is MS's Documentation states they will not keep the information up-to-date. The Group ID is the GUID for the Group in Azure AD that you're using for Group-based licensing.
13 |
14 |
15 | | Record ID | License Type | Group ID | Sku ID |
16 | |-----------|--------------------------|--------------------------------------|--------------------------------------|
17 | | 1 | Teams Audio Conferencing | 00000000-0000-0000-0000-000000000000 | 4dee1f32-0808-4fd2-a2ed-fdd575e3a45f |
18 | | 2 | Microsoft 365 E5 | 00000000-0000-0000-0000-000000000000 | 4eb45c5b-0d19-4e33-b87c-adfc25268f20 |
19 | | 3 | Microsoft Project | 00000000-0000-0000-0000-000000000000 | 64758d81-92b7-4855-bcac-06617becb3e8 |
20 | | 4 | Microsoft Visio | 00000000-0000-0000-0000-000000000000 | 80e52531-ad7f-44ea-abc3-28e389462f1b |
21 | | 5 | PowerBI Pro | 00000000-0000-0000-0000-000000000000 | 49dd7469-0b04-4996-a11a-73947c28a36e |
22 |
23 | # Workflow Automation
24 | 
25 |
26 | **Note:** *The DID component referenced above is not functioning due to a Microsoft Failure. Expect an update once the MS Teams PowerShell Module is fixed for CBA.*
27 | The majority of this workflow will be tuned to the organization, but the following JSON should be used for the the two webhooks:
28 | Check License Availability:
29 | ```json
30 | {
31 | "licensedSku": "{{R3.sku_guid}}",
32 | "ticketNumber": "{{ticket.id_numeric}}",
33 | "licenseName": "{{R3.license_type_value}}",
34 | "operation": "verify"
35 | }
36 | ```
37 |
38 | Process License Assignment:
39 | ```json
40 | {
41 | "licensedSku": "{{R3.sku_guid}}",
42 | "ticketNumber": "{{ticket.id_numeric}}",
43 | "licenseName": "{{R3.license_type_value}}",
44 | "operation": "assign",
45 | "licensedUser": "{{ticket.actual_requester.email}}",
46 | "licensedGroup": "{{R3.group_guid}}"
47 | }
48 | ```
49 |
50 | From here again, your implementation will differ, but in my case, a webhook was sent out to an Azure Function.
51 |
--------------------------------------------------------------------------------
/ADMX/Google Chrome/Readme.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Similar to an on-premises Active Directory environment. Chrome published ADMX policies can be imported and utilized to manage Chrome settings through Microsoft Endpoint Manager.
4 |
5 | While there are a number of configurations that can be done this document will outline importing the ADMX info and configuration settings required for Chrome to be compatible with Azure AD conditional access policies. A preview STIG in Endpoint Manager json format has been published and should be referred to for secure configurations https://public.cyber.mil/stigs/gpo/.
6 |
7 | # Process
8 |
9 | 1. Import the ADMX Files into Intune using the standard process as shown in the table below. The files are in this folder in the repo.
10 |
11 | | Name | OMA-URI | Data type |
12 | |------------------------------------|---------------------------------------------------------------------------------------------------------|-----------|
13 | | chrome.admx | `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/Chrome/Policy/ChromeADMX` | String |
14 |
15 | 2. From here, you should stop and apply the policy to some devices. Verify you succeed, and see the values in the Registry before you continue.
16 |
17 | 3. Add the policies you need to. The below are a few examples. The ExtensionInstallForceList will install extensions required for device based conditional access policies within Azure AD.
18 |
19 | | Name | OMA-URI | Data type |
20 | |----------------------------------|----------------------------------------------------------------------------------------------------------------------|-----------|
21 | | MicrosoftExtensions | `./Device/Vendor/MSFT/Policy/Config/Chrome~Policy~googlechrome~Extensions/ExtensionInstallForcelist` | String |
22 |
23 |
24 | # Details:
25 |
26 | ### MicrosoftExtensions
27 | Contains the values required to configure the Chrome [ExtensionInstallForceList](https://chromeenterprise.google/policies/?policy=ExtensionInstallForcelist) so that the Windows 10 Accounts and Microsoft Defender extensions are automatically installed from the Chrome public marketplace.
28 |
29 | The format of the data within the file follows standard conventions and starts with an `` node to enable the settings. That is followed by a `` node to list out the settings value. The format for the value property is `;`. In this specific file we are installing two extensions, the first one with the incrementing number of 1 is the [Windows Accounts](https://chrome.google.com/webstore/detail/windows-10-accounts/ppnbnpeolgkicgegkbkbjmhlideopiji?hl=en) extension which has an ID of `ppnbnpeolgkicgegkbkbjmhlideopiji`. The second extension is the [Microsoft Defender](https://chrome.google.com/webstore/detail/microsoft-defender-browse/bkbeeeffjjeopflfhgeknacdieedcoml?hl=en) extension which has an ID of `bkbeeeffjjeopflfhgeknacdieedcoml`. The update URL is a common URL if installing from the public Chrome Webstore `https://clients2.google.com/service/update2/crx`.
30 |
31 | The settings within the MicrosoftExtensions.xml file are generic and can be deployed as is to tenants within Commercial, GCC and GCC-H without modification. Deployng as is will ensure the necessary Chrome extensions are install so Chrome will work with device based conditional access policies.
32 |
33 | This sample includes Microsoft specific extensions but you can modify the `` node to include additional extensions to install through the following process.
34 |
35 | 1) Open the extension within the Chrome webstore to discover the extension ID
36 | 2) Review the browser URL for the Extension ID.
37 | https://chrome.google.com/webstore/detail/microsoft-defender-browse/bkbeeeffjjeopflfhgeknacdieedcoml?hl=en is the Defender URL, the extension ID is located at the end of the URL and is `bkbeeeffjjeopflfhgeknacdieedcoml`. The `?hl=en` is not part of the ID
38 |
39 | 3) Append `3;https://clients2.google.com/service/update2/crx` to the value replacing `` with the ID you retrieve from the step 2
40 | 4) You can continue this to add additional ones increasing the 3 to 4 and so on as you add additional extensions
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Dependencies/ApplicationSettings.md:
--------------------------------------------------------------------------------
1 | | name | value | slotSetting |
2 | |---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
3 | | AdDomainName | ad.contoso.com | false |
4 | | AdOrganizationalUnit | OU=Contractors,OU=User Accounts,DC=ad,DC=contoso,DC=com | false |
5 | | AdPassword | password | false |
6 | | AdUserPrincipalNamePrefix | svc-yourserviceaccount | false |
7 | | EntrustEcsCertificate | AAAAABBBBBCCCCCDDDDDEEEEEFFFFF0123456789 | false |
8 | | EntrustEcsPassword | password | false |
9 | | EntrustEcsUser | 0123456789-87654321 | false |
10 | | ExchangeOrganizationName | contoso.onmicrosoft.us | false |
11 | | FreshserviceApiKey | password | false |
12 | | FreshserviceDomain | https://contoso.freshservice.com | false | | false |
13 | | MsGraphClientCertificate | AAAAABBBBBCCCCCDDDDDEEEEEFFFFF0123456789 | false |
14 | | MsGraphClientId | 00000000-0000-0000-0000-000000000000 | false |
15 | | MsGraphClientSecret | QWERTY12345!@#$%ZXCVBzxcvb::::: | false |
16 | | MsGraphEmailSenderId | 00000000-0000-0000-0000-000000000000 | false |
17 | | MsGraphTenantId | 00000000-0000-0000-0000-000000000000 | false |
18 | | WEBSITE_LOAD_CERTIFICATES | * | false |
19 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/Readme.md:
--------------------------------------------------------------------------------
1 | # Overview
2 | There is a known issue with HID ActivClient and how it interacts with Microsoft Information Protection in Microsoft Outlook. Fortunately, there's a simple enough fix for this,
3 | which involves simply removing the permissions for `OUTLOOK.EXE` to access the PIN Caching Subsystem for ActivClient. Fortunately, we don't need to entirely removing the PIN
4 | Caching function to resolve this and the removal can be done manually. This can be resolved by setting a single entry in the Registry. The Key in question is located in `HKLM:\SOFTWARE\Policies\HID Global\SharedStore\Authentication\ExcludeList`. The children of this key should be string (`REG_SZ`) values with the same name and value. In the case of Outlook, you'd follow the format listed in the `PINCachingExcludeList.xml` file that is available in this folder. Fortunately, the US Government has already released the necessary ADMX files in their public repo [here](https://github.com/nsacyber/Windows-Secure-Host-Baseline/tree/master/ActivClient/Group%20Policy%20Templates), with the appropriate usage rights so we'll go right ahead and take advantage of that.
5 |
6 | # Process
7 |
8 | 1. Import the ADMX Files into Intune using the standard process as shown in the table below. The files are in this folder in the repo.
9 |
10 | | Name | OMA-URI | Data type |
11 | |------------------------------------|---------------------------------------------------------------------------------------------------------|-----------|
12 | | HIDGlobal.AdvancedDiagnostics.admx | `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/HIDGlobal/Policy/HIDGlobal.AdvancedDiagnostics` | String |
13 | | HIDGlobal.Logging.admx | `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/HIDGlobal/Policy/HIDGlobal.Logging` | String |
14 | | HIDGlobal.ActivClient0.admx | `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/HIDGlobal/Policy/HIDGlobal.ActivClient0` | String |
15 | | HIDGlobal.ActivClient1.admx | `./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/HIDGlobal/Policy/HIDGlobal.ActivClient1` | String |
16 |
17 | 2. From here, you should stop and apply the policy to some devices. Verify you succeed, and see the values in the Registry before you continue.
18 |
19 | 3. Add the policies you need to. The below are a few examples. The PINCachingExcludeList is what will fix the Outlook issue, and exempting the WHfB from the useable readers should fix the issue with being unable to enroll IdenTrust certificates is taken care of with the ReaderBlackList policy. You can find these files in this same folder using the .xml naming convention.
20 |
21 | | Name | OMA-URI | Data type |
22 | |----------------------------------|----------------------------------------------------------------------------------------------------------------------|-----------|
23 | | PINCachingExcludeList | `./Device/Vendor/MSFT/Policy/Config/HIDGlobal~Policy~CAT_ActivClient~PinCaching/PINCachingExcludeList` | String |
24 | | TimeOutToClearCache | `./Device/Vendor/MSFT/Policy/Config/HIDGlobal~Policy~CAT_ActivClient~PinCaching/TimeOutToClearCache` | String |
25 | | HidePublishToGal | `./Device/Vendor/MSFT/Policy/Config/HIDGlobal~Policy~CAT_ActivClient~UserConsole/HidePublishToGal` | String |
26 | | AutoConfigEFS | `./Device/Vendor/MSFT/Policy/Config/HIDGlobal~Policy~CAT_ActivClient~CertificateAvailability/AutoConfigEFS` | String |
27 | | UnlockCardContactTelephoneNumber | `./Device/Vendor/MSFT/Policy/Config/HIDGlobal~Policy~CAT_ActivClient~PinManagement/UnlockCardContactTelephoneNumber` | String |
28 | | ReaderBlackList | `./Device/Vendor/MSFT/Policy/Config/HIDGlobal~Policy~CAT_ActivClient~SmartCardReaders/ReaderBlackList` | String |
29 |
30 | # Details:
31 |
32 | ### PINCachingExcludeList
33 | This should be used if you want to avoid the S/MIME and MS AIP incompatibility issue. This is probably the reason most of you are here.
34 |
35 | ### TimeOutToClearCache
36 | This should be used to increase or further drop the timeout for the PIN Caching. Default is 15 minutes. Values are 0 (disabled) to 9999 (infinite) which you really shouldn't use.
37 |
38 | ### HidePublishToGal
39 | Are you using Azure AD-joined devices? ActivClient's Publish to GAL button will cause an error. Don't want the helpdesk tickets? Use this one.
40 |
41 | ### AutoConfigEFS
42 | ActivClient will use the default cert (if it is capable) for setting up EFS. You probably don't want that.
43 |
44 | ### UnlockCardContactTelephoneNumber
45 | This will set the contact number it displays for users when they ask for help because their card is locked. You probably want your helpdesk here.
46 |
47 | ### ReaderBlackList
48 | Add WHfB, YubiKey or whatever else you don't want handled by ActivClient Here. Implied wildcard on the end. Case-Sensitive.
49 |
50 |
51 | ## Author
52 | @garrett-wood
53 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Onboard Employees/Send-EmployeeOnboardingMessages.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Author: @garrett-wood
3 | Purpose: Automates the onboarding task of transmitting the welcome email and send the user an encrypted set of credentials
4 | Requirements: This is written for addressing the MS Graph to send the email, and Freshservice API for the ITSM system. Adjust per your environment.
5 | Usage: This function expects a secured webhook provideing a JSON payload in the following format
6 |
7 | ----
8 | {
9 | "name": "John Doe",
10 | "username": "john.doe@contoso.com",
11 | "password": "MyRandomSecurePassword12345!",
12 | "tomail": "john.doe@personalmail.com",
13 | "ticket": "123456"
14 | }
15 | ----
16 |
17 | You can modify the below attributes with adequate understanding of PowerShell if you can't send the payload in that format.
18 | Once the webhook is received, the system sends the welcome email and then waits 30 seconds before sending the encryped creds.
19 |
20 | It is expected that all credential components be passed through application settings.
21 | #>
22 |
23 | using namespace System.Net
24 |
25 | # Input bindings are passed in via param block.
26 | param($Request, $TriggerMetadata)
27 |
28 | # Defines custom function to get MS Graph access token.
29 | function New-MsGraphAccessToken
30 | {
31 | Param
32 | (
33 | # Should probably validate these in some way.
34 | $TenantId,
35 | $ClientId,
36 | $ClientSecret
37 | )
38 | # Pulls proper Graph and Token endpoints from Domain using Well Known OpenId Configuration Endpoint
39 | $TenantWellKnown = Invoke-RestMethod -uri "https://login.microsoftonline.com/$TenantId/v2.0/.well-known/openid-configuration"
40 | $GraphEndpoint = $TenantWellKnown.msgraph_host
41 | $TokenEndpoint = $TenantWellKnown.token_endpoint
42 |
43 | # Sends request to acquire bearer token
44 | $ApiConnection = Invoke-RestMethod `
45 | -Method Post `
46 | -Uri $TokenEndpoint `
47 | -ContentType 'application/x-www-form-urlencoded' `
48 | -Body @{
49 | client_id = "$ClientId"
50 | scope = "https://$GraphEndpoint/.default"
51 | client_secret = "$ClientSecret"
52 | grant_type = "client_credentials"
53 | }
54 | # Returns PSObject which contains the token as a secure string, graph and point and Tenant Id. These are returned in case
55 | # further references are needed in dependent functions.
56 | $BearerToken = ($ApiConnection.access_token | ConvertTo-SecureString -AsPlainText -Force)
57 | $Output = New-Object -TypeName PSObject
58 | $Output | Add-Member -MemberType NoteProperty -Name BearerToken -Value $BearerToken
59 | $Output | Add-Member -MemberType NoteProperty -Name GraphHost -Value $GraphEndpoint
60 | $Output | Add-Member -MemberType NoteProperty -Name TenantScope -Value $TenantId
61 | Return $Output
62 | }
63 |
64 | # Obtains MS Graph token
65 | Write-Information "Obtaining Access Token for Microsoft Graph"
66 | $Token = New-MsGraphAccessToken `
67 | -TenantId $env:MsGraphTenantId `
68 | -ClientId $env:MsGraphClientId `
69 | -ClientSecret $env:MsGraphClientSecret
70 |
71 | # Sets up Credentials for Freshservice API
72 | Write-Information "Building Freshservice API Credential"
73 | [string]$userName = $env:FreshserviceApiKey
74 | [string]$userPassword = 'x'
75 | [securestring]$secStringPassword = ConvertTo-SecureString $userPassword -AsPlainText -Force
76 | [pscredential]$credObject = New-Object System.Management.Automation.PSCredential ($userName, $secStringPassword)
77 | $FreshserviceDomain = ($env:FreshserviceDomain)
78 |
79 | # Converts Webhook Body to a PSObject
80 | $RequestObject = $Request.RawBody | ConvertFrom-Json
81 | Write-Information "Converting Webhook from JSON to PS Object"
82 | Write-Information $RequestObject
83 |
84 | # Sets up Variables so they don't have be be escaped. Those based on Request Object come from a webhook, environment variables are stored in the function.
85 | $ToEmail = $RequestObject.tomail
86 | $ToName = $RequestObject.Name
87 | $SenderGuid = $env:MsGraphEmailSenderId
88 | $PayloadUsername = $RequestObject.username
89 | $PayloadPassword = $RequestObject.password
90 | $Ticket = $RequestObject.ticket
91 |
92 | # Sets up Message Body to send message --- CONTENT MOSTLY REDACTED
93 | $WelcomeMessage = "Hi $ToName, `
94 |
`
95 | Thank you for being a part of Contoso! We are happy to have you on the team. `
96 | In order to get you up and running as quickly as possible, please reference the below items and reach out to the ServiceDesk with questions. Our contact information is at the bottom of this email. `
97 |
`
98 | Logging In:
`
99 | You will receive an encrypted email shortly which contains your Contoso username and password. You can follow the guide in the link below to open the email. Since Contoso uses Single Sign On for most of our systems, this is one of the few passwords you will need to remember here.
`
100 | We look forward to working with you. Once again, welcome to Contoso. `
101 |
`
102 |
`
103 | --- `
104 |
`
105 | Contoso ServiceDesk Team
`
106 | Email: servicedesk@contoso.com
`
107 | Web: https://contoso.freshservice.com
`
108 | Phone: (555) 555-5555 x555
`
109 | "
110 |
111 | $WelcomeMessageBody = @"
112 | {
113 | "message": {
114 | "subject": "Welcome to Contoso",
115 | "body": {
116 | "contentType": "Html",
117 | "content": "$WelcomeMessage"
118 | },
119 | "toRecipients": [{
120 | "emailAddress": {
121 | "address": "$ToEmail"
122 | }
123 | }]
124 | }
125 | }
126 | }
127 | "@
128 |
129 | # Sends Initial Message to User
130 | Write-Information "Sending welcome email to user."
131 | Invoke-RestMethod `
132 | -Method Post `
133 | -ContentType 'application/json' `
134 | -Uri "https://$($Token.GraphHost)/v1.0/users/$SenderGuid/sendMail" `
135 | -Authentication Bearer `
136 | -Token $Token.BearerToken `
137 | -Body $WelcomeMessageBody
138 |
139 | # Sets up Message Body to send message
140 | $CredentialMessage = "Hi $ToName, `
141 |
`
142 | Your Contoso are below: `
143 |
`
144 | Username:
`
145 | $($RequestObject.username) `
146 |
`
147 | Password:
`
148 | $($RequestObject.password) `
149 |
`
150 | For assistance in resetting your password, please visit the following link:
`
151 | LINK TO KB REMOVED `
152 |
`
153 |
`
154 | Please test these credentials, and set your password as soon as possible. Note that some of your accounts may not be available until your start date. `
155 |
`
156 |
`
157 | --- `
158 |
`
159 | Contoso ServiceDesk Team
`
160 | Email: servicedesk@contoso.com
`
161 | Web: https://contoso.freshservice.com
`
162 | Phone: (555) 555-5555 x555
`
163 | "
164 |
165 | $CredentialMessageBody = @"
166 | {
167 | "message": {
168 | "subject": "Contoso Credentials *encrypt*",
169 | "body": {
170 | "contentType": "Html",
171 | "content": "$CredentialMessage"
172 | },
173 | "toRecipients": [{
174 | "emailAddress": {
175 | "address": "$ToEmail"
176 | }
177 | }]
178 | }
179 | }
180 | }
181 | "@
182 |
183 | # Waits 30 seconds to ensure the message that's unencrypted arrives first.
184 | Write-Information "Waiting 30 seconds..."
185 | Start-Sleep -Seconds 30
186 |
187 | # Sends Credentials to User
188 | Write-Information "Sending credentials to user."
189 | Invoke-RestMethod `
190 | -Method Post `
191 | -ContentType 'application/json' `
192 | -Uri "https://$($Token.GraphHost)/v1.0/users/$SenderGuid/sendMail" `
193 | -Authentication Bearer `
194 | -Token $Token.BearerToken `
195 | -Body $CredentialMessageBody
196 |
197 | # Creates post content for updating the ticket in Freshservice
198 | $TicketPostContent = @"
199 | {
200 | "helpdesk_note": {
201 | "body":"The account for $ToName has been created. \n \n Username: \n $($RequestObject.username) \n \n Password: \n $($RequestObject.password)"
202 | }
203 | }
204 | "@
205 |
206 | # Sends ticket update to freshservice
207 | Write-Information "Updating ServiceDesk ticket."
208 | Invoke-RestMethod `
209 | -Uri "$FreshserviceDomain/helpdesk/tickets/$ticket/conversations/note.json" `
210 | -Method Post `
211 | -Authentication Basic `
212 | -Credential $credObject `
213 | -ContentType 'application/json' `
214 | -Body $TicketPostContent
215 |
216 | # Sets up payload for ticket close
217 | $ClosePutContent = @"
218 | {
219 | "helpdesk_ticket": {
220 | "status":5
221 | }
222 | }
223 | "@
224 |
225 | # Closes out onboarding ticket
226 | Write-Information "Closing ServiceDesk ticket."
227 | Invoke-RestMethod `
228 | -Uri "$FreshserviceDomain/helpdesk/tickets/$ticket.json" `
229 | -Method Put `
230 | -Authentication Basic `
231 | -Credential $credObject `
232 | -ContentType 'application/json' `
233 | -Body $ClosePutContent
234 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Automated M365 Licenses/Automated-M365-Licenses.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Author: @garrett-wood
3 | Purpose: To be run in a PowerShell Azure Function to automatically assign licenses when requests through Freshservice Service Catalog. Total time to license
4 | assignment when using this method is under 5 seconds from supervisor approval to assignment. Will also alert a human when licenses are getting low.
5 | #>
6 |
7 | # Note that you MUST setup custom statuses in Freshservice and pipe your own values in. This is specific to our workflow. Sub in yours.
8 | # In the example environment, the naming convention for these groups is "License-$licensename" and the E3 and E5 groups are not handled here.
9 |
10 | using namespace System.Net
11 |
12 | # Input bindings are passed in via param block.
13 | param($Request, $TriggerMetadata)
14 |
15 | <# This functions expects the following format as an input for verification requests
16 |
17 | {
18 | "licensedSku": "{{R3.sku_guid}}",
19 | "ticketNumber": "{{ticket.id_numeric}}",
20 | "licenseName": "{{R3.license_type_value}}",
21 | "operation": "verify"
22 | }
23 |
24 | and the following format for assignment requests
25 |
26 | {
27 | "licensedSku": "{{R3.sku_guid}}",
28 | "ticketNumber": "{{ticket.id_numeric}}",
29 | "licenseName": "{{R3.license_type_value}}",
30 | "operation": "assign",
31 | "licensedUser": "{{ticket.actual_requester.email}}",
32 | "licensedGroup": "{{R3.group_guid}}"
33 | }
34 |
35 | #>
36 |
37 | # Write to the Azure Functions log stream.
38 | Write-Host "PowerShell HTTP trigger function processed a request."
39 |
40 | #########################################################################################################################################
41 | # #
42 | # SECTION 1 - REQUIRED FUNCTIONS #
43 | # #
44 | #########################################################################################################################################
45 |
46 | # Defines custom function to get MS Graph access token.
47 | function New-MsGraphAccessToken
48 | {
49 | Param
50 | (
51 | # Should probably validate these in some way.
52 | $TenantId,
53 | $ClientId,
54 | $ClientSecret
55 | )
56 | # Pulls proper Graph and Token endpoints from Domain using Well Known OpenId Configuration Endpoint
57 | $TenantWellKnown = Invoke-RestMethod -uri "https://login.microsoftonline.com/$TenantId/v2.0/.well-known/openid-configuration"
58 | $GraphEndpoint = $TenantWellKnown.msgraph_host
59 | $TokenEndpoint = $TenantWellKnown.token_endpoint
60 |
61 | # Sends request to acquire bearer token
62 | $ApiConnection = Invoke-RestMethod `
63 | -Method Post `
64 | -Uri $TokenEndpoint `
65 | -ContentType 'application/x-www-form-urlencoded' `
66 | -Body @{
67 | client_id = "$ClientId"
68 | scope = "https://$GraphEndpoint/.default"
69 | client_secret = "$ClientSecret"
70 | grant_type = "client_credentials"
71 | }
72 | # Returns PSObject which contains the token as a secure string, graph and point and Tenant Id. These are returned in case
73 | # further references are needed in dependent functions.
74 | $BearerToken = ($ApiConnection.access_token | ConvertTo-SecureString -AsPlainText -Force)
75 | $Output = New-Object -TypeName PSObject
76 | $Output | Add-Member -MemberType NoteProperty -Name BearerToken -Value $BearerToken
77 | $Output | Add-Member -MemberType NoteProperty -Name GraphHost -Value $GraphEndpoint
78 | $Output | Add-Member -MemberType NoteProperty -Name TenantScope -Value $TenantId
79 | Return $Output
80 | }
81 |
82 | #########################################################################################################################################
83 | # #
84 | # SECTION 2 - VARIABLE ASSIGNMENT #
85 | # #
86 | #########################################################################################################################################
87 |
88 | # Converts Freshservice Payload to PowerShell formatting
89 | Write-Information "The following was receieved as a webhook"
90 | Write-Information $Request.RawBody
91 | $LicenseOperation = $Request.RawBody | Convertfrom-Json
92 |
93 | # Obtains MS Graph token. This is used to send the email.
94 | Write-Information "Obtaining Access Token for Microsoft Graph"
95 | $Token = New-MsGraphAccessToken `
96 | -TenantId $env:MsGraphTenantId `
97 | -ClientId $env:MsGraphClientId `
98 | -ClientSecret $env:MsGraphClientSecret
99 |
100 | # Retreives a list of all licenses for the tenant
101 | Write-Information "Checking Current License Status"
102 | $GraphLicenses = Invoke-RestMethod `
103 | -Method Get `
104 | -ContentType 'application/json' `
105 | -Uri "https://$($Token.GraphHost)/v1.0/subscribedSkus" `
106 | -Authentication Bearer `
107 | -Token $Token.BearerToken | Select -expand value
108 |
109 | # Sets up Message Body to send message
110 | $WarningMessage = "Hi Service Desk Team, `
111 |
`
112 | Human intervention may soon be required on the Service Request for #SR-$($LicenseOperation.ticketNumber). `
113 |
`
114 | The following License is currently at critical assignment status (greater than 95% allocated and/or 3 or fewer left). `
115 |
`
116 | Name:
`
117 | $($LicenseOperation.licenseName) `
118 |
Sku Id:
`
119 | $($LicenseOperation.licensedSku) `
120 |
`
121 | Please re-evaluate current license counts, terminate inactive licenses or purchase more ASAP. `
122 |
`
123 |
`
124 | --- `
125 |
`
126 | Automation Orchestrator
`
127 | "
128 | # CHANGE THIS TO ADDRESS VALUE
129 | $WarningMessageBody = @"
130 | {
131 | "message": {
132 | "subject": "Critical License Threshold - $($LicenseOperation.licenseName)",
133 | "body": {
134 | "contentType": "Html",
135 | "content": "$WarningMessage"
136 | },
137 | "toRecipients": [{
138 | "emailAddress": {
139 | "address": "servicedesk@contoso.com"
140 | }
141 | }]
142 | }
143 | }
144 | }
145 | "@
146 |
147 | # Sets up Credentials for Freshservice API
148 | Write-Information "Building Freshservice Credential Object"
149 | $FreshserviceApiKey = $env:FreshserviceApiKey
150 | $FreshserviceApiPss = 'x' | ConvertTo-SecureString -AsPlainText -Force
151 | $FsCredential = New-Object System.Management.Automation.PSCredential ($FreshserviceApiKey, $FreshserviceApiPss)
152 | $FreshserviceDomain = ($env:FreshserviceDomain)
153 |
154 | # Updates Freshservice Ticket to Alert User
155 | $TicketPostContent = @"
156 | {
157 | "helpdesk_note": {
158 | "body":"We are currently running low on these licenses and may be out by the time your supervisor approves your request. If this happens, we will keep you updated.",
159 | "private":false
160 | }
161 | }
162 | "@
163 |
164 | # Updates Freshservice Ticket to Alert User
165 | $CapacityPostContent = @"
166 | {
167 | "helpdesk_note": {
168 | "body":"We no longer have any licenses available to meet this request. The Service Desk team has already been alerted and will keep you updated.",
169 | "private":false
170 | }
171 | }
172 | "@
173 |
174 | # Updates Freshservice Ticket to Alert User
175 | $SuccessPostContent = @"
176 | {
177 | "helpdesk_note": {
178 | "body":"This license has been assigned to you. Note that this change can take up to an hour to process. Please let us know if anything further is needed.",
179 | "private":false
180 | }
181 | }
182 | "@
183 |
184 | #########################################################################################################################################
185 | # #
186 | # SECTION 3 - VERIFY LICENSE COUNT AND NOTIFY IF REACHED THRESHOLD #
187 | # #
188 | #########################################################################################################################################
189 |
190 | # Gets values for current assignments and maximum assignments
191 | $Consumed = $GraphLicenses | Where-Object SkuId -eq $LicenseOperation.licensedSku | Select -expand consumedUnits
192 | $Maximum = $GraphLicenses | Where-Object SkuId -eq $LicenseOperation.licensedSku | Select -expand prepaidunits | Select -Expand Enabled
193 | Write-Information "Licenses Consumed: $Consumed"
194 | Write-Information "Licenses Maximum: $Maximum"
195 | $ConsumptionRatio = $Consumed / $Maximum
196 | $AvailableLicenses = $Maximum - $Consumed
197 | $CriticalThreshold = ($ConsumptionRatio -gt .95) -or ($AvailableLicenses -lt 4)
198 | $FullyCommitted = ($AvailableLicenses -lt 1)
199 |
200 | # Sends a warning if license usage has reached critical threshold
201 | If ($CriticalThreshold)
202 | {
203 | # Sends a Warning to the ServiceDesk. TODO - Store the GUID for the orchestrator account as a variable.
204 | Write-Information "Opening a ticket with the servicedesk due to critical license count"
205 | Invoke-RestMethod `
206 | -Method Post `
207 | -ContentType 'application/json' `
208 | -Uri "https://$($Token.GraphHost)/v1.0/users/00000000-0000-0000-0000-000000000000/sendMail" `
209 | -Authentication Bearer `
210 | -Token $Token.BearerToken `
211 | -Body $WarningMessageBody
212 |
213 | # Sends ticket update to freshservice
214 | Write-Information "Updating ServiceDesk ticket with critical license issue."
215 | Invoke-RestMethod `
216 | -Uri "$FreshserviceDomain/helpdesk/tickets/$ticket/conversations/note.json" `
217 | -Method Post `
218 | -Authentication Basic `
219 | -Credential $FsCredential `
220 | -ContentType 'application/json' `
221 | -Body $TicketPostContent
222 | }
223 |
224 | #########################################################################################################################################
225 | # #
226 | # SECTION 4 - ASSIGN AND/OR UPDATE TICKET #
227 | # #
228 | #########################################################################################################################################
229 |
230 | # If capacity has been reached, update the ticket.
231 | If ($FullyCommitted)
232 | {
233 | # Sends ticket update to freshservice
234 | Write-Information "No licenses left to assign."
235 | Invoke-RestMethod `
236 | -Uri "$FreshserviceDomain/helpdesk/tickets/$ticket/conversations/note.json" `
237 | -Method Post `
238 | -Authentication Basic `
239 | -Credential $FsCredential `
240 | -ContentType 'application/json' `
241 | -Body $CapacityPostContent
242 | }
243 | # If Capacity has not yet been reached, and the operation is to assign, then assign the license. TODO: Add check to see if user is currently member
244 | ElseIf ($LicenseOperation.operation -eq 'assign')
245 | {
246 | # Obtains User Guid
247 | $User = Invoke-RestMethod `
248 | -Method Get `
249 | -ContentType 'application/json' `
250 | -Uri "https://$($Token.GraphHost)/v1.0/users/$($LicenseOperation.licensedUser)" `
251 | -Authentication Bearer `
252 | -Token $Token.BearerToken
253 | Write-Information "Found User based on UPN"
254 | Write-Information $User
255 |
256 | # Adds User To Group
257 | Invoke-RestMethod `
258 | -Method Post `
259 | -ContentType 'application/json' `
260 | -Uri "https://$($Token.GraphHost)/v1.0/groups/$($LicenseOperation.licensedGroup)/members/`$ref" `
261 | -Authentication Bearer `
262 | -Token $Token.BearerToken `
263 | -Body (@{ "@odata.id" = "https://$($Token.GraphHost)/v1.0/directoryObjects/$($User.id)" } | ConvertTo-Json)
264 |
265 | # Updates Freshservice Ticket
266 | Write-Information "Updating ServiceDesk ticket with success."
267 | Invoke-RestMethod `
268 | -Uri "$FreshserviceDomain/helpdesk/tickets/$($LicenseOperation.ticketNumber)/conversations/note.json" `
269 | -Method Post `
270 | -Authentication Basic `
271 | -Credential $FsCredential `
272 | -ContentType 'application/json' `
273 | -Body $SuccessPostContent
274 |
275 | # Sets ticket to waiting on customer
276 | Write-Information "Setting ticket to waiting on customer"
277 | Invoke-RestMethod `
278 | -Uri "$FreshserviceDomain/helpdesk/tickets/$ticket.json" `
279 | -Method Put `
280 | -Authentication Basic `
281 | -Credential $FsCredential `
282 | -ContentType 'application/json' `
283 | -Body (@{'helpdesk_ticket' = @{'status' = 7}} | ConvertTo-Json)
284 |
285 | }
286 |
--------------------------------------------------------------------------------
/Automations/AzureFunctions/Onboard Contractors/Onboard-ContractorAccount.ps1:
--------------------------------------------------------------------------------
1 |
2 | <#
3 | Author: @garrett-wood
4 | Purpose: This will be called by Freshservice whenever a Contractor Service Catalog Request is initiated. ALL of this is environmentally specific and is intended
5 | only to give you an idea of what and how something can be done. There is no real way to make a for dummies guide on this. You just need to read and understand it.
6 | #>
7 |
8 | using namespace System.Net
9 |
10 | # Input bindings are passed in via param block.
11 | param($Request, $TriggerMetadata)
12 |
13 | # Write to the Azure Functions log stream.
14 | Write-Host "PowerShell HTTP trigger function processed a request."
15 |
16 | #########################################################################################################################################
17 | # #
18 | # SECTION 1 - REQUIRED FUNCTIONS #
19 | # #
20 | #########################################################################################################################################
21 | <#
22 | Generates Passwords Securely using RNGCryptoServiceProvider in a human readable form. Not really necessary to use the XKCD style here
23 | since these will be federated accounts, but I already wrote the function so it does save time. Modified to static path for the
24 | dictionaries. Any reuse of this function would require the manual addition of those dictionaries until I get around to placing this in
25 | the PS Gallery. Note that this function is actually fair computationally expensive. Using a less secure Get-Random on a dictionary of
26 | symbols may be a better fit depending on organizational needs and use context.
27 | #>
28 |
29 | function New-SecurePassword
30 | {
31 | [cmdletBinding()]
32 | [OutputType([string])]
33 |
34 | Param
35 | (
36 | [ValidateRange(1,24)]
37 | [int]
38 | $MinWordLength = 6,
39 |
40 | [ValidateRange(1,24)]
41 | [int]
42 | $MaxWordLength = 12,
43 |
44 | [ValidateRange(1,24)]
45 | [int]
46 | $WordCount = 2,
47 |
48 | [ValidateRange(1,24)]
49 | [int]
50 | $Count = 1,
51 |
52 | [int]$MaxLength = 65535,
53 |
54 | [switch]$NoSymbols = $False,
55 |
56 | [switch]$NoNumbers = $False
57 |
58 | )
59 |
60 | # Modified for this script - declares known location for dictionary files
61 | $LocalPath = 'D:\home\site\wwwroot\modules\XKCDPasswordGenDictionary\'
62 |
63 | #GENERATE RANDOM PASSWORD(S)
64 | $FinalPasswords = @()
65 | For( $Passwords=1; $Passwords -le $Count; $Passwords++ )
66 | {
67 |
68 | #GENERATE RANDOM LENGTHS FOR EACH WORD
69 | $WordLengths = @()
70 | For( $Words=1; $Words -le $WordCount; $Words++ )
71 | {
72 | [System.Security.Cryptography.RNGCryptoServiceProvider] $Random = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
73 | $RandomNumber = new-object byte[] 1
74 | $WordLength = ($Random.GetBytes($RandomNumber))
75 | [int] $WordLength = $MinWordLength + $RandomNumber[0] %
76 | ($MaxWordLength - $MinWordLength + 1)
77 | $WordLengths += $WordLength
78 | }
79 |
80 | #PICK WORD FROM DICTIONARY MATCHING RANDOM LENGTHS
81 | $RandomWords = @()
82 | ForEach ($WordLength in $WordLengths)
83 | {
84 | $DictionaryPath = ($LocalPath + 'Words_' + $WordLength + '.txt')
85 | $Dictionary = Get-Content -Path $DictionaryPath
86 | $MaxWordIndex = Get-Content -Path $DictionaryPath | Measure-Object -Line | Select -Expand Lines
87 | $RandomBytes = New-Object -TypeName 'System.Byte[]' 4
88 | $Random = New-Object -TypeName 'System.Security.Cryptography.RNGCryptoServiceProvider'
89 | #I don't know why but when the below line is commented out, the function breaks and returns the same words each time.
90 | $RandomSeed = $Random.GetBytes($RandomBytes)
91 | $RNG = [BitConverter]::ToUInt32($RandomBytes, 0)
92 | $WordIndex = ($Random.GetBytes($RandomBytes))
93 | [int] $WordIndex = 0 + $RNG[0] %
94 | ($MaxWordIndex - 0 + 1)
95 | $RandomWord = $Dictionary | Select -Index $WordIndex
96 | $RandomWords += $RandomWord
97 | }
98 |
99 | #RANDOMIZE CASE
100 | $RandomCaseWords = ForEach ($RandomWord in $RandomWords)
101 | {
102 | $ChangeCase = Get-Random -InputObject $True,$False
103 | If ($ChangeCase -eq $True)
104 | {
105 | $RandomWord.ToUpper()
106 | }
107 | Else
108 | {
109 | $RandomWord
110 | }
111 | }
112 |
113 | #ADD SYMBOLS
114 | If ($NoSymbols -eq $True)
115 | {
116 | $RandomSymbolWords = $RandomCaseWords
117 | }
118 | Else
119 | {
120 | $RandomSymbolWords = ForEach ($RandomCaseWord in $RandomCaseWords)
121 | {
122 | $Symbols = @('!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+')
123 | $Prepend = Get-Random -InputObject $Symbols
124 | $Append = Get-Random -InputObject $Symbols
125 | [System.String]::Concat($Prepend, $RandomCaseWord, $Append)
126 | }
127 | }
128 |
129 | #ADD NUMBERS
130 | If ($NoNumbers -eq $True)
131 | {
132 | $NumberedPassword = $RandomSymbolWords
133 | }
134 | Else
135 | {
136 | $NumberedPassword = ForEach ($RandomSymbolWord in $RandomSymbolWords)
137 | {
138 | $Numbers = @("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
139 | $Prepend = Get-Random -InputObject $Numbers
140 | $Append = Get-Random -InputObject $Numbers
141 | [System.String]::Concat($Prepend, $RandomSymbolWord, $Append)
142 | }
143 | }
144 |
145 | #JOIN ALL ITEMS IN ARRAY
146 | $FinalPasswordString = $NumberedPassword -Join ''
147 |
148 | #PERFORM FINAL LENGTH CHECK
149 | If ($FinalPasswordString.Length -gt $MaxLength)
150 | {
151 | $FinalPassword = $FinalPasswordString.substring(0, $MaxLength)
152 | }
153 | Else
154 | {
155 | $FinalPassword = $FinalPasswordString
156 | }
157 |
158 | #JOIN GENERATED PASSWORDS TO ARRAY
159 | $FinalPasswords += $FinalPassword
160 |
161 | }
162 |
163 | #PROVIDE RANDOM PASSWORD
164 | Return $FinalPasswords
165 | }
166 |
167 | # Defines custom function to get MS Graph access token.
168 | function New-MsGraphAccessToken
169 | {
170 | Param
171 | (
172 | # Should probably validate these in some way.
173 | $TenantId,
174 | $ClientId,
175 | $ClientSecret
176 | )
177 | # Pulls proper Graph and Token endpoints from Domain using Well Known OpenId Configuration Endpoint
178 | $TenantWellKnown = Invoke-RestMethod -uri "https://login.microsoftonline.com/$TenantId/v2.0/.well-known/openid-configuration"
179 | $GraphEndpoint = $TenantWellKnown.msgraph_host
180 | $TokenEndpoint = $TenantWellKnown.token_endpoint
181 |
182 | # Sends request to acquire bearer token
183 | $ApiConnection = Invoke-RestMethod `
184 | -Method Post `
185 | -Uri $TokenEndpoint `
186 | -ContentType 'application/x-www-form-urlencoded' `
187 | -Body @{
188 | client_id = "$ClientId"
189 | scope = "https://$GraphEndpoint/.default"
190 | client_secret = "$ClientSecret"
191 | grant_type = "client_credentials"
192 | }
193 | # Returns PSObject which contains the token as a secure string, graph and point and Tenant Id. These are returned in case
194 | # further references are needed in dependent functions.
195 | $BearerToken = ($ApiConnection.access_token | ConvertTo-SecureString -AsPlainText -Force)
196 | $Output = New-Object -TypeName PSObject
197 | $Output | Add-Member -MemberType NoteProperty -Name BearerToken -Value $BearerToken
198 | $Output | Add-Member -MemberType NoteProperty -Name GraphHost -Value $GraphEndpoint
199 | $Output | Add-Member -MemberType NoteProperty -Name TenantScope -Value $TenantId
200 | Return $Output
201 | }
202 |
203 | #########################################################################################################################################
204 | # #
205 | # SECTION 2 - VARIABLE ASSIGNMENT #
206 | # #
207 | #########################################################################################################################################
208 |
209 | <# This function is supposed to receive the following as a webhook
210 | {
211 | "displayName": "{{ticket.ri_44_cf_full_name}}",
212 | "givenName": "{{ticket.ri_44_cf_first_name}}",
213 | "surname": "{{ticket.ri_44_cf_lastname}}",
214 | "sAMAccountName": "tbd",
215 | "userPrincipalName": "tbd",
216 | "accountExpirationDate": "{{ticket.ri_44_cf_contract_end_date}}",
217 | "accountPassword": "tbd",
218 | "employeeId": "tbd",
219 | "jobTitle": "{{ticket.ri_44_cf_job_title}}",
220 | "manager": "{{ticket.actual_requester.email}}",
221 | "department": "{{ticket.ri_44_cf_department}}"
222 | "company": "{{ticket.ri_44_cf_company}}",
223 | "ticket": "{{ticket.id}}",
224 | "ticketnumber": "{{ticket.id_numeric}}"
225 | }
226 | #>
227 |
228 |
229 | # Converts Escapes for easier transfer
230 | Write-Host $Request.RawBody
231 | $ContractorRequest = $Request.RawBody | ConvertFrom-Json
232 | $AdOuPath = $env:AdOrganizationalUnit
233 | $fsticket = $ContractorRequest.ticketnumber
234 |
235 | # Sets up credential to talk to Active Directory using Application Settings from the function
236 | Write-Information "Building Active Directory Credential Object"
237 | $AdUserManagerUpn = $env:AdUserPrincipalNamePrefix + '@' + $env:AdDomainName
238 | $AdUserManagerPss = $env:AdPassword| ConvertTo-SecureString -AsPlainText -Force
239 | $AdCredential = New-Object System.Management.Automation.PSCredential ($AdUserManagerUpn, $AdUserManagerPss)
240 |
241 | # Sets up Credentials for Freshservice API
242 | Write-Information "Building Freshservice Credential Object"
243 | $FreshserviceApiKey = $env:FreshserviceApiKey
244 | $FreshserviceApiPss = 'x' | ConvertTo-SecureString -AsPlainText -Force
245 | $FsCredential = New-Object System.Management.Automation.PSCredential ($FreshserviceApiKey, $FreshserviceApiPss)
246 | $FreshserviceDomain = ($env:FreshserviceDomain)
247 |
248 | # Rewrites all user-provided values to remove whitespace
249 | $ContractorRequest.givenName = ($ContractorRequest.givenName).Trim()
250 | $ContractorRequest.surname = ($ContractorRequest.surname).Trim()
251 | $ContractorRequest.jobTitle = ($ContractorRequest.jobTitle).Trim()
252 | $ContractorRequest.company = ($ContractorRequest.company).Trim()
253 |
254 | # Sets up DisplayName to use Contractor format
255 | $ContractorRequest.displayName = $ContractorRequest.givenName + ' ' + $ContractorRequest.surname + ' (CTR)'
256 | Write-Information "Determined preferred displayName to be: $($ContractorRequest.displayName)"
257 |
258 | # Determines Preferred sAMAccountName
259 | $BaseSAMAccountName = "$($ContractorRequest.givenName).$($ContractorRequest.surname)".ToLower()
260 | If ($BaseSAMAccountName.Length -gt 16)
261 | {$ContractorRequest.sAMAccountName = ($BaseSAMAccountName.Substring(0,16)) + '.ctr' }
262 | Else
263 | {$ContractorRequest.sAMAccountName = $BaseSAMAccountName + '.ctr'}
264 | Write-Information "Determined preferred sAMAccountName to be: $($ContractorRequest.sAMAccountName)"
265 |
266 | # Creates UserPrincipalName --- TODO: Remove Explicit company reference
267 | $ContractorRequest.userPrincipalName = ("$($ContractorRequest.givenName).$($ContractorRequest.surname)" + '.ctr@contoso.com').ToLower()
268 | Write-Information "Determined preferred userPrincipalName to be: $($ContractorRequest.userPrincipalName)"
269 |
270 | # Converts Date/Time String into AD Readable Format
271 | $AccountExpirationDate = Get-Date $ContractorRequest.accountExpirationDate
272 | Write-Information "Determined provided Expiration Date to be: $($ContractorRequest.AccountExpirationDate)"
273 |
274 | # Generate Unique Employee ID by cutting up a GUID. This isn't pretty but it should be unique. Probably. There's a better way of doing this, I'm sure.
275 | [GUID]$Guid = New-Guid | Select -Expand Guid
276 | $GuidBase64 = [System.Convert]::ToBase64String($Guid.ToByteArray())
277 | $ContractorRequest.employeeId = $GuidBase64.Substring(0,16)
278 | Write-Information "Generated employeeId as: $($ContractorRequest.employeeId)"
279 |
280 | # Generates a password as plaintext using custom function.
281 | $ContractorRequest.accountPassword = New-SecurePassword
282 | Write-Information "Generated Password as: $($ContractorRequest.accountPassword)"
283 |
284 | # Builds a PS Session to the PAW --- TODO: Should make the IP address a variable and add redundancy.
285 | $usermanagementsession = New-PSSession -ComputerName '127.0.0.1' -Credential $AdCredential -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck)
286 | Write-Information "Created PSRemoting session on provided PAW."
287 |
288 | #########################################################################################################################################
289 | # #
290 | # SECTION 3 - ONBOARDING #
291 | # #
292 | #########################################################################################################################################
293 |
294 | # Creates the user account
295 | ####################################################################################################################################################
296 | $Output = Invoke-Command -Session $usermanagementsession -ScriptBlock {
297 |
298 | # Recreates Contractor Request Object within Remote Session
299 | $ContractorRequest = $using:ContractorRequest
300 | Write-Information "Imported Onboarding user object into PSRemoting session."
301 |
302 | # Converts Password to Secure String
303 | $PasswordSecureString = $ContractorRequest.accountPassword | ConvertTo-SecureString -AsPlaintext -Force
304 | Write-Information "Converted Password into SecureString."
305 |
306 | # Determines if the user already exists in the directory. If so, determines a new UPN and SAM AccountName
307 | Write-Information "Checking to see if a user with the same sAMAccountName or userPrincipalName already exists."
308 | $IncrementValue = 1
309 | $TestUserExists = Get-ADUser -Filter * -Properties description -Credential $using:AdCredential | Where-Object { $_.samaccountname -eq $ContractorRequest.sAMAccountName -or $_.username -eq $ContractorRequest.userPrincipalName }
310 | If ($TestUserExists.description -eq $ContractorRequest.ticket)
311 | {
312 | Write-Information "User already created. Aborting..."
313 | Return "ABORT"
314 | }
315 | Else
316 | {
317 | while ($TestUserExists)
318 | {
319 | Write-Information "Username already exists. Trying to append $IncrementValue"
320 | # Increments the SamAcountName - it should be noted this will only allow for nine people of the same name. Possibly need better logic
321 | $ContractorRequest.samaccountname = "$($ContractorRequest.givenName).$($ContractorRequest.surname)".ToLower()
322 | If ($ContractorRequest.samaccountname.Length -gt 15)
323 | {$ContractorRequest.samaccountname = $ContractorRequest.samaccountname.Substring(0,15) + $IncrementValue + '.ctr'}
324 |
325 | # Creates UserPrincipalName --- TODO: Remove Explicit company reference
326 | $ContractorRequest.userPrincipalName = ("$($ContractorRequest.givenName).$($ContractorRequest.surname)" + $IncrementValue + '.ctr@contoso.com').ToLower()
327 |
328 | # Increments Useraccount value and and retests to see if there is still a collision
329 | $IncrementValue++
330 | $TestUserExists = Get-ADUser -Filter * -Credential $using:AdCredential | Where-Object { $_.samaccountname -eq $samaccountname -or $_.username -eq $userprincipalname}
331 | }
332 |
333 | # Sets email address for commercial access - might be able to deprecate soon.
334 | $AdMail = ($ContractorRequest.userPrincipalName).replace("contoso.com","contoso.global")
335 | Write-Information "Determined Contractor's email as $AdMail"
336 |
337 | # Gets Manager GUID and Department to set for contractor
338 | $AdManager = get-aduser -filter * -Properties department -Credential $using:AdCredential | Where-Object Name -eq $ContractorRequest.manager
339 |
340 | New-ADUser `
341 | -Name $ContractorRequest.displayName `
342 | -DisplayName $ContractorRequest.displayName `
343 | -GivenName $ContractorRequest.givenName `
344 | -Surname $ContractorRequest.surname `
345 | `
346 | -SamAccountName $ContractorRequest.sAMAccountName `
347 | -UserPrincipalName $ContractorRequest.userPrincipalName `
348 | -Enabled $true `
349 | -AccountExpirationDate $ContractorRequest.accountExpirationDate `
350 | -AccountPassword $PasswordSecureString `
351 | -ChangePasswordAtLogon $true `
352 | `
353 | -EmployeeID $ContractorRequest.employeeId `
354 | -EmployeeNumber $ContractorRequest.employeeId `
355 | -Title $ContractorRequest.jobTitle `
356 | -Manager $AdManager.ObjectGuid `
357 | -Department $AdManager.Department `
358 | -Description $ContractorRequest.ticket `
359 | -EmailAddress $AdMail `
360 | -Credential $using:AdCredential `
361 | -Path $using:AdOuPath
362 |
363 | Return $ContractorRequest.userPrincipalName
364 | }
365 | }
366 | Write-Host $Output
367 |
368 | #########################################################################################################################################
369 | # #
370 | # SECTION 4 - TRANSMIT CREDENTIALS #
371 | # #
372 | #########################################################################################################################################
373 |
374 | # Escapes if not needed
375 | If ($Output -eq "ABORT")
376 | {
377 | Exit
378 | }
379 |
380 | # Obtains MS Graph token. This is used to send the email.
381 | Write-Information "Obtaining Access Token for Microsoft Graph"
382 | $Token = New-MsGraphAccessToken `
383 | -TenantId $env:MsGraphTenantId `
384 | -ClientId $env:MsGraphClientId `
385 | -ClientSecret $env:MsGraphClientSecret
386 |
387 |
388 | # Sets up Variables so they don't have be be escaped. Those based on Request Object come from a webhook, environment variables are stored in the function.
389 | $ToEmail = $ContractorRequest.externalemail
390 | $ToName = $ContractorRequest.givenName + ' ' + $ContractorRequest.surname
391 | $SenderGuid = $env:MsGraphEmailSenderId
392 | $PayloadUsername = $Output
393 | $PayloadPassword = $ContractorRequest.accountPassword
394 | $Ticket = $fsticket
395 |
396 | # Sets up Message Body to send message
397 | $WelcomeMessage = "Hi $ToName, `
398 |
`
399 | Thank you for being a part of Contoso! We are happy to have you on the team. `
400 | In order to get you up and running as quickly as possible, please reference the below items and reach out to the ServiceDesk with questions. Our contact information is at the bottom of this email. `
401 |
`
402 | Logging In:
`
403 | You will receive an encrypted email shortly which contains your Contoso username and password. You can follow the guide in the link below to open the email. Since Contoso uses Single Sign On for most of our systems, this is one of the few passwords you will need to remember here.
`
404 | If you use Gmail, click here. https://contoso.freshservice.com/support/solutions/articles/17000029506
`
405 | If you use Outlook or any other provider, click here. https://contoso.freshservice.com/support/solutions/articles/17000029511 `
406 |
`
407 | Your token:
`
408 | In the near future you will receive a token which is a hardware device you can attach to your keychain that generates random numbers when you press the button. Contoso requires the use of this token for certain actions, systems, and when we detect suspicious activity. You can follow the guide below for more information and instructions for testing the token.
`
409 | https://contoso.freshservice.com/support/solutions/articles/55555555555 `
410 |
`
411 |
`
412 | We look forward to working with you. Once again, welcome to Contoso. `
413 |
`
414 |
`
415 | --- `
416 |
`
417 | IT ServiceDesk Team
`
418 | Email: servicedesk@contoso.com
`
419 | Web: https://contoso.freshservice.com
`
420 | Phone: (555) 555-5555 x555
`
421 | "
422 |
423 | $WelcomeMessageBody = @"
424 | {
425 | "message": {
426 | "subject": "Welcome to Contoso",
427 | "body": {
428 | "contentType": "Html",
429 | "content": "$WelcomeMessage"
430 | },
431 | "toRecipients": [{
432 | "emailAddress": {
433 | "address": "$ToEmail"
434 | }
435 | }]
436 | }
437 | }
438 | }
439 | "@
440 |
441 | # Sends Initial Message to User
442 | Write-Information "Sending welcome email to user."
443 | Invoke-RestMethod `
444 | -Method Post `
445 | -ContentType 'application/json' `
446 | -Uri "https://$($Token.GraphHost)/v1.0/users/$SenderGuid/sendMail" `
447 | -Authentication Bearer `
448 | -Token $Token.BearerToken `
449 | -Body $WelcomeMessageBody
450 |
451 | # Sets up Message Body to send message
452 | $CredentialMessage = "Hi $ToName, `
453 |
`
454 | Your Contoso Credentials are below: `
455 |
`
456 | Username:
`
457 | $PayloadUsername `
458 |
`
459 | Password:
`
460 | $PayloadPassword `
461 |
`
462 | For assistance in resetting your password, please visit the following link:
`
463 | https://contoso.freshservice.com/support/solutions/articles/55555555555 `
464 |
`
465 |
`
466 | Please test these credentials, and set your password as soon as possible. Note that some of your accounts may not be available until your start date. `
467 |
`
468 |
`
469 | --- `
470 |
`
471 | IT ServiceDesk Team
`
472 | Email: servicedesk@contoso.com
`
473 | Web: https://contoso.freshservice.com
`
474 | Phone: (555) 555-5555 x555
`
475 | "
476 |
477 | $CredentialMessageBody = @"
478 | {
479 | "message": {
480 | "subject": "Contoso Credentials *encrypt*",
481 | "body": {
482 | "contentType": "Html",
483 | "content": "$CredentialMessage"
484 | },
485 | "toRecipients": [{
486 | "emailAddress": {
487 | "address": "$ToEmail"
488 | }
489 | }]
490 | }
491 | }
492 | }
493 | "@
494 |
495 | # Waits 30 seconds to ensure the message that's unencrypted arrives first.
496 | Write-Information "Waiting 30 seconds..."
497 | Start-Sleep -Seconds 30
498 |
499 | # Sends Credentials to User
500 | Write-Information "Sending credentials to user."
501 | Invoke-RestMethod `
502 | -Method Post `
503 | -ContentType 'application/json' `
504 | -Uri "https://$($Token.GraphHost)/v1.0/users/$SenderGuid/sendMail" `
505 | -Authentication Bearer `
506 | -Token $Token.BearerToken `
507 | -Body $CredentialMessageBody
508 |
509 |
510 | #########################################################################################################################################
511 | # #
512 | # SECTION 4 - CLEANUP #
513 | # #
514 | #########################################################################################################################################
515 |
516 | # Creates post content for updating the ticket in Freshservice
517 | $TicketPostContent = @"
518 | {
519 | "helpdesk_note": {
520 | "body":"The account for $($ContractorRequest.displayName) has been created. \n \n Username: \n $Output \n This request is now complete. If you have not already, please provide a shipping address for this user's OTP Token.",
521 | "private":false
522 | }
523 | }
524 | "@
525 |
526 | # Sends ticket update to freshservice
527 | Invoke-RestMethod `
528 | -Uri "$FreshserviceDomain/helpdesk/tickets/$fsticket/conversations/note.json" `
529 | -Method Post `
530 | -Authentication Basic `
531 | -Credential $FsCredential `
532 | -ContentType 'application/json' `
533 | -Body $TicketPostContent
534 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/HIDGlobal.ActivClient1.admx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
--------------------------------------------------------------------------------
/ADMX/ActivClient/HIDGlobal.ActivClient0.admx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
389 |
390 |
391 |
392 |
393 | -
394 |
395 |
396 | -
397 |
398 |
399 | -
400 |
401 |
402 |
403 |
404 |
405 |
406 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
523 |
524 |
525 |
526 |
527 | -
528 |
529 |
530 | -
531 |
532 |
533 | -
534 |
535 |
536 |
537 |
538 |
539 |
540 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
572 |
573 |
574 |
575 |
576 | -
577 | MD5
578 |
579 | -
580 | SHA1
581 |
582 | -
583 | SHA256
584 |
585 | -
586 | SHA384
587 |
588 | -
589 | SHA512
590 |
591 |
592 |
593 |
594 |
595 |
598 |
599 |
600 |
601 |
602 | -
603 | 3DES
604 |
605 | -
606 | AES (128-bit)
607 |
608 | -
609 | AES (192-bit)
610 |
611 | -
612 | AES (256-bit)
613 |
614 | -
615 | DES
616 |
617 | -
618 | RC2 (40-bit)
619 |
620 | -
621 | RC2 (64-bit)
622 |
623 | -
624 | RC2 (128-bit)
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
--------------------------------------------------------------------------------