I am running into an strange issue building a Powershell script. I want to programatically connecto to Microsoft Teams and execute some skype for businesss online commands.
When I simply do on a terminal
Connect-MicrosoftTeam and get prompted and import my credentials, it all works perfectly, but i need to this programatically.
I did an app registration with the following permissions
And I am authenticating against Azure AD and Graph:
#Connect to Graph
$Body = #{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
client_Id = $ApplicationID
Client_Secret = $AccessSecret
}
$ConnectGraph = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenatDomainName/oauth2/v2.0/token" -Method POST -Body $Body
$token = $ConnectGraph.access_token
#Connect to AD
$uri = "https://login.microsoftonline.com/${tenant_id}/oauth2/token"
$body = #{grant_type='refresh_token';resource='https://graph.windows.net';client_id=$clientId;refresh_token=$refresh_token}
$result = Invoke-RestMethod -Method Post -Uri $uri -Body $body
$accessToken = $result.access_token
Then I run
Connect-MicrosoftTeams -AadAccessToken $accessToken -MsAccessToken $token -AccountId $account
And it doesn't throw an error, works properly. and i gen run commands like Get-Team and returns the info correctly. However when I try to run an skype command like
Get-CsOnlineVoiceUser
I get the error
Get-CsOnlineSession : Run Connect-MicrosoftTeams before running cmdlets.
At C:\Program Files\WindowsPowerShell\Modules\MicrosoftTeams\2.3.1\net472\SfBORemotePowershellModule.psm1:63 char:22
+ $remoteSession = & (Get-CsOnlineSessionCommand)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-CsOnlineSession], UnauthorizedAccessException
+ FullyQualifiedErrorId : UnauthorizedAccessException,Microsoft.Teams.ConfigApi.Cmdlets.GetCsOnlineSession
Invoke-Command : Cannot validate argument on parameter 'Session'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Program Files\WindowsPowerShell\Modules\MicrosoftTeams\2.3.1\net472\SfBORemotePowershellModule.psm1:10006 char:38
+ ... -Session (Get-PSImplicitRemotingSession -CommandName 'Get-CsOnline ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Invoke-Command], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.InvokeCommandCommand
Am I missing something? I am using the 2.3.1 Teams Module.
Thanks!
This is a bit tricky to do, but can be achieved.
I recommend reading this blog post for exact instructions and code examples:
https://paulobrien.co.nz/2020/06/29/s4b-online-powershell-modern-auth/
Should get you started.
Related
I'm trying to call a PowerBI GETinfo Scanner API using PowerShell. One of the requirements is to pass multiple workspaces to get the info. Here is the MS doc link :\
https://learn.microsoft.com/en-us/rest/api/power-bi/admin/workspace-info-post-workspace-info#example
However, I'm not able to pass below syntax for API body in PowerShell.
The below syntax to call multiple workspaces in API body is not working :
$auth_body =#{
"workspaces": [
"97d03602-4873-4760-b37e-1563ef5358e3",
"67b7e93a-3fb3-493c-9e41-2c5051008f24"
]
}
I'm only able to pass single workspace and below syntax works :
$auth_body =#{'workspaces' ="3b7e9b1c-bdac-4e46-a39d-1b3d24a0e122"}
Please help me to form the syntax for multiple workspaces. Seems I'm not able to form key value pair inside PowerShell for multiple workspaces
Updated Code after applying MathiasR.Jessen suggestion:
$authority = 'https://login.microsoftonline.com/oauth2/'+ $tenantID
$authResult = Get-AdalToken -Authority $authority -Resource $resourceAppIdURI -ClientID $UId -Clientsecret $password -TenantID $tenantID
$Token=$authResult.AccessToken
#Write-Output "Token: $Token"
$auth_header = #{
'Accept' = "application/json";
'Authorization' = 'Bearer ' +$Token
}
$auth_body = #{
"workspaces" =
#("50c4bd8e-fc75-433e-a0cd-755f9329515e","97d03602-4873-4760-b37e-1563ef5358e3")
}
$uri = "https://api.powerbi.com/v1.0/myorg/admin/workspaces/getInfo"
$all_workspace = (Invoke-RestMethod -Uri $uri –Headers $auth_header -Body $auth_body –Method Post)
And Error Message :
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
+ ... rkspace1 = (Invoke-RestMethod -Uri $uri –Headers $auth_header -Body $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
However, It works perfectly if I provide single workspace.
You're mixing PowerShell and JSON syntax.
To define an array in PowerShell, use the #() array subexpression operator:
$auth_body = #{
"workspaces" = #(
"97d03602-4873-4760-b37e-1563ef5358e3",
"67b7e93a-3fb3-493c-9e41-2c5051008f24"
)
}
I have been working with Powershell all day, playing with proxy settings and related. A POST request that once worked earlier in the day, is now stating a very bizarre error:
The request:
$tenantId = '8331e1..........'
$client_id = 'a3b869ef................
$client_secret = '0w;m$................'
#************ GET AAD TOKEN ************
$url = "https://login.microsoftonline.com/" + $tenantId + "/oauth2/token"
$body = #{
grant_type = 'client_credentials'
client_id = $client_id
client_secret = $client_secret
resource = 'https://dev.azuresynapse.net'
}
$GetAADResult = Invoke-WebRequest -Method 'Post' -Uri $url -Body $body
$GetAAD_Content_JSON = $GetAADResult.Content | ConvertFrom-Json
$access_token = $GetAAD_Content_JSON.access_token
# print access_token
$access_token
This used to provide a simple token as a response, but now it is returning the error:
Invoke-WebRequest : The remote name could not be resolved: 'http'
At line:24 char:17
+ ... GetAADResult = Invoke-WebRequest -Method 'Post' -Uri $url -Body $body
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : System.Net.WebException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
ConvertFrom-Json : Cannot bind argument to parameter 'InputObject' because it is null.
At line:26 char:48
+ $GetAAD_Content_JSON = $GetAADResult.Content | ConvertFrom-Json
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [ConvertFrom-Json], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
I do not know what needs to change to get this functionating again, it appears PowerShell is looking for a proxy setting in every request...? Anny ideas?
I ended up undoing these steps: https://spaghettidba.com/2017/12/19/recovering-the-psgallery-repository-behind-a-corporate-proxy/
That Powershell script intents to write to Google Sheets considering the user is already logged on his/her Google account on the Browser, but it throws the error System.Net.WebException. Message:
Invoke-WebRequest: The remote server returned an error: (401) Unauthorized.
In C:\Users\F76254C\Desktop\Nova pasta\Batch files\Available Projects\Latam HIL Lab Menu\libs\GAS.ps1:141 character:1
+ Invoke-WebRequest -UseBasicParsing -Uri $GoogleWebAppURL -Method POST ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
I tested this code using a Google Web App deployed with my personal Google account (Who has access to the app: Anyone) and it works fine with no error, but I need to make it working using a Google Web App deployed with my professional Google account (Who has access to the app: Anyone within the company).
$GoogleWebAppURL = 'URL_DEPLOYED_FROM_PROFESSIONAL_GOOGLE_ACCOUNT'
$Column1Name = 'Computer'
$Column1Value = $env:COMPUTERNAME
$Column2Name = 'IP Address'
$Column2Value = (Test-Connection -ComputerName ::1 -Count 1|select ipv4address).ipv4address
$Column3Name = 'OS Version'
$Column3Value = "$([System.Environment]::OSVersion.Version.Major)`.$([System.Environment]::OSVersion.Version.Minor)`.$([System.Environment]::OSVersion.Version.Build)`.$([System.Environment]::OSVersion.Version.Revision)"
$Column4Name = 'Uptime'
$Column4Value = (Get-CimInstance -ClassName win32_operatingsystem | select lastbootuptime).lastbootuptime
$postParams = #{$Column1Name=$Column1Value;$Column2Name=$Column2Value;$Column3Name=$Column3Value;$Column4Name=$Column4Value}
Invoke-WebRequest -UseBasicParsing -Uri $GoogleWebAppURL -Method POST -Body $postParams
Write-Host `"$Column1Name=$Column1Value"&"$Column2Name=$Column2Value"&"$Column3Name=$Column3Value"&"$Column4Name=$Column4Value`"
We have a PowerShell script which checks a service mailbox and updates our wallboards with information, then moves the relevant emails to the deleted folder. This was set up under API v1.0 which is now deprecated and we're needing to get it changed for version 2.0.
Unfortunately, this has led to a lot of confusion and a lot of scratched heads which isn't too fun. This has occurred mainly around getting an oAuth2 token then feeding it into the request for the mailbox.
So far, we've managed to get the Azure AD app registered and it's providing an authentication token, but that's coming back as unauthorised from Microsoft Graph.
# tenantID, clientSecret and clientID not here.
# The resource URI
$resource = "https://graph.microsoft.com"
# Your Client ID and Client Secret obainted when registering your WebApp
$redirectUri = "http://returnuri"
# UrlEncode the ClientID and ClientSecret and URL's for special characters
$clientIDEncoded = [System.Web.HttpUtility]::UrlEncode($ClientID)
$clientSecretEncoded = [System.Web.HttpUtility]::UrlEncode($clientSecret)
$redirectUriEncoded = [System.Web.HttpUtility]::UrlEncode($redirectUri)
$resourceEncoded = [System.Web.HttpUtility]::UrlEncode($resource)
$scopeEncoded = [System.Web.HttpUtility]::UrlEncode("https://outlook.office.com/user.readwrite.all")
$body = #"
client_id=$ClientID
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=$clientSecretEncoded
&grant_type=client_credentials
"#
$userid = 'userID'
$accessToken = Invoke-RestMethod "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method Post -Body $body
#
#$cred = $(Get-Credential)
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users/$userid/messages" -Headers #{Authorization = "Bearer $($accessToken.access_token)"} -Credential $cred
Expected results: access to the mailbox.
Actual results:
Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.
At line:32 char:1
+ Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users/$useri ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I am trying run an simple script on Azure VM (Windows) via Invoke-AzureRmVMRunCommand and also via Invoke-RestMethod cmdlet.
Just trying to get the status of DHCP service.
Tried after restarting the VMs
Created a New VM to run the same script but same error
Tried running the invoke command from a different machine
Script stored in a test.ps1 file
Get-Service DHCP
Command:
Invoke-AzureRmVMRunCommand -ResourceGroupName $Resource_Group -VMName $Resource_Name -CommandId RunPowerShellScript -ScriptPath 'C:\Vincent\Azure\AzureVM\Test.ps1'
I even tried using Azure API but same error:
Command:
$Body = #"
{
"commandId": "RunPowerShellScript",
"script": [
"Get-Service DHCP"
]
}
"#
$AppID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$Key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$TenantId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$SubscriptionID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$GetToken = "https://login.microsoftonline.com/$TenantId/oauth2/token?tenant_id=$TenantId"
$Access_Token = Invoke-RestMethod -Method Post -Uri $GetToken -Body "grant_type=client_credentials&client_id=$AppID&client_secret=$Key&resource=$resource"
$Token = $Access_Token.access_token
$API = "https://management.azure.com/subscriptions/$SubscriptionID/resourceGroups/$Resource_Group/providers/Microsoft.Compute/virtualMachines/$VMName/runCommand?api-version=2017-03-30"
Invoke-RestMethod -Method Post -Uri $API -Headers #{Authorization = "Bearer $Token"} -Body $Body -ContentType 'application/json' -OutVariable Result
Error:
Invoke-AzureRmVMRunCommand:
Invoke-AzureRmVMRunCommand : The Resource
'Microsoft.Compute/virtualMachines/XXXXXXXX' under resource
group 'XXXXXX' was not found. ErrorCode: ResourceNotFound
ErrorMessage: The Resource
'Microsoft.Compute/virtualMachines/XXXXXXXX' under resource group
'XXXXXX' was not found. StatusCode: 404 ReasonPhrase: Not Found
OperationID : d5a9e664-92e2-45d6-b5e8-b3d5bd65814c At line:1 char:1
+ Invoke-AzureRmVMRunCommand -ResourceGroupName $Resource_Group -VMName ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Invoke-AzureRmVMRunCommand], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.Automation.InvokeAzureRmVMRunCommand
Error API:
Invoke-RestMethod : { "error": {
"code": "Conflict",
"message": "Run command extension execution is in progress. Please wait for completion before invoking a run command." } } At line:23
char:1
+ Invoke-RestMethod -Method Post -Uri $API -Headers #{Authorization = " ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod],
WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Invoke-AzureRmVMRunCommand Run command on the VM.
You will receive the error message when you have given wrong “ResourceGroupName”.
You may check the screenshot below: I have provided wrong resource group and changed to correct resource group gives the successful.
In case, if it shows Run command extension execution is in progress, you can check the operation from Azure Portal => Activity log:
You're getting a "resource not found" error:
Error: Invoke-AzureRmVMRunCommand:
Invoke-AzureRmVMRunCommand : The Resource
'Microsoft.Compute/virtualMachines/XXXXXXXX' under resource group
'XXXXXX' was not found. ErrorCode: ResourceNotFound ErrorMessage: The
Resource 'Microsoft.Compute/virtualMachines/XXXXXXXX' under resource
group 'XXXXXX' was not found. StatusCode: 404 ReasonPhrase: Not Found
OperationID : d5a9e664-92e2-45d6-b5e8-b3d5bd65814c At line:1 char:1 +
Invoke-AzureRmVMRunCommand -ResourceGroupName $Resource_Group -VMName
... +
+ CategoryInfo : CloseError: (:) [Invoke-AzureRmVMRunCommand], ComputeCloudException + FullyQualifiedErrorId :
Microsoft.Azure.Commands.Compute.Automation.InvokeAzureRmVMRunCommand
And then you're getting an error saying "You're running invoke-azurermvmruncommand", wait till that's completed:
Error API:
Invoke-RestMethod : { "error": { "code": "Conflict", "message": "Run
command extension execution is in progress. Please wait for completion
before invoking a run command." } } At line:23 char:1 +
Invoke-RestMethod -Method Post -Uri $API -Headers #{Authorization = "
... +
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod],
WebException + FullyQualifiedErrorId :
WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
run this to check if the VM is where it's supposed to be, and then your script:
get-azurermvm -resourcegroupname $Resource_Group -Name $Resource_Name
$file = "C:\Vincent\Azure\AzureVM\Test.ps1"
Invoke-AzureRmVMRunCommand -ResourceGroupName $Resource_Group -VMName $Resource_Name -CommandId RunPowerShellScript -ScriptPath $file
If that still doesn't work, please share with us $Resource_Name.GetType() and $Resource_Group.GetType()
You need to call Set-AzureRmContext before calling Invoke-AzureRmVMRunCommand, by setting the -SubscriptionName from the Virtual Machine's Subscription.