UGDSBPSU.psm1
#Region './Public/Get-Chromebook.ps1' 0 <# .DESCRIPTION This cmdlet will use GAM installed on your system to query Google for chromebooks based on your query and fields .PARAMETER gamLocation The location that GAM files are stored .PARAMETER query The query that you want to use for returning your devices .PARAMETER fields What fields you want it to return .EXAMPLE Retrieve a list of devices with a specific query Get-Chromebook -gamLocation <GAMPATH> -query $query #> function Get-Chromebook{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$gamLocation, [Parameter(Mandatory = $false)]$query, [Parameter(Mandatory = $false)]$fields ) # Setup the regex that we are using to attempt to properly parse the gam output $RegexOptions = [System.Text.RegularExpressions.RegexOptions] $csvSplit = '(,)(?=(?:[^"]|"[^"]*")*$)' # Create a blank list to store the data $devices = [System.Collections.Generic.List[PSCustomObject]]@() # Query Gam with the query/fields passed ($chromebooks = Invoke-Expression -Command "$($gamLocation) print cros query $($query) nolists fields $($fields) 2>&1") | Out-Null # Loop through the lines of the return. Ignore the first line as that should be the headers $startHere = $false for($x = 1; $x -lt $chromebooks.length; $x++) { if($startHere -eq $false){ if($chromebooks[$x] -match "^deviceId,serialNumber.*$"){ $startHere = $true } continue } # Split the line $device = [regex]::Split($chromebooks[$x], $csvSplit, $RegexOptions::ExplicitCapture).replace('"','') # Set the wanIP to null, if we can set it then we do, otherwise it stays null $wanIP = $null if($null -ne $device[8]){ try{$wanIP = ($device[8] | ConvertFrom-JSON).wanIpAddress} catch{} } # Populate custom object for list $obj = [PSCustomObject]@{ "Name" = $device[1] "network" = $wanIP "mac-address" = $device[6] "lastSync" = $device[2] "chromebook-model" = $device[4] "chromebook-os" = $device[5] "location" = $device[7] } $devices.Add($obj) | Out-Null } # Return list return $devices } #EndRegion './Public/Get-Chromebook.ps1' 62 #Region './Public/Get-GoogleOU.ps1' 0 <# .DESCRIPTION This cmdlet will use GAM installed on your system to query Google for the list of your OUs. .PARAMETER gamLocation The location that GAM files are stored .EXAMPLE Retrieve a list of OUs Get-GoogleOU -gamLocation <PATH TO GAM> #> function Get-GoogleOU{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$gamLocation ) # The command that we want to run with GAM $command = "print orgs" # Invoke GAM with the path and command ($ouRaw = Invoke-Expression -Command "$($gamLocation) $($command) 2>&1") | Out-Null # Create a list object to store the results $ouList = [System.Collections.Generic.List[PSCustomObject]]@() # Go through the results of the gam call $skipRows = $true for($i = 1; $i -lt $ouRaw.Count; $i++){ # Skip rows until we hit the header row. This will remove some of the externious GAM output if($skipRows -eq $true){ if($ouRaw[$i] -eq "orgUnitPath,orgUnitId,name,parentOrgUnitId"){ $skipRows = $false } continue } # Split results by comma $ou = $ouRaw[$i] -split "," # Create a object for each line to store in the list $obj = [PSCustomObject]@{ 'orgUnitPath' = $ou[0] 'orgUnitId' = $ou[1] 'name' = $ou[2] 'parentOrgUnitId' = $ou[3] } $ouList.add($obj) | Out-Null } # return list of OUs return $ouList } #EndRegion './Public/Get-GoogleOU.ps1' 46 #Region './Public/Get-KeyVaultSecret.ps1' 0 <# .DESCRIPTION This cmdlet is used to connect to a keyvault as the machine identity of the Azure Machine it is running under .PARAMETER vaultName The name of the vault that we want to check .PARAMETER secretName The name of the secret we want to recover .EXAMPLE Check a secret out of a specific vault Get-KeyVaultSecret -vaultName <VAULT> -secretName <SECRET> #> function Get-KeyVaultSecret{ [CmdletBinding()] [OutputType([System.String])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$vaultName, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$secretName ) # The URI for the vault that we want to access $keyVaultURI = "https://$($vaultName).vault.azure.net/secrets/$($secretName)?api-version=2016-10-01" # Using the identity of the virtual machine account running the script $response = Invoke-RestMethod -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net' -Method GET -Headers @{Metadata="true"} # What the vault token is $keyVaultToken = $response.access_token try{ # Get the relevant secret and return it $secret = Invoke-RestMethod -Uri $keyVaultURI -Method GET -Headers @{Authorization="Bearer $KeyVaultToken"} return $secret.Value | ConvertFrom-Json } # Error handling possible expected errors catch{ if(($Error[0] -match "The remote name could not be resolved")){ $message = "Error: Attempting to connect to Azure Key vault URI $($keyVaultURI)`n$($_)" } elseif(($Error[0] -match "Unauthorized")){ $message = "Error: No authorization to Azure Key Vault URI $($keyVaultURI)`n$($_)" } elseif(($Error[0] -match "SecretNotFound")){ $message = "Error: The secret $($secretName) is not found in Azure Key Vault URI $($keyVaultURI)`n$($_)" } else{ $message = "Error: Unknown error connection to Azure Key vault URI $($keyVaultURI)`n$($_)" } Write-EventLog -LogName "Application" -Source "PowerShell Universal Scripts" -EntryType "Warning" -EventId 1001 -Message $message return $message } } #EndRegion './Public/Get-KeyVaultSecret.ps1' 48 #Region './Public/Get-Values.ps1' 0 <# .DESCRIPTION This cmdlet is designed to help PSU scripts for display of values .PARAMETER fields What fields to display #> function Get-Values(){ param( [Parameter(Mandatory)][string[]]$fields, [Parameter(Mandatory)][PSCustomObject]$item ) $value = "" # Loop through the array to take not of what values were selected, and then return that value. foreach($i in $fields){ if($item.$i){ if($i.Contains('-1')){$value += $i.Substring(0,$i.Length-2) + ","} else{$value += $i + ","} } } return $value.Replace("-"," ") } #EndRegion './Public/Get-Values.ps1' 22 #Region './Public/Get-YesNo.ps1' 0 <# .DESCRIPTION This cmdlet is designed to help PSU scripts for display of yes/no .PARAMETER fields What fields to display #> function Get-YesNo(){ [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true)][string[]]$fields, [Parameter(Mandatory)][PSCustomObject]$item ) # Loop through values that are passed, and if exist, return yes, otherwise return No foreach($i in $fields){ if($item.$i){return "Yes"} } return "No" } #EndRegion './Public/Get-YesNo.ps1' 20 #Region './Public/New-RandomString.ps1' 0 <# .DESCRIPTION This cmdet will generate a random character string based on inputs passed to it. .PARAMETER length The number of characters you want the random string to contain. .PARAMETER characters The list of characters that you want it to use to generate the random string .EXAMPLE New-RandomString -length 10 -characters 'abcdefghiklmnoprstuvwxyzABCDEFGHKLMNOPRSTUVWXYZ1234567890!@#$%^&*' Will Generate a random string of 10 characters in length with the characters in abcdefghiklmnoprstuvwxyzABCDEFGHKLMNOPRSTUVWXYZ1234567890!@#$%^&* #> function New-RandomString{ [CmdletBinding()] [OutputType([System.String])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][int]$length, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$characters ) # Generate a random string based on the length and characters passed $randomString = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length} $private:ofs = "" return [string]$characters[$randomString] } #EndRegion './Public/New-RandomString.ps1' 24 #Region './Public/Test-AllowedGroupMember.ps1' 0 <# .DESCRIPTION This cmdlet is used to check to see if a specific user belongs to a group that is passed .PARAMETER groupList Array of the groups to check .PARAMETER domain If active directory, what domain to check. If you use this, it ignores any of the Az parameters .PARAMETER AzAppRegistration The client id of the azure app registration working under .PARAMETER AzTenant The directory id for the Azure AD tenant .PARAMETER AzSecret The client secret used to connect to MS Graph .EXAMPLE Check for a specific user in active directory Test-AllowedGroupMember -userPrincipalName <UPN> -groupList @("GROUPNAME") -domain <DOMAIN> Check for a specific user in Azure AD group Test-AllowedGroupMember -userPrincipalName <UPN> -groupList @("GROUPNAME") -AzTenant $AzTenant -AzAppRegistration $AzAppRegistration -AzSecret $Secret #> function Test-AllowedGroupMember{ [CmdletBinding()] [OutputType([System.Boolean])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$userPrincipalName, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][Object[]]$groupList, [Parameter()][string]$domain, [Parameter()][string]$AzAppRegistration, [Parameter()][string]$AzTenant, [Parameter()][pscredential]$AzSecret ) # Nested function to be able to recurse through groups in Azure AD since Get-MGGroupMembers does not have this function currently function getNestedMembers{ param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$groupId, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$userPrincipalName ) # Set found to false $results = $false # Get memberes of the group that was passed $members = Get-MgGroupMember -All -GroupId $groupId # If the username is found return true if($userPrincipalName -in $members.AdditionalProperties.userPrincipalName){ return $true } # If not found, check the list for other nested groups else{ $groups = $members | where-object {$_.AdditionalProperties.'@odata.type' -eq "#microsoft.graph.group"} # Loop through those groups those nested function foreach($group in $groups){ $results = getNestedMembers -groupId $groupId -userPrincipalName $userPrincipalName if($results -eq $true){ # if the results returned are true, return true. return $true } } } } # If set to query Azure AD Groups connect to MS Graph if($AzAppRegistration){ # Connect to MS Graph $msalToken = Get-MsalToken -clientID $AzAppRegistration -clientSecret $AzSecret.Password -tenantID $AzTenant Connect-MgGraph -AccessToken $msalToken.AccessToken | Out-Null } foreach($group in $groupList){ try{ if($domain){ # Get all the members and nested members of the group in Active Directory $members = Get-ADGroupMember -Recursive -Server $domain -Identity $group -ErrorAction SilentlyContinue | where-object {$_.objectClass -eq 'User'} | Get-ADUser | select-object UserPrincipalName # Check to see if the list contains the expected UPN and if return true if($members.UserPrincipalName -contains $userPrincipalName){ return $true } } else{ # Get the group from Azure AD $groups = Get-MGgroup -Filter "DisplayName eq '$($group)'" # Loop through if there are multiple groups with the same name foreach($group in $groups){ # Get the results of the function to recurse through the groups $results = getNestedMembers -groupId $group.id -userPrincipalName $userPrincipalName # Return true if correct if($results -eq $true){ return $true } } } } catch{ throw "An error occured while processing group $($group) : $($Error[0])" } } return $false } #EndRegion './Public/Test-AllowedGroupMember.ps1' 95 #Region './Public/Test-SamAccountName.ps1' 0 <# .DESCRIPTION This cmdlet is designed to check Active Directory for a valid samAccountName when creating/changing user. .PARAMETER samAccountName The account name we want to test for .PARAMETER server The server that we want to test against .EXAMPLE Check for a specific samAccountName Test-SamAccountName -samAccountName <NAME> -server <SERVER> #> function Test-SamAccountName{ [CmdletBinding()] [OutputType([System.String],[System.Boolean])] param( [Parameter(Mandatory = $true)]$samAccountName, [Parameter(Mandatory = $true)]$server ) # Default Addition at the end of the name if it exists. $postFix = 2 # Loop through to try to find a valid samAccountName or fail if loops too many times do{ try{ # Check to see if the user already exists. Get-ADUser -Identity $samAccountName -Server $server | Out-Null # If it does exist, then add the postfix if($postFix -eq 2){ $samAccountName = "$($samAccountName)$($postFix)" } # If postfix is greater than default, then remove it (as we max at 9) to add the new postfix else{ $samAccountName = "$($samAccountName.substring(0,$samAccountName.length -1))$($postFix)" } } # If the account doesn't exist, return the samAccountName as good catch [Microsoft.ActiveDirectory.Management.ADIdentityResolutionException] { return $samAccountName } catch { throw $Error[0] } $postFix++ }while($postFix -lt 10) # Return false if we couldn't find a valid samAccountName we could use return $false } #EndRegion './Public/Test-SamAccountName.ps1' 47 |