Problem with returning only subset of machines from Microsoft Defender ATP through API call using filter - powershell

I'm trying to get a subset of machines from Microsoft Defender ATP through API calls using OData $filter queries following Microsoft's instructions (https://learn.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/exposed-apis-odata-samples) but regardless of what I do, I'm getting the same full set of machines which limits at 10,000.
So, some reason my following codes is not working as it should. What am I doing wrong? Also, how do I get more than 10,000 machines?
I removed tenantId, appId, and appSecret variables from the code below.
UPDATE:
I noticed that when I check the value of $machinesUrl2 variable in the PowerShell ISE after running the script, it shows that "$filter" is missing from the URI. The following is the output of variable $machinesUrl2:
https://api.securitycenter.windows.com/api/machines?=healthStatus+eq+'Inactive'
What is causing the drop of "$filter"? is this normal behavior?
Thanks,
$resourceAppIdUri = 'https://securitycenter.onmicrosoft.com/windowsatpservice'
$oAuthUri = "https://login.windows.net/$TenantId/oauth2/token"
$authBody = [Ordered] #{
resource = "$resourceAppIdUri"
client_id = "$appId"
client_secret = "$appSecret"
grant_type = 'client_credentials'
}
$authResponse = Invoke-RestMethod -Method Post -Uri $oAuthUri -Body $authBody -ErrorAction Stop
$aadToken = $authResponse.access_token
$machinesUrl2 = "https://api.securitycenter.windows.com/api/machines?$filter=healthStatus+eq+'Inactive'"
$headers = #{
'Content-Type' = 'application/json'
Accept = 'application/json'
Authorization = "Bearer $aadToken"
}
$machinesResponse = Invoke-WebRequest -Method Get -Uri $machinesUrl2 -Headers $headers -ErrorAction Stop
$machines = ($machinesResponse | ConvertFrom-Json).value

I found the answer while trying to figure out why the $filter was getting dropped out of the query string.
It needed to have a back-tick character (`) added to in front of the "$filter".
https://api.securitycenter.windows.com/api/machines?`$filter=healthStatus+eq+'Inactive'
After adding this character to the query string, the code on this Microsoft documentation started to work.

Related

how to access sharepoint folder using graph api

In my SharePoint site Document Library, I have a folder called OneDriveInventory and I have a few file inside.
I'm trying to access those file but it look like my Uri request is wrong so I would be really appreciated I can get any help or suggestion on how to fix this.
Invoke-WebRequest -Uri "https://graph.microsoft.com/v1.0/sites/$siteId/drives/$driveId/OneDriveInventory/$($filename)" -Method GET -OutFile $filePath -Headers $headers
I tried to reproduce the same in my environment and got below results:
I have one SharePoint document library in which I created folder named OneDriveInventory and added files like below:
You can make use of below Graph API call to access file in the above folder:
GET https://graph.microsoft.com/v1.0/sites/<siteID>/drives/<driveID>/root:/OneDriveInventory:/children/<filename>
When I ran the above query in Graph Explorer, I got results successfully like below:
To get the same results from PowerShell, I registered one Azure AD application and added API permissions like below:
Now I generated access token using below PowerShell script:
$tenantId = <tenantID>
$applicationId = <appID>
$secret= <secret>
$param = #{
Uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token";
Method = 'Post';
Body = #{
grant_type = 'client_credentials';
scope = 'https://graph.microsoft.com/.default';
client_id = $applicationId;
client_secret = $secret
}
}
$result = Invoke-RestMethod #param
$token = $result.access_token
Response:
To access file from folder, I used below PowerShell script:
$siteID = "3b23b598-f5e4-461f-b038-xxxxxx"
$driveID = "xxxxxxxxxxxxxxxxxxx"
$filename = "sridevi.txt"
$headers=#{}
$headers.Add("Content-Type", "text/plain")
$headers.Add("Authorization", "Bearer $token")
$response=Invoke-WebRequest -Uri "https://graph.microsoft.com/v1.0/sites/$siteID/drives/$driveID/root:/OneDriveInventory:/children/$($filename)" -Method GET -OutFile $filePath -Headers $headers
Response:
When I ran $response.Content, I got full response like below:

Get SPO sites using MS Graph API powershell not working

I'm trying to get all SharePoint Online sites' name and url via PowerShell using MS Graph API, but it's not seem to be working. That's all I get from the request:
#{#odata.context=https://graph.microsoft.com/v1.0/$metadata#sites; value=System.Object[]}
The application I use have all the needed Application type API permissions (Sites.Read, Sites.ReadWrite.All) with admin consent.
Do you have any idea why my script not working?
The code:
$TenantID = 'xxxxxxxxx.ONMICROSOFT.COM'
$ApplicationId = "xxxxx-xxxxxx-xxxx-xxxx"
$ApplicationSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$body = #{
'resource' = 'https://graph.microsoft.com'
'client_id' = $ApplicationId
'client_secret' = $ApplicationSecret
'grant_type' = "client_credentials"
'scope' = "openid"
}
$ClientToken = Invoke-RestMethod -Method post -Uri "https://login.microsoftonline.com/$($tenantid)/oauth2/token" -Body $body -ErrorAction Stop
$headers = #{ "Authorization" = "Bearer $($ClientToken.access_token)" }
$AllSites = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/sites?search=*" -Headers $headers -Method Get
Write-Host $AllSites
I've also tried these URIs:
https://graph.microsoft.com/v1.0/sites?search=*
https://graph.microsoft.com/v1.0/sites
https://graph.microsoft.com/v1.0/sites$select=siteCollection,webUrl&$filter=siteCollection/root%20ne%20null
The Write-Host cmdlet's primary purpose is to produce
for-(host)-display-only output, such as printing colored text like
when prompting the user for input in conjunction with Read-Host.
Write-Host uses the ToString() method to write the output. By
contrast, to output data to the pipeline, use Write-Output or implicit
output.
reference
This mean that your output is transformed for display purposes. Where you see System.Object[], there is actually data in there just waiting for you.
Based on your current results, your query look good.
Just do not use Write-Host and dig into the object as needed.
To get the site names, just use $AllSites.Value.Name
$AllSites = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/sites?search=*" -Headers $headers -Method Get
# Return site names
$AllSites.Value.Name
If you need to get additional information from each return you can loop into them, like this to do whatever you need. Here is a custom display of the site name along with an arbitrary index and the associated URL
$index = 0
# Will display results like
# 0: SiteName - www.contoso.sharepoint.com/SiteUrl
foreach ($Site in $AllSites.Value) {
Write-Host "$($index.ToString().PadRight(3,' ')): $($Site.Name) - " -NoNewline
Write-Host $site.webUrl -ForegroundColor Cyan
$index += 1
}
Also, here is an additional reference when working with Azure Graph API that will confirm your requests are working as expected: https://developer.microsoft.com/en-us/graph/graph-explorer

Correct body contents to create a mobileAppContentFile resource using the MsGraph REST API?

I'm attempting to automate the update process for a Line-of-Business app in Intune.
Here is my current code:
function New-AppContentFile {
param(
[Parameter(Mandatory=$true)][System.String]$AppId,
[Parameter(Mandatory=$true)][System.String]$AppContentId
)
$Uri = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/8dda54ec-992a-478d-984a-260cd59c1c33/microsoft.graph.mobileLobApp/contentVersions/1/files"
$script:ReqBody = [ordered]#{
"#odata.type" = "#microsoft.graph.mobileAppContentFile"
"name" = "google.msi"
"size" = 4
"sizeEncrypted" = 13
"manifest" = $null
"isCommitted" = $false
} | ConvertTo-Json
$header = #{
Authorization = "Bearer $($token.AccessToken)"
"content-length" = $ReqBody.Length
"Accept" = "application/json"
}
Invoke-RestMethod -Uri $Uri -Headers $header -Method Post -Body $ReqBody -ContentType "application/json"
}
A few things that I've noticed when testing, the endpoint listed on the REST API is most likely incorrect. If I use a GET method on the following URL "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/8dda54ec-992a-478d-984a-260cd59c1c33/microsoft.graph.mobileLobApp/contentVersions/1/files" I will get a return. If I use the one mentioned in the REST API it returns a (400) Bad Request.
I've also tested numerous variations of the body to include all or some of the properties listed in the example request. Referencing the first of the two references listed below (Line 617), the body in theory should work as the following:
$ReqBody = [ordered]#{
"#odata.type" = "#microsoft.graph.mobileAppContentFile"
"name" = "google.msi"
"size" = 4
"sizeEncrypted" = 13
"manifest" = $null
}
In the example request, the "azureStorageUri" property is specified. In my case I can't specify that, this POST should generate the azureStorageUri so that I can upload the file to that storage endpoint.
I've used these two sources as a reference:
https://github.com/microsoftgraph/powershell-intune-samples/blob/master/LOB_Application/Application_LOB_Add.ps1
https://github.com/MSEndpointMgr/IntuneWin32App/blob/master/Public/Add-IntuneWin32App.ps1
And the following documentation from the Microsoft Graph REST API
https://learn.microsoft.com/en-us/graph/api/intune-apps-mobileappcontentfile-create?view=graph-rest-beta
I should also note that I have tested this with both the BETA and v1.0 of the MsGraph REST API.

Error when trying to use Power BI REST API - Invoke-RestMethod : A positional parameter cannot be found that accepts argument

Lately I've been trying to use Power BI REST API to make the refresh of a certain dataset automatically, by calling a .ps1 program. By following this tutorial, I was able to get this code, which is addapted as you can see below:
$groupID = "me" # the ID of the group that hosts the dataset. Use "me" if this is your My Workspace
$datasetID = "MYDATASETID" # the ID of the dataset that hosts the dataset
$clientId = "MYCLIENTID"
# Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD
function GetAuthToken
{
if(-not (Get-Module AzureRm.Profile)) {
Import-Module AzureRm.Profile
}
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://analysis.windows.net/powerbi/api"
$authority = "https://login.microsoftonline.com/common/oauth2/authorize";
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto")
return $authResult
}
$token = GetAuthToken
$authHeader = #{
'Content-Type'='application/json'
'Authorization'=$token.CreateAuthorizationHeader()
}
$groupsPath = ""
if ($groupID -eq "me") {
$groupsPath = "myorg"
} else {
$groupsPath = "myorg/groups/$groupID"
}
$uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes"
Invoke-RestMethod -Uri $uri –Headers $authHeader –Method POST –Verbose
$uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes"
Invoke-RestMethod -Uri $uri –Headers $authHeader –Method GET –Verbose
I made sure to collect the parameters (groupID, clientID and datasetID) exactly as specified in the links above. However, when I try to execute this code, I get back the error:
Invoke-RestMethod : A positional parameter cannot be found that accepts argument 'â€Headers System.Collections.Hashtable â€Method'.
At C:\Users\me\Desktop:41 char:1
I can't quite tell what's going on, and I even found some similar cases, but none of the solutions worked for me. So, some help would be deeply appreciated.
It looks like this solution is copy/pasted from somewhere and the dashes are screwed up:
Delete the last 3 dashes in Invoke-RestMethod, which looks like dashes, but are other looks like dash unicode symbols, and replace them with normal "typed by the keyboard" ones.
Hope this helps!

Use Azure Table SAS token to read data using Invoke-RestMethod

I'm wondering if it is possible to use a SAS token for the authorization header in a REST API call to Azure Tables using PowerShell. I've created a test Account SAS and tried passing the actual token value starting with the "sr=" tag and also the full URI however I'm getting the following error:
Invoke-RestMethod :
AuthenticationFailed
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
$resource = "$tableName(PartitionKey='$domain',RowKey='$apiKey')"
$tableUrl = "https://$storageAccount.table.core.windows.net/$resource"
$sasReadToken = "SharedAccessSignature ?sv=2017-07-29&ss=t&srt=o&sp=r&se=2019-03-07T02:37:08Z&st=2018-03-06T18:37:08Z&spr=https&sig=<removed>"
$GMTTime = (Get-Date).ToUniversalTime().toString('R')
$header = #{
Authorization = $sasReadToken;
'x-ms-date' = $GMTTime;
Accept = "application/json;odata=fullmetadata";
}
$result = Invoke-RestMethod -Uri $tableUrl -Headers $header -Method Get -Verbose
While I realize there is an AzureRm module to handle some of this, I don't want to install unnecessary libraries on the host PC. Is this even possible?
NOTE: The signature has been removed in my example.
SAS Tokens are not valid in the Authorization header. They are only valid as a collection of query string parameters.
See https://learn.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1 for more info about Azure Storage SAS tokens.
I was able to use my SAS as part of the URI to authenticate to the storage using the following code. Notice the SAS token is part of the $tableUri variable and not part of the header. I also had to add the Accept = 'application/json;odata=nometadata' parameter in the header otherwise I received a (415) error (Unsupported Media Type). Lastly, I had to add the -UseBasicParsing in PowerShell to read the data coming back.
function Get-MyAdvisorToken {
[cmdletbinding()]
param (
[parameter()]$MyAdvisorApiKey,
[parameter()]$DomainName
)
#retrieves SaSToken from Azure Table when supplying the API KEY and DOMAIN
$partitionKey = $DomainName #partitionKey
$rowKey = $MyAdvisorApiKey #rowKey
$sasReadToken = "?sv=2017-07-29&ss=t&srt=o&sp=r&se=2018-03-06T19:37:08Z&st=2018-03-06T18:37:08Z&spr=https&sig=<removed>"
$tableUri = "https://$storageAccount.table.core.windows.net/$tableName(PartitionKey='$partitionKey',RowKey='$rowKey')$sasReadToken"
$GMTTime = (Get-Date).ToUniversalTime().toString('R')
$header = #{
'x-ms-date' = $GMTTime;
Accept = 'application/json;odata=nometadata'
}
$result = Invoke-WebRequest -Uri $tableUri -Headers $header -UseBasicParsing
$jsonResult = $result.Content | ConvertFrom-Json
return $jsonResult
}