├── Enums ├── ActionAD.ps1 ├── ActionAzureAD.ps1 ├── ActionExchange.ps1 ├── ActionExchangeOnline.ps1 ├── Condition.ps1 ├── Connect.ps1 ├── TriggerComputer.ps1 ├── TriggerGroup.ps1 ├── TriggerUserAD.ps1 └── TriggerUserAzureAD.ps1 ├── Examples ├── CreateConfiguration.ps1 ├── MyConfiguration1.xml ├── RunBook.BackupDefinedUser.ps1 ├── RunBook.EnableRemoteMailbox.ps1 ├── RunBook.JustTrigger-NoAction.ps1 ├── RunBook.UsersAddOffboarded.ps1 ├── RunBook.UsersAzure.ps1 ├── RunBook.UsersAzurePlayLicenses.ps1 ├── RunBook.UsersDisable.ps1 ├── RunBook.UsersEnableOffboarded.ps1 ├── RunBook.UsersEnabledAddedToGroup.ps1 ├── RunBook.UsersOffboarding.1.ps1 ├── RunBook.UsersOffboarding.2.ps1 └── RunBook.UsersRevive.ps1 ├── PSAutomator.psd1 ├── PSAutomator.psm1 ├── Private ├── ActiveDirectory │ ├── Add-WinADUserGroups.ps1 │ ├── Get-ADAdministrativeGroups.ps1 │ ├── Get-WinADGroups.ps1 │ ├── Get-WinADGroupsByDN.ps1 │ ├── Get-WinADGroupsTranslate.ps1 │ ├── Get-WinADOrganizationalUnitData.ps1 │ ├── Get-WinADOrganizationalUnitFromDN.ps1 │ ├── Get-WinADUserSnapshot.ps1 │ ├── Get-WinADUsers.ps1 │ ├── Get-WinADUsersByOU.ps1 │ ├── Get-WinADUsersTranslate.ps1 │ ├── Get-WinADusersByDN.ps1 │ ├── Remove-WinADUserGroups.ps1 │ ├── Set-WinADGroupSynchronization.ps1 │ ├── Set-WinADUserFields.ps1 │ ├── Set-WinADUserSettingGAL.ps1 │ └── Set-WinADUserStatus.ps1 ├── AzureAD │ ├── Get-WinAzureADUsers.ps1 │ ├── Set-WinAzureADUserField.ps1 │ ├── Set-WinAzureADUserLicense.ps1 │ └── Set-WinAzureADUserStatus.ps1 ├── Configuration │ └── Get-PSAutomatorConfiguration.ps1 ├── Main │ ├── Complete-WorkFlow.ps1 │ ├── Get-WinDocumentationText.ps1 │ ├── Resolve-IgnoreTexts.ps1 │ ├── Search-ObjectToIgnore.ps1 │ ├── Start-Configuration.ps1 │ ├── Submit-ActionActiveDirectory.ps1 │ ├── Submit-ActionAzureActiveDirectory.ps1 │ ├── Submit-ActionExchange.ps1 │ ├── Submit-ConditionEmptyOrNull.ps1 │ ├── Submit-ConditionFields.ps1 │ └── Submit-ConditionOrganizationalUnit.ps1 ├── Output │ ├── Out-ActionStatus.ps1 │ ├── Out-ConfigurationStatus.ps1 │ ├── Out-ConnectionStatus.ps1 │ ├── Out-ServiceStatus.ps1 │ └── Out-TriggerStatus.ps1 └── Parameters │ ├── Script.Debug.ps1 │ ├── Script.GroupProperties.ps1 │ ├── Script.UserProperties.ps1 │ └── Script.WriteParameters.ps1 ├── Public ├── Configuration │ └── New-PSAutomatorConfiguration.ps1 └── Main │ ├── Action.ps1 │ ├── Condition.ps1 │ ├── Connect.ps1 │ ├── Service.ps1 │ └── Trigger.ps1 ├── Publish └── Manage-Module.ps1 └── README.MD /Enums/ActionAD.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum ActionAD { 8 | AccountAddGroupsSpecific, 9 | AccountDisable, 10 | AccountEnable, 11 | AccountHideInGAL, 12 | AccountShowInGAL, 13 | AccountRemoveGroupsAll, 14 | AccountRemoveGroupsSecurity, 15 | AccountRemoveGroupsDistribution, 16 | AccountRemoveGroupsSpecific, // Array - Specific groups 17 | AccountRemoveGroupsDomainLocal, // true - false 18 | AccountRemoveGroupsGlobal, // true - false 19 | AccountRemoveGroupsUniversal, // true - false 20 | AccountRename, 21 | AccountSnapshot 22 | } 23 | } 24 | "@ -------------------------------------------------------------------------------- /Enums/ActionAzureAD.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum ActionAzureAD { 8 | AccountAddGroupsSpecific, 9 | AccountDisable, 10 | AccountEnable, 11 | AccountRemoveGroupsAll, 12 | AccountRemoveGroupsSecurity, 13 | AccountRemoveGroupsDistribution, 14 | AccountRemoveGroupsSpecific, // Array - Specific groups 15 | AccountRename, 16 | AccountSnapshot, 17 | AddLicense, 18 | RemoveLicense, 19 | RemoveLicenseAll, 20 | ReplaceLicense, 21 | EnableMFA, 22 | DisableMFA, 23 | SetUserRole, 24 | SetField, 25 | SynchronizeFields 26 | } 27 | } 28 | "@ -------------------------------------------------------------------------------- /Enums/ActionExchange.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum ActionExchange { 8 | MailboxConvertToSharedMailbox, // True/False 9 | MailboxEmailAddressPolicyEnable, // True/False 10 | ContactConvertToMailContact, // Array 11 | MailboxRemoteEnable 12 | } 13 | } 14 | "@ -------------------------------------------------------------------------------- /Enums/ActionExchangeOnline.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum ActionExchangeOnline { 8 | MailboxConvertToSharedMailbox, // True/False 9 | MailboxEmailAddressPolicyEnable, // True/False 10 | ContactConvertToMailContact // Array 11 | } 12 | } 13 | "@ -------------------------------------------------------------------------------- /Enums/Condition.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum Condition { 8 | EmptyOrNull, 9 | Field, 10 | GroupMembership, 11 | OrganizationalUnit 12 | } 13 | } 14 | "@ -------------------------------------------------------------------------------- /Enums/Connect.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | public enum Connect { 7 | ActiveDirectory, 8 | Azure, 9 | AzureAD, 10 | Exchange, 11 | ExchangeOnline 12 | } 13 | } 14 | "@ -------------------------------------------------------------------------------- /Enums/TriggerComputer.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum TriggerComputer { 8 | Always, 9 | OrganizationalUnit, 10 | GroupMembership, 11 | Filter 12 | } 13 | } 14 | "@ -------------------------------------------------------------------------------- /Enums/TriggerGroup.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum TriggerGroup { 8 | Always, 9 | OrganizationalUnit, 10 | Filter 11 | } 12 | } 13 | "@ -------------------------------------------------------------------------------- /Enums/TriggerUserAD.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum TriggerUserAD { 8 | Always, 9 | OrganizationalUnit, 10 | GroupMembership, 11 | Filter 12 | } 13 | } 14 | "@ -------------------------------------------------------------------------------- /Enums/TriggerUserAzureAD.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSAutomator 5 | { 6 | [Flags] 7 | public enum TriggerUserAzureAD { 8 | All, 9 | 10 | ByFields, 11 | //ByCountry, 12 | //ByCity, 13 | //ByDepartment, 14 | //ByState, 15 | //ByTitle, 16 | //ByUsageLocation, 17 | 18 | Deleted, 19 | Domain, 20 | 21 | //HasErrors, 22 | 23 | Unlicensed, 24 | UserPrincipalName, 25 | 26 | Search, 27 | Synchronized 28 | } 29 | } 30 | "@ -------------------------------------------------------------------------------- /Examples/CreateConfiguration.ps1: -------------------------------------------------------------------------------- 1 | $Configuration = [ordered] @{ 2 | Prettify = [ordered] @{ 3 | CompanyName = 'Evotec' 4 | Debug = @{ 5 | Verbose = $false 6 | } 7 | DisplayConsole = @{ 8 | Standard = @{ 9 | ShowTime = $true 10 | LogFile = "" 11 | TimeFormat = "yyyy-MM-dd HH:mm:ss" 12 | } 13 | } 14 | } 15 | Services = [ordered] @{ 16 | OnPremises = [ordered] @{ 17 | ActiveDirectory = [ordered] @{ 18 | Credentials = [ordered] @{ 19 | Username = '' 20 | Password = '' 21 | PasswordAsSecure = $true 22 | PasswordFromFile = $true 23 | } 24 | Use = $true 25 | Prefix = '' 26 | SessionName = 'Active Directory' 27 | } 28 | Exchange = [ordered] @{ 29 | Credentials = [ordered] @{ 30 | UserName = '' # if Kerberos leave empty (domain joined computers usually) 31 | Password = '' # same as above 32 | PasswordAsSecure = $true 33 | PasswordFromFile = $true 34 | } 35 | Use = $false 36 | Prefix = '' 37 | 38 | SessionName = 'Exchange On-Premises' 39 | Authentication = 'Kerberos' 40 | ConnectionURI = 'http://ex2013x3.ad.evotec.xyz/PowerShell' 41 | LeaveOpen = $true 42 | 43 | } 44 | } 45 | Office365 = [ordered] @{ 46 | Credentials = [ordered] @{ 47 | Username = 'przemyslaw.klys@evotec.pl' 48 | Password = 'C:\Support\Important\Password-O365-Evotec.txt' 49 | PasswordAsSecure = $true 50 | PasswordFromFile = $true 51 | } 52 | Azure = [ordered] @{ 53 | Use = $true 54 | SessionName = 'O365 Azure MSOL' # MSOL 55 | } 56 | AzureAD = [ordered] @{ 57 | Use = $false 58 | SessionName = 'O365 Azure AD' # Azure 59 | Prefix = '' 60 | } 61 | ExchangeOnline = [ordered] @{ 62 | Use = $false 63 | Authentication = 'Basic' 64 | ConnectionURI = 'https://outlook.office365.com/powershell-liveid/' 65 | Prefix = 'O365' 66 | SessionName = 'O365 Exchange' 67 | } 68 | Teams = [ordered] @{ 69 | Use = $false 70 | Prefix = '' 71 | SessionName = 'O365 Teams' 72 | } 73 | } 74 | } 75 | } 76 | 77 | New-PSAutomatorConfiguration -Configuration $Configuration -Path 'Examples\MyConfiguration1.xml' -------------------------------------------------------------------------------- /Examples/MyConfiguration1.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | System.Collections.Specialized.OrderedDictionary 5 | System.Object 6 | 7 | 8 | 9 | Prettify 10 | 11 | 12 | 13 | 14 | CompanyName 15 | Evotec 16 | 17 | 18 | Debug 19 | 20 | 21 | System.Collections.Hashtable 22 | System.Object 23 | 24 | 25 | 26 | Verbose 27 | false 28 | 29 | 30 | 31 | 32 | 33 | DisplayConsole 34 | 35 | 36 | 37 | 38 | Standard 39 | 40 | 41 | 42 | 43 | ShowTime 44 | true 45 | 46 | 47 | TimeFormat 48 | yyyy-MM-dd HH:mm:ss 49 | 50 | 51 | LogFile 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Services 65 | 66 | 67 | 68 | 69 | OnPremises 70 | 71 | 72 | 73 | 74 | ActiveDirectory 75 | 76 | 77 | 78 | 79 | Credentials 80 | 81 | 82 | 83 | 84 | Username 85 | 86 | 87 | 88 | Password 89 | 90 | 91 | 92 | PasswordAsSecure 93 | true 94 | 95 | 96 | PasswordFromFile 97 | true 98 | 99 | 100 | 101 | 102 | 103 | Use 104 | true 105 | 106 | 107 | Prefix 108 | 109 | 110 | 111 | SessionName 112 | Active Directory 113 | 114 | 115 | 116 | 117 | 118 | Exchange 119 | 120 | 121 | 122 | 123 | Credentials 124 | 125 | 126 | 127 | 128 | UserName 129 | 130 | 131 | 132 | Password 133 | 134 | 135 | 136 | PasswordAsSecure 137 | true 138 | 139 | 140 | PasswordFromFile 141 | true 142 | 143 | 144 | 145 | 146 | 147 | Use 148 | false 149 | 150 | 151 | Prefix 152 | 153 | 154 | 155 | SessionName 156 | Exchange On-Premises 157 | 158 | 159 | Authentication 160 | Kerberos 161 | 162 | 163 | ConnectionURI 164 | http://ex2013x3.ad.evotec.xyz/PowerShell 165 | 166 | 167 | LeaveOpen 168 | true 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | Office365 178 | 179 | 180 | 181 | 182 | Credentials 183 | 184 | 185 | 186 | 187 | Username 188 | przemyslaw.klys@evotec.pl 189 | 190 | 191 | Password 192 | C:\Support\Important\Password-O365-Evotec.txt 193 | 194 | 195 | PasswordAsSecure 196 | true 197 | 198 | 199 | PasswordFromFile 200 | true 201 | 202 | 203 | 204 | 205 | 206 | Azure 207 | 208 | 209 | 210 | 211 | Use 212 | true 213 | 214 | 215 | SessionName 216 | O365 Azure MSOL 217 | 218 | 219 | 220 | 221 | 222 | AzureAD 223 | 224 | 225 | 226 | 227 | Use 228 | false 229 | 230 | 231 | SessionName 232 | O365 Azure AD 233 | 234 | 235 | Prefix 236 | 237 | 238 | 239 | 240 | 241 | 242 | ExchangeOnline 243 | 244 | 245 | 246 | 247 | Use 248 | false 249 | 250 | 251 | Authentication 252 | Basic 253 | 254 | 255 | ConnectionURI 256 | https://outlook.office365.com/powershell-liveid/ 257 | 258 | 259 | Prefix 260 | O365 261 | 262 | 263 | SessionName 264 | O365 Exchange 265 | 266 | 267 | 268 | 269 | 270 | Teams 271 | 272 | 273 | 274 | 275 | Use 276 | false 277 | 278 | 279 | Prefix 280 | 281 | 282 | 283 | SessionName 284 | O365 Teams 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /Examples/RunBook.BackupDefinedUser.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods -Force 4 | 5 | Service -Name 'Active Directory Offboarding' -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration1.xml' { 6 | Trigger -Name 'OU Offboarded Users' -User Filter -Value @{ Filter = "UserPrincipalName -eq 'przemyslaw.klys@ad.evotec.xyz'"; SearchBase = 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' } | 7 | Condition -Name 'No conditions' | 8 | Condition -Name 'Ignore Windows Email Address if Empty or null' -Condition EmptyOrNull -Value EmailAddress | 9 | Action -Name 'Make User Snapshot' -ActiveDirectory AccountSnapshot -Value 'C:\Users\pklys\Desktop\MyExport' -WhatIf 10 | } -------------------------------------------------------------------------------- /Examples/RunBook.EnableRemoteMailbox.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods -Force 4 | 5 | Service -Name 'Active Directory Remote Mailbox' -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration1.xml' { 6 | Trigger -Name 'OU Offboarded Users' -User Filter -Value @{ Filter = '*'; SearchBase = 'OU=Production,DC=ad,DC=evotec,DC=xyz' } | 7 | Condition -Name 'Member of Disabled Users' -Condition GroupMembership -Value @{ Field = 'Name'; Operator = 'eq'; Value = 'Disabled Users' } | 8 | Condition -Name 'Not member of OU' -Condition OrganizationalUnit -Value @{ Field = 'DistinguishedName'; Operator = 'notlike'; Valuee = 'Users-Offboarded*' } | 9 | #Condition -Name 'Ignore MyUser Account' -Condition Field -Value @{ Field = 'UserPrincipalName'; Operator = 'notlike'; Value = 'myuser*' } | 10 | Condition | 11 | Action -Name 'Make User Snapshot' -ActiveDirectory AccountSnapshot -Value 'C:\Users\pklys\Desktop\MyExport' -WhatIf | 12 | Action -Name 'Enable remote mailbox on Office 365' -Exchange MailboxRemoteEnable -WhatIf 13 | 14 | } -------------------------------------------------------------------------------- /Examples/RunBook.JustTrigger-NoAction.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods #-Force 4 | 5 | Service -Name 'Active Directory Offboarding' -Status Enable -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration1.xml' { 6 | Trigger -Name 'OU Offboarded Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' 7 | } 8 | -------------------------------------------------------------------------------- /Examples/RunBook.UsersAddOffboarded.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods -Force 4 | 5 | Service -Name 'Active Directory Add Users To Group' { 6 | Trigger -Name 'Find Offboarded Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 7 | Condition | 8 | Action -Name 'Add Users To Disabled Group' -ActiveDirectory AccountAddGroupsSpecific -Value 'Disabled Users' -WhatIf 9 | } -------------------------------------------------------------------------------- /Examples/RunBook.UsersAzure.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods #-Force 4 | 5 | Service -Name 'Active Directory Offboarding' -Status Enable -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration1.xml' { 6 | Trigger -Name 'Synchronized Users from AD' -UserAzureAD Synchronized | 7 | Condition -Name 'Ignore Synchronization Account' -Condition Field -Value @{ Field = 'UserPrincipalName'; Operator = 'notlike'; Value = 'Sync_ADConnect*' } | 8 | Action -Name 'Disable Synchronized Users' -AzureActiveDirectory AccountDisable -WhatIf 9 | } 10 | -------------------------------------------------------------------------------- /Examples/RunBook.UsersAzurePlayLicenses.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods -Force 4 | 5 | Service -Name 'Removing Licenses from Some Users' -Status Enable -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration1.xml' { 6 | Trigger -Name 'All users in Azure AD' -UserAzureAD All | 7 | Condition -Name 'Ignore Synchronization Account' -Condition Field -Value @{ Field = 'UserPrincipalName'; Operator = 'notlike'; Value = 'Sync_ADConnect*' } | 8 | Condition -Name 'Only Licensed Users' -Condition Field -Value @{ Field = 'IsLicensed'; Operator = 'eq'; Value = $true } | 9 | Condition -Name 'Only Synchronized Users' -Condition Field -Value @{ Field = 'LastDirSyncTime'; Operator = 'ne'; Value = $null } | 10 | Action -Name 'Remove all licenses' -AzureActiveDirectory RemoveLicenseAll #-WhatIf 11 | } 12 | 13 | return 14 | 15 | Service -Name 'Adding licenses to Some users' -Status Enable -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration1.xml' { 16 | Trigger -Name 'All unlicensed users in Azure AD' -UserAzureAD Unlicensed | 17 | Condition -Name 'Ignore Synchronization Account' -Condition Field -Value @{ Field = 'UserPrincipalName'; Operator = 'notlike'; Value = 'Sync_ADConnect*' } | 18 | Condition -Name 'Only Synchronized Users' -Condition Field -Value @{ Field = 'LastDirSyncTime'; Operator = 'ne'; Value = $null } | 19 | Action -Name 'Set usage location' -AzureActiveDirectory SetField -Value @{ Field = 'UsageLocation'; Value = 'PL' } | 20 | Action -Name 'Add business essentials license' -AzureActiveDirectory AddLicense -Value 'evotecpoland:O365_BUSINESS_ESSENTIALS' | 21 | Action -Name 'Add flow license' -AzureActiveDirectory AddLicense -Value 'evotecpoland:FLOW_FREE' 22 | } 23 | 24 | <# 25 | evotecpoland:FLOW_FREE 26 | evotecpoland:STANDARDPACK 27 | 28 | AccountSkuId ActiveUnits WarningUnits ConsumedUnits 29 | ------------ ----------- ------------ ------------- 30 | evotecpoland:DESKLESSPACK 2 0 2 31 | evotecpoland:FLOW_FREE 10000 0 1 32 | evotecpoland:O365_BUSINESS_ESSENTIALS 2 0 2 33 | evotecpoland:STANDARDPACK 1 0 1 34 | 35 | #> -------------------------------------------------------------------------------- /Examples/RunBook.UsersDisable.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods #-Force 4 | 5 | Service -Name 'Active Directory Disable Users in Group' { 6 | Trigger -Name 'User is a member of Disabled Users group' -User GroupMembership -Value 'Disabled Users' | 7 | Condition -Name 'Ignore Email Address like *@evotec.pl' -Condition Field -Value @{ Field = 'EmailAddress'; Operator = 'notlike'; Value = '*@evotec.pl' } | 8 | Condition -Name 'Ignore Email Address if Empty or Null' -Condition EmptyOrNull -Value EmailAddress | 9 | Action -Name 'Disable Evotec Users' -ActiveDirectory AccountDisable -WhatIf 10 | } -------------------------------------------------------------------------------- /Examples/RunBook.UsersEnableOffboarded.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods #-Force 4 | 5 | Service -Name 'Active Directory Enable Users in OU' { 6 | Trigger -Name 'Find Offboarded Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 7 | Condition | 8 | Action -Name 'Enable Offboarded Users' -ActiveDirectory AccountEnable -WhatIf | 9 | Action -Name 'Add to group GDS-TestGroup5' -ActiveDirectory AccountAddGroupsSpecific -Value 'GDS-TestGroup5' -WhatIf | 10 | Action -Name 'Add to group GDS-TestGroup4' -ActiveDirectory AccountAddGroupsSpecific -Value 'GDS-TestGroup4' -Whatif | 11 | Action -Name 'Remove Offboarded Tag' -ActiveDirectory AccountRename -Value @{ Action = 'RemoveText'; Fields = 'DisplayName', 'Name' ; Text = ' (offboarded)'; } -WhatIf 12 | } -------------------------------------------------------------------------------- /Examples/RunBook.UsersEnabledAddedToGroup.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods #-Force 4 | 5 | Service -Name 'Active Directory Offboarding' -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration.xml' { 6 | Trigger -Name 'Reenabling my users for testing purposes' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 7 | Condition -Name 'No conditions' | 8 | Condition -Name 'Ignore Windows Email Address if Empty or null' -Condition EmptyOrNull -Value EmailAddress | 9 | Action -Name 'Enable AD Account' -ActiveDirectory AccountEnable -WhatIf | 10 | Action -Name 'Add user to Disabled Users' -ActiveDirectory AccountAddGroupsSpecific -Value 'Disabled Users' -WhatIf 11 | } -------------------------------------------------------------------------------- /Examples/RunBook.UsersOffboarding.1.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods #-Force 4 | 5 | Service -Name 'Active Directory Prepare Users' { 6 | Trigger -Name 'Offboard Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 7 | Condition | 8 | Action -Name 'Disable Users' -ActiveDirectory AccountDisable -WhatIf | 9 | Action -Name 'Add to group' -ActiveDirectory AccountAddGroupsSpecific -Value 'Disabled Users' -WhatIf 10 | } -------------------------------------------------------------------------------- /Examples/RunBook.UsersOffboarding.2.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods -Force 4 | 5 | Service -Name 'Active Directory Offboarding' -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration.xml' { 6 | Trigger -Name 'OU Offboarded Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 7 | Condition -Name 'No conditions' | 8 | Condition -Name 'Ignore Windows Email Address if Empty or null' -Condition EmptyOrNull -Value 'EmailAddress' | 9 | Action -Name 'Make User Snapshot' -ActiveDirectory AccountSnapshot -Value 'C:\Users\pklys\Desktop\MyExport' -Whatif | 10 | Action -Name 'Disable AD Account' -ActiveDirectory AccountDisable -WhatIf | 11 | Action -Name 'Hide account in GAL' -ActiveDirectory AccountHideInGAL -WhatIf | 12 | Action -Name 'Remove all security groups' -ActiveDirectory AccountRemoveGroupsSecurity -WhatIf | 13 | Action -Name 'Rename Account' -ActiveDirectory AccountRename -Value @{ Action = 'AddText'; Where = 'After'; Fields = 'DisplayName', 'Name'; Text = ' (offboarded)'; } -WhatIf 14 | } -------------------------------------------------------------------------------- /Examples/RunBook.UsersRevive.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Import-Module PSAutomator -Force #-Verbose 3 | Import-Module PSSharedGoods #-Force 4 | 5 | Service -Name 'Active Directory Prepare Users' { 6 | Trigger -Name 'Enable already Offboarded Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 7 | Condition | 8 | Action -Name 'Enable Users' -ActiveDirectory AccountEnable -WhatIf | 9 | Action -Name 'Remove Users From Group' -ActiveDirectory AccountRemoveGroupsSpecific -Value 'Disabled Users' -WhatIf 10 | } -------------------------------------------------------------------------------- /PSAutomator.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | AliasesToExport = 'Ignore' 3 | Author = 'Przemyslaw Klys' 4 | CmdletsToExport = @() 5 | CompanyName = 'Evotec' 6 | Copyright = '(c) 2018 Przemyslaw Klys. All rights reserved.' 7 | Description = 'PowerShell Module is new approach to onboarding, offboarding and business as usual processes running in companies infrastructure. Usually each company has different rules, different approaches on how processes should look like and this module takes an easy approach that''s similar to what you can find in services like IFTTT or Microsoft Flow' 8 | FunctionsToExport = @('New-PSAutomatorConfiguration', 'Action', 'Condition', 'Connect', 'Service', 'Trigger') 9 | GUID = '1be9e392-28cb-4ac6-aba7-b924defbf9da' 10 | ModuleVersion = '0.0.3' 11 | PowerShellVersion = '5.1' 12 | PrivateData = @{ 13 | PSData = @{ 14 | Tags = @('ActiveDirectory', 'Offboarding', 'Onboarding', 'Windows') 15 | ProjectUri = 'https://github.com/EvotecIT/PSAutomator' 16 | IconUri = 'https://evotec.xyz/wp-content/uploads/2018/10/PSAutomator.png' 17 | } 18 | } 19 | RequiredModules = @('PSSharedGoods', 'PSWriteColor') 20 | RootModule = 'PSAutomator.psm1' 21 | } -------------------------------------------------------------------------------- /PSAutomator.psm1: -------------------------------------------------------------------------------- 1 | #Get public and private function definition files. 2 | $Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 3 | $Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 4 | 5 | $AssemblyFolders = Get-ChildItem -Path $PSScriptRoot\Lib -Directory -ErrorAction SilentlyContinue 6 | if ($AssemblyFolders.BaseName -contains 'Standard') { 7 | $Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Standard\*.dll -ErrorAction SilentlyContinue ) 8 | } else { 9 | if ($PSEdition -eq 'Core') { 10 | $Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Core\*.dll -ErrorAction SilentlyContinue ) 11 | } else { 12 | $Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Default\*.dll -ErrorAction SilentlyContinue ) 13 | } 14 | } 15 | $FoundErrors = @( 16 | Foreach ($Import in @($Assembly)) { 17 | try { 18 | Add-Type -Path $Import.Fullname -ErrorAction Stop 19 | } catch [System.Reflection.ReflectionTypeLoadException] { 20 | Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)" 21 | $LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique 22 | foreach ($E in $LoaderExceptions) { 23 | Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)" 24 | } 25 | $true 26 | #Write-Error -Message "StackTrace: $($_.Exception.StackTrace)" 27 | } catch { 28 | Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)" 29 | $LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique 30 | foreach ($E in $LoaderExceptions) { 31 | Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)" 32 | } 33 | $true 34 | #Write-Error -Message "StackTrace: $($_.Exception.StackTrace)" 35 | } 36 | } 37 | #Dot source the files 38 | Foreach ($Import in @($Private + $Public)) { 39 | Try { 40 | . $Import.Fullname 41 | } Catch { 42 | Write-Error -Message "Failed to import functions from $($import.Fullname): $_" 43 | $true 44 | } 45 | } 46 | ) 47 | 48 | if ($FoundErrors.Count -gt 0) { 49 | $ModuleName = (Get-ChildItem $PSScriptRoot\*.psd1).BaseName 50 | Write-Warning "Importing module $ModuleName failed. Fix errors before continuing." 51 | break 52 | } 53 | 54 | Export-ModuleMember -Function '*' -Alias '*' -------------------------------------------------------------------------------- /Private/ActiveDirectory/Add-WinADUserGroups.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Output of Get-ADPrincipalGroupmembership: 3 | 4 | distinguishedName : CN=Organization Management,OU=Microsoft Exchange Security Groups,DC=ad,DC=evotec,DC=xyz 5 | GroupCategory : Security 6 | GroupScope : Universal 7 | name : Organization Management 8 | objectClass : group 9 | objectGUID : 551c2400-f0d2-4aa6-8dbf-f9722ceb8675 10 | SamAccountName : Organization Management 11 | SID : S-1-5-21-853615985-2870445339-3163598659-1117 12 | 13 | #> 14 | 15 | function Add-WinADUserGroups { 16 | <# 17 | .SYNOPSIS 18 | Adds a user to specified Active Directory groups. 19 | 20 | .DESCRIPTION 21 | This function adds a user to the specified Active Directory groups. It retrieves the user's current group memberships and adds the user to the specified groups if they are not already a member. 22 | 23 | .PARAMETER User 24 | The user object to add to the groups. 25 | 26 | .PARAMETER Groups 27 | An array of group names to add the user to. 28 | 29 | .PARAMETER FieldSearch 30 | The field to search for group names. Default is 'Name'. 31 | 32 | .PARAMETER WhatIf 33 | Specifies whether to perform a test run without making any changes. 34 | 35 | .EXAMPLE 36 | Add-WinADUserGroups -User $UserObject -Groups @("Group1", "Group2") 37 | 38 | Adds the user specified by $UserObject to the groups "Group1" and "Group2". 39 | 40 | .EXAMPLE 41 | Add-WinADUserGroups -User $UserObject -Groups @("Group1", "Group2") -FieldSearch 'SamAccountName' 42 | 43 | Adds the user specified by $UserObject to the groups "Group1" and "Group2" using 'SamAccountName' for group name search. 44 | 45 | .NOTES 46 | File Name : Add-WinADUserGroups.ps1 47 | Prerequisite : Requires Active Directory module. 48 | #> 49 | [CmdletBinding()] 50 | [alias("Add-ADUserGroups")] 51 | param( 52 | [parameter(Mandatory = $true)][Object] $User, 53 | [string[]] $Groups, 54 | [string] $FieldSearch = 'Name', 55 | [switch] $WhatIf 56 | ) 57 | $Object = @() 58 | try { 59 | $ADgroups = Get-ADPrincipalGroupMembership -Identity $User.DistinguishedName | Where-Object {$_.Name -ne "Domain Users" } 60 | } catch { 61 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 62 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 63 | } 64 | if ($Groups) { 65 | foreach ($Group in $Groups) { 66 | if ($ADgroups.$FieldSearch -notcontains $Group) { 67 | try { 68 | if (-not $WhatIf) { 69 | Add-ADGroupMember -Identity $Group -Members $User.DistinguishedName -ErrorAction Stop 70 | } 71 | $Object += @{ Status = $true; Output = $Group; Extended = 'Added to group.' } 72 | 73 | } catch { 74 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 75 | $Object += @{ Status = $false; Output = $Group; Extended = $ErrorMessage } 76 | } 77 | } else { 78 | # Turned off to not clutter view, may required turning back on. 79 | #$Object += @{ Status = $false; Output = $Group; Extended = 'Already exists.' } 80 | } 81 | } 82 | } 83 | return $Object 84 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-ADAdministrativeGroups.ps1: -------------------------------------------------------------------------------- 1 | function Get-ADADministrativeGroups { 2 | <# 3 | .SYNOPSIS 4 | Retrieves administrative groups information from Active Directory. 5 | 6 | .DESCRIPTION 7 | This function retrieves information about administrative groups in Active Directory based on the specified parameters. 8 | 9 | .PARAMETER Type 10 | Specifies the type of administrative groups to retrieve. Valid values are 'DomainAdmins' and 'EnterpriseAdmins'. 11 | 12 | .PARAMETER Forest 13 | Specifies the name of the forest to query for administrative groups. 14 | 15 | .PARAMETER ExcludeDomains 16 | Specifies an array of domains to exclude from the query. 17 | 18 | .PARAMETER IncludeDomains 19 | Specifies an array of domains to include in the query. 20 | 21 | .PARAMETER ExtendedForestInformation 22 | Specifies additional information about the forest to include in the query. 23 | 24 | .EXAMPLE 25 | Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins 26 | 27 | Output (Where VALUE is Get-ADGroup output): 28 | Name Value 29 | ---- ----- 30 | ByNetBIOS {EVOTEC\Domain Admins, EVOTEC\Enterprise Admins, EVOTECPL\Domain Admins} 31 | ad.evotec.xyz {DomainAdmins, EnterpriseAdmins} 32 | ad.evotec.pl {DomainAdmins} 33 | 34 | .NOTES 35 | This function requires Active Directory module to be installed on the system. 36 | #> 37 | [cmdletBinding()] 38 | param( 39 | [parameter(Mandatory)][validateSet('DomainAdmins', 'EnterpriseAdmins')][string[]] $Type, 40 | [alias('ForestName')][string] $Forest, 41 | [string[]] $ExcludeDomains, 42 | [alias('Domain', 'Domains')][string[]] $IncludeDomains, 43 | [System.Collections.IDictionary] $ExtendedForestInformation 44 | ) 45 | $ADDictionary = [ordered] @{ } 46 | $ADDictionary['ByNetBIOS'] = [ordered] @{ } 47 | $ADDictionary['BySID'] = [ordered] @{ } 48 | 49 | $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation 50 | foreach ($Domain in $ForestInformation.Domains) { 51 | $ADDictionary[$Domain] = [ordered] @{ } 52 | $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] 53 | $DomainInformation = Get-ADDomain -Server $QueryServer 54 | 55 | if ($Type -contains 'DomainAdmins') { 56 | Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-512'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { 57 | $ADDictionary['ByNetBIOS']["$($DomainInformation.NetBIOSName)\$($_.Name)"] = $_ 58 | $ADDictionary[$Domain]['DomainAdmins'] = "$($DomainInformation.NetBIOSName)\$($_.Name)" 59 | $ADDictionary['BySID'][$_.SID.Value] = $_ 60 | } 61 | } 62 | } 63 | # We need to treat EnterpriseAdmins separatly as it should be always available, not only when requested specific domain 64 | foreach ($Domain in $ForestInformation.Forest.Domains) { 65 | if (-not $ADDictionary[$Domain]) { 66 | $ADDictionary[$Domain] = [ordered] @{ } 67 | } 68 | if ($Type -contains 'EnterpriseAdmins') { 69 | $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] 70 | $DomainInformation = Get-ADDomain -Server $QueryServer 71 | 72 | Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-519'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { 73 | $ADDictionary['ByNetBIOS']["$($DomainInformation.NetBIOSName)\$($_.Name)"] = $_ 74 | $ADDictionary[$Domain]['EnterpriseAdmins'] = "$($DomainInformation.NetBIOSName)\$($_.Name)" 75 | $ADDictionary['BySID'][$_.SID.Value] = $_ #"$($DomainInformation.NetBIOSName)\$($_.Name)" 76 | } 77 | } 78 | } 79 | return $ADDictionary 80 | } 81 | 82 | #Get-WinADForestDetails -IncludeDomains 'ad.evotec.xyz' 83 | #Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -IncludeDomains 'ad.evotec.pl' -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADGroups.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADGroups { 2 | [CmdletBinding()] 3 | param( 4 | $Filter, 5 | $OrganizationalUnit 6 | ) 7 | $Splatting = @{} 8 | if ($Filter -eq $null -and $OrganizationalUnit -eq $null) { 9 | $Splatting = $Filter 10 | } else { 11 | if ($OrganizationalUnit) { 12 | $Splatting.SearchBase = $OrganizationalUnit 13 | } 14 | if ($Filter) { 15 | $Splatting.Filter = $Filter 16 | } 17 | } 18 | $Groups = Get-ADGroup @Splatting -Properties $Script:GroupProperties 19 | return $Groups 20 | } 21 | 22 | #Get-ADGroup -Filter * -Properties * # $Script:GroupProperties 23 | 24 | 25 | #Get-WinADGroupsByDN -DistinguishedName 'CN=Disabled Users,OU=SecurityGroups,OU=Groups,OU=Production,DC=ad,DC=evotec,DC=xyz' -Field 'Name' 26 | -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADGroupsByDN.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADGroupsByDN { 2 | 3 | <# Returns one of the values 4 | DistinguishedName : CN=Disabled Users,OU=SecurityGroups,OU=Groups,OU=Production,DC=ad,DC=evotec,DC=xyz 5 | GroupCategory : Security 6 | GroupScope : Universal 7 | Name : Disabled Users 8 | ObjectClass : group 9 | ObjectGUID : b7b5961e-e190-4f01-973f-abdf824261a3 10 | SamAccountName : Disabled Users 11 | SID : S-1-5-21-853615985-2870445339-3163598659-1162 12 | #> 13 | 14 | param( 15 | [alias('DN')][string[]] $DistinguishedName, 16 | [string] $Field = 'Name', # return field 17 | [switch] $All 18 | ) 19 | $Output = foreach ($DN in $DistinguishedName) { 20 | try { 21 | Get-AdGroup -Identity $DN 22 | } catch { 23 | # returns empty, basically ignores stuff 24 | } 25 | } 26 | if ($All) { 27 | return $Output 28 | } else { 29 | return $Output.$Field 30 | } 31 | } 32 | 33 | 34 | 35 | 36 | #Get-WinADUsersByDN -DistinguishedName 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADGroupsTranslate.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADGroupsTranslate { 2 | param ( 3 | [System.Object[]] $Groups 4 | ) 5 | $ReturnGroups = @( 6 | foreach ($Group in $Groups) { 7 | #$User = $Users | Where { $_.DistinguishedName -eq $Group.ManagedBy } 8 | [PSCustomObject] @{ 9 | 'Group Name' = $Group.Name 10 | 'Group Display Name' = $Group.DisplayName 11 | 'Group Category' = $Group.GroupCategory 12 | 'Group Scope' = $Group.GroupScope 13 | 'Group SID' = $Group.SID.Value 14 | 'High Privileged Group' = if ($Group.AdminCount -eq 1) { $True } else { $False } 15 | 'Member Count' = $Group.Members.Count 16 | 'MemberOf Count' = $Group.MemberOf.Count 17 | 'Manager' = $Group.ManagedBy 18 | #'Manager' = $User.Name 19 | #'Manager Email' = $User.EmailAddress 20 | #'Group Members' = (Get-ADObjectFromDistingusishedName -ADCatalog $Data.DomainUsersFullList, $Data.DomainComputersFullList, $Data.DomainGroupsFullList -DistinguishedName $Group.Members -Type 'SamAccountName') 21 | 'Group Members' = $Group.Members 22 | } 23 | } 24 | ) 25 | return $ReturnGroups 26 | } 27 | -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADOrganizationalUnitData.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADOrganizationalUnitData { 2 | <# 3 | .SYNOPSIS 4 | Retrieves detailed information about Active Directory Organizational Units. 5 | 6 | .DESCRIPTION 7 | This function retrieves detailed information about the specified Active Directory Organizational Units, including properties like CanonicalName, City, Country, Description, and more. 8 | 9 | .PARAMETER OrganizationalUnit 10 | Specifies the Organizational Units to retrieve information for. 11 | 12 | .EXAMPLE 13 | Get-WinADOrganizationalUnitData -OrganizationalUnit 'OU=Users-O365,OU=Production,DC=ad,DC=evotec,DC=xyz' 14 | Retrieves information for the specified Organizational Unit 'Users-O365' under 'Production' in the Active Directory domain 'ad.evotec.xyz'. 15 | 16 | .NOTES 17 | Output of function: 18 | CanonicalName : ad.evotec.xyz/Production/Users-O365 19 | City : 20 | CN : 21 | Country : PL 22 | Created : 09.11.2018 17:38:32 23 | Description : OU for Synchronization of Users to Office 365 24 | DisplayName : 25 | DistinguishedName : OU=Users-O365,OU=Production,DC=ad,DC=evotec,DC=xyz 26 | LinkedGroupPolicyObjects : {cn={74D09C6F-35E9-4743-BCF7-F87D7010C60D},cn=policies,cn=system,DC=ad,DC=evotec,DC=xyz} 27 | ManagedBy : 28 | Modified : 19.11.2018 22:54:47 29 | Name : Users-O365 30 | PostalCode : 31 | ProtectedFromAccidentalDeletion : True 32 | State : 33 | StreetAddress : 34 | 35 | #> 36 | [CmdletBinding()] 37 | param( 38 | [string[]] $OrganizationalUnit 39 | ) 40 | $Output = foreach ($OU in $OrganizationalUnit) { 41 | $Data = Get-ADOrganizationalUnit -Identity $OU -Properties CanonicalName, City, CN, Country, Created, Description, DisplayName, DistinguishedName, ManagedBy, Modified, Name, OU, PostalCode, ProtectedFromAccidentalDeletion, State, StreetAddress 42 | 43 | [PsCustomobject][Ordered] @{ 44 | CanonicalName = $Data.CanonicalName 45 | City = $Data.City 46 | CN = $Data.CN 47 | Country = $Data.Country 48 | Created = $Data.Created 49 | Description = $Data.Description 50 | DisplayName = $Data.DisplayName 51 | DistinguishedName = $Data.DistinguishedName 52 | LinkedGroupPolicyObjects = $Data.LinkedGroupPolicyObjects 53 | ManagedBy = Get-WinADUsersByDN -DistinguishedName $U.ManagedBy 54 | Modified = $Data.Modified 55 | Name = $Data.Name 56 | PostalCode = $Data.PostalCode 57 | ProtectedFromAccidentalDeletion = $Data.ProtectedFromAccidentalDeletion 58 | State = $Data.State 59 | StreetAddress = $Data.StreetAddress 60 | } 61 | } 62 | return $Output 63 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADOrganizationalUnitFromDN.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADOrganizationalUnitFromDN { 2 | <# 3 | .SYNOPSIS 4 | This function extracts the Organizational Unit (OU) from a given Distinguished Name (DN). 5 | 6 | .DESCRIPTION 7 | This function takes a Distinguished Name (DN) as input and returns the Organizational Unit (OU) part of it. 8 | 9 | .PARAMETER DistinguishedName 10 | Specifies the Distinguished Name (DN) from which to extract the Organizational Unit (OU). 11 | 12 | .EXAMPLE 13 | Extract the Organizational Unit (OU) from a Distinguished Name. 14 | 15 | $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' 16 | Get-WinADOrganizationalUnitFromDN -DistinguishedName $DistinguishedName 17 | 18 | .NOTES 19 | This function uses regular expressions to extract the Organizational Unit (OU) from the given Distinguished Name (DN). 20 | #> 21 | [CmdletBinding()] 22 | param( 23 | $DistinguishedName 24 | ) 25 | return [Regex]::Match($DistinguishedName,'(?=OU)(.*\n?)(?<=.)').Value 26 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADUserSnapshot.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADUserSnapshot { 2 | <# 3 | .SYNOPSIS 4 | Retrieves a snapshot of Active Directory user information and saves it to an XML file. 5 | 6 | .DESCRIPTION 7 | The Get-WinADUserSnapshot function retrieves detailed information about an Active Directory user and saves it to an XML file specified by the XmlPath parameter. 8 | 9 | .PARAMETER User 10 | Specifies the Active Directory user object for which to retrieve the snapshot. 11 | 12 | .PARAMETER XmlPath 13 | Specifies the path where the XML snapshot file will be saved. 14 | 15 | .PARAMETER WhatIf 16 | Indicates whether the operation should only be simulated without actually saving the snapshot. 17 | 18 | .EXAMPLE 19 | Get-WinADUserSnapshot -User $userObject -XmlPath "C:\Snapshots" -WhatIf 20 | Retrieves a snapshot of the user object and simulates saving it to the specified path. 21 | 22 | .EXAMPLE 23 | Get-WinADUserSnapshot -User $userObject -XmlPath "C:\Snapshots" 24 | Retrieves a snapshot of the user object and saves it to the specified path. 25 | 26 | #> 27 | [CmdletBinding()] 28 | [alias("Get-ADUserSnapshot")] 29 | param ( 30 | [parameter(Mandatory = $true)][Object] $User, 31 | [string] $XmlPath, 32 | [switch] $WhatIf 33 | ) 34 | $Object = @() 35 | try { 36 | $FullData = Get-ADUser -Identity $User.DistinguishedName -Properties * 37 | if (($XmlPath) -and (Test-Path $XmlPath)) { 38 | $FullPath = [IO.Path]::Combine($XmlPath, "$($User.SamAccountName).xml") # 39 | if (-not $WhatIf) { 40 | $FullData | Export-Clixml -Path $FullPath -ErrorAction Stop 41 | } 42 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Saved to $FullPath" } 43 | 44 | } else { 45 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = 'XmlPath Incorrect' } 46 | } 47 | } catch { 48 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 49 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } 50 | } 51 | return $Object 52 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADUsers.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADUsers { 2 | [CmdletBinding()] 3 | param( 4 | $Filter, 5 | $OrganizationalUnit, 6 | $Group 7 | ) 8 | $Splatting = @{} 9 | if ($OrganizationalUnit) { 10 | $Splatting.SearchBase = $OrganizationalUnit 11 | $Splatting.Filter = '*' 12 | } 13 | if ($Filter) { 14 | if ($Filter -is [hashtable]) { 15 | # $Splatting.Filter = $Filter.Filter 16 | # $Splatting.SearchBase = $Filter.SearchBase 17 | $Splatting = $Filter 18 | } elseif ($Filter -is [string]) { 19 | $Splatting.Filter = $Filter 20 | } else { 21 | 22 | } 23 | } 24 | 25 | #Write-Color $Group -Color Red 26 | if ($Group) { 27 | $Users = @() 28 | $GroupMembers = Get-ADGroupMember -Identity $Group 29 | #Get-ADUser $Groupmembers 30 | $Users = foreach ($Member in $GroupMembers) { 31 | #Write-COlor $Member -Color Red 32 | Get-ADUser -Identity $Member -Properties $Script:UserProperties #| Select-Object $Script:UserProperties 33 | } 34 | } else { 35 | $Users = Get-ADUser @Splatting -Properties $Script:UserProperties #| Select-Object $Script:UserProperties 36 | } 37 | 38 | 39 | $UserList = foreach ($U in $Users) { 40 | $Manager = Get-WinADUsersByDN -DistinguishedName $U.Manager 41 | $PrimaryGroup = Get-WinADGroupsByDN -DistinguishedName $U.PrimaryGroup -All #-Field 'Name' 42 | $Groups = Get-WinADGroupsByDN -DistinguishedName $U.MemberOf -All #-Field 'Name' 43 | $OrganizationalUnit = Get-WinADOrganizationalUnitFromDN -DistinguishedName $U.DistinguishedName 44 | $OrganizationalUnitData = Get-WinADOrganizationalUnitData -OrganizationalUnit $OrganizationalUnit 45 | 46 | [PsCustomObject][ordered] @{ 47 | 'Name' = $U.Name 48 | 'UserPrincipalName' = $U.UserPrincipalName 49 | 'SamAccountName' = $U.SamAccountName 50 | 'Display Name' = $U.DisplayName 51 | 'Given Name' = $U.GivenName 52 | 'Surname' = $U.Surname 53 | 'EmailAddress' = $U.EmailAddress 54 | 'PasswordExpired' = $U.PasswordExpired 55 | 'PasswordLastSet' = $U.PasswordLastSet 56 | 'Password Last Changed' = if ($U.PasswordLastSet -ne $Null) { "$(-$($U.PasswordLastSet - [DateTime]::Today).Days) days" } else { 'N/A'} 57 | 'PasswordNotRequired' = $U.PasswordNotRequired 58 | 'PasswordNeverExpires' = $U.PasswordNeverExpires 59 | 'Enabled' = $U.Enabled 60 | 'Manager' = $Manager.Name 61 | 'Manager Email' = $Manager.EmailAddress 62 | 'DateExpiry' = Convert-ToDateTime -Timestring $($U."msDS-UserPasswordExpiryTimeComputed") #-Verbose 63 | "DaysToExpire" = (Convert-TimeToDays -StartTime (GET-DATE) -EndTime (Convert-ToDateTime -Timestring $($U."msDS-UserPasswordExpiryTimeComputed"))) 64 | "AccountExpirationDate" = $U.AccountExpirationDate 65 | "AccountLockoutTime" = $U.AccountLockoutTime 66 | "AllowReversiblePasswordEncryption" = $U.AllowReversiblePasswordEncryption 67 | "BadLogonCount" = $U.BadLogonCount 68 | "CannotChangePassword" = $U.CannotChangePassword 69 | "CanonicalName" = $U.CanonicalName 70 | 71 | "Description" = $U.Description 72 | "DistinguishedName" = $U.DistinguishedName 73 | "EmployeeID" = $U.EmployeeID 74 | "EmployeeNumber" = $U.EmployeeNumber 75 | "LastBadPasswordAttempt" = $U.LastBadPasswordAttempt 76 | "LastLogonDate" = $U.LastLogonDate 77 | 'Last Logon Days' = if ($U.LastLogonDate -ne $Null) { "$(-$($U.LastLogonDate - [DateTime]::Today).Days) days" } else { 'N/A'} 78 | 79 | "Created" = $U.Created 80 | "Modified" = $U.Modified 81 | "Protected" = $U.ProtectedFromAccidentalDeletion 82 | 83 | "PrimaryGroup" = $PrimaryGroup # Whole Object 84 | "MemberOf" = $Groups #Whole Objects 85 | #"Domain" = $Domain 86 | 'Identity' = $U.Identity 87 | 'OU' = $OrganizationalUnit 88 | 'OrganizationalUnit' = $OrganizationalUnitData 89 | } 90 | 91 | } 92 | return $UserList 93 | } 94 | <# 95 | 96 | $Splat = @{ 97 | Filter = '*' 98 | } 99 | 100 | $Splat = @{ 101 | Filter = "UserPrincipalName -eq 'przemyslaw.klys@ad.evotec.xyz'" 102 | SearchBase = 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' 103 | } 104 | 105 | Get-ADUser @Splat 106 | #> 107 | 108 | <# 109 | 110 | $Script:UserProperties = 'Name', 'UserPrincipalName', 'SamAccountName', 'Enabled', 'PasswordLastSet', ` 111 | 'PasswordExpired', 'PasswordNeverExpires', 'PasswordNotRequired', 'EmailAddress', 'DisplayName', 'GivenName', ` 112 | 'Surname', 'Manager', "AccountExpirationDate", "AccountLockoutTime", "AllowReversiblePasswordEncryption", ` 113 | "BadLogonCount", "CannotChangePassword", "CanonicalName", "Description", "DistinguishedName", "EmployeeID", ` 114 | "EmployeeNumber", "LastBadPasswordAttempt", "LastLogonDate", "Created", "Modified", "PrimaryGroup", "MemberOf", ` 115 | 'msDS-UserPasswordExpiryTimeComputed','msExchHideFromAddressLists' 116 | 117 | 118 | $User = Get-WinADUsers -Filter "UserPrincipalName -eq 'przemyslaw.klys@ad.evotec.xyz'" 119 | #$User.MemberOf.Name 120 | #$User."MemberOf.Name" 121 | 122 | $string = 'memberOf.Name' 123 | $value = $user 124 | foreach($part in $string.Split('.')){ 125 | $Part 126 | $value = $value."$part" 127 | } 128 | #> 129 | 130 | #Get-Aduser -Filter * -Properties * | Select-Object MemberOf 131 | 132 | #> 133 | <# 134 | $Script:UserProperties = 'Name', 'UserPrincipalName', 'SamAccountName', 'Enabled', 'PasswordLastSet', ` 135 | 'PasswordExpired', 'PasswordNeverExpires', 'PasswordNotRequired', 'EmailAddress', 'DisplayName', 'GivenName', ` 136 | 'Surname', 'Manager', "AccountExpirationDate", "AccountLockoutTime", "AllowReversiblePasswordEncryption", ` 137 | "BadLogonCount", "CannotChangePassword", "CanonicalName", "Description", "DistinguishedName", "EmployeeID", ` 138 | "EmployeeNumber", "LastBadPasswordAttempt", "LastLogonDate", "Created", "Modified", "PrimaryGroup", "MemberOf", ` 139 | 'msDS-UserPasswordExpiryTimeComputed','msExchHideFromAddressLists' 140 | 141 | Get-WinADUsers -Filter '*' 142 | 143 | #> -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADUsersByOU.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADUsersByOU { 2 | <# 3 | .SYNOPSIS 4 | Retrieves Active Directory users within a specified Organizational Unit. 5 | 6 | .DESCRIPTION 7 | This function retrieves Active Directory users within the specified Organizational Unit. 8 | 9 | .PARAMETER OrganizationalUnit 10 | Specifies the Organizational Unit from which to retrieve users. 11 | 12 | .EXAMPLE 13 | Get-WinADUsersByOU -OrganizationalUnit "OU=Sales,DC=Contoso,DC=com" 14 | Retrieves all users within the Sales Organizational Unit in the Contoso domain. 15 | 16 | #> 17 | [CmdletBinding()] 18 | param ( 19 | $OrganizationalUnit 20 | ) 21 | $OU = Get-ADOrganizationalUnit $OrganizationalUnit 22 | if ($OU.ObjectClass -eq 'OrganizationalUnit') { 23 | try { 24 | $Users = Get-ADUser -SearchBase $OU -Filter * -Properties $Script:UserProperties 25 | } catch { 26 | Write-Color @Script:WriteParameters -Text '[i]', ' One or more properties are invalid - Terminating', ' Terminating' -Color Yellow, White, Red 27 | return 28 | } 29 | } 30 | return $Users 31 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADUsersTranslate.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADUsersTranslate { 2 | [CmdletBinding()] 3 | param( 4 | [System.Object[]] $Users 5 | ) 6 | $UserList = @() 7 | foreach ($U in $Users) { 8 | $UserList += [PSCustomObject] @{ 9 | 'Name' = $U.Name 10 | 'UserPrincipalName' = $U.UserPrincipalName 11 | 'SamAccountName' = $U.SamAccountName 12 | 'Display Name' = $U.DisplayName 13 | 'Given Name' = $U.GivenName 14 | 'Surname' = $U.Surname 15 | 'EmailAddress' = $U.EmailAddress 16 | 'PasswordExpired' = $U.PasswordExpired 17 | 'PasswordLastSet' = $U.PasswordLastSet 18 | 'PasswordLastChanged' = if ($U.PasswordLastSet -ne $Null) { "$(-$($U.PasswordLastSet - [DateTime]::Today).Days)" } else { ''} 19 | 'PasswordNotRequired' = $U.PasswordNotRequired 20 | 'PasswordNeverExpires' = $U.PasswordNeverExpires 21 | 'Enabled' = $U.Enabled 22 | 'Manager' = $U.Manager # (Get-ADObjectFromDistingusishedName -ADCatalog $ADCatalogUsers -DistinguishedName $U.Manager).Name 23 | # 'Manager Email' = (Get-ADObjectFromDistingusishedName -ADCatalog $ADCatalogUsers -DistinguishedName $U.Manager).EmailAddress 24 | 'DateExpiry' = Convert-ToDateTime -Timestring $($U."msDS-UserPasswordExpiryTimeComputed") -Verbose 25 | "DaysToExpire" = (Convert-TimeToDays -StartTime GET-DATE -EndTime (Convert-ToDateTime -Timestring $($U."msDS-UserPasswordExpiryTimeComputed"))) 26 | "AccountExpirationDate" = $U.AccountExpirationDate 27 | "AccountLockoutTime" = $U.AccountLockoutTime 28 | "AllowReversiblePasswordEncryption" = $U.AllowReversiblePasswordEncryption 29 | "BadLogonCount" = $U.BadLogonCount 30 | "CannotChangePassword" = $U.CannotChangePassword 31 | "CanonicalName" = $U.CanonicalName 32 | 33 | "Description" = $U.Description 34 | "DistinguishedName" = $U.DistinguishedName 35 | "EmployeeID" = $U.EmployeeID 36 | "EmployeeNumber" = $U.EmployeeNumber 37 | "LastBadPasswordAttempt" = $U.LastBadPasswordAttempt 38 | "LastLogonDate" = $U.LastLogonDate 39 | 40 | "Created" = $U.Created 41 | "Modified" = $U.Modified 42 | "Protected" = $U.ProtectedFromAccidentalDeletion 43 | 44 | "PrimaryGroup" = $U.PrimaryGroup # (Get-ADObjectFromDistingusishedName -ADCatalog $ADCatalog -DistinguishedName $U.PrimaryGroup -Type 'SamAccountName') 45 | "MemberOf" = $U.MemberOf # (Get-ADObjectFromDistingusishedName -ADCatalog $ADCatalog -DistinguishedName $U.MemberOf -Type 'SamAccountName' -Splitter ', ') 46 | "Domain" = $Domain 47 | } 48 | 49 | } 50 | return $UserList 51 | } 52 | 53 | <# 54 | 55 | $Users = Get-ADUser -Filter * -Properties 'Name', 'UserPrincipalName', 'SamAccountName', 'Enabled', 'PasswordLastSet', ` 56 | 'PasswordExpired', 'PasswordNeverExpires', 'PasswordNotRequired', 'EmailAddress', 'DisplayName', 'GivenName', ` 57 | 'Surname', 'Manager', "AccountExpirationDate", "AccountLockoutTime", "AllowReversiblePasswordEncryption", ` 58 | "BadLogonCount", "CannotChangePassword", "CanonicalName", "Description", "DistinguishedName", "EmployeeID", ` 59 | "EmployeeNumber", "LastBadPasswordAttempt", "LastLogonDate", "Created", "Modified", "PrimaryGroup", "MemberOf", ` 60 | 'msDS-UserPasswordExpiryTimeComputed' 61 | 62 | Get-WinADUsers -Users $Users | Format-Table -AutoSize 63 | 64 | #> -------------------------------------------------------------------------------- /Private/ActiveDirectory/Get-WinADusersByDN.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinADUsersByDN { 2 | <# 3 | .SYNOPSIS 4 | Retrieves Active Directory user information based on the provided DistinguishedName(s). 5 | 6 | .DESCRIPTION 7 | This function retrieves Active Directory user information based on the provided DistinguishedName(s). It returns specific user properties for the given DistinguishedName(s). 8 | 9 | .PARAMETER DistinguishedName 10 | Specifies the DistinguishedName(s) of the user(s) to retrieve information for. 11 | 12 | .PARAMETER Field 13 | Specifies the specific field to return for each user. Default value is 'DisplayName'. 14 | 15 | .PARAMETER All 16 | Indicates whether to return all properties of the user(s). 17 | 18 | .EXAMPLE 19 | Get-WinADUsersByDN -DistinguishedName "CN=John Doe,OU=Users,DC=contoso,DC=com" 20 | Retrieves the DisplayName of the user with the specified DistinguishedName. 21 | 22 | .EXAMPLE 23 | Get-WinADUsersByDN -DistinguishedName "CN=Jane Smith,OU=Users,DC=contoso,DC=com" -Field "EmailAddress" 24 | Retrieves the EmailAddress of the user with the specified DistinguishedName. 25 | 26 | .EXAMPLE 27 | Get-WinADUsersByDN -DistinguishedName "CN=Admin,OU=Users,DC=contoso,DC=com" -All 28 | Retrieves all properties of the user with the specified DistinguishedName. 29 | 30 | #> 31 | param( 32 | [alias('DN')][string[]]$DistinguishedName, 33 | [string] $Field = 'DisplayName', # return field 34 | [switch] $All 35 | ) 36 | $Properties = 'DistinguishedName', 'Enabled', 'GivenName', 'Name', 'SamAccountName', 'SID', 'Surname', 'UserPrincipalName', 'EmailAddress', 'DisplayName' 37 | 38 | $Users = foreach ($DN in $DistinguishedName) { 39 | try { 40 | get-aduser -Identity $DN -Properties $Properties 41 | } catch { 42 | # returns empty, basically ignores stuff 43 | } 44 | } 45 | 46 | if ($All) { 47 | return $Users #.PSObject.Properties.Name 48 | } else { 49 | return $Users.$Field 50 | } 51 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Remove-WinADUserGroups.ps1: -------------------------------------------------------------------------------- 1 | function Remove-WinADUserGroups { 2 | <# 3 | .SYNOPSIS 4 | Removes specified Active Directory groups from a user. 5 | 6 | .DESCRIPTION 7 | This function removes specified Active Directory groups from a user account. It provides options to remove groups based on category, scope, or all groups. 8 | 9 | .PARAMETER User 10 | The user object from which groups will be removed. 11 | 12 | .PARAMETER GroupCategory 13 | Specifies the category of groups to remove. Valid values are "Distribution" and "Security". 14 | 15 | .PARAMETER GroupScope 16 | Specifies the scope of groups to remove. Valid values are "DomainLocal", "Global", and "Universal". 17 | 18 | .PARAMETER Groups 19 | An array of specific group names to remove. 20 | 21 | .PARAMETER All 22 | If specified, removes all groups from the user. 23 | 24 | .PARAMETER WhatIf 25 | Shows what would happen if the command runs without actually running it. 26 | 27 | .EXAMPLE 28 | Remove-WinADUserGroups -User $User -All 29 | Removes all groups from the specified user account. 30 | 31 | .EXAMPLE 32 | Remove-WinADUserGroups -User $User -GroupCategory "Security" -GroupScope "Global" 33 | Removes all security groups with a global scope from the specified user account. 34 | #> 35 | [CmdletBinding()] 36 | [alias("Remove-ADUserGroups")] 37 | param( 38 | [parameter(Mandatory = $true)][Object] $User, 39 | [ValidateSet("Distribution", "Security")][String] $GroupCategory , 40 | [ValidateSet("DomainLocal", "Global", "Universal")][String] $GroupScope, 41 | [string[]] $Groups, 42 | [switch] $All, 43 | [switch] $WhatIf 44 | ) 45 | $Object = @() 46 | try { 47 | $ADgroups = Get-ADPrincipalGroupMembership -Identity $User.DistinguishedName -ErrorAction Stop | Where-Object { $_.Name -ne "Domain Users" } 48 | } catch { 49 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 50 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 51 | } 52 | if ($ADgroups) { 53 | if ($All) { 54 | #Write-Color @Script:WriteParameters -Text '[i]', ' Removing groups ', ($ADgroups.Name -join ', '), ' from user ', $User.DisplayName -Color White, Yellow, Green, White, Yellow 55 | foreach ($Group in $ADgroups) { 56 | try { 57 | if (-not $WhatIf) { 58 | Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $Group -Confirm:$false -ErrorAction Stop 59 | } 60 | $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } 61 | } catch { 62 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 63 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 64 | } 65 | } 66 | } 67 | if ($GroupCategory) { 68 | $ADGroupsByCategory = $ADgroups | Where-Object { $_.GroupCategory -eq $GroupCategory } 69 | if ($ADGroupsByCategory) { 70 | #Write-Color @Script:WriteParameters -Text '[i]', ' Removing groups (by category - ', $GroupCategory, ") ", ($ADGroupsByCategory.Name -join ', '), ' from user ', $User.DisplayName -Colo White, Yellow, Green, White, Yellow, White, Blue 71 | foreach ($Group in $ADGroupsByCategory) { 72 | try { 73 | if (-not $WhatIf) { 74 | Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $Group -Confirm:$false -ErrorAction Stop 75 | } 76 | $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } 77 | } catch { 78 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 79 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 80 | } 81 | } 82 | } 83 | } 84 | if ($GroupScope) { 85 | $ADGroupsByScope = $ADgroups | Where-Object { $_.GroupScope -eq $GroupScope } 86 | if ($ADGroupsByScope) { 87 | #Write-Color @Script:WriteParameters -Text '[i]', ' Removing groups (by scope ', " - $GroupScope) ", ($ADGroupsByScope.Name -join ', '), ' from user ', $User.DisplayName -Color White, Yellow, Green, White, Yellow, White, Blue 88 | foreach ($Group in $ADGroupsByScope) { 89 | try { 90 | if (-not $WhatIf) { 91 | Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $Group -Confirm:$false -ErrorAction Stop 92 | } 93 | $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } 94 | } catch { 95 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 96 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 97 | } 98 | } 99 | } 100 | } 101 | if ($Groups) { 102 | foreach ($Group in $Groups) { 103 | $ADGroupsByName = $ADgroups | Where-Object { $_.Name -like $Group } 104 | if ($ADGroupsByName) { 105 | #Write-Color @Script:WriteParameters -Text '[i]', ' Removing groups (by name) ', ($ADGroupsByName.Name -join ', '), ' from user ', $User.DisplayName -Color White, Yellow, Green, White, Yellow, White, Yellow 106 | try { 107 | if (-not $WhatIf) { 108 | Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $ADGroupsByName -Confirm:$false -ErrorAction Stop 109 | } 110 | $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } 111 | } catch { 112 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 113 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 114 | } 115 | } else { 116 | $Object += @{ Status = $false; Output = $Group.Name; Extended = 'Not available on user.' } 117 | } 118 | } 119 | } 120 | } 121 | return $Object 122 | } 123 | -------------------------------------------------------------------------------- /Private/ActiveDirectory/Set-WinADGroupSynchronization.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | $Group1 = 'GDS-TestGroup1' 4 | $Group2 = 'GDS-TestGroup2' 5 | 6 | Set-WinADGroupSynchronization -GroupFrom $Group1 -GroupTo $Group2 -Type 'All' -Recursive None 7 | #> 8 | 9 | function Set-WinADGroupSynchronization { 10 | <# 11 | .SYNOPSIS 12 | Sets up synchronization between two Active Directory groups. 13 | 14 | .DESCRIPTION 15 | This function sets up synchronization between two Active Directory groups by copying members from one group to another based on specified criteria. 16 | 17 | .PARAMETER GroupFrom 18 | The name of the source Active Directory group from which members will be synchronized. 19 | 20 | .PARAMETER GroupTo 21 | The name of the target Active Directory group to which members will be synchronized. 22 | 23 | .PARAMETER Type 24 | Specifies the type of members to synchronize. Valid values are 'User', 'Group', or 'All'. Default is 'User'. 25 | 26 | .PARAMETER Recursive 27 | Specifies the type of synchronization to perform. Valid values are 'None', 'RecursiveFrom', 'RecursiveBoth', or 'RecursiveTo'. Default is 'None'. 28 | 29 | .PARAMETER WhatIf 30 | Shows what would happen if the synchronization is performed without actually performing it. 31 | 32 | .EXAMPLE 33 | Set-WinADGroupSynchronization -GroupFrom 'GDS-TestGroup1' -GroupTo 'GDS-TestGroup2' -Type 'All' -Recursive None 34 | Synchronizes all members from 'GDS-TestGroup1' to 'GDS-TestGroup2' without recursion. 35 | 36 | .EXAMPLE 37 | Set-WinADGroupSynchronization -GroupFrom 'GDS-TestGroup1' -GroupTo 'GDS-TestGroup2' -Type 'User' -Recursive RecursiveBoth 38 | Synchronizes only user members from 'GDS-TestGroup1' to 'GDS-TestGroup2' with recursion in both groups. 39 | 40 | #> 41 | [CmdletBinding()] 42 | param( 43 | [parameter(Mandatory = $true)][string] $GroupFrom, 44 | [parameter(Mandatory = $true)][string] $GroupTo, 45 | [parameter(Mandatory = $false)][ValidateSet("User", "Group", "All")][string] $Type = 'User', 46 | [parameter(Mandatory = $false)][ValidateSet("None", "RecursiveFrom", "RecursiveBoth", "RecursiveTo")] $Recursive = 'None', 47 | [switch] $WhatIf 48 | ) 49 | Begin { 50 | $Object = @() 51 | if ($Recursive -eq 'None') { 52 | $GroupFromRecursive = $false 53 | $GroupToRecursive = $false 54 | } elseif ($Recursive -eq 'RecursiveFrom') { 55 | $GroupFromRecursive = $true 56 | $GroupToRecursive = $false 57 | } elseif ($Recursive -eq 'RecursiveBoth') { 58 | $GroupFromRecursive = $true 59 | $GroupToRecursive = $true 60 | } else { 61 | $GroupFromRecursive = $false 62 | $GroupToRecursive = $true 63 | } 64 | } 65 | Process { 66 | try { 67 | 68 | $GroupMembersFrom = Get-ADGroupMember -Identity $GroupFrom -Recursive:$GroupFromRecursive | Select-Object Name, ObjectClass, SamAccountName, UserPrincipalName 69 | } catch { 70 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 71 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 72 | } 73 | try { 74 | $GroupMembersTo = Get-ADGroupMember -Identity $GroupTo -Recursive:$GroupToRecursive | Select-Object Name, ObjectClass, SamAccountName, UserPrincipalName 75 | } catch { 76 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 77 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 78 | } 79 | if ($Object.Count -gt 0) { 80 | # Something went seriously wrong. Terminate ASAP 81 | return $Object 82 | } 83 | 84 | foreach ($User in $GroupMembersFrom) { 85 | if ($User.ObjectClass -eq "user") { 86 | if ($Type -eq 'User' -or $Type -eq 'All') { 87 | if ($GroupMembersTo.SamAccountName -notcontains $User.SamAccountName) { 88 | #Write-Color "Not a member ", $User.SamAccountName, " of $GroupTo", ". Adding!" -Color Red -LogFile $LogFile 89 | try { 90 | if (-not $WhatIf) { 91 | Add-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName 92 | } 93 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Added to group $GroupTo" } 94 | } catch { 95 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 96 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 97 | } 98 | } 99 | } 100 | } else { 101 | if ($Type -eq 'Group' -or $Type -eq 'All') { 102 | if ($GroupMembersTo.SamAccountName -notcontains $User.SamAccountName) { 103 | #Write-Color "Not a member ", $User.SamAccountName, " of $GroupTo", ". Adding!" -Color Red -LogFile $LogFile 104 | try { 105 | if (-not $WhatIf) { 106 | Add-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName 107 | } 108 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Added to group $GroupTo" } 109 | } catch { 110 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 111 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | foreach ($User in $GroupMembersTo) { 118 | if ($User.ObjectClass -eq "user") { 119 | if ($Type -eq 'User' -or $Type -eq 'All') { 120 | if ($GroupMembersFrom.SamAccountName -notcontains $User.SamAccountName) { 121 | Write-Color "Not a member of $GroupFrom - requires removal from $GroupTo ", $User.SamAccountName -Color Red -LogFile $LogFile 122 | try { 123 | if (-not $WhatIf) { 124 | Remove-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName -Confirm:$false 125 | } 126 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Removed from group $GroupTo" } 127 | } catch { 128 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 129 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 130 | } 131 | } 132 | } 133 | } else { 134 | if ($Type -eq 'Group' -or $Type -eq 'All') { 135 | if ($GroupMembersFrom.SamAccountName -notcontains $User.SamAccountName) { 136 | Write-Color "Not a member of $GroupFrom - requires removal from $GroupTo ", $User.SamAccountName -Color Red -LogFile $LogFile 137 | try { 138 | if (-not $WhatIf) { 139 | Remove-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName -Confirm:$false 140 | } 141 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Removed from group $GroupTo" } 142 | } catch { 143 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 144 | $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } 145 | } 146 | } 147 | } 148 | } 149 | } 150 | } 151 | End { 152 | return $object 153 | } 154 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Set-WinADUserFields.ps1: -------------------------------------------------------------------------------- 1 | function Set-WinADUserFields { 2 | <# 3 | .SYNOPSIS 4 | Sets specified fields for an Active Directory user with additional options. 5 | 6 | .DESCRIPTION 7 | This function allows setting specified fields for an Active Directory user with the option to add text before or after the existing field value. 8 | 9 | .PARAMETER User 10 | Specifies the Active Directory user object to modify. 11 | 12 | .PARAMETER Option 13 | Specifies whether to add the text before or after the existing field value. Valid values are 'Before' and 'After'. 14 | 15 | .PARAMETER TextToAdd 16 | Specifies the text to add before or after the existing field value. 17 | 18 | .PARAMETER TextToRemove 19 | Specifies the text to remove from the existing field value. 20 | 21 | .PARAMETER Fields 22 | Specifies an array of fields to modify for the user. 23 | 24 | .PARAMETER WhatIf 25 | Indicates that the cmdlet should display what changes would occur without actually making any changes. 26 | 27 | .EXAMPLE 28 | Set-WinADUserFields -User $user -Option 'After' -TextToAdd 'New' -Fields 'Name' 29 | Adds the text 'New' after the existing 'Name' field value for the specified user. 30 | 31 | .EXAMPLE 32 | Set-WinADUserFields -User $user -Option 'Before' -TextToAdd 'Old' -Fields 'Description' 33 | Adds the text 'Old' before the existing 'Description' field value for the specified user. 34 | #> 35 | [CmdletBinding()] 36 | [alias("Set-ADUserName")] 37 | param ( 38 | [parameter(Mandatory = $true)][Object] $User, 39 | [parameter(Mandatory = $false)][ValidateSet("Before", "After")][String] $Option, 40 | [string] $TextToAdd, 41 | [string] $TextToRemove, 42 | [string[]] $Fields, 43 | [switch] $WhatIf 44 | ) 45 | $Object = @() 46 | if ($TextToAdd) { 47 | foreach ($Field in $Fields) { 48 | if ($User.$Field -notlike "*$TextToAdd*") { 49 | 50 | if ($Option -eq 'After') { 51 | $NewName = "$($User.$Field)$TextToAdd" 52 | } elseif ($Option -eq 'Before') { 53 | $NewName = "$TextToAdd$($User."$Field")" 54 | } 55 | if ($NewName -ne $User.$Field) { 56 | if ($Field -eq 'Name') { 57 | try { 58 | if (-not $WhatIf) { 59 | Rename-ADObject -Identity $User.DistinguishedName -NewName $NewName #-WhatIf 60 | } 61 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed account '$Field' to '$NewName'" } 62 | 63 | } catch { 64 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 65 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } 66 | } 67 | } else { 68 | $Splat = @{ 69 | Identity = $User.DistinguishedName 70 | "$Field" = $NewName 71 | } 72 | try { 73 | if (-not $WhatIf) { 74 | Set-ADUser @Splat 75 | } 76 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed field '$Field' to '$NewName'" } 77 | 78 | } catch { 79 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 80 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } 81 | } 82 | } 83 | 84 | 85 | } 86 | 87 | } 88 | } 89 | } 90 | if ($TextToRemove) { 91 | foreach ($Field in $Fields) { 92 | if ($User.$Field -like "*$TextToRemove*") { 93 | $NewName = $($User.$Field).Replace($TextToRemove, '') 94 | if ($Field -eq 'Name') { 95 | try { 96 | if (-not $WhatIf) { 97 | Rename-ADObject -Identity $User.DistinguishedName -NewName $NewName #-WhatIf 98 | } 99 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed account '$Field' to '$NewName'" } 100 | 101 | } catch { 102 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 103 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = "Field: '$Field' Error: '$ErrorMessage'" } 104 | } 105 | } else { 106 | $Splat = @{ 107 | Identity = $User.DistinguishedName 108 | "$Field" = $NewName 109 | } 110 | try { 111 | if (-not $WhatIf) { 112 | Set-ADUser @Splat #-WhatIf 113 | } 114 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed field $Field to $NewName" } 115 | 116 | } catch { 117 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 118 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = "Field: $Field Error: $ErrorMessage" } 119 | } 120 | } 121 | } 122 | } 123 | 124 | } 125 | return $Object 126 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Set-WinADUserSettingGAL.ps1: -------------------------------------------------------------------------------- 1 | Function Set-WinADUserSettingGAL { 2 | <# 3 | .SYNOPSIS 4 | Sets the Exchange Global Address List (GAL) visibility for a specified user. 5 | 6 | .DESCRIPTION 7 | This function allows you to hide or show a user in the Global Address List (GAL) of Exchange. 8 | It updates the msExchHideFromAddressLists attribute of the user object in Active Directory. 9 | 10 | .PARAMETER User 11 | Specifies the user object for which the GAL visibility needs to be set. 12 | 13 | .PARAMETER Option 14 | Specifies whether to 'Hide' or 'Show' the user in the GAL. 15 | 16 | .PARAMETER WhatIf 17 | Displays what would happen if the command runs without actually running the command. 18 | 19 | .EXAMPLE 20 | Set-WinADUserSettingGAL -User "JohnDoe" -Option "Hide" 21 | Hides the user "JohnDoe" from the Global Address List. 22 | 23 | .EXAMPLE 24 | Set-WinADUserSettingGAL -User "JaneSmith" -Option "Show" 25 | Shows the user "JaneSmith" in the Global Address List. 26 | 27 | #> 28 | [CmdletBinding()] 29 | [alias("Set-ADUserSettingGAL")] 30 | param ( 31 | [parameter(Mandatory = $true)][Object] $User, 32 | [parameter(Mandatory = $true)][ValidateSet("Hide", "Show")][String]$Option, 33 | [switch] $WhatIf 34 | ) 35 | $Object = @() 36 | if ($User) { 37 | if ($Option -eq 'Hide') { 38 | if (-not $User.msExchHideFromAddressLists) { 39 | #Write-Color @Script:WriteParameters -Text '[i]', ' Hiding user ', $User.DisplayName, ' in GAL (Exchange Address Lists)' -Color White, Yellow, Green, White, Yellow 40 | try { 41 | if (-not $WhatIf) { 42 | Set-ADObject -Identity $User.DistinguishedName -Replace @{msExchHideFromAddressLists = $true} 43 | } 44 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Hidden from GAL.' } 45 | } catch { 46 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 47 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } 48 | } 49 | } 50 | } elseif ($Option -eq 'Show') { 51 | if ($User.msExchHideFromAddressLists) { 52 | #Write-Color @Script:WriteParameters -Text '[i]', ' Unhiding user ', $User.DisplayName, ' in GAL (Exchange Address Lists)' -Color White, Yellow, Green, White, Yellow 53 | try { 54 | if ($WhatIf) { 55 | Set-ADObject -Identity $User.DistinguishedName -Clear msExchHideFromAddressLists 56 | } 57 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Unhidden in GAL.' } 58 | } catch { 59 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 60 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } 61 | } 62 | } 63 | } 64 | } 65 | return $Object 66 | } -------------------------------------------------------------------------------- /Private/ActiveDirectory/Set-WinADUserStatus.ps1: -------------------------------------------------------------------------------- 1 | function Set-WinADUserStatus { 2 | <# 3 | .SYNOPSIS 4 | Enables or disables a user account in Active Directory. 5 | 6 | .DESCRIPTION 7 | The Set-WinADUserStatus function enables or disables a specified user account in Active Directory based on the provided option. It also provides an option to simulate the action using the WhatIf switch. 8 | 9 | .PARAMETER User 10 | Specifies the user account to enable or disable. 11 | 12 | .PARAMETER Option 13 | Specifies whether to enable or disable the user account. Valid values are "Enable" or "Disable". 14 | 15 | .PARAMETER WhatIf 16 | Indicates that the cmdlet should display what would happen if it were to run, without actually performing any action. 17 | 18 | .EXAMPLE 19 | Set-WinADUserStatus -User $user -Option "Enable" 20 | Enables the user account specified by $user in Active Directory. 21 | 22 | .EXAMPLE 23 | Set-WinADUserStatus -User $user -Option "Disable" -WhatIf 24 | Displays what would happen if the user account specified by $user were to be disabled in Active Directory, without actually disabling it. 25 | 26 | #> 27 | [CmdletBinding()] 28 | [alias("Set-ADUserStatus")] 29 | param ( 30 | [parameter(Mandatory = $true)][Object] $User, 31 | [parameter(Mandatory = $true)][ValidateSet("Enable", "Disable")][String] $Option, 32 | [switch] $WhatIf 33 | # $WriteParameters 34 | ) 35 | $Object = @() 36 | if ($Option -eq 'Enable' -and $User.Enabled -eq $false) { 37 | #if (-not $WriteParameters) { 38 | # Write-Color @Script:WriteParameters -Text 'Enabling user ', $User.DisplayName, ' in Active Directory.' -Color Yellow, Green, White, Yellow 39 | #} else { 40 | # Write-Color @WriteParameters 41 | #} 42 | try { 43 | if (-not $WhatIf) { 44 | Set-ADUser -Identity $User.DistinguishedName -Enabled $true 45 | } 46 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Enabled user.' } 47 | } catch { 48 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 49 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } 50 | } 51 | } elseif ($Option -eq 'Disable' -and $User.Enabled -eq $true) { 52 | #if (-not $WriteParameters) { 53 | # Write-Color @Script:WriteParameters -Text 'Disabling user ', $User.DisplayName, 'in Active Directory.' -Color Yellow, Green, White, Yellow 54 | #} else { 55 | # Write-Color @WriteParameters 56 | #} 57 | try { 58 | if (-not $WhatIf) { 59 | Set-ADUser -Identity $User.DistinguishedName -Enabled $false 60 | } 61 | $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Disabled user.' } 62 | 63 | } catch { 64 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 65 | $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } 66 | } 67 | } 68 | return $Object 69 | } -------------------------------------------------------------------------------- /Private/AzureAD/Get-WinAzureADUsers.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinAzureADUsers { 2 | [CmdletBinding()] 3 | param( 4 | [ValidateSet("All", "DisabledOnly", "EnabledOnly")][string] $Filter = 'All', 5 | [int] $MaxResults = 5000000, 6 | [string] $UserPrincipalName, 7 | [switch] $ReturnDeletedUsers, 8 | [switch] $ReturnUnlicensedUsers, 9 | [string] $Country, 10 | [string] $City, 11 | [string] $Department, 12 | [string] $State, 13 | [switch] $Synchronized, 14 | [string] $DomainName, 15 | [string] $Title, 16 | [switch] $All, 17 | [switch] $LicenseReconciliationNeededOnly, 18 | [string] $SearchString, 19 | [switch] $HasErrorsOnly, 20 | [Guid] $TenantId, 21 | [string] $UsageLocation 22 | 23 | ) 24 | 25 | $UserSplat = @{} 26 | if ($UserPrincipalName) { $UserSplat.UserPrincipalName = $UserPrincipalName } 27 | 28 | if ($DomainName) { $UserSplat.DomainName = $DomainName } 29 | 30 | if ($MaxResults) { $UserSplat.MaxResults = $MaxResults } 31 | 32 | <# 33 | EnabledFilter = $Filter 34 | ReturnDeletedUsers = $ReturnDeletedUsers 35 | UnlicensedUsersOnly = $ReturnUnlicensedUsers 36 | 37 | Country = $Country 38 | City = $City 39 | State = $State 40 | UsageLocation = $UsageLocation 41 | 42 | Title = $Title 43 | Department = $Department 44 | 45 | 46 | 47 | LicenseReconciliationNeededOnly = $LicenseReconciliationNeededOnly 48 | SearchString = $SearchString 49 | HasErrorsOnly = $HasErrorsOnly 50 | TenantID = $TenantId 51 | #> 52 | 53 | if ($All) { 54 | #$UserSplat.All = $All 55 | #$UserSplat.DomainName = 'evotec.xyz' 56 | 57 | } 58 | 59 | $Users = Get-MsolUser -All:$All -Synchronized:$Synchronized -ReturnDeletedUsers:$ReturnDeletedUsers -UnlicensedUsersOnly:$ReturnUnlicensedUsers 60 | $Users 61 | 62 | } 63 | 64 | #Get-WinAzureADUsers -MaxResults 3 -Country 'Poland' -ReturnDeletedUsers -ReturnUnlicensedUsers -------------------------------------------------------------------------------- /Private/AzureAD/Set-WinAzureADUserField.ps1: -------------------------------------------------------------------------------- 1 | function Set-WinAzureADUserField { 2 | [CmdletBinding()] 3 | param ( 4 | [parameter(Mandatory = $true)][Object] $User, 5 | [parameter(Mandatory = $false)][Object] $Value, 6 | [switch] $WhatIf 7 | ) 8 | 9 | $Splat = @{} 10 | $Splat.UserPrincipalName = $User.UserPrincipalName 11 | $Splat.ErrorAction = 'Stop' 12 | if ($Value) { 13 | $Field = "$($Value.Field)" 14 | if ($Field -eq 'UserPrincipalName') { 15 | # if UserPrincipalName it means user wants to rename UserPrincipalName 16 | # that requires different method 17 | $Field = 'NewUserPrincipalName' 18 | } 19 | $Data = $Value.Value 20 | $Splat.$Field = $Data 21 | } 22 | 23 | $Object = @() 24 | if ($User.$Field -ne $Data) { 25 | try { 26 | if (-not $WhatIf) { 27 | if ($Field -eq 'UserPrincipalName') { 28 | Set-MsolUserPrincipalName @Splat 29 | } else { 30 | Set-MsolUser @Splat 31 | } 32 | } 33 | 34 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = "Set $Field to $Data" } 35 | } catch { 36 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " -Replace ' ',' ' 37 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 38 | } 39 | } 40 | return $Object 41 | } -------------------------------------------------------------------------------- /Private/AzureAD/Set-WinAzureADUserLicense.ps1: -------------------------------------------------------------------------------- 1 | function Set-WinAzureADUserLicense { 2 | [CmdletBinding()] 3 | param ( 4 | [parameter(Mandatory = $true)][Object] $User, 5 | [parameter(Mandatory = $true)][ValidateSet("Add", "Remove", "RemoveAll", "Replace")][String] $Option, 6 | [parameter(Mandatory = $false)][string] $License, 7 | [parameter(Mandatory = $false)][string] $LicenseToReplace, 8 | [switch] $WhatIf 9 | ) 10 | $Object = @() 11 | if ($Option -eq 'Add') { 12 | try { 13 | if (-not $WhatIf) { 14 | Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $License -ErrorAction Stop 15 | } 16 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = "Added license $License to user." } 17 | } catch { 18 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 19 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 20 | } 21 | } elseif ($Option -eq 'Remove') { 22 | try { 23 | if (-not $WhatIf) { 24 | Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -RemoveLicenses $License -ErrorAction Stop 25 | } 26 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = "Removed license $License from user." } 27 | } catch { 28 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 29 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 30 | } 31 | } elseif ($Option -eq 'RemoveAll') { 32 | try { 33 | foreach ($License in $User.Licenses.AccountSKUID) { 34 | if (-not $WhatIf) { 35 | Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -RemoveLicenses $License -ErrorAction Stop 36 | } 37 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = "Removed license $License from user." } 38 | } 39 | } catch { 40 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 41 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 42 | } 43 | } elseif ($Option -eq 'Replace') { 44 | [bool] $Success = $true 45 | try { 46 | if (-not $WhatIf) { 47 | Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $License 48 | } 49 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = "Added license $License to user before removing $LicenseToReplace." } 50 | } catch { 51 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 52 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 53 | $Success = $false 54 | } 55 | if ($Success) { 56 | try { 57 | if (-not $WhatIf) { 58 | Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -RemoveLicenses $License -ErrorAction Stop 59 | } 60 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = "Removed license $LicenseToReplace from user." } 61 | } catch { 62 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 63 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 64 | } 65 | } 66 | } 67 | return $Object 68 | } -------------------------------------------------------------------------------- /Private/AzureAD/Set-WinAzureADUserStatus.ps1: -------------------------------------------------------------------------------- 1 | function Set-WinAzureADUserStatus { 2 | [CmdletBinding()] 3 | param ( 4 | [parameter(Mandatory = $true)][Object] $User, 5 | [parameter(Mandatory = $true)][ValidateSet("Enable", "Disable")][String] $Option, 6 | [switch] $WhatIf 7 | ) 8 | $Object = @() 9 | if ($Option -eq 'Enable' -and $User.BlockCredential -eq $true) { 10 | try { 11 | if (-not $WhatIf) { 12 | Set-MsolUser -UserPrincipalName $User.UserPrincipalName -BlockCredential $false 13 | } 14 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = 'Enabled user.' } 15 | } catch { 16 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 17 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 18 | } 19 | } elseif ($Option -eq 'Disable' -and $User.BlockCredential -eq $false) { 20 | try { 21 | if (-not $WhatIf) { 22 | Set-MsolUser -UserPrincipalName $User.UserPrincipalName -BlockCredential $true 23 | } 24 | $Object += @{ Status = $true; Output = $User.UserPrincipalName; Extended = 'Disabled user.' } 25 | } catch { 26 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 27 | $Object += @{ Status = $false; Output = $User.UserPrincipalName; Extended = $ErrorMessage } 28 | } 29 | } 30 | return $Object 31 | } -------------------------------------------------------------------------------- /Private/Configuration/Get-PSAutomatorConfiguration.ps1: -------------------------------------------------------------------------------- 1 | function Get-PSAutomatorConfiguration { 2 | [CmdletBinding()] 3 | param( 4 | $ConfigurationPath 5 | ) 6 | if (($ConfigurationPath) -and (Test-Path $ConfigurationPath)) { 7 | $Script:Configuration = Import-Clixml -Path $ConfigurationPath 8 | } else { 9 | $Script:Configuration = $null 10 | } 11 | } -------------------------------------------------------------------------------- /Private/Main/Complete-WorkFlow.ps1: -------------------------------------------------------------------------------- 1 | Function Complete-WorkFlow { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(ValueFromPipeline = $true, Mandatory = $false, Position = 0)] $Object 5 | ) 6 | Begin { 7 | 8 | } 9 | Process { 10 | if ($null -eq $Object) { 11 | Write-Warning "Complete-WorkFlow can't be used out of order. Terminating!" 12 | Exit 13 | } 14 | Start-Configuration -Configuration $Script:Configuration 15 | 16 | foreach ($Trigger in $Object.Triggers) { 17 | Out-TriggerStatus -Trigger $Trigger 18 | 19 | if ($Trigger.Type -eq 'User') { 20 | switch ($Trigger.Trigger) { 21 | Always { 22 | $Object.ProcessingData.Users += Get-WinADUsers -Filter '*' 23 | } 24 | Filter { 25 | $Object.ProcessingData.Users += Get-WinADUsers -Filter $Trigger.Value 26 | } 27 | GroupMembership { 28 | $Object.ProcessingData.Users += Get-WinADUsers -Group $Trigger.Value 29 | } 30 | OrganizationalUnit { 31 | $Object.ProcessingData.Users += Get-WinADUsers -OrganizationalUnit $Trigger.Value 32 | } 33 | } 34 | } 35 | if ($Trigger.Type -eq 'UserAzureAD') { 36 | switch ($Trigger.Trigger) { 37 | All { 38 | $Object.ProcessingData.Users += Get-WinAzureADUsers -All 39 | } 40 | ByFields { 41 | $Object.ProcessingData.Users += Get-WinAzureADUsers -Trigger $Trigger.Value 42 | } 43 | Deleted { 44 | $Object.ProcessingData.Users += Get-WinAzureADUsers -ReturnDeletedUsers 45 | } 46 | Domain { 47 | $Object.ProcessingData.Users += Get-WinAzureADUsers -Trigger $Trigger.Value 48 | } 49 | Synchronized { 50 | $Object.ProcessingData.Users += Get-WinAzureADUsers -Synchronized 51 | } 52 | Unlicensed { 53 | $Object.ProcessingData.Users += Get-WinAzureADUsers -ReturnUnlicensedUsers 54 | } 55 | UserPrincipalName { 56 | $Object.ProcessingData.Users += Get-WinAzureADUsers -UserPrincipalName $Trigger.Value 57 | } 58 | Search { 59 | $Object.ProcessingData.Users += Get-WinAzureADUsers -Trigger $Trigger.Value 60 | } 61 | } 62 | } 63 | } 64 | 65 | 66 | foreach ($Condition in $Object.Conditions) { 67 | if (-not [string]::IsNullOrEmpty($Condition.Value) -and $Condition.Condition -ne $null) { 68 | if ($Condition.Value -is [string]) { 69 | $WriteInformation = @{ 70 | Text = '[+]', ' Running Condition', ' for ', $Condition.Name, ' as ', $Condition.Condition 71 | Color = [ConsoleColor]::Magenta, [ConsoleColor]::White, [ConsoleColor]::White, ` 72 | [ConsoleColor]::Magenta, [ConsoleColor]::White, [ConsoleColor]::Magenta, [ConsoleColor]::White, [ConsoleColor]::Magenta, ` 73 | [ConsoleColor]::White, [ConsoleColor]::Magenta 74 | StartSpaces = 4 75 | } 76 | } else { 77 | $WriteInformation = @{ 78 | Text = '[+]', ' Running Condition', ' for ', $Condition.Name, ' as ', $Condition.Condition, ' with operator ', $Condition.Value.Operator, ' on field ', $Condition.Value.Field 79 | Color = [ConsoleColor]::Magenta, [ConsoleColor]::White, [ConsoleColor]::White, ` 80 | [ConsoleColor]::Magenta, [ConsoleColor]::White, [ConsoleColor]::Magenta, [ConsoleColor]::White, [ConsoleColor]::Magenta, ` 81 | [ConsoleColor]::White, [ConsoleColor]::Magenta 82 | StartSpaces = 4 83 | } 84 | } 85 | Write-Color @WriteInformation 86 | switch ($Condition.Condition) { 87 | EmptyOrNull { 88 | $Object.ProcessingData.Users = Submit-ConditionEmptyOrNull -Object $Object.ProcessingData.Users -Value $Condition.Value 89 | } 90 | Field { 91 | $Object.ProcessingData.Users = Submit-ConditionFields -Type 'Default' -Object $Object.ProcessingData.Users -Value $Condition.Value 92 | } 93 | GroupMembership { 94 | $Object.ProcessingData.Users = Submit-ConditionFields -Type 'GroupMembership' -Object $Object.ProcessingData.Users -Value $Condition.Value 95 | } 96 | OrganizationalUnit { 97 | $Object.ProcessingData.Users = Submit-ConditionFields -Type 'OrganizationalUnit' -Object $Object.ProcessingData.Users -Value $Condition.Value 98 | } 99 | } 100 | } else { 101 | $WriteInformation = @{ 102 | Text = '[-]', ' Running Condition', ' for ', $Condition.Name, ' was skipped due to either ', 'Condition', ' or/and ', 'Value', ' missing.' 103 | Color = [ConsoleColor]::Red, [ConsoleColor]::White, [ConsoleColor]::White, ` 104 | [ConsoleColor]::Red, [ConsoleColor]::White, [ConsoleColor]::Red, [ConsoleColor]::White, [ConsoleColor]::Red, [ConsoleColor]::White, [ConsoleColor]::Red, [ConsoleColor]::White 105 | StartSpaces = 4 106 | } 107 | Write-Color @WriteInformation 108 | } 109 | } 110 | 111 | 112 | $CountUsers = Get-ObjectCount -Object $Object.ProcessingData.Users 113 | 114 | foreach ($Action in $Object.Actions) { 115 | 116 | $WriteInformation = @{ 117 | Color = [ConsoleColor]::DarkGreen, [ConsoleColor]::White, [ConsoleColor]::DarkGreen, [ConsoleColor]::White, ` 118 | [ConsoleColor]::DarkGreen, [ConsoleColor]::White, [ConsoleColor]::DarkGreen, [ConsoleColor]::White, [ConsoleColor]::DarkGreen 119 | StartSpaces = 4 120 | } 121 | if ($Action.WhatIf) { 122 | $WriteInformation.Text = '[+] ', 'Action ', $Action.Name, ' on ', $CountUsers, ' objects based on trigger (pretending only!)' #, $Trigger.Trigger, ' with value ', $Trigger.Value 123 | } else { 124 | $WriteInformation.Text = '[*] ', 'Action ', $Action.Name, ' on ', $CountUsers, ' objects based on trigger' #, $Trigger.Trigger, ' with value ', $Trigger.Value 125 | } 126 | Write-Color @WriteInformation 127 | 128 | if ($Action.Type -eq 'ActiveDirectory') { 129 | Submit-ActionActiveDirectory -Object $Object -Action $Action 130 | } 131 | if ($Action.Type -eq 'AzureActiveDirectory') { 132 | Submit-ActionAzureActiveDirectory -Object $Object -Action $Action 133 | } 134 | if ($Action.Type -eq 'Exchange') { 135 | 136 | } 137 | } 138 | } 139 | End { 140 | return $Object 141 | } 142 | } -------------------------------------------------------------------------------- /Private/Main/Get-WinDocumentationText.ps1: -------------------------------------------------------------------------------- 1 | function Get-WinDocumentationText { 2 | [CmdletBinding()] 3 | param ( 4 | [string[]] $Text, 5 | [Object] $Forest, 6 | [string] $Domain 7 | ) 8 | 9 | $Replacement = @{ 10 | '' = $Forest.ForestName 11 | '' = $Forest.RootDSE.defaultNamingContext 12 | '' = $Domain 13 | '' = $Forest.FoundDomains.$Domain.DomainInformation.NetBIOSName 14 | '' = $Forest.FoundDomains.$Domain.DomainInformation.DistinguishedName 15 | } 16 | $Array = @() 17 | foreach ($T in $Text) { 18 | foreach ($Key in $Replacement.Keys) { 19 | if ($T -like "*$Key*") { 20 | if ($Replacement.$Key) { 21 | $T = $T.Replace($Key, $Replacement.$Key) 22 | } else { 23 | Write-Warning "Replacing $Key failed. No value available for substition" 24 | } 25 | } 26 | } 27 | $Array += $T 28 | } 29 | return $Array 30 | } -------------------------------------------------------------------------------- /Private/Main/Resolve-IgnoreTexts.ps1: -------------------------------------------------------------------------------- 1 | function Resolve-IgnoreTexts { 2 | param ( 3 | [string[]] $IgnoreText 4 | ) 5 | $Ignores = New-ArrayList 6 | foreach ($Ignore in $IgnoreText) { 7 | if ($Script:ActiveDirectory.Domains) { 8 | foreach ($Domain in $Script:ActiveDirectory.Domains) { 9 | $Text = Get-WinDocumentationText -Text $Ignore -Forest $Script:ActiveDirectory.Forest -Domain $Domain 10 | Add-ToArrayAdvanced -List $Ignores -Element $Text -SkipNull -RequireUnique 11 | } 12 | } else { 13 | $Text = Get-WinDocumentationText -Text $Ignore -Forest $Script:ActiveDirectory.Forest -Domain '' 14 | Add-ToArrayAdvanced -List $Ignores -Element $Text -SkipNull -RequireUnique 15 | } 16 | } 17 | return $Ignores 18 | } 19 | -------------------------------------------------------------------------------- /Private/Main/Search-ObjectToIgnore.ps1: -------------------------------------------------------------------------------- 1 | function Search-ObjectToIgnore { 2 | [CmdletBinding()] 3 | param( 4 | $Object, 5 | $Ignore 6 | ) 7 | #Write-Color @Script:WriteParameters -Text '[i]', ' Processing object ', $Object.DisplayName, ' for ignore list candidate' -Color Yellow, White, Red 8 | foreach ($Key in $Ignore.Keys) { 9 | if ($Key -eq 'MatchingEmptyOrNull') { 10 | foreach ($SubKey in $Ignore.$Key.Keys) { 11 | $FieldType = $SubKey 12 | $IgnoreValues = $Ignore.$Key.$SubKey 13 | foreach ($Value in $IgnoreValues) { 14 | if ($FieldType -and $Value) { 15 | if ([String]::IsNullOrWhiteSpace($Object.$FieldType)) { 16 | Write-Color @Script:WriteParameters -Text '[i]', ' Adding object ', $Object.DisplayName, ' to Ignore List because field: ', $FieldType, ' is null or empty.' -Color Yellow, White, Red, White, Green, White, Yellow, White 17 | return 18 | } 19 | } 20 | } 21 | } 22 | } 23 | if ($Key -eq 'MatchingObjects') { 24 | foreach ($SubKey in $Ignore.$Key.Keys) { 25 | $FieldType = $SubKey 26 | $IgnoreValues = $Ignore.$Key.$SubKey 27 | foreach ($Value in $IgnoreValues) { 28 | if ($FieldType -and $Value) { 29 | if ($FieldType -eq 'Mailbox') { 30 | if ($Object.$Value) { 31 | # for example $Contact.WindowsEmailAddress 32 | $User = Get-User $($Object.$Value) -ErrorAction SilentlyContinue 33 | if ($User) { 34 | Write-Color @Script:WriteParameters -Text '[i]', ' Adding object ', $Object.DisplayName, ' to Ignore List because Exchange Mailbox ', $User.DisplayName, ' already exists.' -Color Yellow, White, Red, White, Green, White, Yellow, White 35 | return 36 | } 37 | } 38 | } elseif ($FieldType -eq 'ADUser') { 39 | if ($Object.$Value) { 40 | # for example $Contact.WindowsEmailAddress 41 | $User = Get-ADUser $($Object.$Value) -ErrorAction SilentlyContinue 42 | if ($User) { 43 | Write-Color @Script:WriteParameters -Text '[i]', ' Adding object ', $Object.DisplayName, ' to Ignore List because AD User ', $User.DisplayName, ' already exists.' -Color Yellow, White, Red, White, Green, White, Yellow, White 44 | return 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | if ($Key -eq 'MatchingFields') { 53 | foreach ($SubKey in $Ignore.$Key.Keys) { 54 | $FieldType = $SubKey 55 | $IgnoreValues = $Ignore.$Key.$SubKey 56 | foreach ($Value in $IgnoreValues) { 57 | if ($FieldType -and $Value) { 58 | if ($Object.$FieldType -like $Value) { 59 | Write-Color @Script:WriteParameters -Text '[i]', ' Adding object ', $Object.DisplayName, ' to Ignore List because field: ', $FieldType, ' with Value: ', $Value, ' matched.' -Color Yellow, White, Red, White, Green, White, Yellow, White 60 | return 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | return $Object 68 | } -------------------------------------------------------------------------------- /Private/Main/Start-Configuration.ps1: -------------------------------------------------------------------------------- 1 | function Start-Configuration { 2 | param( 3 | $Configuration 4 | ) 5 | Out-ConfigurationStatus -Option 'Start' 6 | if ($Configuration.Services.OnPremises.ActiveDirectory.Use) { 7 | $CommandOutput = Connect-WinService -Type 'ActiveDirectory' ` 8 | -Credentials $Configuration.Services.OnPremises.ActiveDirectory.Credentials ` 9 | -Service $Configuration.Services.OnPremises.ActiveDirectory -Verbose:$false -Output 10 | Out-ConnectionStatus -CommandOutput $CommandOutput 11 | } 12 | if ($Configuration.Services.OnPremises.Exchange.Use) { 13 | $CommandOutput = Connect-WinService -Type 'Exchange' ` 14 | -Credentials $Configuration.Services.OnPremises.Exchange.Credentials ` 15 | -Service $Configuration.Services.OnPremises.Exchange -Verbose:$false -Output 16 | Out-ConnectionStatus -CommandOutput $CommandOutput 17 | } 18 | if ($Configuration.Services.Office365.Azure.Use) { 19 | $CommandOutput = Connect-WinService -Type 'Azure' ` 20 | -Credentials $Configuration.Services.Office365.Credentials ` 21 | -Service $Configuration.Services.Office365.Azure -Verbose:$false -Output 22 | Out-ConnectionStatus -CommandOutput $CommandOutput 23 | } 24 | if ($Configuration.Services.Office365.AzureAD.Use) { 25 | $CommandOutput = Connect-WinService -Type 'AzureAD' ` 26 | -Credentials $Configuration.Services.Office365.Credentials ` 27 | -Service $Configuration.Services.Office365.AzureAD -Verbose:$false -Output 28 | Out-ConnectionStatus -CommandOutput $CommandOutput 29 | } 30 | if ($Configuration.Services.Office365.ExchangeOnline.Use) { 31 | $CommandOutput = Connect-WinService -Type 'ExchangeOnline' ` 32 | -Credentials $Configuration.Services.Office365.Credentials ` 33 | -Service $Configuration.Services.Office365.ExchangeOnline -Verbose:$false -Output 34 | Out-ConnectionStatus -CommandOutput $CommandOutput 35 | } 36 | if ($Configuration.Services.Office365.Teams.Use) { 37 | $CommandOutput = Connect-WinService -Type 'MicrosoftTeams' ` 38 | -Credentials $Configuration.Services.Office365.Credentials ` 39 | -Service $Configuration.Services.Office365.Teams -Verbose:$false -Output 40 | Out-ConnectionStatus -CommandOutput $CommandOutput 41 | } 42 | Out-ConfigurationStatus -Option 'End' 43 | } -------------------------------------------------------------------------------- /Private/Main/Submit-ActionActiveDirectory.ps1: -------------------------------------------------------------------------------- 1 | function Submit-ActionActiveDirectory { 2 | [CmdletBinding()] 3 | param( 4 | $Object, 5 | $Action 6 | ) 7 | foreach ($User in $Object.ProcessingData.Users) { 8 | switch ( $Action.Action ) { 9 | AccountAddGroupsSpecific { 10 | $CommandOutput = Add-WinADUserGroups -User $User -Groups $Action.Value -FieldSearch 'Name' -WhatIf:$Action.WhatIf 11 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 12 | } 13 | AccountDisable { 14 | $CommandOutput = Set-WinADUserStatus -User $User -Option Disable -WhatIf:$Action.WhatIf 15 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 16 | } 17 | AccountEnable { 18 | $CommandOutput = Set-WinADUserStatus -User $User -Option Enable -WhatIf:$Action.WhatIf 19 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 20 | } 21 | AccountHideInGAL { 22 | $CommandOutput = Set-WinADUserSettingGAL -User $User -Option Hide -WhatIf:$Action.WhatIf 23 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 24 | } 25 | AccountShowInGAL { 26 | $CommandOutput = Set-WinADUserSettingGAL -User $User -Option Show -WhatIf:$Action.WhatIf 27 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 28 | } 29 | AccountRemoveGroupsAll { 30 | $CommandOutput = Remove-WinADUserGroups -User $User -All -WhatIf:$Action.WhatIf 31 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 32 | } 33 | AccountRemoveGroupsSecurity { 34 | $CommandOutput = Remove-WinADUserGroups -User $User -GroupCategory Security -WhatIf:$Action.WhatIf 35 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 36 | } 37 | AccountRemoveGroupsDistribution { 38 | $CommandOutput = Remove-WinADUserGroups -User $User -GroupCategory Distribution -WhatIf:$Action.WhatIf 39 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 40 | } 41 | AccountRemoveGroupsDomainLocal { 42 | $CommandOutput = Remove-WinADUserGroups -User $User -GroupScope DomainLocal -WhatIf:$Action.WhatIf 43 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 44 | } 45 | AccountRemoveGroupsGlobal { 46 | $CommandOutput = Remove-WinADUserGroups -User $User -GroupScope Global -WhatIf:$Action.WhatIf 47 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 48 | } 49 | AccountRemoveGroupsUniversal { 50 | $CommandOutput = Remove-WinADUserGroups -User $User -GroupScope Universal -WhatIf:$Action.WhatIf 51 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 52 | } 53 | AccountRemoveGroupsSpecific { 54 | $CommandOutput = Remove-WinADUserGroups -User $User -Groups $Action.Value -WhatIf:$Action.WhatIf 55 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 56 | } 57 | AccountRename { 58 | if ($Action.Value.Action -eq 'AddText') { 59 | $CommandOutput = Set-WinADUserFields -User $User -Option $Action.Value.Where -TextToAdd $Action.Value.Text -Fields $Action.Value.Fields -WhatIf:$Action.WhatIf 60 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 61 | } elseif ($Action.Value.Action -eq 'RemoveText') { 62 | $CommandOutput = Set-WinADUserFields -User $User -TextToRemove $Action.Value.Text -Fields $Action.Value.Fields -WhatIf:$Action.WhatIf 63 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 64 | } 65 | } 66 | AccountSnapshot { 67 | $CommandOutput = Get-WinADUserSnapshot -User $User -XmlPath $Action.Value -WhatIf:$Action.WhatIf 68 | Out-ActionStatus -CommandOutput $CommandOutput -User $User -Name $Action.Name -WhatIf:$Action.WhatIf 69 | } 70 | } 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /Private/Main/Submit-ActionAzureActiveDirectory.ps1: -------------------------------------------------------------------------------- 1 | function Submit-ActionAzureActiveDirectory { 2 | [CmdletBinding()] 3 | param( 4 | $Object, 5 | $Action 6 | ) 7 | foreach ($User in $Object.ProcessingData.Users) { 8 | switch ( $Action.Action ) { 9 | AccountAddGroupsSpecific { 10 | 11 | } 12 | AccountDisable { 13 | $CommandOutput = Set-WinAzureADUserStatus -User $User -Option Disable -WhatIf:$Action.WhatIf 14 | Out-ActionStatus -CommandOutput $CommandOutput -UserAzureAD $User -Name $Action.Name -WhatIf:$Action.WhatIf 15 | } 16 | AccountEnable { 17 | $CommandOutput = Set-WinAzureADUserStatus -User $User -Option Enable -WhatIf:$Action.WhatIf 18 | Out-ActionStatus -CommandOutput $CommandOutput -UserAzureAD $User -Name $Action.Name -WhatIf:$Action.WhatIf 19 | } 20 | AccountRemoveGroupsAll { 21 | 22 | } 23 | AccountRemoveGroupsSecurity { 24 | 25 | } 26 | AccountRemoveGroupsDistribution { 27 | 28 | } 29 | AccountRemoveGroupsSpecific { 30 | 31 | } 32 | AccountRename { 33 | 34 | } 35 | AccountSnapshot { 36 | 37 | } 38 | AddLicense { 39 | $CommandOutput = Set-WinAzureADUserLicense -User $User -Option Add -License $Action.Value -WhatIf:$Action.WhatIf 40 | Out-ActionStatus -CommandOutput $CommandOutput -UserAzureAD $User -Name $Action.Name -WhatIf:$Action.WhatIf 41 | } 42 | RemoveLicense { 43 | $CommandOutput = Set-WinAzureADUserLicense -User $User -Option Remove -License $Action.Value -WhatIf:$Action.WhatIf 44 | Out-ActionStatus -CommandOutput $CommandOutput -UserAzureAD $User -Name $Action.Name -WhatIf:$Action.WhatIf 45 | } 46 | RemoveLicenseAll { 47 | $CommandOutput = Set-WinAzureADUserLicense -User $User -Option RemoveAll -License '' -WhatIf:$Action.WhatIf 48 | Out-ActionStatus -CommandOutput $CommandOutput -UserAzureAD $User -Name $Action.Name -WhatIf:$Action.WhatIf 49 | } 50 | ReplaceLicense { 51 | $CommandOutput = Set-WinAzureADUserLicense -User $User -Option Replace -License $Action.Value -WhatIf:$Action.WhatIf 52 | Out-ActionStatus -CommandOutput $CommandOutput -UserAzureAD $User -Name $Action.Name -WhatIf:$Action.WhatIf 53 | } 54 | EnableMFA { 55 | 56 | } 57 | DisableMFA { 58 | 59 | } 60 | SetUserRole { 61 | 62 | } 63 | SetField { 64 | $CommandOutput = Set-WinAzureADUserField -User $User -Value $Action.Value -WhatIf:$Action.WhatIf 65 | Out-ActionStatus -CommandOutput $CommandOutput -UserAzureAD $User -Name $Action.Name -WhatIf:$Action.WhatIf 66 | } 67 | SynchronizeFields { 68 | 69 | } 70 | 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Private/Main/Submit-ActionExchange.ps1: -------------------------------------------------------------------------------- 1 | function Submit-ActionExchange { 2 | [CmdletBinding()] 3 | param( 4 | $Object, 5 | $Action 6 | ) 7 | foreach ($User in $Object.ProcessingData.Users) { 8 | switch ( $Action.Action ) { 9 | MailboxConvertToSharedMailbox { 10 | 11 | } 12 | MailboxEmailAddressPolicyEnable { 13 | 14 | } 15 | ContactConvertToMailContact { 16 | 17 | } 18 | MailboxRemoteEnable { 19 | 20 | } 21 | } 22 | } 23 | } 24 | 25 | function Set-WinExchangeRemoteMailbox { 26 | param( 27 | 28 | ) 29 | 30 | $RemoteRoutingAddress = '' 31 | Enable-RemoteMailbox -Identity $User.DistinguishedName -RemoteRoutingAddress $RemoteRoutingAddress 32 | } 33 | 34 | -------------------------------------------------------------------------------- /Private/Main/Submit-ConditionEmptyOrNull.ps1: -------------------------------------------------------------------------------- 1 | function Submit-ConditionEmptyOrNull { 2 | param( 3 | [Object] $Object, 4 | [Object] $Value 5 | ) 6 | $Field = "$Value" 7 | $ObjectOutput = $Object | Where-Object { $null -ne $_.$Field -and $_.$Field -ne '' } 8 | 9 | #$CountBefore = $Object.Count 10 | #$CountAfter = $ObjectOutput.Count 11 | 12 | return $ObjectOutput 13 | } -------------------------------------------------------------------------------- /Private/Main/Submit-ConditionFields.ps1: -------------------------------------------------------------------------------- 1 | function Submit-ConditionFields { 2 | [CmdletBinding()] 3 | param( 4 | [Object] $Object, 5 | [Object] $Value, 6 | [string] $Type = 'Default' 7 | ) 8 | [string] $Field = '' 9 | if ($Type -eq 'Default') { 10 | $Field = "$($Value.Field)" 11 | } elseif ($Type -eq 'OrganizationalUnit') { 12 | $Field = "$($Value.Field)" 13 | } elseif ($Type -eq 'GroupMembership') { 14 | $Field = "$($Value.Field)" 15 | } 16 | 17 | [string] $Operator = $Value.Operator 18 | [Object] $Value = $Value.Value 19 | 20 | # Negative 21 | if ($Operator -eq 'notlike') { 22 | if ($Type -eq 'OrganizationalUnit') { 23 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -notlike $Value } 24 | } elseif ($Type -eq 'GroupMembership') { 25 | return $Object | Where-Object { $_.MemberOf.$Field -notlike $Value } 26 | } else { 27 | 28 | return $Object | Where-Object { $_.$Field -notlike $Value } 29 | } 30 | } 31 | if ($Operator -eq 'notcontains') { 32 | if ($Type -eq 'OrganizationalUnit') { 33 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -notcontains $Value } 34 | } elseif ($Type -eq 'GroupMembership') { 35 | return $Object | Where-Object { $_.MemberOf.$Field -notcontains $Value } 36 | } else { 37 | return $Object | Where-Object { $_.$Field -notcontains $Value } 38 | } 39 | } 40 | if ($Operator -eq 'ne') { 41 | if ($Type -eq 'OrganizationalUnit') { 42 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -ne $Value } 43 | } elseif ($Type -eq 'GroupMembership') { 44 | return $Object | Where-Object { $_.MemberOf.$Field -ne $Value } 45 | } else { 46 | return $Object | Where-Object { $_.$Field -ne $Value } 47 | } 48 | } 49 | if ($Operator -eq 'cnotlike') { 50 | if ($Type -eq 'OrganizationalUnit') { 51 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -cnotlike $Value } 52 | } elseif ($Type -eq 'GroupMembership') { 53 | return $Object | Where-Object { $_.MemberOf.$Field -cnotlike $Value } 54 | } else { 55 | return $Object | Where-Object { $_.$Field -cnotlike $Value } 56 | } 57 | } 58 | if ($Operator -eq 'cne') { 59 | if ($Type -eq 'OrganizationalUnit') { 60 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -cne $Value } 61 | } elseif ($Type -eq 'GroupMembership') { 62 | return $Object | Where-Object { $_.MemberOf.$Field -cne $Value } 63 | } else { 64 | return $Object | Where-Object { $_.$Field -cne $Value } 65 | } 66 | } 67 | if ($Operator -eq 'cnotcontains') { 68 | if ($Type -eq 'OrganizationalUnit') { 69 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -cnotcontains $Value } 70 | } elseif ($Type -eq 'GroupMembership') { 71 | return $Object | Where-Object { $_.MemberOf.$Field -cnotcontains $Value } 72 | } else { 73 | return $Object | Where-Object { $_.$Field -cnotcontains $Value } 74 | } 75 | } 76 | 77 | # Positive 78 | if ($Operator -eq 'like') { 79 | if ($Type -eq 'OrganizationalUnit') { 80 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -like $Value } 81 | } elseif ($Type -eq 'GroupMembership') { 82 | return $Object | Where-Object { $_.MemberOf.$Field -like $Value } 83 | } else { 84 | return $Object | Where-Object { $_.$Field -like $Value } 85 | } 86 | } 87 | if ($Operator -eq 'contains') { 88 | if ($Type -eq 'OrganizationalUnit') { 89 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -contains $Value } 90 | } elseif ($Type -eq 'GroupMembership') { 91 | return $Object | Where-Object { $_.MemberOf.$Field -contains $Value } 92 | } else { 93 | return $Object | Where-Object { $_.$Field -contains $Value } 94 | } 95 | } 96 | if ($Operator -eq 'eq') { 97 | if ($Type -eq 'OrganizationalUnit') { 98 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -eq $Value } 99 | } elseif ($Type -eq 'GroupMembership') { 100 | return $Object | Where-Object { $_.MemberOf.$Field -eq $Value } 101 | } else { 102 | return $Object | Where-Object { $_.$Field -eq $Value } 103 | } 104 | } 105 | if ($Operator -eq 'clike') { 106 | if ($Type -eq 'OrganizationalUnit') { 107 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -clike $Value } 108 | } elseif ($Type -eq 'GroupMembership') { 109 | return $Object | Where-Object { $_.MemberOf.$Field -clike $Value } 110 | } else { 111 | return $Object | Where-Object { $_.$Field -clike $Value } 112 | } 113 | } 114 | if ($Operator -eq 'ceq') { 115 | if ($Type -eq 'OrganizationalUnit') { 116 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -ceq $Value } 117 | } elseif ($Type -eq 'GroupMembership') { 118 | return $Object | Where-Object { $_.MemberOf.$Field -ceq $Value } 119 | } else { 120 | return $Object | Where-Object { $_.$Field -ceq $Value } 121 | } 122 | } 123 | if ($Operator -eq 'ccontains') { 124 | if ($Type -eq 'OrganizationalUnit') { 125 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -ccontains $Value } 126 | } elseif ($Type -eq 'GroupMembership') { 127 | return $Object | Where-Object { $_.MemberOf.$Field -ccontains $Value } 128 | } else { 129 | return $Object | Where-Object { $_.$Field -ccontains $Value } 130 | } 131 | } 132 | 133 | 134 | if ($Operator -eq 'gt') { 135 | if ($Type -eq 'OrganizationalUnit') { 136 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -gt $Value } 137 | } elseif ($Type -eq 'GroupMembership') { 138 | return $Object | Where-Object { $_.MemberOf.$Field -gt $Value } 139 | } else { 140 | return $Object | Where-Object { $_.$Field -gt $Value } 141 | } 142 | } 143 | 144 | if ($Operator -eq 'ge') { 145 | if ($Type -eq 'OrganizationalUnit') { 146 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -ge $Value } 147 | } elseif ($Type -eq 'GroupMembership') { 148 | return $Object | Where-Object { $_.MemberOf.$Field -ge $Value } 149 | } else { 150 | return $Object | Where-Object { $_.$Field -ge $Value } 151 | } 152 | } 153 | 154 | if ($Operator -eq 'lt') { 155 | if ($Type -eq 'OrganizationalUnit') { 156 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -lt $Value } 157 | } elseif ($Type -eq 'GroupMembership') { 158 | return $Object | Where-Object { $_.MemberOf.$Field -lt $Value } 159 | } else { 160 | return $Object | Where-Object { $_.$Field -lt $Value } 161 | } 162 | } 163 | 164 | if ($Operator -eq 'le') { 165 | if ($Type -eq 'OrganizationalUnit') { 166 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -le $Value } 167 | } elseif ($Type -eq 'GroupMembership') { 168 | return $Object | Where-Object { $_.MemberOf.$Field -le $Value } 169 | } else { 170 | return $Object | Where-Object { $_.$Field -le $Value } 171 | } 172 | } 173 | 174 | if ($Operator -eq 'match') { 175 | if ($Type -eq 'OrganizationalUnit') { 176 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -match $Value } 177 | } elseif ($Type -eq 'GroupMembership') { 178 | return $Object | Where-Object { $_.MemberOf.$Field -match $Value } 179 | } else { 180 | return $Object | Where-Object { $_.$Field -match $Value } 181 | } 182 | } 183 | 184 | if ($Operator -eq 'match') { 185 | if ($Type -eq 'OrganizationalUnit') { 186 | return $Object | Where-Object { $_.OrganizationalUnit.$Field -notmatch $Value } 187 | } elseif ($Type -eq 'GroupMembership') { 188 | return $Object | Where-Object { $_.MemberOf.$Field -notmatch $Value } 189 | } else { 190 | return $Object | Where-Object { $_.$Field -match $Value } 191 | } 192 | } 193 | } -------------------------------------------------------------------------------- /Private/Main/Submit-ConditionOrganizationalUnit.ps1: -------------------------------------------------------------------------------- 1 | function Submit-ConditionOrganizationalUnit { 2 | param( 3 | 4 | ) 5 | } -------------------------------------------------------------------------------- /Private/Output/Out-ActionStatus.ps1: -------------------------------------------------------------------------------- 1 | function Out-ActionStatus { 2 | [CmdletBinding(DefaultParameterSetName = 'ActiveDirectory')] 3 | param( 4 | [parameter(Mandatory = $false)][Array] $CommandOutput, 5 | [parameter(Mandatory = $true, ParameterSetName = "ActiveDirectory")][Object] $User, 6 | [parameter(Mandatory = $true, ParameterSetName = "AzureActiveDirectory")][Object] $UserAzureAD, # [Microsoft.Online.Administration.User] $UserAzureAD, 7 | [parameter(Mandatory = $true)][string] $Name, 8 | [switch] $WhatIf 9 | ) 10 | switch ($PSCmdlet.ParameterSetName) { 11 | ActiveDirectory { 12 | $UserInformation = $User.DistinguishedName 13 | } 14 | AzureActiveDirectory { 15 | $UserInformation = $UserAzureAD.UserPrincipalName 16 | } 17 | } 18 | if ($WhatIf) { 19 | $WriteSuccess = @{ 20 | Text = '[+] ', 'WhatIf: ', 'Execution ', $Name, ' on account ', $UserInformation, ' done.' 21 | Color = [System.ConsoleColor]::Cyan, [System.ConsoleColor]::DarkMagenta, [System.ConsoleColor]::White, [System.ConsoleColor]::Cyan, 22 | [System.ConsoleColor]::White, [System.ConsoleColor]::Cyan, [System.ConsoleColor]::White, [System.ConsoleColor]::Cyan, 23 | [System.ConsoleColor]::White, [System.ConsoleColor]::Cyan 24 | StartSpaces = 8 25 | } 26 | $WriteSkip = @{ 27 | Text = '[+] ', 'WhatIf: ', 'Execution ', $Name, ' on account ', $UserInformation, ' done.' 28 | Color = 'Yellow', [System.ConsoleColor]::DarkMagenta, 'White', 'Yellow', 'White', 'Yellow', 'White', 'Yellow', 'White', 'Yellow' 29 | StartSpaces = 8 30 | } 31 | 32 | $WriteStatusSuccess = @{ 33 | StartSpaces = 12 34 | Color = 'Green', [System.ConsoleColor]::DarkMagenta, 'White', 'Green', 'White', 'Green' 35 | } 36 | $WriteStatusFail = @{ 37 | StartSpaces = 12 38 | Color = 'Red', [System.ConsoleColor]::DarkMagenta, 'White', 'Red', 'White', 'Red' 39 | } 40 | 41 | } else { 42 | $WriteSuccess = @{ 43 | Text = '[+] ', 'Execution ', $Name, ' on account ', $UserInformation, ' done.' 44 | Color = 'Cyan', 'White', 'Cyan', 'White', 'Cyan', 'White', 'Cyan', 'White', 'Cyan' 45 | StartSpaces = 8 46 | } 47 | $WriteSkip = @{ 48 | Text = '[+] ', 'Execution ', $Name, ' on account ', $UserInformation, ' done.' 49 | Color = 'Yellow', 'White', 'Yellow', 'White', 'Yellow', 'White', 'Yellow', 'White', 'Yellow' 50 | StartSpaces = 8 51 | } 52 | 53 | $WriteStatusSuccess = @{ 54 | StartSpaces = 12 55 | Color = 'Green', 'White', 'Green', 'White', 'Green' 56 | } 57 | $WriteStatusFail = @{ 58 | StartSpaces = 12 59 | Color = 'Red', 'White', 'Red', 'White', 'Red' 60 | } 61 | } 62 | 63 | if ($CommandOutput) { 64 | Write-Color @WriteSuccess 65 | foreach ($Output in $CommandOutput) { 66 | if ($Output.Status) { 67 | if ($WhatIf) { 68 | Write-Color @WriteStatusSuccess -Text '[+] ', 'WhatIf: ', 'Successfully processed ', $Output.Output, ' Extended information: ', $Output.Extended 69 | } else { 70 | Write-Color @WriteStatusSuccess -Text '[+] ', 'Successfully processed ', $Output.Output, ' Extended information: ', $Output.Extended 71 | } 72 | } else { 73 | if ($WhatIf) { 74 | Write-Color @WriteStatusFail -Text '[-] ', 'Whatif: ', 'Skipped ', $Output.Output, ' Extended information: ', $Output.Extended 75 | } else { 76 | Write-Color @WriteStatusFail -Text '[-] ', 'Skipped ', $Output.Output, ' Extended information: ', $Output.Extended 77 | } 78 | } 79 | } 80 | } else { 81 | Write-Color @WriteSkip 82 | } 83 | } -------------------------------------------------------------------------------- /Private/Output/Out-ConfigurationStatus.ps1: -------------------------------------------------------------------------------- 1 | function Out-ConfigurationStatus { 2 | [CmdletBinding()] 3 | param( 4 | [parameter(Mandatory = $false)][Array] $CommandOutput, 5 | [string] $Option = 'Start' 6 | ) 7 | 8 | $WriteStatusSuccess = @{ 9 | StartSpaces = 4 10 | Color = 'Green', 'White', 'Green', 'White', 'Green', 'White', 'Green' 11 | } 12 | $WriteStatusEnd = @{ 13 | StartSpaces = 4 14 | Color = 'Green', 'White', 'Green', 'White', 'Green', 'White', 'Green' 15 | } 16 | $WriteStatusFail = @{ 17 | StartSpaces = 4 18 | Color = 'Red', 'White', 'Red', 'White', 'Red', 'White', 'Red' 19 | } 20 | if ($Option -eq 'Start') { 21 | Write-Color @WriteStatusSuccess -Text '[+] ', 'Running ', 'Configuration' 22 | } elseif ($Option -eq 'End') { 23 | Write-Color @WriteStatusEnd -Text '[+] ', 'Ending ', 'Configuration' 24 | } else { 25 | Write-Color @WriteStatusFail -Text '[-] ', 'Failed ', 'Configuration' 26 | } 27 | } -------------------------------------------------------------------------------- /Private/Output/Out-ConnectionStatus.ps1: -------------------------------------------------------------------------------- 1 | function Out-ConnectionStatus { 2 | [CmdletBinding()] 3 | param( 4 | [parameter(Mandatory = $false)][Array] $CommandOutput 5 | ) 6 | 7 | $WriteStatusSuccess = @{ 8 | StartSpaces = 8 9 | Color = 'Green', 'White', 'Green', 'White', 'Green', 'White', 'Green' 10 | } 11 | $WriteStatusFail = @{ 12 | StartSpaces = 8 13 | Color = 'Red', 'White', 'Red', 'White', 'Red', 'White', 'Red' 14 | } 15 | if ($CommandOutput) { 16 | foreach ($Output in $CommandOutput) { 17 | if ($Output.Status) { 18 | Write-Color @WriteStatusSuccess -Text '[+] ', 'Running ', 'Connection', ' for ', $Output.Output, ' Extended information: ', $Output.Extended 19 | } else { 20 | Write-Color @WriteStatusFail -Text '[-] ', 'Running ', 'Connection', ' for ', $Output.Output, ' Extended information: ', $Output.Extended 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Private/Output/Out-ServiceStatus.ps1: -------------------------------------------------------------------------------- 1 | function Out-ServiceStatus { 2 | param( 3 | [string] $Name 4 | ) 5 | $WriteInformation = @{ 6 | Text = '[i]', ' Running ', 'Service', ' for ', $Name 7 | Color = [ConsoleColor]::Green, [ConsoleColor]::White, [ConsoleColor]::Green, [ConsoleColor]::White, [ConsoleColor]::Green 8 | StartSpaces = 0 9 | } 10 | Write-Color @WriteInformation 11 | } -------------------------------------------------------------------------------- /Private/Output/Out-TriggerStatus.ps1: -------------------------------------------------------------------------------- 1 | function Out-TriggerStatus { 2 | param( 3 | $Trigger 4 | ) 5 | $WriteInformation = @{ 6 | Text = '[+]', ' Running Trigger', ' for ', $Trigger.Name 7 | Color = [ConsoleColor]::Green, [ConsoleColor]::White, [ConsoleColor]::White, [ConsoleColor]::Green 8 | StartSpaces = 4 9 | } 10 | Write-Color @WriteInformation 11 | } -------------------------------------------------------------------------------- /Private/Parameters/Script.Debug.ps1: -------------------------------------------------------------------------------- 1 | $Script:Debug = @{ 2 | Verbose = $false 3 | } -------------------------------------------------------------------------------- /Private/Parameters/Script.GroupProperties.ps1: -------------------------------------------------------------------------------- 1 | $Script:GroupProperties = @( 2 | 'Name', 3 | 'DisplayName', 4 | 'GroupCategory', 5 | 'GroupScope', 6 | 'SID', 7 | 'AdminCount', 8 | 'Members', 9 | 'MemberOf', 10 | 'ManagedBy', 11 | 'Created', 12 | 'Modified', 13 | 'SamAccountName', 14 | 'CanonicalName' 15 | ) -------------------------------------------------------------------------------- /Private/Parameters/Script.UserProperties.ps1: -------------------------------------------------------------------------------- 1 | $Script:UserProperties = @( 2 | 'Name', 3 | 'UserPrincipalName', 4 | 'SamAccountName', 5 | 'Enabled', 6 | 'PasswordLastSet', 7 | 'PasswordExpired', 8 | 'PasswordNeverExpires', 9 | 'PasswordNotRequired', 10 | 'EmailAddress', 11 | 'DisplayName', 12 | 'GivenName', 13 | 'Surname', 14 | 'Manager', 15 | 'AccountExpirationDate', 16 | 'AccountLockoutTime', 17 | 'AllowReversiblePasswordEncryption', 18 | 'BadLogonCount', 19 | 'CannotChangePassword', 20 | 'CanonicalName', 21 | 'Description', 22 | 'DistinguishedName', 23 | 'EmployeeID', 24 | 'EmployeeNumber', 25 | 'LastBadPasswordAttempt', 26 | 'LastLogonDate', 27 | 'Created', 28 | 'Modified', 29 | 'PrimaryGroup', 30 | 'MemberOf', 31 | 'msDS-UserPasswordExpiryTimeComputed', 32 | 'msExchHideFromAddressLists' 33 | ) -------------------------------------------------------------------------------- /Private/Parameters/Script.WriteParameters.ps1: -------------------------------------------------------------------------------- 1 | # Default value / overwritten if set in config 2 | $Script:WriteParameters = @{ 3 | ShowTime = $true 4 | LogFile = "" 5 | TimeFormat = "yyyy-MM-dd HH:mm:ss" 6 | } -------------------------------------------------------------------------------- /Public/Configuration/New-PSAutomatorConfiguration.ps1: -------------------------------------------------------------------------------- 1 | function New-PSAutomatorConfiguration { 2 | [CmdletBinding()] 3 | param( 4 | [Object] $Configuration, 5 | $Path 6 | ) 7 | if ($Configuration) { 8 | $Configuration | Export-Clixml -Path $Path -Encoding UTF8 9 | } 10 | } -------------------------------------------------------------------------------- /Public/Main/Action.ps1: -------------------------------------------------------------------------------- 1 | Function Action { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] $Object, 5 | [parameter(Mandatory = $false)] [string] $Name, 6 | [parameter(Mandatory = $false, ParameterSetName = "ActiveDirectory")][PSAutomator.ActionAD] $ActiveDirectory, 7 | [parameter(Mandatory = $false, ParameterSetName = "AzureActiveDirectory")][PSAutomator.ActionAzureAD] $AzureActiveDirectory, 8 | [parameter(Mandatory = $false, ParameterSetName = "Exchange")][PSAutomator.ActionExchange] $Exchange, 9 | [parameter(Mandatory = $false)] [Object] $Value, 10 | [parameter(Mandatory = $false)] [switch] $WhatIf 11 | ) 12 | Begin {} 13 | Process { 14 | if ($Object -eq $null) { 15 | Write-Warning "Action can't be used out of order. Terminating!" 16 | Exit 17 | } 18 | $Action = @{ 19 | Name = $Name 20 | Value = $Value 21 | Type = $PSCmdlet.ParameterSetName 22 | WhatIf = $WhatIf 23 | } 24 | switch ($PSCmdlet.ParameterSetName) { 25 | ActiveDirectory { 26 | $Action.Action = $ActiveDirectory 27 | } 28 | AzureActiveDirectory { 29 | $Action.Action = $AzureActiveDirectory 30 | } 31 | Exchange { 32 | $Action.Action = $Exchange 33 | } 34 | } 35 | 36 | # Add prepared data to Object 37 | $Object.Actions += $Action 38 | } 39 | End { 40 | return $Object 41 | } 42 | } -------------------------------------------------------------------------------- /Public/Main/Condition.ps1: -------------------------------------------------------------------------------- 1 | function Condition { 2 | [CmdletBinding()] 3 | [alias('Ignore')] 4 | param( 5 | [Parameter(ValueFromPipeline = $true, Mandatory = $false, Position = 0)] $Object, 6 | [string] $Name, 7 | [alias('Ignore')][PSAutomator.Condition] $Condition, 8 | [Object] $Value 9 | ) 10 | Begin {} 11 | Process { 12 | if ($Object -eq $null) { 13 | Write-Warning "Condition can't be used out of order. Terminating!" 14 | Exit 15 | } 16 | $Object.Conditions += @{ 17 | Name = if ($Name -eq '') { 'No name given' } else { $Name } 18 | Condition = $Condition 19 | Value = $Value 20 | } 21 | } 22 | End { 23 | return $Object 24 | } 25 | } -------------------------------------------------------------------------------- /Public/Main/Connect.ps1: -------------------------------------------------------------------------------- 1 | function Connect { 2 | [CmdletBinding()] 3 | param ( 4 | [PSAutomator.Connect] $Service, 5 | [string] $UserName, 6 | [string] $Password, 7 | [switch] $AsSecure, 8 | [switch] $FromFile 9 | ) 10 | } -------------------------------------------------------------------------------- /Public/Main/Service.ps1: -------------------------------------------------------------------------------- 1 | Function Service { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(Mandatory = $true, Position = 0)][string] $Name, 5 | [string] $Status, 6 | [Alias('Tags')][string[]] $Tag = @(), 7 | [string] $ConfigurationPath, 8 | [Parameter(Position = 1)][ValidateNotNull()][ScriptBlock] $ServiceData = $(Throw "No test script block is provided. (Have you put the open curly brace on the next line?)") 9 | ) 10 | Begin { 11 | $TimeRun = Start-TimeLog 12 | } 13 | Process { 14 | if ($Status -eq 'Disable') { return } 15 | Out-ServiceStatus -Name $Name 16 | Get-PSAutomatorConfiguration -ConfigurationPath $ConfigurationPath 17 | 18 | $Object = Invoke-Command -ScriptBlock $ServiceData 19 | $Final = Complete-WorkFlow -Object $Object 20 | } 21 | End { 22 | $TimeEnd = $TimeRun | Stop-TimeLog -Option 'Array' 23 | 24 | $WriteInformation = @{ 25 | Text = '[i]', ' Ending Service for ', $Name, ' - Time to Execute: ', $TimeEnd 26 | Color = [ConsoleColor]::Green, [ConsoleColor]::White, [ConsoleColor]::Green, [ConsoleColor]::Green, [ConsoleColor]::White 27 | LinesAfter = 1 28 | StartSpaces = 0 29 | } 30 | Write-Color @WriteInformation 31 | 32 | # Finish Service 33 | $Script:Configuration = $null 34 | return #$Final 35 | } 36 | } -------------------------------------------------------------------------------- /Public/Main/Trigger.ps1: -------------------------------------------------------------------------------- 1 | Function Trigger { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] $Object, 5 | [parameter(Mandatory = $false)] [string] $Name, 6 | [parameter(Mandatory = $false, ParameterSetName = "User")][PSAutomator.TriggerUserAD] $User, 7 | [parameter(Mandatory = $false, ParameterSetName = "UserAzureAD")][PSAutomator.TriggerUserAzureAD] $UserAzureAD, 8 | [parameter(Mandatory = $false, ParameterSetName = "Group")][PSAutomator.TriggerGroup] $Group, 9 | [parameter(Mandatory = $false, ParameterSetName = "Computer")][PSAutomator.TriggerComputer] $Computer, 10 | [parameter(Mandatory = $false)] [Object] $Value 11 | ) 12 | Begin { 13 | 14 | } 15 | Process { 16 | if ($null -eq $Object) { 17 | # if object is null it's the first one 18 | $Object = [ordered] @{ 19 | Triggers = @() 20 | Conditions = @() 21 | Ignores = @() 22 | Actions = @() 23 | ProcessingData = @{ 24 | Users = @() 25 | } 26 | } 27 | } 28 | $Trigger += @{ 29 | Name = $Name 30 | Value = $Value 31 | Type = $PSCmdlet.ParameterSetName 32 | } 33 | switch ($PSCmdlet.ParameterSetName) { 34 | User { 35 | $Trigger.Trigger = $User 36 | } 37 | UserAzureAD { 38 | $Trigger.Trigger = $UserAzureAD 39 | } 40 | Group { 41 | $Trigger.Trigger = $Group 42 | } 43 | Computer { 44 | $Trigger.Trigger = $Computer 45 | } 46 | 47 | } 48 | $Object.Triggers += $Trigger 49 | } 50 | End { 51 | return $Object 52 | } 53 | } -------------------------------------------------------------------------------- /Publish/Manage-Module.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $Configuration = @{ 4 | Information = @{ 5 | ModuleName = 'PSAutomator' 6 | DirectoryProjects = 'C:\Support\GitHub' 7 | Manifest = @{ 8 | # Minimum version of the Windows PowerShell engine required by this module 9 | PowerShellVersion = '5.1' 10 | 11 | ModuleVersion = '0.0.3' 12 | 13 | # ID used to uniquely identify this module 14 | GUID = '1be9e392-28cb-4ac6-aba7-b924defbf9da' 15 | # Author of this module 16 | Author = 'Przemyslaw Klys' 17 | # Company or vendor of this module 18 | CompanyName = 'Evotec' 19 | # Copyright statement for this module 20 | Copyright = '(c) 2018 Przemyslaw Klys. All rights reserved.' 21 | # Description of the functionality provided by this module 22 | Description = "PowerShell Module is new approach to onboarding, offboarding and business as usual processes running in companies infrastructure. Usually each company has different rules, different approaches on how processes should look like and this module takes an easy approach that's similar to what you can find in services like IFTTT or Microsoft Flow" 23 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 24 | # Tags applied to this module. These help with module discovery in online galleries. 25 | Tags = @('ActiveDirectory', 'Offboarding', 'Onboarding', 'Windows') 26 | 27 | IconUri = 'https://evotec.xyz/wp-content/uploads/2018/10/PSAutomator.png' 28 | 29 | ProjectUri = 'https://github.com/EvotecIT/PSAutomator' 30 | 31 | RequiredModules = @('PSSharedGoods', 'PSWriteColor') 32 | 33 | } 34 | } 35 | Options = @{ 36 | Merge = @{ 37 | Sort = 'None' 38 | FormatCodePSM1 = @{ 39 | Enabled = $true 40 | RemoveComments = $true 41 | FormatterSettings = @{ 42 | IncludeRules = @( 43 | 'PSPlaceOpenBrace', 44 | 'PSPlaceCloseBrace', 45 | 'PSUseConsistentWhitespace', 46 | 'PSUseConsistentIndentation', 47 | 'PSAlignAssignmentStatement', 48 | 'PSUseCorrectCasing' 49 | ) 50 | 51 | Rules = @{ 52 | PSPlaceOpenBrace = @{ 53 | Enable = $true 54 | OnSameLine = $true 55 | NewLineAfter = $true 56 | IgnoreOneLineBlock = $true 57 | } 58 | 59 | PSPlaceCloseBrace = @{ 60 | Enable = $true 61 | NewLineAfter = $false 62 | IgnoreOneLineBlock = $true 63 | NoEmptyLineBefore = $false 64 | } 65 | 66 | PSUseConsistentIndentation = @{ 67 | Enable = $true 68 | Kind = 'space' 69 | PipelineIndentation = 'IncreaseIndentationAfterEveryPipeline' 70 | IndentationSize = 4 71 | } 72 | 73 | PSUseConsistentWhitespace = @{ 74 | Enable = $true 75 | CheckInnerBrace = $true 76 | CheckOpenBrace = $true 77 | CheckOpenParen = $true 78 | CheckOperator = $true 79 | CheckPipe = $true 80 | CheckSeparator = $true 81 | } 82 | 83 | PSAlignAssignmentStatement = @{ 84 | Enable = $true 85 | CheckHashtable = $true 86 | } 87 | 88 | PSUseCorrectCasing = @{ 89 | Enable = $true 90 | } 91 | } 92 | } 93 | } 94 | FormatCodePSD1 = @{ 95 | Enabled = $true 96 | RemoveComments = $false 97 | } 98 | Integrate = @{ 99 | ApprovedModules = 'PSWriteColor', 'Connectimo', 'PSUnifi', 'PSWebToolbox', 'PSMyPassword' 100 | } 101 | } 102 | Standard = @{ 103 | FormatCodePSM1 = @{ 104 | 105 | } 106 | FormatCodePSD1 = @{ 107 | Enabled = $true 108 | #RemoveComments = $true 109 | } 110 | } 111 | PowerShellGallery = @{ 112 | ApiKey = 'C:\Support\Important\PowerShellGalleryAPI.txt' 113 | FromFile = $true 114 | } 115 | GitHub = @{ 116 | ApiKey = 'C:\Support\Important\GithubAPI.txt' 117 | FromFile = $true 118 | UserName = 'EvotecIT' 119 | #RepositoryName = 'PSPublishModule' # not required, uses project name 120 | } 121 | Documentation = @{ 122 | Path = 'Docs' 123 | PathReadme = 'Docs\Readme.md' 124 | } 125 | } 126 | Steps = @{ 127 | BuildModule = @{ # requires Enable to be on to process all of that 128 | Enable = $true 129 | DeleteBefore = $false 130 | Merge = $true 131 | MergeMissing = $true 132 | SignMerged = $true 133 | Releases = $true 134 | ReleasesUnpacked = $false 135 | RefreshPSD1Only = $false 136 | } 137 | BuildDocumentation = $false 138 | ImportModules = @{ 139 | Self = $true 140 | RequiredModules = $false 141 | Verbose = $false 142 | } 143 | PublishModule = @{ # requires Enable to be on to process all of that 144 | Enabled = $false 145 | Prerelease = '' 146 | RequireForce = $false 147 | GitHub = $false 148 | } 149 | } 150 | } 151 | 152 | New-PrepareModule -Configuration $Configuration -Verbose -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # PSAutomator - PowerShell Module 2 | 3 | Overview of this module is available at: https://evotec.xyz/hub/scripts/psautomator-powershell-module/ 4 | 5 | ### Description 6 | 7 | This PowerShell Module is new approach to onboarding, offboarding and business as usual processes running in companies infrastructure. Usually each company has different rules, different approaches on how processes should look like and this module takes an easy approach that's similar to what you can find in services like **IFTTT** or **Microsoft Flow**. Those services work in known schema such as Services, Triggers, Ingredients and Applets. For this PowerShell Module I've taken similar approach which is described below. 8 | 9 | While it's encouraged to keep correct order Service, Trigger, Ignore, Condition, Action it actually only requires Service, Trigger to be in correct order. 10 | 11 | - [x] **Service** – is kind of a wrapper for other blocks above. It has also ability to load configuration from file. Currently loading file doesn't do anything. 12 | - [x] **Trigger** – is first block in Service. Before an Action can be executed it needs a **Trigger**. **Trigger** can be membership in Group, Organizational Unit etc 13 | - [ ] User Based Triggers 14 | - [ ] Always, 15 | - [x] OrganizationalUnit, 16 | - [x] GroupMembership, 17 | - [ ] Filter 18 | - [x] **Ignore** – But Trigger can also have things that need to be ignored. For example lack of email address field. 19 | - [ ] User Based Ignore 20 | - [x] MatchingEmptyOrNull, 21 | - [ ] MatchingObjects, 22 | - [ ] MatchingFields 23 | - [x] **Condition** – It can also be conditioned for example Last User Modification Date should be more then 30 days. 24 | - [ ] User Based Conditions 25 | - [ ] RequireGroupMembership, 26 | - [ ] RequireLastModified 27 | - [x] **Action** – are essentially Tasks that are about to be executed. This can be adding a user to a group, disabling user etc. This is also final step to close Service. 28 | - [ ] User Based Actions 29 | - [x] AccountAddGroupsSpecific 30 | - [x] AccountDisable 31 | - [x] AccountEnable 32 | - [x] AccountHideInGAL 33 | - [x] AccountShowInGAL 34 | - [x] AccountRemoveGroupsAll 35 | - [x] AccountRemoveGroupsSecurity 36 | - [x] AccountRemoveGroupsDistribution 37 | - [x] AccountRemoveGroupsSpecific 38 | - [x] AccountRemoveGroupsDomainLocal 39 | - [x] AccountRemoveGroupsGlobal 40 | - [x] AccountRemoveGroupsUniversal 41 | - [ ] AccountRename, 42 | - [x] AccountSnapshot 43 | 44 | Keep in mind that following is true for Service: 45 | - [x] Can hold only 1 trigger 46 | - [x] Can have multiple Ignore blocks 47 | - [x] Can have multiple Condition blocks 48 | - [x] Can have multiple Action blocks 49 | 50 | **This is proof-of-concept. Heavy work in progres... Please take your time and leave feedback!** 51 | 52 | ## DO NOT USE IN **PRODUCTION** YET - UNLESS YOU LIKE FIRES! 53 | 54 | ### Sample offboarding 55 | 56 | ![image](https://evotec.xyz/wp-content/uploads/2018/10/img_5bce250f1fe42.png) 57 | 58 | ```powershell 59 | Clear-Host 60 | Import-Module PSAutomator -Force #-Verbose 61 | Import-Module PSSharedGoods -Force 62 | Service -Name 'Active Directory Offboarding' -ConfigurationPath 'C:\Support\GitHub\PSAutomator\Examples\MyConfiguration.xml' { 63 | Trigger -Name 'OU Offboarded Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 64 | Condition -Name 'No conditions' | 65 | Ignore -Name 'Ignore Windows Email Address if Empty or null' -Ignore MatchingEmptyOrNull -Value EmailAddress | 66 | Action -Name 'Make User Snapshot' -ActiveDirectory AccountSnapshot -Value 'C:\Users\pklys\Desktop\MyExport' | 67 | Action -Name 'Disable AD Account' -ActiveDirectory AccountDisable | 68 | Action -Name 'Hide account in GAL' -ActiveDirectory AccountHideInGAL | 69 | Action -Name 'Remove all security groups' -ActiveDirectory AccountRemoveGroupsSecurity | 70 | Action -Name 'Rename Account' -ActiveDirectory AccountRename -Value @{ Action = 'AddText'; Where = 'After'; Text = ' (offboarded)'; } 71 | } 72 | ``` 73 | 74 | ### Sample onboarding 75 | 76 | ![image](https://evotec.xyz/wp-content/uploads/2018/10/img_5bce267af35e6.png) 77 | 78 | ```powershell 79 | Clear-Host 80 | Import-Module PSAutomator -Force #-Verbose 81 | Import-Module PSSharedGoods -Force 82 | Service -Name 'Active Directory Enable Users in OU' { 83 | Trigger -Name 'Find Offboarded Users' -User OrganizationalUnit -Value 'OU=Users-Offboarded,OU=Production,DC=ad,DC=evotec,DC=xyz' | 84 | Ignore | 85 | Action -Name 'Enable Offboarded Users' -ActiveDirectory AccountEnable | 86 | Action -Name 'Add to group GDS-TestGroup5' -ActiveDirectory AccountAddGroupsSpecific -Value 'GDS-TestGroup5' | 87 | Action -Name 'Add to group GDS-TestGroup4' -ActiveDirectory AccountAddGroupsSpecific -Value 'GDS-TestGroup4' | 88 | Action -Name 'Remove Offboarded Tag' -ActiveDirectory AccountRename -Value @{ Action = 'RemoveText'; Fields = 'DisplayName', 'Name' ; Text = ' (offboarded)'; } 89 | } 90 | ``` 91 | 92 | ## DO NOT USE IN **PRODUCTION** YET - UNLESS YOU LIKE FIRES! --------------------------------------------------------------------------------