├── 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 | ![Workflow Overview](https://github.com/cooeycomrades/cooey-tools/blob/45e7a97c49966be04f1d8041d2443d838787af59/Automations/AzureFunctions/Automated%20M365%20Licenses/WorkflowOverview.PNG) 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 | --------------------------------------------------------------------------------