diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fd72bb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +~*.pptx \ No newline at end of file diff --git a/BenReader/AAD_Dynamic_Groups/01.AADGraphCode.ps1 b/BenReader/AAD_Dynamic_Groups/01.AADGraphCode.ps1 new file mode 100644 index 0000000..24f7bb2 --- /dev/null +++ b/BenReader/AAD_Dynamic_Groups/01.AADGraphCode.ps1 @@ -0,0 +1,131 @@ +#region params +$result = [System.Collections.ArrayList]::new() +$appName = "Notepad++" +$encodedAppName = [System.Web.HttpUtility]::UrlEncode($appName) +$groupId = 'd20a418e-a00f-47a5-a8ed-e12a9d98f83a' +$baseGraphUri = 'https://graph.microsoft.com/beta' +$env:appId = '' +$env:secret = '' +$env:tenant = '' + +$cred = (New-Object System.Management.Automation.PSCredential $env:appId, ($env:secret | ConvertTo-SecureString -AsPlainText -Force)) +Connect-AzAccount -ServicePrincipal -Credential $cred -Tenant $env:tenant | Out-Null +$token = (Get-AzAccessToken -ResourceUrl 'https://graph.microsoft.com').Token +$script:authHeader = @{Authorization = "Bearer $token" } +#endregion + +#region functions +function Invoke-GraphCall { + [cmdletbinding()] + param ( + [parameter(Mandatory = $false)] + [ValidateSet('Get', 'Post', 'Delete')] + [string]$Method = 'Get', + + [parameter(Mandatory = $false)] + [hashtable]$Headers = $script:authHeader, + + [parameter(Mandatory = $true)] + [string]$Uri, + + [parameter(Mandatory = $false)] + [string]$ContentType = 'Application/Json', + + [parameter(Mandatory = $false)] + [hashtable]$Body + ) + try { + $params = @{ + Method = $Method + Headers = $Headers + Uri = $Uri + ContentType = $ContentType + } + if ($Body) { + $params.Body = $Body | ConvertTo-Json -Depth 20 + } + $query = Invoke-RestMethod @params + return $query + } + catch { + Write-Warning $_.Exception.Message + } +} +function Format-Result { + [cmdletbinding()] + param ( + [parameter(Mandatory = $true)] + [string]$DeviceID, + + [parameter(Mandatory = $true)] + [string]$DeviceName, + + [parameter(Mandatory = $true)] + [bool]$IsCompliant, + + [parameter(Mandatory = $true)] + [bool]$IsMember, + + [parameter(Mandatory = $true)] + [ValidateSet('Added', 'Removed', 'NoActionTaken')] + [string]$Action + ) + $result = [PSCustomObject]@{ + DeviceID = $DeviceID + DeviceName = $DeviceName + IsCompliant = $IsCompliant + IsMember = $IsMember + Action = $Action + } + return $result +} +#endregion + +#region Get existing group members +$graphUri = "$baseGraphUri/groups/$groupId/members" +$groupMembers = Invoke-GraphCall -Uri $graphUri +#endregion + +#region Get devices with notepad++ installed +$detectedAppsBaseUri = "$baseGraphUri/deviceManagement/detectedApps" +$daItem = (Invoke-GraphCall -Uri "$($detectedAppsBaseUri)?`$filter=(contains(displayName,'$([System.Web.HttpUtility]::UrlEncode($encodedAppName))'))").value +if ($daItem.deviceCount -gt 0) { + $detectedDevices = (Invoke-GraphCall -Uri "$detectedAppsBaseUri/$($daItem.id)/managedDevices").value | Select-Object id, deviceName + foreach ($device in $detectedDevices) { + #region Swap the detected device for Intune + AAD object from Intune object + $intuneDevice = Invoke-GraphCall -Uri "$baseGraphUri/deviceManagement/managedDevices/$($device.id)" + $aadDevice = (Invoke-GraphCall -Uri "$baseGraphUri/devices?`$filter=(deviceId eq '$($intuneDevice.azureADDeviceId)')").value + $device | Add-Member -MemberType NoteProperty -Name "deviceId" -Value $aadDevice.deviceId + #endregion + #region add devices + if ($groupMembers.value.deviceId -notcontains $aadDevice.deviceId) { + #region Device not in group and has software + $graphUri = "$baseGraphUri/groups/$groupId/members/`$ref" + $body = @{"@odata.id" = "$baseGraphUri/directoryObjects/$($aadDevice.id)" } + Invoke-GraphCall -Uri $graphUri -Method Post -Body $body + $result.Add($(Format-Result -DeviceId $device.deviceId -DeviceName $device.deviceName -IsCompliant $true -IsMember $true -Action Added)) | Out-Null + #endregion + } + else { + #region device is compliant and already a member + $result.Add($(Format-Result -DeviceId $device.deviceId -DeviceName $device.deviceName -IsCompliant $true -IsMember $true -Action NoActionTaken)) | Out-Null + #endregion + } + #endregion + } + #region Remove devices + $devicesToRemove = $groupMembers.value | Where-Object { $_.deviceId -notIn $detectedDevices.deviceId} + if ($devicesToRemove.count -gt 0) { + foreach ($dtr in $devicesToRemove){ + #region Device found in group, but doesnt have software. + $graphUri = "$baseGraphUri/groups/$groupId/members/$($dtr.id)/`$ref" + Invoke-GraphCall -Uri $graphUri -Method Delete + $result.Add($(Format-Result -DeviceId $dtr.deviceId -DeviceName $dtr.displayName -IsCompliant $false -IsMember $false -Action Removed)) | Out-Null + #endregion + } + + } + #endregion +} +#endregion +$result \ No newline at end of file diff --git a/BenReader/AAD_Dynamic_Groups/02.SimpleExplanation.http b/BenReader/AAD_Dynamic_Groups/02.SimpleExplanation.http new file mode 100644 index 0000000..b4e960f --- /dev/null +++ b/BenReader/AAD_Dynamic_Groups/02.SimpleExplanation.http @@ -0,0 +1,37 @@ +@baseGraphUri = https://graph.microsoft.com/beta +@groupId = d20a418e-a00f-47a5-a8ed-e12a9d98f83a + + +### Get the current members of the security group +GET {{baseGraphUri}}/groups/{{groupId}}/members HTTP/1.1 +Authorization: Bearer 123... + +### Find the detected app +GET {{baseGraphUri}}/deviceManagement/detectedApps?$filter=(displayname, 'notepad++') HTTP/1.1 +Authorization: Bearer 123... + +### Get the devices from the detected app +GET {{baseGraphUri}}/deviceManagement/detectedApps/{{detectedAppID}}/managedDevices HTTP/1.1 +Authorization: Bearer 123... + +# Iterate through each device and get the data we need: +### Intune Device +GET {{baseGraphUri}}/deviceManagement/detectedApps/{{detectedAppID}}/managedDevices/{{IntuneID}} HTTP/1.1 +Authorization: Bearer 123... + +### AAD Device ID +GET {{baseGraphUri}}/devices?$filter=(deviceId eq '{{IntuneDeviceAadDeviceId}}') HTTP/1.1 +Authorization: Bearer 123... + +# Now we have all the data. do the logic +### Add to group +POST {{baseGraphUri}}/groups/{{groupId}}/members/$ref HTTP/1.1 +Authorization: Bearer 123... + +{ + "@odata.id": "$baseGraphUri/directoryObjects/{{AADDeviceID}})" +} + +### OR Delete from group +DELETE {{baseGraphUri}}/groups/{{groupId}}/members/{{AADDeviceId}}/$ref HTTP/1.1 +Authorization: Bearer 123.. \ No newline at end of file diff --git a/BenReader/AAD_Dynamic_Groups/99.AadMsiRoles.ps1 b/BenReader/AAD_Dynamic_Groups/99.AadMsiRoles.ps1 new file mode 100644 index 0000000..eb3422a --- /dev/null +++ b/BenReader/AAD_Dynamic_Groups/99.AadMsiRoles.ps1 @@ -0,0 +1,98 @@ +Connect-AzAccount -UseDeviceAuthentication +$script:token = (Get-AzAccessToken -ResourceUrl 'https://graph.microsoft.com').Token + +#region functions +function Add-GraphApiRoleToMSI { + [cmdletbinding()] + param ( + [parameter(Mandatory = $true)] + [string]$ApplicationName, + + [parameter(Mandatory = $true)] + [string[]]$GraphApiRole + ) + + $baseUri = 'https://graph.microsoft.com/v1.0/servicePrincipals' + $graphAppId = '00000003-0000-0000-c000-000000000000' + $spSearchFiler = '"displayName:{0}" OR "appId:{1}"' -f $ApplicationName, $graphAppId + + try { + $msiParams = @{ + Method = 'Get' + Uri = '{0}?$search={1}' -f $baseUri, $spSearchFiler + Headers = @{Authorization = "Bearer $script:token"; ConsistencyLevel = "eventual" } + } + $spList = (Invoke-RestMethod @msiParams).Value + $msiId = ($spList | Where-Object { $_.displayName -eq $applicationName }).Id + $graphId = ($spList | Where-Object { $_.appId -eq $graphAppId }).Id + $msiItem = Invoke-RestMethod @msiParams -Uri "$($baseUri)/$($msiId)?`$expand=appRoleAssignments" + + $graphRoles = (Invoke-RestMethod @msiParams -Uri "$baseUri/$($graphId)/appRoles").Value | + Select-Object AllowedMemberTypes, id, value + foreach ($role in $GraphApiRole) { + $roleItem = $graphRoles | Where-Object { $_.value -eq $role } + if ($roleItem.id -notIn $msiItem.appRoleAssignments.appRoleId) { + Write-Host "Adding role ($($roleItem.value)) to identity: $($applicationName).." + $params = @{ + managedIdentityId = $msiId + graphId = $graphId + apiRoleId = $roleItem.id + token = $script:token + } + Send-RoleToMSI @params + } + else { + Write-Host "role ($($roleItem.value)) already found in $($applicationName).." + } + } + + } + catch { + Write-Warning $_.Exception.Message + } + +} +function Send-RoleToMSI { + [cmdletbinding()] + param ( + [parameter(Mandatory = $true)] + [string]$managedIdentityId, + + [parameter(Mandatory = $true)] + [string]$graphId, + + [parameter(Mandatory = $true)] + [string]$apiRoleId, + + [parameter(Mandatory = $true)] + [string]$token + ) + try { + $baseUri = 'https://graph.microsoft.com/v1.0/servicePrincipals' + $body = @{ + "principalId" = $managedIdentityId + "resourceId" = $graphId + "appRoleId" = $apiRoleId + } | ConvertTo-Json + $restParams = @{ + Method = "Post" + Uri = "$baseUri/$($graphId)/appRoleAssignedTo" + Body = $body + Headers = @{Authorization = "Bearer $script:token" } + ContentType = 'Application/Json' + } + $roleRequest = Invoke-RestMethod @restParams + return $roleRequest + } + catch { + Write-Warning $_.Exception.Message + } +} +#endregion + +$roles = @( + "GroupMember.ReadWrite.All" + "Device.Read.All" + "DeviceManagementManagedDevices.Read.All" + ) +Add-GraphApiRoleToMSI -ApplicationName "PSCONFEU2022-AADDEMO" -GraphApiRole $roles diff --git a/BenReader/AAD_Dynamic_Groups/NewFunctionApp.mp4 b/BenReader/AAD_Dynamic_Groups/NewFunctionApp.mp4 new file mode 100644 index 0000000..c150298 Binary files /dev/null and b/BenReader/AAD_Dynamic_Groups/NewFunctionApp.mp4 differ diff --git a/BenReader/AAD_Dynamic_Groups/PSCONFEU22_BenReader.1.pptx b/BenReader/AAD_Dynamic_Groups/PSCONFEU22_BenReader.1.pptx new file mode 100644 index 0000000..6f6850e Binary files /dev/null and b/BenReader/AAD_Dynamic_Groups/PSCONFEU22_BenReader.1.pptx differ diff --git a/BenReader/PowerShell_Intune_Measure_Once/PSCONFEU22_Ben-Steve.pptx b/BenReader/PowerShell_Intune_Measure_Once/PSCONFEU22_Ben-Steve.pptx new file mode 100644 index 0000000..beebdce Binary files /dev/null and b/BenReader/PowerShell_Intune_Measure_Once/PSCONFEU22_Ben-Steve.pptx differ diff --git a/BenReader/PowerShell_Intune_Measure_Once/demo1.ps1 b/BenReader/PowerShell_Intune_Measure_Once/demo1.ps1 new file mode 100644 index 0000000..06c1d78 --- /dev/null +++ b/BenReader/PowerShell_Intune_Measure_Once/demo1.ps1 @@ -0,0 +1,5 @@ +. wt + +#region CHEAT SHEET +Build-IntuneConfigReport -Tenant Intune.training -OutputFolder "C:\data\reports\" +#endregion \ No newline at end of file diff --git a/BenReader/PowerShell_Intune_Measure_Once/demo2.ps1 b/BenReader/PowerShell_Intune_Measure_Once/demo2.ps1 new file mode 100644 index 0000000..6e94d9a --- /dev/null +++ b/BenReader/PowerShell_Intune_Measure_Once/demo2.ps1 @@ -0,0 +1,22 @@ +$baseUri = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts" +$token = Get-MsalToken -TenantId 'intune.training' -ClientId "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" -DeviceCode + +#region list all the scripts +$header = @{ Authorization = $token.CreateAuthorizationHeader() } +$params = @{ + Method = "Get" + Uri = "$baseUri" + Headers = $header + ContentType = 'Application/Json' +} +$result = Invoke-RestMethod @params +$result.value +#endregion + +#region get the script fron the policy +$scriptId = ($result.value | Where-Object { $_.displayName -eq 'VeryImportantScript'}).id +$scriptUri = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/$scriptId" +$scriptContent = (Invoke-RestMethod @params -Uri $scriptUri).scriptContent +$decodedContent = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("$($scriptContent)")) +$decodedContent +#endregion \ No newline at end of file diff --git a/BenReader/PowerShell_Intune_Measure_Once/demo3.0.ps1 b/BenReader/PowerShell_Intune_Measure_Once/demo3.0.ps1 new file mode 100644 index 0000000..f2627c2 --- /dev/null +++ b/BenReader/PowerShell_Intune_Measure_Once/demo3.0.ps1 @@ -0,0 +1,56 @@ +Connect-AzAccount +$baseUri = "https://graph.microsoft.com/beta/deviceManagement/auditEvents" +$token = Get-MsalToken -TenantId 'intune.training' -ClientId "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" -DeviceCode + +#region Look at all "PowerShell" create events +$alertFilter = "?`$filter=(activityOperationType eq 'Create' and activityType eq 'createDeviceManagementScript DeviceManagementScript')" +$header = @{ Authorization = $token.CreateAuthorizationHeader() } +$params = @{ + Method = "Get" + Uri = "$($baseUri)$alertFilter" + Headers = $header + ContentType = 'Application/Json' +} +$result = Invoke-RestMethod @params +$result.value +#endregion + +#region show me scripts added by the intern in the last day +$dateRange = [datetime]::now.AddDays(-1).ToUniversalTime().ToString("yyyy-MM-dd") +$alertFilter = "?`$filter=(activityOperationType eq 'Create' and activityType eq 'createDeviceManagementScript DeviceManagementScript' and activityDateTime gt $dateRange)" +$result = Invoke-RestMethod @params -Uri "$($baseUri)$alertFilter" +$naughtyScript = $result.value | Where-Object { $_.actor.userPrincipalName -eq "ben@intune.training" } +$scriptId = $naughtyScript.resources.resourceId +#endregion + +#region get the script fron the policy +$scriptUri = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/$scriptId" +$scriptContent = Invoke-RestMethod @params -Uri $scriptUri +$decodedContent = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("$($scriptContent)")) +$decodedContent +#endregion + +#region get the scripts fron the policy +foreach ($script in $naughtyScript){ + $scriptUri = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/$($script.resources.resourceId)" + $params = @{ + Method = "Get" + Uri = $scriptUri + Headers = $header + ContentType = 'Application/Json' + } + $scriptContent = (Invoke-RestMethod @params) + $decodedContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("$($scriptContent.scriptContent)")) + $tempFile = New-TemporaryFile + $decodedContent | Out-File $tempFile -Force -Encoding utf8 + + Write-Output "Getting storage context.." + $ctx = New-AzStorageContext -ConnectionString $env:AzureWebJobsStorage + Write-Output "Getting storage container.. $($env:AZURE_CONTAINER)" + $container = (Get-AzStorageContainer -Name $env:AZURE_CONTAINER -Context $ctx).CloudBlobContainer + Write-Output "uploading file.." + $result = Set-AzStorageBlobContent -File $tempFile -Blob $scriptContent.fileName -Container $container.Name -Context $ctx + $result + Send-TeamsMessage -ActorUpn $script.actor.userPrincipalName -ScriptDisplayName $scriptContent.displayName -UrlToScript $result.ICloudBlob.Uri.AbsoluteUri +} +#endregion \ No newline at end of file diff --git a/BenReader/PowerShell_Intune_Measure_Once/demo3.1.ps1 b/BenReader/PowerShell_Intune_Measure_Once/demo3.1.ps1 new file mode 100644 index 0000000..9f033d9 --- /dev/null +++ b/BenReader/PowerShell_Intune_Measure_Once/demo3.1.ps1 @@ -0,0 +1,157 @@ +using namespace System.Net + +# Input bindings are passed in via param block. +param($Request, $TriggerMetadata) + +#region config +$baseUri = "https://graph.microsoft.com/beta/deviceManagement/auditEvents" +$token = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com/").Token +$header = @{ Authorization = "Bearer $token" } +#endregion + +# Write to the Azure Functions log stream. +Write-Host "PowerShell HTTP trigger function processed a request." + +#region functions +function Send-TeamsMessage { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$ActorUpn, + + [Parameter(Mandatory = $true)] + [string]$ScriptDisplayName, + + [Parameter(Mandatory = $true)] + [string]$CreatedDate, + + [Parameter(Mandatory = $true)] + [string]$UrlToScript + ) + try { + $teamsUri = "https://intunetraining.webhook.office.com/webhookb2/ABCDEFG" + $json = @" + { + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "type": "AdaptiveCard", + "body": [ + { + "type": "Container", + "items": [ + { + "type": "TextBlock", + "size": "Large", + "weight": "Bolder", + "text": "Intune Script Creation Alert!!", + "style": "heading", + "color": "attention" + }, + { + "type": "TextBlock", + "text": "Script metadata below..", + "wrap": true + }, + { + "type": "FactSet", + "facts": [ + { + "title": "Uploaded by:", + "value": "$($ActorUpn)" + }, + { + "title": "Script Name:", + "value": "$($ScriptDisplayName)" + }, + { + "title": "Created date:", + "value": "$($CreatedDate)" + }, + { + "title": "Script contents:", + "value": "[$($UrlToScript)]($($UrlToScript))" + } + ] + } + ] + } + ], + "msteams": { + "width": "Full" + }, + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.2" + } + } + ] +} +"@ + + $restParams = @{ + Uri = $teamsUri + ContentType = "application/json" + Method = 'POST' + Body = $json + } + $null = Invoke-WebRequest @restParams + } + catch { + Write-Warning $_.Exception.Message + } + +} +#endregion + +#region find any scripts created in the last 24 hours + +#region show me scripts added by the intern in the last day +$dateRange = [datetime]::now.AddDays(-1).ToUniversalTime().ToString("yyyy-MM-dd") +$alertFilter = "?`$filter=(activityOperationType eq 'Create' and activityType eq 'createDeviceManagementScript DeviceManagementScript' and activityDateTime gt $dateRange)" +$params = @{ + Method = "Get" + Uri = "$($baseUri)$alertFilter" + Headers = $header + ContentType = 'Application/Json' +} +$result = Invoke-RestMethod @params +$naughtyScript = $result.value | Where-Object { $_.actor.userPrincipalName -eq "ben@intune.training" } +#endregion + +#region get the scripts fron the policy +foreach ($script in $naughtyScript){ + $scriptUri = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/$($script.resources.resourceId)" + $params = @{ + Method = "Get" + Uri = $scriptUri + Headers = $header + ContentType = 'Application/Json' + } + Write-Output "Getting script.." + $scriptContent = (Invoke-RestMethod @params) + $scriptContent | Format-List + $decodedContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("$($scriptContent.scriptCOntent)")) + $tempFile = New-TemporaryFile + $decodedContent | Out-File $tempFile -Force -Encoding utf8 + + Write-Output "Getting storage context.." + $ctx = New-AzStorageContext -ConnectionString $env:AzureWebJobsStorage + Write-Output "Getting storage container.. $($env:AZURE_CONTAINER)" + $container = (Get-AzStorageContainer -Name $env:AZURE_CONTAINER -Context $ctx).CloudBlobContainer + Write-Output "uploading file.." + $result = Set-AzStorageBlobContent -File $tempFile -Blob $scriptContent.fileName -Container $container.Name -Context $ctx -Force + $result | Format-List + Write-Output "sending teams notif.." + Send-TeamsMessage -ActorUpn $script.actor.userPrincipalName -ScriptDisplayName $scriptContent.displayName -CreatedDate $scriptContent.createdDateTime.ToString() -UrlToScript $result.ICloudBlob.Uri.AbsoluteUri +} +#endregion +#endregion + + +# Associate values to output bindings by calling 'Push-OutputBinding'. +Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = "cool." + }) diff --git a/BenReader/PowerShell_Intune_Measure_Once/obviousVirus.ps1 b/BenReader/PowerShell_Intune_Measure_Once/obviousVirus.ps1 new file mode 100644 index 0000000..b2e3228 --- /dev/null +++ b/BenReader/PowerShell_Intune_Measure_Once/obviousVirus.ps1 @@ -0,0 +1,2 @@ +write-host "hey siri, give the people what they want..." +start https://www.youtube.com/watch?v=szvt8iWJ0oo \ No newline at end of file