CT-PS-UserMgmt.psm1
<# -------------------------------------------------------------------------------------------------- This is a module used internally by CT for managing users on client networks. Any changes to this module need to be published using the powershell script "Build_CT_Module.ps1" -------------------------------------------------------------------------------------------------- HOW TO IMPORT INTO SCRIPT: -------------------------------------------------------------------------------------------------- This module requires the CT-PS-Standard module imported first in the script. This module should be imported using the commands below (do not copy the asterix's, just whats between). This will import this module AND initialise the script with all the standard features required by scripts, including all the log files for each transaction ***************** Install-Module -Name "CT-PS-UserMgmt" -Force -AllowClobber -Scope CurrentUser -Verbose:$VerbosePreference -ErrorAction Stop Import-Module -Name "CT-PS-UserMgmt" -Force -Verbose:$VerbosePreference -ErrorAction Stop ***************** -------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------- LOG FILES -------------------------------------------------------------------------------------------------- There are four log files initialised by this module that can be used for output. You can write to each of these logs accordingly. $UserMgmt_Log: This is the log for each action performed within this module. -------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------- #> # -------------------------------------------------------------------------------------------------- # The following commands will run when the module is imported # Define an object type called "O365skuids" # this object uses the SKUIDS from https://learn.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference # A script is written to grab this csv and output it to notepad so it can be updated here easily. This needs to be run periodically. # NB for Lexi: Look at building this into a regex replace during the module publish script in the future try{ #<!-- SKUID START --> enum O365skuids { ADV_COMMS ADV_COMMS_TEAMS_ADVCOMMS CDSAICAPACITY CDSAICAPACITY_CDSAICAPACITY CDSAICAPACITY_EXCHANGE_S_FOUNDATION SPZA_IW SPZA_IW_SPZA SPZA_IW_EXCHANGE_S_FOUNDATION MCOMEETADV WORKPLACE_ANALYTICS_WORKPLACE_ANALYTICS WORKPLACE_ANALYTICS_WORKPLACE_ANALYTICS_INSIGHTS_BACKEND WORKPLACE_ANALYTICS_WORKPLACE_ANALYTICS_INSIGHTS_USER } #<!-- SKUID END --> # Now create a global variable with these skuids $global:O365skuidlist = [Enum]::GetNames([O365skuids]).Trim() $SelfUpdateScriptBlock = { $SKUIDLink = "https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv" $env:CTPSUserMgmtSelfUpdate = "True" $skuidCSV = Invoke-WebRequest -Uri $SKUIDLink -UseBasicParsing # -OutFile "skuids.csv" $SkuidList = ConvertFrom-Csv $skuidCSV $skuids = @() $TotalItems = $SkuidList.Count $CurrentItem = 0 $PercentComplete = 0 $selfmodule = (Get-Module -ListAvailable -Name CT-PS-UserMgmt)[0] $FilePath = "$($selfmodule.ModuleBase)\$($selfmodule.RootModule)" Write-Host "Updating $($FilePath)" foreach($skuidID in $SkuidList) { Write-Progress -Activity "Compiling O365 Skuids" -Status "$PercentComplete% Complete:" -PercentComplete $PercentComplete $skuidIDName = $skuidID.String_Id.trim() $skuidIDName = $skuidIDName.replace(" ","_") $skuidIDName = $skuidIDName.replace("(","") $skuidIDName = $skuidIDName.replace(")","") $skuidIDName = $skuidIDName.replace("/","") $skuidIDName = $skuidIDName.replace("+","") $skuidIDName = $skuidIDName.replace("`t","") $skuidSPN = "$($skuidID.String_Id.trim())_$($skuidID.Service_Plan_Name.trim())" $skuidSPN = $skuidSPN.replace(" ","_") $skuidSPN = $skuidSPN.replace("(","") $skuidSPN = $skuidSPN.replace(")","") $skuidSPN = $skuidSPN.replace("/","") $skuidSPN = $skuidSPN.replace("+","") $skuidSPN = $skuidSPN.replace("`t","") if (!($skuids | where-object -FilterScript {$_ -in $skuidIDName})) { $skuids += $skuidIDName } if (!($skuids | where-object -FilterScript {$_ -in $skuidSPN})) { $skuids += $skuidSPN } $CurrentItem++ $PercentComplete = [int](($CurrentItem / $TotalItems) * 100) } $skuidreplacement = "#<!-- SKUID START -->`n enum O365skuids`n {`n" foreach($skuid in $skuids){ $skuidreplacement = $skuidreplacement + " $($skuid)`n" } $skuidreplacement = $skuidreplacement + " }`n #<!-- SKUID END -->`n" $allTheText = [System.Io.File]::ReadAllText($FilePath) $FindText = $allTheText | select-string '(?smi)#<!-- SKUID START -->[^!]+<!-- SKUID END -->' | %{ $_.Matches } | %{ $_.Value } $replacedContent = $allTheText.Replace($FindText,$skuidreplacement) $replacedContent | Set-Content -Path $FilePath Write-Host "Updated $($FilePath)" #Import-Module -Name "CT-PS-UserMgmt" -Scope Local -Verbose:$VerbosePreference -ErrorAction Stop } # This self-updates this module with the latest SKUIDS and then re-imports itself ready for use. $CTPSUserMgmtSelfUpdate = $env:CTPSUserMgmtSelfUpdate If($CTPSUserMgmtSelfUpdate -ne "True") { #$powershellPath = "$env:windir\system32\windowspowershell\v1.0\powershell.exe" #$process = Write-Output "Self-updating module" Invoke-Command -ScriptBlock $SelfUpdateScriptBlock Import-Module -Name "CT-PS-UserMgmt" -Scope Local -Verbose:$VerbosePreference -ErrorAction Stop #Start-Process $powershellPath -NoNewWindow -ArgumentList ("-ExecutionPolicy Bypass -noninteractive -noprofile " + $SelfUpdateScriptBlock) #Update-O365SelfCode -SKUIDLink "https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv" #exit } Write-Output "Module self-updated" $env:CTPSUserMgmtSelfUpdate = "" $global:UserMgmt_Log = "$CT_DEST\logs\$($Script_Name)\$($DateStamp)_UserMgmt.log" # The output #Define ADUser PSObject Type class ADUser { [ValidateNotNullOrEmpty()][string] $FirstName [ValidateNotNullOrEmpty()][string] $LastName [ValidateNotNull()][string] $DisplayName = "" [AllowNull()][string] $Title [AllowNull()][string] $Department [AllowNull()][string] $BusinessUnit [AllowNull()][string] $HomeDriveLocation [AllowNull()][string] $HomeDriveLetter [ValidateNotNullOrEmpty()][array] $MembershipGroups [ValidateLength(2,2)][string] $DefaultAreaCode = "03" [ValidateNotNullOrEmpty()][int] $ExtentionLength [AllowNull()][string] $DirectDial [AllowNull()][string] $Manager [ValidateNotNullOrEmpty()][O365skuids] $Default365LicenseSKU [AllowNull()][O365skuids] $Additional365LicenseSKU [ValidateNotNullOrEmpty()][string] $TicketNumber [AllowNull()][string] $EmailAddress [ValidateNotNullOrEmpty()][string] $UserPrincipalName [AllowNull()][string] $CompanyName [AllowNull()][string] $WWWHomePage [AllowNull()][string] $OfficePhone [AllowNull()][string] $StreetAddress [AllowNull()][string] $City [AllowNull()][string] $State [AllowNull()][string] $PostalCode [AllowNull()][string] $Country [AllowNull()][string] $Office [AllowNull()][string] $PasswordPlainText [ValidateNotNullOrEmpty()][bool] $ChangePasswordAtLogon = $true [ValidateNotNullOrEmpty()][string] $OUPath [AllowNull()][bool] $MFA [AllowNull()][bool] $Hybrid [AllowNull()][string] $AccountGUID } } catch { $line = $_.InvocationInfo.ScriptLineNumber Write-Error "($($line)): $($_)" -ErrorAction Stop Throw } # This ends the script block that run on module import # -------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------- # This function takes an array list of O365 SKUIDs and checks the tenancy to see whether there are enough available, # reporting back a hashtable of licence counts for each array entry (SKUID, count) function Search-AvailableOffice365Licenses { [CmdletBinding(SupportsShouldProcess=$true)] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName,HelpMessage="Please provide the credentials of an Office 365/Azure AD admin account as PSCredential variable type")] [pscredential[]] $AADCredentials, [Parameter(Mandatory,ValueFromPipelineByPropertyName,HelpMessage="Connection URI for Office 365 / Azure AD")] [string] $ConnectionURI, # Array of options to present [Parameter(Mandatory,ValueFromPipelineByPropertyName,HelpMessage="SKUIDs to search for as an array")] [array] $ProductSKUID ) Process{ $AvaliableSKUs = Get-MsolAccountSKU -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) | Where-Object {$_.skuPartNumber -eq $ProductSKU} foreach($item in $AvaliableSKUs) { $avaliable = $item.ActiveUnits $consumed = $item.ConsumedUnits if($avaliable -ge $consumed) { $count = $avaliable - $consumed return $count } elseif($avaliable -eq $consumed) { return 0 } else { return -1 } } } } # -------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------- # This is used to create a new user account in Active Directory # This function must be called from a script running on the AD server of the organisation Function New-UserAccount { [CmdletBinding(SupportsShouldProcess=$true)] Param( [Parameter(Mandatory,ValueFromPipelineByPropertyName,HelpMessage="Please provide the credentials of a domain admin account as PSCredential variable type")] [pscredential[]] $ADCredentials, [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Main Contact Name")] [string] $MainContact = "Samantha", [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Main Contact Email")] [string] $MainEmail = "<sjordan@ct.com.au>", [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Any emails you want BCC'ed to the onboarding confirmation")] [string] $BCCs = "<sjordan@ct.com.au>", [Parameter(ValueFromPipelineByPropertyName,HelpMessage="ADFS Server name.")] [string] $ADFSServer, [Parameter(Mandatory,ValueFromPipelineByPropertyName,HelpMessage="Domain Controller name")] [string] $DomainController = $env:COMPUTERNAME, [Parameter(HelpMessage="MFA in use?")] [switch] $MFA, [Parameter(HelpMessage="Hybrid Exchange in use?")] [switch] $Hybrid, [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Home Drive Location (if any)")] [string] $HomeDriveLocation, [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Home Drive Letter (if any)")] [string] $HomeDriveLetter, [Parameter(Mandatory,ValueFromPipelineByPropertyName,HelpMessage="AD Groups to add user to")] [array] $DefaultGroups, [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Default area code for direct dial numbers (this is incase an 8 digit number is entered)")] [string][ValidateLength(2,2)] $DefaultAreaCode = "03", [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Extension length (how many numbers for a users extension)")] [int] $ExtentionLength, [Parameter(Mandatory,ValueFromPipelineByPropertyName,HelpMessage="Office 365 Licence SKU")] [ArgumentCompletions('SPB', 'ENTERPRISEPACK','DESKLESSPACK','DESKLESSPACK_GOV','DESKLESSPACK_YAMMER','DESKLESSWOFFPACK','DESKLESSWOFFPACK_GOV','EDUPACK_FACULTY','EDUPACK_STUDENT','ENTERPRISEPACK_FACULTY','ENTERPRISEPACK_FACULTY','ENTERPRISEPACK_STUDENT','ENTERPRISEPACKLRG','ENTERPRISEPACKWITHOUTPROPLUS','ENTERPRISEPACKWSCAL','ENTERPRISEPREMIUM','ENTERPRISEPREMIUM_FACULTY','ENTERPRISEPREMIUM_NOPSTNCONF','ENTERPRISEPREMIUM_OFFICESUBSCRIPTION','ENTERPRISEPREMIUM_STUDENT','ENTERPRISEPREMIUM_STUDENT','ENTERPRISEWITHSCAL_FACULTY','ENTERPRISEWITHSCAL_FACULTY','ENTERPRISEWITHSCAL_STUDENT','LITEPACK','LITEPACK_P2','M365_F1','M365_G3_GOV','M365EDU_A1','M365EDU_A3_FACULTY','M365EDU_A3_STUDENT','M365EDU_A3_STUDENT','M365EDU_A5_FACULTY','M365EDU_A5_FACULTY','M365EDU_A5_FACULTY','MIDSIZEPACK','O365_BUSINESS_ESSENTIALS','O365_BUSINESS_PREMIUM','OFFICE_BASIC','OFFICE_BUSINESS','SMB_BUSINESS_ESSENTIALS','SMB_BUSINESS_PREMIUM','SPE_E3','SPE_E3','SPE_E5','SPE_F1','STANDARD_B_PILOT')] [string] $Default365LicenseSKU, [Parameter()] [hashtable] $PostData, # The hashtable that needs to be posted to the API [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Stores notes to email through on ticket.")] $TicketNotes, # The hashtable that needs to be posted to the API [Parameter()] [int] $Retry = 2 # Attempts a retry of the post if it fails ) Process{ #Do stuff } } # -------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------- # This is used to self-update the O365 class in this module # A different URL can be passed at any stage Function Update-O365SelfCode { [CmdletBinding(SupportsShouldProcess=$true)] Param( [Parameter(ValueFromPipelineByPropertyName,HelpMessage="Please provide the URL to grab CSV file from")] [ValidateNotNullOrEmpty()][string[]] $SKUIDLink = "https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv" ) Process{ Start-Process (Get-Process -Id $pid).Path -ArgumentList "-File '$PSScriptRoot\update_skuids.ps1' -NonInteractive" -NoNewWindow } } # -------------------------------------------------------------------------------------------------- |