UGDSB.PS.psm1
#Region '.\Public\Add-GraphGroupMember.ps1' 0 function Add-GraphGroupMember{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$groupId, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string[]]$ids ) # Confirm we have a valid graph token if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Get Graph Headers for Call $headers = Get-GraphHeader try{ $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() $batches = [System.Collections.Generic.List[PSCustomObject]]@() for($i = 1; $i -le $ids.Count; ++$i){ $obj = [PSCustomObject]@{ "id" = $i "headers" = @{ "Content-type" = "application/json" } "method" = "POST" "url" = "/groups/$($groupId)/members/`$ref" "body" = @{ "@odata.id" = "https://graph.microsoft.com/beta/directoryObjects/$($ids[$i-1])" } } $batchObj.Add($obj) | Out-Null if($($i % 20) -eq 0){ $batches.Add($batchObj) | Out-Null $batchObj = $null $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() } } $batches.Add($batchObj) | Out-Null foreach($batch in $batches){ $json = [PSCustomObject]@{ "requests" = $batch } | ConvertTo-JSON -Depth 5 $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json } } catch{ throw "Unable to add members. $($_.Exception.Message)" } } #EndRegion '.\Public\Add-GraphGroupMember.ps1' 48 #Region '.\Public\Add-GraphIntuneAppAddToESP.ps1' 0 function Add-GraphIntuneAppAddToESP{ [CmdletBinding()] param( [Parameter(Mandatory = $true,ParameterSetName = 'id')][ValidateNotNullOrEmpty()][string]$id, [Parameter(Mandatory = $true, ParameterSetName = 'displayName')][ValidateNotNullOrEmpty()][string]$displayName, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid ) # Body for JSON if($id){ $currentData = Get-GraphIntuneEnrollmentStatusPage -id $id } elseif($displayName){ $currentData = Get-GraphIntuneEnrollmentStatusPage -displayName $displayName } # Endpoint $endpoint = "deviceManagement/deviceEnrollmentConfigurations/$($currentData.id)" # Add Application to the ESP $currentData.selectedMobileAppIds = @("$($currentData.selectedMobileAppIds -join ','),$($applicationid)") -split "," $params = @{ "@odata.type" = "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration" id = $currentData.id displayName = $currentData.displayName description = $currentData.description showInstallationProgress = $currentData.showInstallationProgress blockDeviceSetupRetryByUser = $currentData.blockDeviceSetupRetryByUser allowDeviceResetOnInstallFailure = $currentData.allowDeviceResetOnInstallFailure allowLogCollectionOnInstallFailure = $currentData.allowLogCollectionOnInstallFailure customErrorMessage = $currentData.customErrorMessage installProgressTimeoutInMinutes = $currentData.installProgressTimeoutInMinutes allowDeviceUseOnInstallFailure = $currentData.allowDeviceUseOnInstallFailure selectedMobileAppIds = $currentData.selectedMobileAppIds trackInstallProgressForAutopilotOnly = $currentData.trackInstallProgressForAutopilotOnly disableUserStatusTrackingAfterFirstUser = $currentData.disableUserStatusTrackingAfterFirstUser roleScopeTagIds = $currentData.roleScopeTagIds allowNonBlockingAppInstallation = $currentData.allowNonBlockingAppInstallation installQualityUpdates = $currentData.installQualityUpdates } try{ $uri = "https://graph.microsoft.com/beta/$($endpoint)" $headers = Get-GraphHeader Invoke-RestMethod -Method Patch -Uri $uri -Headers $headers -Body $($params | ConvertTo-Json -Depth 10) -StatusCodeVariable statusCode } catch{ $_ } } #EndRegion '.\Public\Add-GraphIntuneAppAddToESP.ps1' 47 #Region '.\Public\Add-GraphIntuneAppAssignment.ps1' 0 function Add-GraphIntuneAppAssignment{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid, [Parameter(Mandatory = $true)][ValidateSet("available","required","uninstall")][string]$intent, [Parameter(Mandatory = $false)][string[]]$groups, [Parameter(Mandatory = $false)][Object[]]$filters = $null, [Parameter(Mandatory = $false)][switch]$exclude, [Parameter(Mandatory = $false)][bool]$foreground = $false, [Parameter(Mandatory = $false)][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # Default format for assignment body $assignment = [PSCustomObject]@{ "@odata.type" = "#microsoft.graph.mobileAppAssignment" "intent" = $intent "target" = $null "settings" = $null } foreach($group in $groups){ # Set Filter details $filterId = $null $filterType = "none" if($null -ne $filters.$group){ $assignmentFilters = Get-GraphIntuneFilters $filterId = ($assignmentFilters | Where-Object {$_.DisplayName -eq $filters.$group.filterName}).id $filterType = $filters.$group.filterType } $target = [PSCustomObject]@{ "deviceAndAppManagementAssignmentFilterId" = $filterId "deviceAndAppManagementAssignmentFilterType" = $filterType } # Targeting Values switch($group.ToLower()){ "all users" { $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.allLicensedUsersAssignmentTarget" } "all devices" { $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.allDevicesAssignmentTarget" } default { if($exclude){ $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.exclusionGroupAssignmentTarget" } else{ $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.groupAssignmentTarget" } try{ $groupdetails = Get-GraphGroup -groupName $group $target | Add-Member -MemberType "NoteProperty" -Name "groupId" -Value $groupdetails.id } catch{ throw "Unable to get ID of the group selected. $($_.Exception.Message)" } } } $assignment.target = $target # Settings Values if(!$exclude){ $settings = [PSCustomObject]@{ "@odata.type" = "#microsoft.graph.win32LobAppAssignmentSettings" } if($foreground){ $settings | Add-Member -MemberType "NoteProperty" -Name "deliveryOptimizationPriority" -Value "foreground" } $assignment.settings = $settings } try{ $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)/assignments" $headers = Get-GraphHeader Invoke-RestMethod -Method post -Uri $endpoint -Headers $headers -Body $($assignment | ConvertTo-Json -Depth 10) -StatusCodeVariable statusCode | Out-Null } catch{ if(([REGEX]::Match($((($_ | ConvertFrom-Json).error.message | ConvertFrom-JSON).Message),"The MobileApp Assignment already exists")).Success){ continue } else{ throw $($_.Exception.Message) } } } } #EndRegion '.\Public\Add-GraphIntuneAppAssignment.ps1' 82 #Region '.\Public\Add-TopdeskAssetAssignment.ps1' 0 <# .DESCRIPTION This cmdlet is designed to add an location assignment to an asset .PARAMETER assetID The unid of the asset we want to update .PARAMETER locationID The location id that we want to add to asset .EXAMPLE #> function Add-TopdeskAssetAssignment{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$assetID, [Parameter(Mandatory = $true)][string]$locationID ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } $body = @{ "assetIds" = @( $assetID ) "branchId" = $locationID "linkToId" = $locationID "linkType" = "branch" } $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/assetmgmt/assets/assignments" try{ $results = Invoke-RestMethod -Method PUT -Uri $uri -Headers $global:topdeskAccessToken -body ($body | ConvertTo-Json) -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } return $results } #EndRegion '.\Public\Add-TopdeskAssetAssignment.ps1' 38 #Region '.\Public\Add-TopdeskIncidentAttachment.ps1' 0 function Add-TopdeskIncidentAttachment{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$filepath, [Parameter()][bool]$invisibleForCaller = $false ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } $uri = "https://ugdsb-test.topdesk.net/tas/api/incidents/id/$($id)/attachments" # Information on file $item = Get-Item -Path $filepath # Get content of file $FileContent = Get-Content $filepath # Get bytes of file $fileContentInBytes = [System.Text.Encoding]::UTF8.GetBytes($FileContent) # Get base 64 of file $fileContentEncoded = [System.Convert]::ToBase64String($fileContentInBytes) # Build body for upload $body = "--BOUNDARY Content-Disposition: form-data; name=`"file`"; filename=`"$($item.Name)`" Content-Type: application/plain;charset=utf-8 Content-Transfer-Encoding: base64 $($fileContentEncoded) --BOUNDARY--" try{ $header = $global:topdeskAccessToken.Clone() $header."Content-Type" = "multipart/form-data; boundary=BOUNDARY" Invoke-RestMethod -Method POST -Uri $uri -Headers $header -body $body -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } } #EndRegion '.\Public\Add-TopdeskIncidentAttachment.ps1' 38 #Region '.\Public\Connect-Meraki.ps1' 0 <# .DESCRIPTION This cmdlet is designed to convert and store header information for meraki api .PARAMETER credential The credential to connect to the API endpoints .PARAMETER organizationId Your meraki organization ID #> function Connect-Meraki{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][SecureString]$credential, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$organizationId, [Parameter()][ValidateNotNullOrEmpty()][string]$URI = "https://api.meraki.com/api/v1/" ) # This sets the global variables that are used to connect to the topdesk API $global:merakiHeader = @{ "X-Cisco-Meraki-API-Key" = ConvertFrom-SecureString $credential -AsPlainTex "Content-Type" = "application/json" } # This sets a variable for the orgId $global:merakiOrgId = $organizationId # This sets a variable for the orgId $global:merakiApiURI = $URI } #EndRegion '.\Public\Connect-Meraki.ps1' 26 #Region '.\Public\Connect-Topdesk.ps1' 0 <# .DESCRIPTION This cmdlet is designed to convert and store header information for topdesk api .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test #> function Connect-Topdesk{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][pscredential]$credential, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$environment ) # This sets the global variables that are used to connect to the topdesk API $global:topdeskAccessToken = @{ "Authorization" = "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($credential.username):$($credential.GetNetworkCredential().password)")))" "Content-Type" = "application/json" } # This sets a variable for the enviorment $global:topdeskEnvironment = $environment } #EndRegion '.\Public\Connect-Topdesk.ps1' 23 #Region '.\Public\Convert-EntraObjIDtoSid.ps1' 0 <# .DESCRIPTION This cmdlet will convert a Azure AD Object ID TO Sid .PARAMETER ObjectId Azure AD Object ID .EXAMPLE Convert AzADObject to Sid Convert-EntraObjIDtoSid -objectId <ID> #> function Convert-EntraObjIDtoSid{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$ObjectId ) $bytes = [Guid]::Parse($ObjectId).ToByteArray() $array = New-Object 'UInt32[]' 4 [Buffer]::BlockCopy($bytes, 0, $array, 0, 16) $sid = "S-1-12-1-$array".Replace(' ', '-') return $sid } #EndRegion '.\Public\Convert-EntraObjIDtoSid.ps1' 21 #Region '.\Public\Convert-SidtoEntraObjID.ps1' 0 <# .DESCRIPTION This cmdlet will convert a SID to an Azure AD Object ID .PARAMETER sid SID of object .EXAMPLE Convert Sid to Object ID Convert-SidtoEntraObjID -sid <SID> #> function Convert-SidtoEntraObjID{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$sid ) $text = $sid.Replace('S-1-12-1-', '') $array = [UInt32[]]$text.Split('-') $bytes = New-Object 'Byte[]' 16 [Buffer]::BlockCopy($array, 0, $bytes, 0, 16) [Guid]$guid = $bytes return $guid } #EndRegion '.\Public\Convert-SidtoEntraObjID.ps1' 22 #Region '.\Public\Copy-GraphIntuneAppAssignments.ps1' 0 function Copy-GraphIntuneAppAssignments{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$copyapplicationid ) # Get the Assignments that we will be copying $assignments = Get-GraphIntuneAppAssignment -applicationid $copyapplicationid # Loop through the assignments foreach($assignment in $assignments){ $assignment = [PSCustomObject]@{ "@odata.type" = "#microsoft.graph.mobileAppAssignment" "intent" = $assignment.intent "target" = $assignment.target "settings" = $assignment.settings } try{ $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)/assignments" $headers = Get-GraphHeader Invoke-RestMethod -Method post -Uri $endpoint -Headers $headers -Body $($assignment | ConvertTo-Json -Depth 10) -StatusCodeVariable statusCode | Out-Null } catch{ if(([REGEX]::Match($((($_ | ConvertFrom-Json).error.message | ConvertFrom-JSON).Message),"The MobileApp Assignment already exists")).Success){ continue } else{ throw $($_.Exception.Message) } } } } #EndRegion '.\Public\Copy-GraphIntuneAppAssignments.ps1' 32 #Region '.\Public\Disable-Chromebook.ps1' 0 function Disable-Chromebook{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$deviceID ) # Ensure that they have a access token if(-not $global:googleAccessToken){ throw "Please ensure that you have called Get-GoogleAccessToken cmdlet" } # Confirm we have a valid access token if(-not $(Test-GoogleAccessToken)){ Get-GoogleAccessToken -json $global:googleJSON -customerId $global:googleCustomerId } # Generate URI for REST API call $uri = "https://admin.googleapis.com/admin/directory/v1/customer/$($global:googleCustomerId)/devices/chromeos/$($deviceID)/action" # REST API Call to Get Orginzation Lists $headers = @{ authorization = "Bearer $($Global:googleAccessToken)" "content-type" = "application/json" } $body = @{ "action" = "disable" } $result = Invoke-RestMethod -Method "POST" -URI $uri -Headers $headers -Body ($body | ConvertTo-Json) -StatusCodeVariable statusCode Write-Verbose "Status Result: $($statusCode)" } #EndRegion '.\Public\Disable-Chromebook.ps1' 28 #Region '.\Public\Enable-Chromebook.ps1' 0 function Enable-Chromebook{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$deviceID ) # Ensure that they have a access token if(-not $global:googleAccessToken){ throw "Please ensure that you have called Get-GoogleAccessToken cmdlet" } # Confirm we have a valid access token if(-not $(Test-GoogleAccessToken)){ Get-GoogleAccessToken -json $global:googleJSON -customerId $global:googleCustomerId } # Generate URI for REST API call $uri = "https://admin.googleapis.com/admin/directory/v1/customer/$($global:googleCustomerId)/devices/chromeos/$($deviceID)/action" # REST API Call to Get Orginzation Lists $headers = @{ authorization = "Bearer $($Global:googleAccessToken)" "content-type" = "application/json" } $body = @{ "action" = "reenable" } $result = Invoke-RestMethod -Method "POST" -URI $uri -Headers $headers -Body ($body | ConvertTo-Json) -StatusCodeVariable statusCode Write-Verbose "Status Result: $($statusCode)" } #EndRegion '.\Public\Enable-Chromebook.ps1' 28 #Region '.\Public\Get-AlertFactoryTicketDetails.ps1' 0 <# .DESCRIPTION This cmdlet is designed to parse out data from emails for Alert Factory #> function Get-AlertFactoryTicketDetails{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$details, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$emails ) # Generate blank hashtable for ticket $ticketDetails = @{} foreach($obj in $details.PSObject.Properties){ if($null -ne $obj.value.type){ if($null -ne $obj.value.attribute){ switch($obj.value.attribute){ "createdDateTime" { $content = $emails[0].createdDateTime } "receivedDateTime" { $content = $emails[0].receivedDateTime } "sentDateTime" { $content = $emails[0].sentDateTime } "subject" { $content = $emails[0].subject } "bodyPreview"{ $content = $emails[0].bodyPreview } "body" { $content = $emails[0].body.content } "sender" { $content = $emails[0].sender.emailAddress.address } "from" { $content = $emails[0].from.emailAddress.address } } } else{ $content = $obj.value.value } switch($obj.value.type){ "source" { $ticketDetails.Add($obj.Name,$content) | Out-Null } "string" { $ticketDetails.Add($obj.Name,$obj.value.value) | Out-Null } "regex" { $match = [Regex]::Match($content,$obj.value.value) $val = $null if($match.Success){ $val = $match.Value } $ticketDetails.Add($obj.Name,$val) | Out-Null } } } } return $ticketDetails } #EndRegion '.\Public\Get-AlertFactoryTicketDetails.ps1' 66 #Region '.\Public\Get-ChromeDevices.ps1' 0 <# .DESCRIPTION This cmdlet will retrive chrome OS devices https://developers.google.com/admin-sdk/directory/reference/rest/v1/chromeosdevices/list https://developers.google.com/admin-sdk/directory/v1/list-query-operators .PARAMETER maxResults How many results to return per page, maximum per page is 300 .PARAMETER orderBy How the results should be sorted .PARAMETER orgUnitPath Restrict to a specific organization unit .PARAMETER projection If we want basic or full data. Default is full. .PARAMETER query The query to use against the data https://developers.google.com/admin-sdk/directory/v1/list-query-operators .PARAMETER sortOrder Ascending or Descending sort order .PARAMETER includeChildOrgunits If we should include child organization in use with orgUnitPath .PARAMETER all If we should return all results and not just a single page #> function Get-ChromeDevices{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter()][int]$maxResults, [Parameter()][ValidateSet('ANNOTATED_LOCATION','ANNOTATED_USER','LAST_SYNC','NOTES','SERIAL_NUMBER','STATUS')][string]$orderBy, [Parameter()][string]$orgUnitPath, [Parameter()][ValidateSet('BASIC','FULL')][string]$projection, [Parameter()][string]$query, [Parameter()][ValidateSet('ASCENDING','DESCENDING')][string]$sortOrder, [Parameter()][switch]$includeChildOrgunits, [Parameter()][switch]$all ) # Ensure that they have a access token if(-not $global:googleAccessToken){ throw "Please ensure that you have called Get-GoogleAccessToken cmdlet" } # Confirm we have a valid access token if(-not $(Test-GoogleAccessToken)){ Get-GoogleAccessToken -json $global:googleJSON -customerId $global:googleCustomerId } # Generate URI for REST API call $uri = "https://admin.googleapis.com/admin/directory/v1/customer/$($global:googleCustomerId)/devices/chromeos" $options = [System.Collections.Generic.List[String]]@() if($maxResults){ $options.Add("maxResults=$($maxResults)") | Out-Null } if($orderBy){ $options.Add("orderBy=$($orderBy)") | Out-Null } if($orgUnitPath){ $options.Add("orgUnitPath=$($orgUnitPath)") | Out-Null } if($projection){ $options.Add("projection=$($projection)") | Out-Null } if($sortOrder){ $options.Add("sortOrder=$($sortOrder)") | Out-Null } if($includeChildOrgunits){ $options.Add("includeChildOrgunits=$($includeChildOrgunits)") | Out-Null } if($query){ $options.Add("query=$($query)") | Out-Null } if($options.count -gt 0){ $uri = "$($uri)?$($options -join "&")" } # REST API Call to Get Orginzation Lists $splat = @{ Method = "GET" Headers = @{authorization = "Bearer $($Global:googleAccessToken)"} } $baseURI = $uri $deviceList = [System.Collections.Generic.List[PSCustomObject]]@() do{ Write-Verbose "$($baseURI)" Write-Verbose "Count: $($deviceList.count)" $result = Invoke-RestMethod @splat -uri $baseURI foreach($item in $result.chromeosdevices){ $deviceList.add($item) | Out-Null } if($options.count -eq 0){$baseURI = "$($uri)?"} else{$baseURI = "$($uri)&"} $baseURI = "$($baseURI)pageToken=$($result.nextPageToken)" }while($null -ne $result.nextPageToken -and $all) return $deviceList } #EndRegion '.\Public\Get-ChromeDevices.ps1' 93 #Region '.\Public\Get-GoogleAccessToken{.ps1' 0 function Get-GoogleAccessToken{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][PSCustomObject]$json, [Parameter(Mandatory = $true)][string]$customerId ) if($Global:googleAccessToken){ if(Test-GoogleAccessToken){return} } # Convert JSOn to object $json = $json | ConvertFrom-Json # COvert Private Key to Byte Stream $rsaPrivateKey = [System.Text.Encoding]::UTF8.GetBytes($json.private_key) # List of Scopes for the token $scopes = @( "https://www.googleapis.com/auth/admin.directory.device.chromeos", "https://www.googleapis.com/auth/admin.directory.group.member", "https://www.googleapis.com/auth/admin.directory.orgunit", "https://www.googleapis.com/auth/admin.directory.user", "https://www.googleapis.com/auth/admin.directory.user.security", "https://www.googleapis.com/auth/admin.directory.rolemanagement", "https://www.googleapis.com/auth/admin.directory.userschema", "https://www.googleapis.com/auth/admin.directory.customer", "https://www.googleapis.com/auth/admin.directory.domain", "https://www.googleapis.com/auth/admin.directory.resource.calendar", "https://mail.google.com/", "http://sites.google.com/feeds", "https://www.googleapis.com/auth/apps.alerts", "https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/classroom.announcements", "https://www.googleapis.com/auth/classroom.coursework.students", "https://www.googleapis.com/auth/classroom.courseworkmaterials", "https://www.googleapis.com/auth/classroom.profile.emails", "https://www.googleapis.com/auth/classroom.rosters", "https://www.googleapis.com/auth/classroom.topics", "https://www.googleapis.com/auth/cloud-identity", "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/contacts", "https://www.googleapis.com/auth/datastudio", "https://www.googleapis.com/auth/documents", "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.activity", "https://www.googleapis.com/auth/drive.admin.labels", "https://www.googleapis.com/auth/drive.labels", "https://www.googleapis.com/auth/gmail.modify", "https://www.googleapis.com/auth/gmail.settings.basic", "https://www.googleapis.com/auth/gmail.settings.sharing", "https://www.googleapis.com/auth/keep", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/tasks", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/admin.directory.device.mobile" ) # Get Current Time $now = (Get-Date).ToUniversalTime() # Expiry Time $expiry = (Get-Date).ToUniversalTime().AddHours(1) # Convert to Format for JWT $createDate = [Math]::Floor([decimal](Get-Date($now) -UFormat "%s")) $expiryDate = [Math]::Floor([decimal](Get-Date($expiry) -UFormat "%s")) # Create JWT Payload $jwtPayload = @{ sub = $json.client_email scope = $($scopes -join " ") aud = "https://oauth2.googleapis.com/token" iat = $createDate } $jwt = New-JWT -Algorithm 'RS256' -Issuer $json.client_email -SecretKey $rsaPrivateKey -ExpiryTimestamp $expiryDate -PayloadClaims $jwtPayload # Request Google API Token $tokenVars = @{ Method = "POST" Uri = "https://oauth2.googleapis.com/token" ContentType = "application/x-www-form-urlencoded" Body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=$jwt" } $token = Invoke-WebRequest @tokenVars $Global:googleAccessToken = ($token.content | ConvertFrom-JSON).access_token $global:googleJSON = $json $global:googleCustomerId = $customerId } #EndRegion '.\Public\Get-GoogleAccessToken{.ps1' 82 #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. https://developers.google.com/admin-sdk/directory/reference/rest/v1/orgunits/list .PARAMETER Type The type of organization units to return. .PARAMETER orgUnitPath The starting point for the OU table #> function Get-GoogleOU{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter()][ValidateSet('All','Children','All_Including_Parent')][string]$Type, [Parameter()][string]$orgUnitPath ) # Ensure that they have a access token if(-not $global:googleAccessToken){ throw "Please ensure that you have called Get-GoogleAccessToken cmdlet" } # Confirm we have a valid access token if(-not $(Test-GoogleAccessToken)){ Get-GoogleAccessToken -json $global:googleJSON -customerId $global:googleCustomerId } # Generate URI for REST API call $uri = "https://admin.googleapis.com/admin/directory/v1/customer/$($global:googleCustomerId)/orgunits" $options = [System.Collections.Generic.List[String]]@() if($Type){ $options.Add("type=$($type)") | Out-Null } if($orgUnitPath){ $options.Add("orgUnitPath=$($orgUnitPath)") | Out-Null } if($options.count -gt 0){ $uri = "$($uri)?$($options -join "&")" } # REST API Call to Get Orginzation Lists $splat = @{ Method = "GET" Uri = $uri Headers = @{authorization = "Bearer $($Global:googleAccessToken)"} } $orglist = Invoke-RestMethod @splat # Return the list return $orglist.organizationUnits } #EndRegion '.\Public\Get-GoogleOU.ps1' 47 #Region '.\Public\Get-GraphAccessToken.ps1' 0 <# .DESCRIPTION This cmdlet is designed to use MSAL.PS to get an access token through an app registration, and then store in a global access token variable .PARAMETER clientID The client ID for the app registration used .PARAMETER clientSecret The secret used for the app registration .PARAMETER tenantID The tenant id for the app registration #> function Get-GraphAccessToken{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$clientID, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][SecureString]$clientSecret, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$tenantID ) if($(Test-GraphAcessToken $global:graphAccessToken)){ return $global:graphAccessToken } $accessTokenVars = @{ "clientID" = $clientID "clientSecret" = $clientSecret "tenantID" = $tenantID "ForceRefresh" = $true } $global:graphAccessToken = Get-MsalToken @accessTokenVars } #EndRegion '.\Public\Get-GraphAccessToken.ps1' 29 #Region '.\Public\Get-GraphDevice.ps1' 0 <# .DESCRIPTION This cmdlet is designed to get devices from Azure ID #> function Get-GraphDevice{ [CmdletBinding()] param( [Parameter()][ValidateNotNullOrEmpty()][string[]]$id, [Parameter()][ValidateNotNullOrEmpty()][string[]]$deviceId, [Parameter()][ValidateNotNullOrEmpty()][bool]$accountEnabled, [Parameter()][ValidateNotNullOrEmpty()][string]$displayName, [Parameter()][ValidateNotNullOrEmpty()][string]$fields ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Create empty list $filters = [System.Collections.Generic.List[PSCustomObject]]@() if($displayName){ $filters.Add("displayName eq '$($displayName)'") | Out-Null } if($accountEnabled){ $filters.Add("accountEnabled eq '$($accountEnabled)'") | Out-Null } if($deviceId.count -eq 1){ $filters.Add("deviceId eq '$($deviceId)'") | Out-Null } $batch = $false # General endpoint $endpoint = "devices" if($id.count -eq 1){ $endpoint = "$($endpoint)/$($id)" } elseif($id.count -gt 1 -or $deviceId.count -gt 1){ $batch = $true } # Create query string for the filter $filterList = $filters -join " and " # Create empty list $deviceList = [System.Collections.Generic.List[PSCustomObject]]@() # Get Graph Headers for Call $headers = Get-GraphHeader # If ID and deviceID are not an array if(-not $batch){ # Setup endpoint based on if filter or fields are passed if($filterList){ $endpoint = "$($endpoint)?`$filter=$($filterList)" } if($filterList -and $fields){ $endpoint = "$($endpoint)&`$select=$($fields)" } elseif($fields){ $endpoint = "$($endpoint)?`$select=$($fields)" } # Try to call graph API and get results back try{ $uri = "https://graph.microsoft.com/beta/$($endpoint)" do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode if($results.value){ foreach($item in $results.value){ $deviceList.Add($item) | Out-Null } } else{ $deviceList.Add($results) | Out-Null } $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") } catch{ throw "Unable to get devices. $($_.Exception.Message)" } return $deviceList } # If a batch job because id or device id is an array else{ $objid = 1 $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() $batches = [System.Collections.Generic.List[PSCustomObject]]@() # if trying to return multiple ids if($id.count -gt 1){ foreach($device in $id){ if($objid -lt 21){ if($fields){ $uri = "$($endpoint)/$($device)?`$select=$($fields)" } else{ $uri = "$($endpoint)/$($device)" } $obj = [PSCustomObject]@{ "id" = $objid "method" = "GET" "url" = $uri } $batchObj.Add($obj) | Out-Null $objid++ } if($objId -eq 21){ $batches.Add($batchObj) | Out-Null $batchObj = $null $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() $objid = 1 } } $batches.Add($batchObj) | Out-Null } # if trying to return multiple deviceids elseif($deviceId.Count -gt 1){ foreach($device in $deviceId){ if($objid -lt 21){ if($fields){ $uri = "$($endpoint)?`$filter=deviceId eq '$($device)'&`$select=$($fields)" } else{ $uri = "$($endpoint)?`$filter=deviceId eq '$($device)'" } $obj = [PSCustomObject]@{ "id" = $objid "method" = "GET" "url" = $uri } $batchObj.Add($obj) | Out-Null $objid++ } if($objId -eq 21){ $batches.Add($batchObj) | Out-Null $batchObj = $null $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() $objid = 1 } } $batches.Add($batchObj) | Out-Null } for($x = 0; $x -lt $batches.count; $x++){ if($batches[$x].count -gt 0){ $json = [PSCustomObject]@{ "requests" = $batches[$x] } | ConvertTo-JSON $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json foreach($item in $results.responses.body){ if($item.value){ $deviceList.Add($item.value) | Out-Null } else{ $deviceList.Add($item) | Out-Null } } } } return $deviceList } } #EndRegion '.\Public\Get-GraphDevice.ps1' 155 #Region '.\Public\Get-GraphGroup.ps1' 0 <# .DESCRIPTION This cmdlet is designed to query graph for Entra ID groups .PARAMETER groupName If want to find based on group name .PARAMETER groupId If want to lookup by group id .PARAMETER All If want to return all groups #> function Get-GraphGroup{ [CmdletBinding()] param( [Parameter(Mandatory = $true,ParameterSetName = 'groupName')][ValidateNotNullOrEmpty()][string]$groupName, [Parameter(Mandatory = $true, ParameterSetName = 'groupId')][ValidateNotNullOrEmpty()][string]$groupId, [Parameter(Mandatory = $true, ParameterSetName = 'All')][switch]$All ) # Confirm we have a valid graph token if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Create empty list $groupList = [System.Collections.Generic.List[PSCustomObject]]@() # Build the headers we will use to get groups $headers = Get-GraphHeader # Base URI for resource call $uri = "https://graph.microsoft.com/beta/groups" if($groupName){ # Filter based on group name is required $uri = "$($uri)?`$filter=displayName eq '$($groupName)'" } elseif($groupId){ # Filter based on group ID $uri = "$($uri)/$($groupId)" } try{ # Loop until nextlink is null do{ # Execute call against graph $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode # Add results to a list variable foreach($item in $results.value){ $groupList.Add($item) | Out-Null } # Set the URI to the nextlink if it exists $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") # If there is only one result, return that if($groupList.count -eq 0){ return $results } else{ # Return the group list if it exists return $groupList } } catch{ throw "Unable to get groups. $($_.Exception.Message)" } } #EndRegion '.\Public\Get-GraphGroup.ps1' 61 #Region '.\Public\Get-GraphGroupMembers.ps1' 0 #https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-beta&tabs=http function Get-GraphGroupMembers{ [CmdletBinding()] param( [Parameter(Mandatory = $true,ParameterSetName = 'groupName')][ValidateNotNullOrEmpty()][string]$groupName, [Parameter(Mandatory = $true, ParameterSetName = 'groupId')][ValidateNotNullOrEmpty()][string]$groupId, [Parameter()][switch]$Recurse ) # Confirm we have a valid graph token if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Get the Group ID if Group Name was Sent if($groupName){ $group = Get-GraphGroup -groupName $groupName $groupId = $group.id } # Create empty list $groupMemberList = [System.Collections.Generic.List[PSCustomObject]]@() # Create List for recurse if needed $groupList = [System.Collections.Generic.List[PSCustomObject]]@() # Build the headers we will use to get groups $headers = Get-GraphHeader # Deterime if we just want members of transitive members if($Recurse){ $uri = "https://graph.microsoft.com/beta/groups/$($groupId)/transitiveMembers" } else{ $uri = "https://graph.microsoft.com/beta/groups/$($groupId)/members" } try{ # Loop until nextlink is null do{ # Execute call against graph $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode # Add results to a list variable foreach($item in $results.value){ $groupMemberList.Add($item) } # Set the URI to the nextlink if it exists $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") return $groupMemberList } catch{ throw "Unable to get group members. $($_.Exception.Message)" } } #EndRegion '.\Public\Get-GraphGroupMembers.ps1' 49 #Region '.\Public\Get-GraphHeader.ps1' 0 <# .DESCRIPTION This cmdlet is designed to format the graph header for the REST api calls .PARAMETER ConsistencyLevel This field will add the ConsistencyLevel variable to eventual #> function Get-GraphHeader{ [CmdletBinding()] param( [Parameter()][switch]$ConsistencyLevel ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Base header variables $headerVars = @{ Authorization = "Bearer $($global:graphAccessToken.AccessToken)" "Content-Type" = "application/json" } # If flagged to include the Consitency Level header if($ConsistencyLevel.IsPresent){ $headerVars.Add("ConsistencyLevel","eventual") } return $headerVars } #EndRegion '.\Public\Get-GraphHeader.ps1' 26 #Region '.\Public\Get-GraphIntuneApp.ps1' 0 function Get-GraphIntuneApp{ [CmdletBinding(DefaultParameterSetName = 'All')] param( [Parameter(Mandatory = $true,ParameterSetName = 'id')][ValidateNotNullOrEmpty()][string]$id, [Parameter(Mandatory = $true, ParameterSetName = 'displayName')][ValidateNotNullOrEmpty()][string]$displayName, [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("microsoft.graph.androidManagedStoreApp","microsoft.graph.iosStoreApp","microsoft.graph.iosVppApp","microsoft.graph.macOSLobApp","microsoft.graph.macOSMicrosoftEdgeApp","microsoft.graph.macOSOfficeSuiteApp","microsoft.graph.macOSPkgApp","microsoft.graph.macOsVppApp","microsoft.graph.managedAndroidStoreApp","microsoft.graph.managedIOSStoreApp","microsoft.graph.officeSuiteApp","microsoft.graph.webApp","microsoft.graph.win32LobApp","microsoft.graph.winGetApp")] [string]$type, [Parameter()][ValidateNotNullOrEmpty()][string]$fields ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # URI Endpoint $endpoint = "deviceAppManagement/mobileApps" # Build filters for URI $filters = [System.Collections.Generic.List[PSCustomObject]]@() if($id){ $filters.Add("id eq '$($id)'") | Out-Null } if($displayName){ $filters.Add("displayName eq '$($displayName)'") | Out-Null } if($type){ $filters.Add("(isof('$($type)'))") | Out-Null } # Create query string for the filter $filterList = $filters -join " and " if($filterList){ $endpoint = "$($endpoint)?`$filter=$($filterList)" } if($filterList -and $fields){ $endpoint = "$($endpoint)&`$select=$($fields)" } elseif($fields){ $endpoint = "$($endpoint)?`$select=$($fields)" } # Create empty list $applicationList = [System.Collections.Generic.List[PSCustomObject]]@() # Get Graph Headers for Call $headers = Get-GraphHeader try{ $uri = "https://graph.microsoft.com/beta/$($endpoint)" do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode if($results.value){ foreach($item in $results.value){ $applicationList.add($item) } } $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") } catch{ throw "Unable to get devices. $($_.Exception.Message)" } return $applicationList } #EndRegion '.\Public\Get-GraphIntuneApp.ps1' 60 #Region '.\Public\Get-GraphIntuneAppAssignment.ps1' 0 function Get-GraphIntuneAppAssignment{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$applicationid ) $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)/assignments" $headers = Get-GraphHeader $results = Invoke-RestMethod -Method "GET" -Uri $endpoint -Headers $headers return $results.value } #EndRegion '.\Public\Get-GraphIntuneAppAssignment.ps1' 11 #Region '.\Public\Get-GraphIntuneEnrollmentStatusPage.ps1' 0 function Get-GraphIntuneEnrollmentStatusPage{ [CmdletBinding()] param( [Parameter()][ValidateNotNullOrEmpty()][string]$id, [Parameter()][ValidateNotNullOrEmpty()][string]$displayName ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # URI Endpoint $endpoint = "deviceManagement/deviceEnrollmentConfigurations" if($id){ $endpoint = "$($endpoint)/$($id)" } if($displayName){ $endpoint = "$($endpoint)?`$filter=displayName eq '$($displayName)'" } # Create empty list $esplist = [System.Collections.Generic.List[PSCustomObject]]@() # Get Graph Headers for Call $headers = Get-GraphHeader try{ $uri = "https://graph.microsoft.com/beta/$($endpoint)" do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode if($results.value){ foreach($item in $results.value){ $esplist.add($item) } } else{ $esplist.add($results) } $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") } catch{ throw "Unable to get devices. $($_.Exception.Message)" } return $esplist } #EndRegion '.\Public\Get-GraphIntuneEnrollmentStatusPage.ps1' 42 #Region '.\Public\Get-GraphIntuneFilters.ps1' 0 function Get-GraphIntuneFilters{ [CmdletBinding()] param( [Parameter()][ValidateNotNullOrEmpty()][string]$id, [Parameter()][ValidateNotNullOrEmpty()][string]$displayName, [Parameter()][ValidateNotNullOrEmpty()][string]$platform ) # Construct array list to build the dynamic filter list $FilterList = [System.Collections.Generic.List[PSCustomObject]]@() if($id){ $FilterList.Add("`$PSItem.id -eq '$($id)'") | Out-Null } if($displayName){ $FilterList.Add("`$PSItem.displayName -eq '$($displayName)'") | Out-Null } if($platform){ $FilterList.Add("`$PSItem.platform -eq '$($platform)'") | Out-Null } # Construct script block from filter list array $FilterExpression = [scriptblock]::Create(($FilterList -join " -and ")) # Create empty list $filters = [System.Collections.Generic.List[PSCustomObject]]@() # Build the headers we will use to get groups $headers = Get-GraphHeader # Endpoint for the API $uri = "https://graph.microsoft.com/beta/deviceManagement/assignmentFilters" try{ # Loop until nextlink is null do{ # Execute call against graph $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode # Add results to a list variable foreach($item in $results.value){ $filters.Add($item) } # Set the URI to the nextlink if it exists $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") if($FilterList.Count -gt 0){ return $filters | Where-Object -FilterScript $FilterExpression } return $filters } catch{ throw "Unable to get group members. $($_.Exception.Message)" } } #EndRegion '.\Public\Get-GraphIntuneFilters.ps1' 48 #Region '.\Public\Get-GraphMail.ps1' 0 <# .DESCRIPTION This cmdlet is designed to read email from a specific mailbox .PARAMETER emailAddress The email address of the account that we are reading from .PARAMETER folder The ID of the folder that we want to read from, if it is not the whole mailbox .PARAMETER unread If we want to return only unread email #> function Get-GraphMail{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$emailAddress, [Parameter()][ValidateNotNullOrEmpty()][string]$folder, [Parameter()][switch]$unread ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } $headers = Get-GraphHeader $uri = "https://graph.microsoft.com/beta/users/$($emailAddress)/messages" $FilterList = [System.Collections.Generic.List[PSCustomObject]]@() if ($folder) { $FilterList.Add("parentFolderId eq '$($folderInID)'") | Out-Null } if ($unread) { $FilterList.Add("isRead eq false") | Out-Null } if($FilterList -ne "") { $FilterExpression = [scriptblock]::Create(($FilterList -join " and ")) $uri = "$($uri)?`$filter=$($FilterExpression)" } try{ $emailList = [System.Collections.Generic.List[PSCustomObject]]@() do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode foreach($item in $results.value){ $emailList.Add($item) | Out-Null } $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") # If there is only one result, return that if($emailList.count -eq 0){ return $results } else{ # Return the group list if it exists return $emailList } } catch{ throw "Unable to get emails from mailbox." } } #EndRegion '.\Public\Get-GraphMail.ps1' 57 #Region '.\Public\Get-GraphManagedDevice.ps1' 0 <# .DESCRIPTION This cmdlet is designed to get managed devices (intune) from the graph endpoints #> function Get-GraphManagedDevice{ [CmdletBinding()] param( [Parameter()][ValidateNotNullOrEmpty()][datetime]$lastSyncBefore, [Parameter()][ValidateNotNullOrEmpty()][datetime]$lastSyncAfter, [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("Windows","Android","macOS","iOS")][string]$operatingSystem, [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("compliant","noncompliant","unknown")][string]$complianceState, [Parameter()][ValidateNotNullOrEmpty()][string]$OSVersion, [Parameter()][ValidateNotNullOrEmpty()][string]$OSVersionStartsWith, [Parameter()][ValidateNotNullOrEmpty()][string]$id, [Parameter()][ValidateNotNullOrEmpty()][string]$azureADDeviceId, [Parameter()][ValidateNotNullOrEmpty()][string]$userPrincipalName, [Parameter()][ValidateNotNullOrEmpty()][string]$model, [Parameter()][ValidateNotNullOrEmpty()][string]$manufacturer, [Parameter()][ValidateNotNullOrEmpty()][string]$serialNumber, [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("disabled","enabled")][string]$lostModeState, [Parameter()][ValidateNotNullOrEmpty()][string]$minimumOSVersion, [Parameter()][ValidateNotNullOrEmpty()][string]$maximumOSVersion, [Parameter()][ValidateNotNullOrEmpty()][bool]$isEncrypted, [Parameter()][ValidateNotNullOrEmpty()][string]$fields, [Parameter()][switch]$batch ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Create Filters for the URI # Create empty list $filters = [System.Collections.Generic.List[PSCustomObject]]@() # Build Filters if($lastSyncBefore){ $filters.Add("lastSyncDateTime le $($lastSyncBefore.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))") | Out-Null } if($lastSyncAfter){ $filters.Add("lastSyncDateTime ge $($lastSyncAfter.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))") | Out-Null } if($operatingSystem){ $filters.Add("operatingSystem eq '$($operatingSystem)'") | Out-Null } if($complianceState){ $filters.Add("complianceState eq '$($complianceState)'") | Out-Null } if($OSVersion){ $filters.Add("OSVersion eq '$($OSVersion)'") | Out-Null } if($OSVersionStartsWith){ $filters.Add("startsWith(OSVersion,'$($OSVersionStartsWith)')") | Out-Null } if($azureADDeviceId){ $filters.Add("azureADDeviceId eq '$($azureADDeviceId)'") | Out-Null } if($userPrincipalName){ $filters.Add("userPrincipalName eq '$($userPrincipalName)'") | Out-Null } if($model){ $filters.Add("model eq '$($model)'") | Out-Null } if($manufacturer){ $filters.Add("manufacturer eq '$($manufacturer)'") | Out-Null } if($serialNumber){ $filters.Add("serialNumber eq '$($serialNumber)'") | Out-Null } # Create query string for the filter $filterList = $filters -join " and " # URI Endpoint $endpoint = "deviceManagement/managedDevices" if($id){ $uri = "$($endpoint)/$($id)" } else{ $uri = "$($endpoint)" } if($filterList){ $uri = "$($uri)?`$filter=$($filterList)" } if(!$batch){ if($fields -ne ""){ if($filters.count -gt 0){ $uri = "$($uri)&`$select=$($fields)" } else{ $uri = "$($uri)?`$select=$($fields)" } } } else{ if($fields -ne ""){ if($filters.count -gt 0){ $uri = "$($uri)&`$select=id" } else{ $uri = "$($uri)?`$select=id" } } } # Create empty list $deviceList = [System.Collections.Generic.List[PSCustomObject]]@() # Create empty list $idlist = [System.Collections.Generic.List[PSCustomObject]]@() # Get Graph Headers for Call $headers = Get-GraphHeader try{ $uri = "https://graph.microsoft.com/beta/$($uri)" do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode if($results.value){ foreach($item in $results.value){ if(!$batch){$deviceList.Add($item) | Out-Null} else{$idlist.Add($item) | Out-Null} } } else{ if(!$batch){$deviceList.Add($item) | Out-Null} else{$idlist.Add($item) | Out-Nul} } $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") } catch{ throw "Unable to get devices. $($_.Exception.Message)" } if(!$batch) { return $deviceList } $objid = 1 $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() $batches = [System.Collections.Generic.List[PSCustomObject]]@() foreach($device in $idlist){ if($objid -lt 21){ $url = "deviceManagement/managedDevices/$($device.id)" if($fields -ne ""){ $url = "$($url)?`$select=$($fields)" } $obj = [PSCustomObject]@{ "id" = $objid "method" = "GET" "url" = $url } $batchObj.Add($obj) | Out-Null $objid++ } if($objId -eq 21){ $batches.Add($batchObj) | Out-Null $batchObj = $null $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() $objid = 1 } } $batches.Add($batchObj) | Out-Null for($x = 0; $x -lt $batches.count; $x++){ if($batches[$x].count -gt 0){ $json = [PSCustomObject]@{ "requests" = $batches[$x] } | ConvertTo-JSON $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json foreach($item in $results.responses.body){ $deviceList.Add($item) | Out-Null } } } return $deviceList } #EndRegion '.\Public\Get-GraphManagedDevice.ps1' 168 #Region '.\Public\Get-GraphSignInAuditLogs.ps1' 0 <# .DESCRIPTION This cmdlet is designed to query the sign in logs for the users in the entra id tenant .PARAMETER userDisplayName The list of user display names that we should be looking for .PARAMETER userPrincipalName The list of user principal names that we should be looking for .PARAMETER userId The lsit of user ids that we should be looking for .PARAMETER appDisplayName The name of the application that we attempted to sign into .PARAMETER ipAddress The list of ipaddresses that we should be looking for .PARAMETER afterDateTime Sign ins after this date #> function Get-GraphSignInAuditLogs{ [CmdletBinding()] param( [Parameter()][string[]]$userDisplayName, [Parameter()][string[]]$userPrincipalName, [Parameter()][string[]]$userId, [Parameter()][string[]]$appDisplayName, [Parameter()][string[]]$ipAddress, [Parameter()][datetime]$afterDateTime ) # Confirm we have a valid graph token if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Create Filters for the URI # Create empty list $filters = [System.Collections.Generic.List[PSCustomObject]]@() # URI Endpoint $endpoint = "auditLogs/signIns" # Create empty list $signinList = [System.Collections.Generic.List[PSCustomObject]]@() # Build Filters # User Display Name Filter if($userDisplayName){ $list = [System.Collections.Generic.List[String]]@() foreach($item in $userDisplayName){ $list.Add("userDisplayName eq '$($item)'") | Out-Null } $filters.Add("($($list -join " or "))") | Out-Null } # User Principal Name Filter if($userPrincipalName){ $list = [System.Collections.Generic.List[String]]@() foreach($item in $userPrincipalName){ $list.Add("userPrincipalName eq '$($item)'") | Out-Null } $filters.Add("($($list -join " or "))") | Out-Null } # User ID Filter if($userId){ $list = [System.Collections.Generic.List[String]]@() foreach($item in $userId){ $list.Add("userId eq '$($item)'") | Out-Null } $filters.Add("($($list -join " or "))") | Out-Null } # App Display Name Filter if($appDisplayName){ $list = [System.Collections.Generic.List[String]]@() foreach($item in $appDisplayName){ $list.Add("appDisplayName eq '$($item)'") | Out-Null } $filters.Add("($($list -join " or "))") | Out-Null } # IP Address Filter if($ipAddress){ $list = [System.Collections.Generic.List[String]]@() foreach($item in $ipAddress){ $list.Add("ipAddress eq '$($item)'") | Out-Null } $filters.Add("($($list -join " or "))") | Out-Null } # Date Filter if($afterDateTime){ $filters.Add("createdDateTime ge $($afterDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))") | Out-Null } # Create query string for the filter $filterList = $filters -join " and " if($filterList){ $endpoint = "$($endpoint)?`$filter=$($filterList)" } # Get Graph Headers for Call $headers = Get-GraphHeader try{ $uri = "https://graph.microsoft.com/beta/$($endpoint)" do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode if($results.value){ foreach($item in $results.value){ $signinList.Add($item) | Out-Null } } $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") return $signinList } catch{ throw "Unable to get devices. $($_.Exception.Message)" } } #EndRegion '.\Public\Get-GraphSignInAuditLogs.ps1' 107 #Region '.\Public\Get-GraphUser.ps1' 0 function Get-GraphUser{ [CmdletBinding(DefaultParameterSetName="All")] param( [Parameter(Mandatory = $true,ParameterSetName = 'userPrincipalName')][ValidateNotNullOrEmpty()][string]$userPrincipalName, [Parameter(Mandatory = $true, ParameterSetName = 'userid')][ValidateNotNullOrEmpty()][string]$userid, [Parameter()][switch]$All, [Parameter()][switch]$ConsistencyLevel, [Parameter()][switch]$Count, [Parameter()][ValidateNotNullOrEmpty()][string]$filter, [Parameter()][ValidateNotNullOrEmpty()][string]$select ) # Confirm we have a valid graph token if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Create empty list $userList = [System.Collections.Generic.List[PSCustomObject]]@() # Build the headers we will use to get groups $ConsistencyLevelHeader = @{} if($ConsistencyLevel.IsPresent){ $ConsistencyLevelHeader.Add("ConsistencyLevel",$true) | Out-Null } $headers = Get-GraphHeader @ConsistencyLevelHeader # Base URI for resource call $uri = "https://graph.microsoft.com/beta/users" if($userPrincipalName){ # Filter based on group name is required $uri = "$($uri)/$($userPrincipalName)" } elseif($userid){ # Filter based on group ID $uri = "$($uri)/$($userid)" } if($filter){ $uri = "$($uri)?`$filter=$($filter)" if($select){ $uri = "$($uri)&`$select=$($select)" } } if($count.IsPresent){ $uri = "$($uri)&`$count=true" } try{ # Loop until nextlink is null do{ # Execute call against graph $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode # Add results to a list variable foreach($item in $results.value){ $userList.Add($item) | Out-Null } # Set the URI to the nextlink if it exists $uri = $results."@odata.nextLink" }while($null -ne $results."@odata.nextLink") # If there is only one result, return that if($userList.count -eq 0){ return $results } else{ # Return the group list if it exists return $userList } } catch{ throw "Unable to get users. $($_.Exception.Message)" } } #https://graph.microsoft.com/beta/users?$filter=startsWith(jobTitle,'Occasional') #"16e6375b-4c11-4306-be0f-b6ad3984fe89" <# [Parameter()][switch]$signInActivity, [Parameter()][switch]$accountEnabled, [Parameter()][string]$assignedLicenses, [Parameter()][string]$displayName, [Parameter()][string]$employeeId, [Parameter()][string]$officeLocation, [Parameter()][string]$onPremisesExtensionAttributes, [Parameter()][string]$onPremisesSamAccountName, [Parameter()][string]$onPremisesUserPrincipalName, [Parameter()][string]$userType, [Parameter()][string]$department #> #EndRegion '.\Public\Get-GraphUser.ps1' 86 #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-MerakiNetwork.ps1' 0 <# .DESCRIPTION This cmdlet is designed to convert get the meraki networks .PARAMETER type The type of network that we should filter to #> function Get-MerakiNetwork{ [CmdletBinding()] param( [Parameter()][ValidateSet("wireless","systemsmanager")][string]$type ) # Confirm we have a valid meraki header if(!$global:merakiHeader){ throw "Please Call Connect-Meraki before calling this cmdlet" } # Generate URI for call $uri = "$($global:merakiApiURI)/organizations/$($global:merakiOrgId)/networks" # Execute API Call $networks = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:merakiHeader -StatusCodeVariable statusCode -FollowRelLink # Filter for productTypes $networkList = [System.Collections.Generic.List[PSCustomObject]]@() foreach($network in $networks){ foreach($item in $network){ if($type -and $type -notin $item.productTypes){continue} $networkList.Add($item) | Out-Null } } return $networkList } #EndRegion '.\Public\Get-MerakiNetwork.ps1' 30 #Region '.\Public\Get-MerakiSystemsManagerDevice.ps1' 0 <# .DESCRIPTION This cmdlet is designed to get system managed devices in a network .PARAMETER networkId The network that we want to get the devices from .PARAMETER fields Additional fields that we want to return #> function Get-MerakiSystemsManagerDevice{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$networkId, [Parameter()][ValidateNotNullOrEmpty()][string]$fields ) # Confirm we have a valid meraki header if(!$global:merakiHeader){ throw "Please Call Connect-Meraki before calling this cmdlet" } # Generate URI for call $uri = "$($global:merakiApiURI)/networks/$($networkId)/sm/devices" if($fields){ $uri = "$($uri)?fields[]=$($fields)" } # Execute API Call $devices = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:merakiHeader -StatusCodeVariable statusCode -FollowRelLink # Filter for productTypes $deviceList = [System.Collections.Generic.List[PSCustomObject]]@() foreach($device in $devices){ foreach($item in $device){ $deviceList.Add($item) | Out-Null } } return $deviceList } #EndRegion '.\Public\Get-MerakiSystemsManagerDevice.ps1' 35 #Region '.\Public\Get-ScriptVariables.ps1' 0 function Get-ScriptVariables{ [CmdLetBinding()] param( [Parameter(Mandatory = $true,ParameterSetName = 'JSON')][ValidateNotNullOrEmpty()][String]$JSON, [Parameter(Mandatory = $true,ParameterSetName = 'URI')][ValidateNotNullOrEmpty()][String]$URI, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$Environment, [Parameter()][ValidateNotNullOrEmpty()][String]$Script ) # If path to JSON file is selected if($JSON){ $vars = Get-Content -Path $JSON | ConvertFrom-JSON -Depth 10 } # If a URI to a JSON is provided else{ $vars = (Invoke-WebRequest -Uri $URI -Method "GET" -UseBasicParsing).Content | ConvertFrom-JSON -Depth 10 } foreach ($var in $vars.PSObject.Properties) { if($var.Name -eq "Environment"){ foreach($item in $var.Value.PSObject.Properties){ if($item.Name -eq $Environment){ foreach($obj in $item.Value.PSObject.Properties){ Set-Variable -Name $obj.Name -Value $obj.Value -Scope Global } break } } } elseif($var.Name -eq "ScriptSpecific"){ foreach($item in $var.Value.PSObject.Properties){ if($item.Name -eq $Script){ foreach($obj in $item.Value.PSObject.Properties){ Set-Variable -Name $obj.Name -Value $obj.Value -Scope Global } break } } } else{ Set-Variable -Name $var.Name -Value $var.Value -Scope Global } } } #EndRegion '.\Public\Get-ScriptVariables.ps1' 43 #Region '.\Public\Get-TopdeskAsset.ps1' 0 <# .DESCRIPTION This cmdlet is designed to query the assets in your enviroment .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER nameFragment Query a specific name fragment from the name field .PARAMETER searchTerm Add an additional search term to your filter .PARAMETER templateId Filter for specific template id for assets .PARAMETER templateName Filter for specific template name for assets .PARAMETER archived If you want to only include non-archived, or archived assets .PARAMETER includeArchived If you haven't specified archive behavior, default is false. This includes all archived as well .PARAMETER fields What fields you want to return by default .PARAMETER showAssignments If you want to show any asset assingments to locations .PARAMETER linkedTo .PARAMETER filter What to add a custom filter .RETURNS Returns a list of assets that fall into the parameters .EXAMPLE Return all assets Get-TopdeskAsset Return all assets for a specific asset template id Get-TopdeskAsset -templateid <TEMPLATEID> Return all assets for a specific asset template name Get-TopdeskAsset-templateName <TEMPLATENAME> Return assets with their assignments Get-TopdeskAsset -showAssignments $true Return assets starting with a specific name fragment Get-TopdeskAsset -nameFragment <FRAGEMENT> #> function Get-TopdeskAsset{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSObject]])] param( [Parameter()][string]$nameFragment, [Parameter()][string]$searchTerm, [Parameter()][string]$templateId, [Parameter()][string]$templateName, [Parameter()][bool]$archived = $false, [Parameter()][bool]$includeArchived = $false, [Parameter()][string]$fields, [Parameter()][switch]$showAssignments, [Parameter()][string]$linkedTo, [Parameter()][string]$filter ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Base URI for retrieval $baseuri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/assetmgmt/assets?`$orderby=name asc&fields=text,archived,id,name,$($fields)" # Filter base on either template ID or template Name if($templateId){ $baseuri = "$($baseuri)&templateId=$($templateId)" } elseif($templateName){ $baseuri = "$($baseuri)&templateName=$($templateName)" } # Fragment of the name if($nameFragment){ $baseuri = "$($baseuri)&nameFragment=$($nameFragment)" } # Search term if($searchTerm){ $baseuri = "$($baseuri)&searchTerm=$($searchTerm)" } # If the devices are archived or not if($archived){ $baseuri = "$($baseuri)&archived='true'" } elseif($archived -eq $false -and -not $includeArchived){ $baseuri = "$($baseuri)&archived='false'" } # If we want to show the assignments for the asset if($showAssignments){ $baseuri = "$($baseuri)&showAssignments=$($showAssignments)" } # Custom filter if($filter){ $baseuri = "$($baseuri)&`$filter=$($filter)" } # If it is linked to specific id if($linkedTo){ $baseuri = "$($baseuri)&linkedTo=$($linkedTo)" } # Set the first URI to query $uri = $baseuri try{ # Empty List for Results $data = [System.Collections.Generic.List[PSObject]]@() do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode foreach($item in $results.dataSet){ $data.Add($item) | Out-Null } # Set next URI if we are going to need to loop again. $uri = "$($baseuri)&lastSeenName='$($data[$data.count - 1].Name)'&lastSeenOrderbyValue='$($data[$data.count - 1].Name)'" Write-Verbose "Next Query: $($uri)" Write-Verbose "Found $($data.count) assets." } while($statusCode -eq 206) } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # Return results return $data } #EndRegion '.\Public\Get-TopdeskAsset.ps1' 119 #Region '.\Public\Get-TopdeskAssetDropdown.ps1' 0 <# .DESCRIPTION This cmdlet is designed to get the values of a asset dropdown field .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER dropdownId The id of the dropdown field that trying to query .PARAMETER dropdownName The name of the dropdown field trying to query .PARAMETER includeArchived Should we include archived items .RETURNS Returns a list of dropdown values that fall into the parameters .EXAMPLE Return values for a specific dropdown by name Get-TopdeskAssetDropdown -dropdownName <DROPDOWNNAME> Return values for a specific dropdown by id Get-TopdeskAssetDropdown dropdownId <DROPDOWNNAME> #> function Get-TopdeskAssetDropdown{ [CmdletBinding()] param( [Parameter(Mandatory = $true,ParameterSetName = 'dropdownId')][string]$dropdownId, [Parameter(Mandatory = $true,ParameterSetName = 'dropdownName')][string]$dropdownName, [Parameter()][bool]$includeArchived = $false ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # We require either the ID or the Name of the dropdown that we are looking for if($dropdownId){ $dropdown = $dropdownId } elseif($dropdownName){ $dropdown = $dropdownName } # Base URI $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/assetmgmt/dropdowns/$($dropdown)?field=name" # Include archived if requested if($includeArchived){ $uri = "$($uri)&includeArchived=$($includeArchived)" } try{ # Get data from the API $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # Return results return $results.results } #EndRegion '.\Public\Get-TopdeskAssetDropdown.ps1' 56 #Region '.\Public\Get-TopdeskAssetTemplates.ps1' 0 <# .DESCRIPTION This cmdlet will return a list of asset templates that are in your topdesk enviroment .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER searchTerm If you are looking for a specific template you can search for it. .RETURNS Returns a list of asset templates .EXAMPLE Return all asset templates Get-TopdeskAssetTemplates Return only asset templates that start with the word Apple Get-TopdeskAssetTemplates -searchTerm "Apple" #> function Get-TopdeskAssetTemplates{ [CmdletBinding()] param( [Parameter()][string]$searchTerm ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Base URI for the list of asset management templates $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/assetmgmt/templates" # If search term is passed, add that to URI to filter if($searchTerm){ $uri = "$($uri)?searchTerm=$($searchTerm)" } try{ # Retrieve data from API $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # Return the data retrieved return $results.dataSet } #EndRegion '.\Public\Get-TopdeskAssetTemplates.ps1' 43 #Region '.\Public\Get-TopdeskBranches.ps1' 0 <# .DESCRIPTION This cmdlet will return the branches in your enviroment .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER fields The fields that return from the data. Does not work when using the ID filter .PARAMETER id The id of the subcategory you are trying to retrieve .PARAMETER startsWith The start of the name of the branches .PARAMETER clientReferenceNumber The start of the client reference number .RETURNS Returns a list of branches .EXAMPLE Return all branches Get-TopdeskBranches Return specific branch by ID Get-TopdeskBranches -id <ID> Return specific branch where the name starts with Get-TopdeskBranches -startsWith <NAME> Return specific fields Get-TopdeskBranches -fields <FIELDS> #> function Get-TopdeskBranches{ [CmdletBinding()] param( [Parameter()][string]$fields, [Parameter()][string]$id, [Parameter()][string]$startsWith, [Parameter()][string]$clientReferenceNumber ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # The base URI for the branches endpoint $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/branches?" # If ID, get details of specific branch. This is more detailed, and does not allow additional filtering if($id){ $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/branches/id/$($id)?" } else{ # By default the query is null $query = $null # If only want specific fields, set what fields if($fields){ $uri = "$($uri)`$fields=$($fields)" } # If Name is populated, filter based on the name, using starts with if($startsWith){ $query = "&query=name=sw=$($startsWith)" } # If Client Reference Number is populated, filter using starts with if($clientReferenceNumber){ if($null -eq $query){$query = "&query="} else{$query = "$($query);"} $query = "$($query)clientReferenceNumber=sw=$($clientReferenceNumber)" } # If query is not blank, add it to the URI if($null -ne $query){ $uri = "$($uri)$($query)" } } try{ # Get base data from Topdesk $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # Return results $results } #EndRegion '.\Public\Get-TopdeskBranches.ps1' 78 #Region '.\Public\Get-TopdeskChangeProgress.ps1' 0 <# .DESCRIPTION This cmdlet will return the change progress text for specific change .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER changeID The id of the change that you want the original request text from. .EXAMPLE Return change request progress Get-TopdeskChangeProgress -changeID <CHANGEID> #> function Get-TopdeskChangeProgress{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$changeID ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/operatorChanges/$($changeID)/progresstrail" try{ # Invoke API to get the details $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # Return the details of the ticket return $results.results } #EndRegion '.\Public\Get-TopdeskChangeProgress.ps1' 34 #Region '.\Public\Get-TopDeskChangeRequest.ps1' 0 <# .DESCRIPTION This cmdlet is designed to query operator changes in Topdesk and return their details .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER query If you want to add a filtered query to the details .PARAMETER sort If there is a parameter you want to sort by .PARAMETER direction The direction of the sort only applicable if sort is set .PARAMETER pageSize The number of results you want to return .PARAMETER pageStart If you want to skip a certain number of results and start your retrieval there .PARAMETER fields What fields you want to retrieve from the API .PARAMETER all If you want to retrieve all relevant results, or just the first page .RETURNS Returns a list of changes that fall into the parameters .EXAMPLE Return the first page based on default sort Get-TopDeskChangeRequest Return all pages based on default sort Get-TopDeskChangeRequest -all Return a specific change based on the query function Get-TopDeskChangeRequest -query "number=='<CHANGENUMBER>'" #> function Get-TopDeskChangeRequest{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSObject]])] param( [Parameter()][string]$query, [Parameter()][ValidateSet("id","creationDate","simple.closedDate","simple.plannedImplementationDate","simple.plannedStartDate","phases.rfc.plannedEndDate","phases.progress.plannedEndDate","phases.evaluation.plannedEndDate")] [string]$sort, [Parameter()][ValidateSet("asc","desc")][string]$direction = "asc", [Parameter()][string]$pageSize, [Parameter()][int]$pageStart = 0, [Parameter()][string]$fields, [Parameter()][switch]$all ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } try{ # Base URI for Operator Changes. $base = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/operatorChanges?pageStart=$($pageStart)" # If we are expecting a different page size from default if($pageSize -ne ""){ $base = "$($base)&pageSize=$($pageSize)" } # If we want to sort based on specific criteria, and the direction of that sort if($sort -ne ""){ $base = "$($base)&sort=$($sort):$($direction)" } # If we have added a query to our API call if($query -ne ""){ $base = "$($base)&query=$($query)" } # What fields to return if we want something other than the default if($fields -ne ""){ $base = "$($base)&fields=$($fields)" } # Set the initial URI to what we determined for the URI $uri = $base # Put inside a loop in case we want to get all. Only loop if result code is 206 and set to all $data = [System.Collections.Generic.List[PSObject]]@() do{ # Query API based on URI $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode # Populate the URI to the next link returned by API $uri = $results.next # Loop through results and add to list foreach($item in $results.results){ $data.Add($item) | Out-Null } Write-Verbose "Next Query: $($uri)" Write-Verbose "Found $($data.count) tickets." }while($statusCode -eq 206 -and $all.IsPresent -ne $false) } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } return $data } #EndRegion '.\Public\Get-TopDeskChangeRequest.ps1' 90 #Region '.\Public\Get-TopdeskChangeRequestText.ps1' 0 <# .DESCRIPTION This cmdlet will return the change request text for specific change .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER changeID The id of the change that you want the original request text from. .EXAMPLE Return change request text Get-TopdeskChangeRequestText -changeID <CHANGEID> #> function Get-TopdeskChangeRequestText{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$changeID ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Base URI for change request data $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/operatorChanges/$($changeID)/requests" try{ # Invoke API to get the details $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # Return the details of the ticket return $results.results } #EndRegion '.\Public\Get-TopdeskChangeRequestText.ps1' 35 #Region '.\Public\Get-TopdeskIncidentCategory.ps1' 0 <# .DESCRIPTION This cmdlet will return the categories you have configured for your incidents .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER id The id of the category you are trying to retrieve .PARAMETER name The name of the category you are trying to retrieve .RETURNS Returns a list of categories .EXAMPLE Return all categories Get-TopdeskIncidentCategory Return specific category by ID Get-TopdeskIncidentCategory -id <ID> Return specific category by Name Get-TopdeskIncidentCategory -name <NAME> #> function Get-TopdeskIncidentCategory{ [CmdletBinding()] param( [Parameter()][string]$id, [Parameter()][string]$name ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Topdesk URI for incident categories $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/incidents/categories" try{ # Retrieve data from API $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # Filter for either Id or Name, or return all if neither specificed if($id){ return $results | Where-Object {$_.id -eq $id} } elseif($name){ return $results | Where-Object {$_.name -eq $name} } else{ return $results } } #EndRegion '.\Public\Get-TopdeskIncidentCategory.ps1' 52 #Region '.\Public\Get-TopdeskIncidentSearchList.ps1' 0 <# .DESCRIPTION This cmdlet will recover the details of the optional fields search lists. It will .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER tab What tabs to get data from. This is an array .PARAMETER searchList What search lists to check for data. This is an array .PARAMETER includeEmpty Return empty data .RETURNS This returns a hashtable with the tabs and values. .EXAMPLE Return all search lists data Get-TopdeskIncidentSearchList Return all search lists data that are not empty Get-TopdeskIncidentSearchList -includeEmpty $false #> function Get-TopdeskIncidentSearchList{ [CmdletBinding()] [OutputType([hashtable])] param( [Parameter()][int[]]$tab = @(1,2), [Parameter()][int[]]$searchList = @(1,2,3,4,5), [Parameter()][bool]$includeEmpty = $true ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Iniatilize a empty list. $list = @{} # Loop through the tabs that hold the search lists foreach($t in $tab){ # Iniatilize a empty sublist $sublist = @{} # Loop through the items in the tab foreach($l in $searchList){ # Set the URI for the search list to get details of $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/incidents/free_fields/$($t)/searchlists/$($l)" try{ # Query API for data $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode # If Include Empty is false then skip anything that is blank if($null -eq $results.id -and $includeEmpty -eq $false){continue} # Add Results to Sublist $sublist.Add($l,$results) | Out-Null } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } } # If include empty is false, and the sublist is empty, skip. if($sublist.Count -eq 0 -and $includeEmpty -eq $false){continue} # Add sublist to the over all list $list.Add($t,$sublist) | Out-Null } # Return data return $list } #EndRegion '.\Public\Get-TopdeskIncidentSearchList.ps1' 64 #Region '.\Public\Get-TopdeskIncidentSubcategory.ps1' 0 <# .DESCRIPTION This cmdlet will return the subcategories that you have in your incident module .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER id The id of the subcategory you are trying to retrieve .PARAMETER name The name of the subcategory you are trying to retrieve .PARAMETER category_id The id of the category you are trying to retrieve .PARAMETER category_name The name of the category you are trying to retrieve .RETURNS Returns a list of subcategories .EXAMPLE Return all subcategories Get-TopdeskIncidentSubcategory Return specific subcategory by ID Get-TopdeskIncidentSubcategory -id <ID> Return specific subcategory by Name Get-TopdeskIncidentSubcategory <NAME> Return specific subcategory by what category id it is in Get-TopdeskIncidentSubcategory -category_id <CATEGORYID> Return specific subcategory by what category name it is in Get-TopdeskIncidentSubcategory -category_name <NAME> #> function Get-TopdeskIncidentSubcategory{ [CmdletBinding()] param( [Parameter()][string]$id, [Parameter()][string]$name, [Parameter()][string]$category_id, [Parameter()][string]$category_name ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Base URI for subcategory data $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/incidents/subcategories" try{ # Get base data from Topdesk $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } # If looking for specific id, just return it if($id){ return $results | Where-Object {$_.id -eq $id} } else{ # If filtering by name, narrow results to match name if($name){ $results = $results | Where-Object {$_.name -eq $name} } # If filtering by category id, narrow results to match if($category_id){ $results = $results | Where-Object {$_.category.id -eq $category_id} } # If filtering by category name, narrow results to match if($category_name){ $results = $results | Where-Object {$_.category.name -eq $category_name} } # Return data return $results } } #EndRegion '.\Public\Get-TopdeskIncidentSubcategory.ps1' 72 #Region '.\Public\Get-TopdeskOperator.ps1' 0 function Get-TopdeskOperator{ [CmdletBinding()] param( [Parameter()][ValidateNotNullOrEmpty()][string]$query, [Parameter()][ValidateNotNullOrEmpty()][string]$fields ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Default Page Size. Between 1 and 100 $pageSize = 10 # The base URI for the branches endpoint $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/operators?start=0&page_size=$($pageSize)" # If query set add it to the uri if($query){ $uri = "$($uri)&query=$($query)" } # If fields set filter to those fields if($fields){ $uri = "$($uri)&fields=$($fields)" } try{ $data = [System.Collections.Generic.List[PSObject]]@() do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode foreach($item in $results){ $data.Add($item) | Out-Null } $currentStart = [Regex]::Match($uri,"\d+") $uri = $uri -replace "start=$($currentStart.Value)","start=$($currentStart.Value/1 + $pageSize)" } while($statusCode -eq 206) return $data } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } } #EndRegion '.\Public\Get-TopdeskOperator.ps1' 39 #Region '.\Public\Get-TopdeskOperatorGroup.ps1' 0 function Get-TopdeskOperatorGroup{ [CmdletBinding()] param( [Parameter()][ValidateNotNullOrEmpty()][string]$query, [Parameter()][ValidateNotNullOrEmpty()][string]$fields ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Default Page Size. Between 1 and 100 $pageSize = 10 # The base URI for the branches endpoint $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/operatorgroups?start=0&page_size=$($pageSize)" # If query set add it to the uri if($query){ $uri = "$($uri)&query=$($query)" } # If fields set filter to those fields if($fields){ $uri = "$($uri)&fields=$($fields)" } try{ $data = [System.Collections.Generic.List[PSObject]]@() do{ $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode foreach($item in $results){ $data.Add($item) | Out-Null } $currentStart = [Regex]::Match($uri,"\d+") $uri = $uri -replace "start=$($currentStart.Value)","start=$($currentStart.Value/1 + $pageSize)" } while($statusCode -eq 206) return $data } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } } #EndRegion '.\Public\Get-TopdeskOperatorGroup.ps1' 39 #Region '.\Public\Get-TopdeskOrderedItems.ps1' 0 <# .DESCRIPTION This cmdlet will return any ordered items that are attached to the specific change id .PARAMETER credential The credential to connect to the API endpoints .PARAMETER environment The topdesk enviroment URI. For examble https://test.topdesk.net then this value would be test .PARAMETER changeID The id of the change that you want to look for items on .RETURNS Returns a list of ordered items .EXAMPLE Return the ordered items of a change Get-TopdeskOrderedItems-changeID <CHANGEID> #> function Get-TopdeskOrderedItems{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$changeID ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # URI to get ordered items of a change $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/operatorChanges/$($changeID)/orderedItems" try{ # Query the API for the relevant data $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } catch{ throw $Error[0] } # Return results return $results.results } #EndRegion '.\Public\Get-TopdeskOrderedItems.ps1' 37 #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\Move-GraphMail.ps1' 0 <# .DESCRIPTION This cmdlet is designed to move emails between folders in a mailbox .PARAMETER id The id of the mail message we are acting on .PARAMETER emailAddress The email address of the account that we are reading from .PARAMETER folder The id of the folder that we are moving the message to #> function Move-GraphMail{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$emailAddress, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$folder ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } $headers = Get-GraphHeader # Body Content $body = @{ "destinationId" = $folder } | ConvertTo-Json $uri = "https://graph.microsoft.com/beta/users/$($emailAddress)/messages/$($id)/move" $results = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body -StatusCodeVariable statusCode # Return Results if($statusCode -in (200,201)){ return $results } else{ throw "Unable to move email." } } #EndRegion '.\Public\Move-GraphMail.ps1' 36 #Region '.\Public\Move-MerakiSystemsManagerDevice.ps1' 0 <# .DESCRIPTION This cmdlet is designed to move devices from one network to another .PARAMETER networkId The network that we want to get the devices from .PARAMETER newNetworkId The network that we want to get the devices to .PARAMETER ids If we want to move devices based on their id .PARAMETER serialNumbers If we want to move devices based on their serial number #> function Move-MerakiSystemsManagerDevice{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$networkId, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$newNetworkId, [Parameter()][ValidateNotNullOrEmpty()][System.Object]$ids, [Parameter()][ValidateNotNullOrEmpty()][System.Object]$serialNumbers ) # Confirm we have a valid meraki header if(!$global:merakiHeader){ throw "Please Call Connect-Meraki before calling this cmdlet" } # Confirm we have items to move if(-not $ids -and -not $serialNumbers){ throw "You need to specify at least one id or one serial number" } # Generate URI for call $uri = "$($global:merakiApiURI)/networks/$($networkId)/sm/devices/move" # Create Body $body = @{ "newNetwork" = $newNetworkId } if($ids){ $body.Add("ids",$ids) } if($serialNumbers){ $body.Add("serials",$serialNumbers) } # Try to move devices try{ $results = Invoke-RestMethod -Method "Post" -Uri $uri -Headers $global:merakiHeader -Body ($body | ConvertTo-Json) -StatusCodeVariable statusCode } catch{ throw "Unable to move devices. $($_.Exception.Message)" } } #EndRegion '.\Public\Move-MerakiSystemsManagerDevice.ps1' 49 #Region '.\Public\New-AlertFactoryIncident.ps1' 0 <# .DESCRIPTION This cmdlet is designed to create a new Topdesk Support Ticket .PARAMETER details The details that we will be using for the ticket .PARAMETER emails The emails that will be part of this incident .PARAMETER sourceDir The directory that the process is running from, so it can save the emails to html files #> function New-AlertFactoryIncident{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][hashtable]$details, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$emails, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$sourceDir, [Parameter()][ValidateNotNullOrEmpty()][int]$count = 1 ) $body = @{} foreach($item in $details.GetEnumerator()){ if($null -ne $item.Value){ switch($item.key){ "email"{ $body.Add("caller_dynamicName",$item.Value) $body.Add("caller_email",$item.Value) } "location" { $body.Add("caller_branch_id",(Get-TopdeskBranches -clientReferenceNumber $item.Value | Select-Object -first 1).id) } "briefDescription" { $description = $item.Value if($count -gt 1){ $description = "$($description) (Has Occured $($count) times)" } $body.Add("briefDescription",$description) } "callType" { $body.Add("callType_name",$item.Value) } "category" { $body.Add("category_name",$item.Value) } "subcategory" { $body.Add("subcategory_name",$item.Value) } "impact" { $body.Add("impact_name",$item.Value) } "urgency" { $body.Add("urgency_name",$item.Value) } "priorty" { $body.Add("priority_name",$item.Value) } "duration" { $body.Add("duration_name",$item.Value) } "operatorGroup" { $body.Add("operatorGroup_id",(Get-TopdeskOperatorGroup -query "groupName=='$($item.value)'" -fields id | Select-Object -first 1).id) } "operator" { $body.Add("operator_id",(Get-TopdeskOperator -query "dynamicName=='$($item.value)'" -fields id | Select-Object -first 1).id) } "status" { $body.Add("processingStatus_name",$item.Value) } "request" { $body.Add("request",((ConvertFrom-HTML -Content ($item.value -replace "</p>","\r\n")).innerText -replace "\\r\\n","<br/>")) } } } } try{ $incident = New-TopdeskIncident @body foreach($email in $emails) { $tempFile = Join-Path -Path $sourceDir -ChildPath "Temp" -AdditionalChildPath "$(Get-Random).html" $email.body.content | Out-File $tempFile Add-TopdeskIncidentAttachment -id $incident.id -filepath $tempFile } return $incident } catch{ throw "Unable to create incident. $($Error[0])" } } #EndRegion '.\Public\New-AlertFactoryIncident.ps1' 88 #Region '.\Public\New-GraphGroup.ps1' 0 <# .DESCRIPTION This cmdlet is designed to create a new Entra ID group via graph .PARAMETER displayName The display name of the group .PARAMETER mailEnabled If the group should be mail enabled, default false .PARAMETER mailNickname What the mailnickname will be, required even if mailenabled is false .PARAMETER description The description for the group .PARAMETER securityEnabled If the group should be security enabled, default true #> function New-GraphGroup{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$displayName, [Parameter()][bool]$mailEnabled = $false, [Parameter(Mandatory = $true)][string]$mailNickname, [Parameter()][string]$description, [Parameter()][bool]$securityEnabled = $true ) # Confirm we have a valid graph token if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Build the headers we will use to get groups $headers = Get-GraphHeader # Variables $body = $PsBoundParameters | ConvertTo-Json # Base URI for resource call $uri = "https://graph.microsoft.com/beta/groups" try{ # Execute call against graph $results = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body -StatusCodeVariable statusCode return $results } catch{ throw "Unable to create group. $($_.Exception.Message)" } } #EndRegion '.\Public\New-GraphGroup.ps1' 44 #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\New-TopdeskAssetUpload.ps1' 0 function New-TopdeskAssetUpload{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$filePath, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$fileName, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$TopdeskTenant ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } $global:topdeskAccessToken."Content-Type" = "application/octet-stream" try{ $uri = "https://$($TopdeskTenant).topdesk.net/services/import-to-api-v1/api/sourceFiles?filename=$($fileName)" Invoke-RestMethod -Uri $uri -Method PUT -headers $global:topdeskAccessToken -InFile $filePath } catch{ throw "Error Accessing API at $($uri). $($Error[1])" } } #EndRegion '.\Public\New-TopdeskAssetUpload.ps1' 21 #Region '.\Public\New-TopdeskIncident.ps1' 0 function New-TopdeskIncident{ [CmdletBinding()] param( [Parameter(Mandatory = $true,ParameterSetName = 'registeredCaller')][ValidateNotNullOrEmpty()][string]$caller_id, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_branch_id, [Parameter(Mandatory = $true,ParameterSetName = 'nonregisteredCaller')][ValidateNotNullOrEmpty()][string]$caller_dynamicName, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_phoneNumber, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_mobileNumber, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_email, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_department_id, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_department_name, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_location_id, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_budgetHolder_id, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_budgetHolder_name, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_personExtraFieldA_id, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_personExtraFieldA_name, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_personExtraFieldB_id, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_personExtraFieldB_name, [Parameter()][ValidateNotNullOrEmpty()][string]$caller_callerLookup_id, [Parameter()][ValidateNotNullOrEmpty()][string]$status, [Parameter()][ValidateNotNullOrEmpty()][string]$briefDescription, [Parameter()][ValidateNotNullOrEmpty()][string]$request, [Parameter()][ValidateNotNullOrEmpty()][string]$action, [Parameter()][ValidateNotNullOrEmpty()][bool]$actionInvisibleForCaller, [Parameter()][ValidateNotNullOrEmpty()][string]$entryType_id, [Parameter()][ValidateNotNullOrEmpty()][string]$entryType_name, [Parameter()][ValidateNotNullOrEmpty()][string]$callType_id, [Parameter()][ValidateNotNullOrEmpty()][string]$callType_name, [Parameter()][ValidateNotNullOrEmpty()][string]$category_id, [Parameter()][ValidateNotNullOrEmpty()][string]$category_name, [Parameter()][ValidateNotNullOrEmpty()][string]$subcategory_id, [Parameter()][ValidateNotNullOrEmpty()][string]$subcategory_name, [Parameter()][ValidateNotNullOrEmpty()][string]$externalNumber, [Parameter()][ValidateNotNullOrEmpty()][string]$object_id, [Parameter()][ValidateNotNullOrEmpty()][string]$object_name, [Parameter()][ValidateNotNullOrEmpty()][string]$location_id, [Parameter()][ValidateNotNullOrEmpty()][string]$branch_id, [Parameter()][ValidateNotNullOrEmpty()][string]$mainIncident_id, [Parameter()][ValidateNotNullOrEmpty()][string]$mainIncident_number, [Parameter()][ValidateNotNullOrEmpty()][string]$impact_id, [Parameter()][ValidateNotNullOrEmpty()][string]$impact_name, [Parameter()][ValidateNotNullOrEmpty()][string]$urgency_id, [Parameter()][ValidateNotNullOrEmpty()][string]$urgency_name, [Parameter()][ValidateNotNullOrEmpty()][string]$priority_id, [Parameter()][ValidateNotNullOrEmpty()][string]$priority_name, [Parameter()][ValidateNotNullOrEmpty()][string]$duration_id, [Parameter()][ValidateNotNullOrEmpty()][string]$duration_name, [Parameter()][ValidateNotNullOrEmpty()][datetime]$targetDate, [Parameter()][ValidateNotNullOrEmpty()][string]$sla_id, [Parameter()][ValidateNotNullOrEmpty()][bool]$onHold, [Parameter()][ValidateNotNullOrEmpty()][string]$operator_id, [Parameter()][ValidateNotNullOrEmpty()][string]$operatorGroup_id, [Parameter()][ValidateNotNullOrEmpty()][string]$supplier_id, [Parameter()][ValidateNotNullOrEmpty()][string]$processingStatus_id, [Parameter()][ValidateNotNullOrEmpty()][string]$processingStatus_name, [Parameter()][ValidateNotNullOrEmpty()][bool]$responded, [Parameter()][ValidateNotNullOrEmpty()][datetime]$responseDate, [Parameter()][ValidateNotNullOrEmpty()][bool]$completed, [Parameter()][ValidateNotNullOrEmpty()][datetime]$completedDate, [Parameter()][ValidateNotNullOrEmpty()][bool]$closed, [Parameter()][ValidateNotNullOrEmpty()][datetime]$closedDate, [Parameter()][ValidateNotNullOrEmpty()][string]$closureCode_id, [Parameter()][ValidateNotNullOrEmpty()][string]$closureCode_name, [Parameter()][ValidateNotNullOrEmpty()][decimal]$costs, [Parameter()][ValidateNotNullOrEmpty()][int]$feedbackRating, [Parameter()][ValidateNotNullOrEmpty()][string]$feedbackMessage, [Parameter()][ValidateNotNullOrEmpty()][bool]$majorCall, [Parameter()][ValidateNotNullOrEmpty()][string]$majorCallObject_id, [Parameter()][ValidateNotNullOrEmpty()][string]$majorCallObject_number, [Parameter()][ValidateNotNullOrEmpty()][bool]$publishToSsd, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields1_boolean1, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields1_boolean2, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields1_boolean3, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields1_boolean4, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields1_boolean5, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields1_number1, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields1_number2, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields1_number3, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields1_number4, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields1_number5, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_text1, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_text2, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_text3, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_text4, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_text5, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_memo1, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_memo2, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_memo3, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_memo4, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_memo5, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields1_date1, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields1_date2, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields1_date3, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields1_date4, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields1_date5, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist1_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist1_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist2_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist2_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist3_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist3_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist4_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist4_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist5_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields1_searchlist5_name, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields2_boolean1, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields2_boolean2, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields2_boolean3, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields2_boolean4, [Parameter()][ValidateNotNullOrEmpty()][bool]$optionalFields2_boolean5, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields2_number1, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields2_number2, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields2_number3, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields2_number4, [Parameter()][ValidateNotNullOrEmpty()][decimal]$optionalFields2_number5, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_text1, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_text2, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_text3, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_text4, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_text5, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_memo1, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_memo2, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_memo3, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_memo4, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_memo5, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields2_date1, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields2_date2, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields2_date3, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields2_date4, [Parameter()][ValidateNotNullOrEmpty()][datetime]$optionalFields2_date5, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist1_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist1_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist2_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist2_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist3_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist3_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist4_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist4_name, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist5_id, [Parameter()][ValidateNotNullOrEmpty()][string]$optionalFields2_searchlist5_name, [Parameter()][ValidateNotNullOrEmpty()][string]$externalLink_id, [Parameter()][ValidateNotNullOrEmpty()][string]$externalLink_type, [Parameter()][ValidateNotNullOrEmpty()][string]$externalLink_date ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } $body = @{} foreach($item in $PsBoundParameters.GetEnumerator()){ $key = $item.Key.split("_") if($key.count -gt 1){ $parent = "" for($i = 0; $i -lt $key.count - 1; $i++){ if($i -eq 0){ if(!$body.ContainsKey($key[$i])){ $body.Add($key[$i],@{}) | Out-Null } $parent = $key[$i] } else{ $scriptBlock = " if(!`$body.$($parent).ContainsKey(`"$($key[$i])`")){ `$body.$($parent).Add(`"$($key[$i])`",@{}) | Out-Null } `$parent = `"$($parent).$($key[$i])`" " Invoke-Expression $scriptBlock } } $scriptBlock = " `$body.$($parent).Add(`"$($key[$i])`",`$item.value) " Invoke-Expression $scriptBlock } else{ if(!$body.ContainsKey($item.Key)){ $body.Add($item.Key,$item.Value) | Out-Null } } } $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/incidents" try{ $results = Invoke-RestMethod -Method POST -Uri $uri -Headers $global:topdeskAccessToken -body ($body | ConvertTo-Json) -StatusCodeVariable statusCode } catch{ throw "Error Accessing API at $($uri). $($Error[0])" } return $results } #EndRegion '.\Public\New-TopdeskIncident.ps1' 191 #Region '.\Public\Remove-GraphGroupMember.ps1' 0 function Remove-GraphGroupMember{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$groupId, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string[]]$ids ) # Confirm we have a valid graph token if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } # Get Graph Headers for Call $headers = Get-GraphHeader try{ $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() $batches = [System.Collections.Generic.List[PSCustomObject]]@() for($i = 1; $i -le $ids.Count; ++$i){ $obj = [PSCustomObject]@{ "id" = $i "method" = "DELETE" "url" = "/groups/$($groupId)/members/$($ids[$i-1])/`$ref" } $batchObj.Add($obj) | Out-Null if($($i % 20) -eq 0){ $batches.Add($batchObj) | Out-Null $batchObj = $null $batchObj = [System.Collections.Generic.List[PSCustomObject]]@() } } $batches.Add($batchObj) | Out-Null foreach($batch in $batches){ $json = [PSCustomObject]@{ "requests" = $batch } | ConvertTo-JSON -Depth 5 $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json } } catch{ throw "Unable to remove members. $($_.Exception.Message)" } } #EndRegion '.\Public\Remove-GraphGroupMember.ps1' 41 #Region '.\Public\Remove-GraphIntuneApp.ps1' 0 function Remove-GraphIntuneApp{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid ) # Invoke graph API to remove the application $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)" $headers = Get-GraphHeader Invoke-RestMethod -Method Delete -Uri $endpoint -Headers $headers -StatusCodeVariable statusCode | Out-Null } #EndRegion '.\Public\Remove-GraphIntuneApp.ps1' 11 #Region '.\Public\Remove-TopdeskAssetAssignment.ps1' 0 <# .DESCRIPTION This cmdlet will remove a location assignment for an asset .PARAMETER asset The asset that we want to update with the assignments listed .PARAMETER locationID The location ID that we want to remove .EXAMPLE #> function Remove-TopdeskAssetAssignment{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][PSCustomObject]$asset, [Parameter(Mandatory = $true)][string]$locationID ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } if($null -eq $asset.'@assignments'.locations){ throw "Asset has no location assignments" } foreach($link in $asset.'@assignments'.locations){ if($link.branch.id -eq $locationID){ $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/assetmgmt/assets/$($asset.unid)/assignments/$($link.linkid)" Invoke-RestMethod -Method DELETE -Uri $uri -Headers $global:topdeskAccessToken -StatusCodeVariable statusCode } } } #EndRegion '.\Public\Remove-TopdeskAssetAssignment.ps1' 30 #Region '.\Public\Set-GraphMailRead.ps1' 0 <# .DESCRIPTION This cmdlet is designed to mark a specific email as read .PARAMETER id The id of the mail message we are acting on .PARAMETER emailAddress The email address of the account that we are reading from #> function Set-GraphMailRead{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$emailAddress ) if(!$(Test-GraphAcessToken $global:graphAccessToken)){ throw "Please Call Get-GraphAccessToken before calling this cmdlet" } $headers = Get-GraphHeader # Body Content $body = @{ "isRead" = $true } | ConvertTo-Json # Execute Graph Call $uri = "https://graph.microsoft.com/beta/users/$($emailAddress)/messages/$($id)" $results = Invoke-RestMethod -Method Patch -Uri $uri -Headers $headers -Body $body -StatusCodeVariable statusCode # Return Results if($statusCode -in (200,201)){ return $results } else{ throw "Unable to mark email as read." } } #EndRegion '.\Public\Set-GraphMailRead.ps1' 34 #Region '.\Public\Test-AlertFactoryRule.ps1' 0 <# .DESCRIPTION This cmdlet is designed to test rules against emails that are in the mailbox for alert factory .PARAMETER rule The rule we are testing against .PARAMETER emails The emails that will be part of this incident #> function Test-AlertFactoryRule{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$rule, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$emails ) foreach($obj in $rule.PSObject.Properties){ if($null -ne $obj.value.type){ switch($obj.name){ "sender" { $lookupField = "from.emailAddress.Address" } "body" { $lookupField = "body.content" } "subject" { $lookupField = "subject" } } switch($obj.value.type){ "equals" { $command = "[System.Collections.Generic.List[PSObject]]`$emails = `$emails | Where-Object {`$_.$($lookupField) -eq `"$($obj.value.expression)`"}" } "contains" { $command = "[System.Collections.Generic.List[PSObject]]`$emails = `$emails | Where-Object {`$_.$($lookupField) -match `"$($obj.value.expression)`"}" } "regex" { $command = "[System.Collections.Generic.List[PSObject]]`$emails = `$emails | Where-Object {`$_.$($lookupField) -match `"$($obj.value.expression)`"}" } } Invoke-Expression -Command $command } } return $emails } #EndRegion '.\Public\Test-AlertFactoryRule.ps1' 45 #Region '.\Public\Test-AllowedGroupMember.ps1' 0 # TEST (maybe split) <# .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' 96 #Region '.\Public\Test-GoogleAccessToken.ps1' 0 function Test-GoogleAccessToken{ [CmdletBinding()] param() if(-not $global:googleAccessToken){ throw "Please ensure that you have called Get-GoogleAccessToken cmdlet" } try{ $uri = "https://oauth2.googleapis.com/tokeninfo?access_token=$($Global:googleAccessToken)" $tokenDetails = Invoke-RestMethod -Method "GET" -URI $uri -StatusCodeVariable statusCode if([int]$tokenDetails.expires_in -gt 900){ Write-Verbose "Token is valid for more than 15 minutes, not getting new token." return $true } else{ Write-Verbose "Token is valid for less than 15 minutes, getting new token." return $false } } catch{ Write-Verbose "Unable to check token. Marking as needing refresh." return $false } "hello" } #EndRegion '.\Public\Test-GoogleAccessToken.ps1' 26 #Region '.\Public\Test-GraphAcessToken.ps1' 0 <# .DESCRIPTION This cmdlet is tests to see if the passed variable is not null, and expires in less than 10 minutes .PARAMETER token The current access tokenb variable #> function Test-GraphAcessToken{ [CmdletBinding()] param( [Parameter()][System.Object]$token ) if(!$token){ return $false } $expiryTime = $token.ExpiresOn - (Get-Date) if($expiryTime.Minutes -lt 10){ return $false } else{ return $true } } #EndRegion '.\Public\Test-GraphAcessToken.ps1' 23 #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 #Region '.\Public\Update-TopdeskAsset.ps1' 0 <# .DESCRIPTION This cmdlet will update an asset .PARAMETER unid The unid of the asset that we want to update .PARAMETER update A hashtabe of the values for the change .EXAMPLE #> function Update-TopdeskAsset(){ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$unid, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][hashtable]$update ) # Confirm we have a valid graph token if(!$global:topdeskAccessToken){ throw "Please Call Connect-Topdesk before calling this cmdlet" } # Base URI for subcategory data $uri = "https://$($global:topdeskEnvironment).topdesk.net/tas/api/assetmgmt/assets/$($unid)" try{ $results = Invoke-RestMethod -Method Post -Uri $uri -Headers $global:topdeskAccessToken -body ($update | ConvertTo-Json) -StatusCodeVariable statusCode } catch{ throw $Error[0] } return $results } #EndRegion '.\Public\Update-TopdeskAsset.ps1' 30 |