Non-Interactive - Get-MgUser : Insufficient privileges to complete the operation - powershell

I followed https://www.christianfrohn.dk/2022/04/23/connect-to-microsoft-graph-with-powershell-using-a-certificate-and-an-azure-service-principal/ to connect to Microsoft Graph but I'm getting the following error.
Get-MgUser -Top 1
> Get-MgUser : Insufficient privileges to complete the operation.
> At line:1 char:1
> + Get-MgUser -Top 1
> + ~~~~~~~~~~~~~~~~~
> + CategoryInfo : InvalidOperation: ({ ConsistencyLe...ndProperty = }: <>f__AnonymousType62`9) [Get-MgUser
> _List1], RestException`1
> + FullyQualifiedErrorId : > Authorization_RequestDenied,Microsoft.Graph.PowerShell.Cmdlets.GetMgUser_List1
From what I can tell I need to consent to the permissions. I found numerous sources for how to do this for interactive sessions but nothing said how to do this for non-interactive sessions.
I tried adding -Scopes to the connection string but got this error
Connect-MgGraph -ClientID [snip] -TenantId [snip] -CertificateThumbprint [snip] -Scopes 'User.Read.All'
> Connect-MgGraph : Parameter set cannot be resolved using the specified named parameters.
> At line:1 char:1
> + Connect-MgGraph -ClientID 19cb80c5-b355-42bc-a892-e73d11f57ef4 -Tenan ...
> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + CategoryInfo : InvalidArgument: (:) [Connect-MgGraph], ParameterBindingException
> + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.Graph.PowerShell.Authentication.Cmdlets.ConnectMgGraph
How do I do this?
EDIT
This is how I'm connecting
Connect-MgGraph -ClientId $clientId -TenantId $tenantId -CertificateThumbprint $thumbPrint
Welcome To Microsoft Graph!
API Permissions
Thanks

Your App Registration has the incorrect permissions. There are 2 types of permissions, delegated (aka scope), and application (aka role).
Reference: Permission types
For an "interactive" session, your app will be interacting on behalf of the user, therefore uses delegated permissions.
For a "non-interactive" session, your app will be acting as itself, so it needs application type permissions.
When connecting as an application ("non-interactive"), you also don't specify the -Scopes parameter

To identify the permissions needed to run a specific cmdlet of the microsoft.graph module you can use the find-mgGraphCommand cmdlet, e.g.:
(Find-MgGraphCommand -Command get-mguser).permissions
To identify which permissions are assigned to the current session you can use the get-mgcontext cmdlet, e.g.:
(get-mgcontext).scopes
If you run a interactive session you have to specify the scopes, e.g.:
Connect-MgGraph -Scopes user.read.all
To connect in the context of a service principal by using a certificate you can do:
#Get the certificate used as secret from the Windows certificate store
$cert = Get-ChildItem -Path 'Cert:\LocalMachine\MY' | ?{$_.thumbprint -eq $CertificateThumbprint}
#establish connection
connect-mggraph -certificate $cert -tenantid [tenantId] -clientId [clientId]
btw. clientId = objectId of the service principal

Related

Error on: Connect-MgGraph -AccessToken $token -Scopes "User.ReadWrite.All"

I'm able to connect if I do this:
Connect-MgGraph -AccessToken $token
Remove-MgUserMessage -UserId $email -MessageId $item.id
but I'm getting unauthorized errors when trying to delete an email.
I tried this as well:
Connect-MgGraph -AccessToken $token -Scopes "User.ReadWrite.All"
Remove-MgUserMessage -UserId $email -MessageId $item.id
But then I get this error:
Connect-MgGraph : Parameter set cannot be resolved using the specified named parameters.
At D:\Scripts\GraphAPITest2.ps1:159 char:1
+ Connect-MgGraph -AccessToken $token -Scopes "User.ReadWrite.All"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Connect-MgGraph], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.Graph.PowerShell.Authentication.Cmdlets.ConnectMgGraph
Is not allowed to combine the -AccessToken and the -Scopes parameter?
I've been told that I've been given Mail.ReadWrite and ServiceMessageViewpoint.Write privileges.
When using a token, is it supposed to get all the scopes from the token?
Or do you still have to tell the PowerShell program that your intent is to do an delete or update, and not just a read?
I've also posted this question about "Variants", but no reply yet: What are "variants" in Azure permissions
If you connect by using a AccessToken there is no need to specify the scopes, as those are already defined in the token. After you did establish a connection you can verify which permissions the current session has with:
(get-mgcontext).Scopes
Once you authenticate to get the accessToken in the first step ensure that you have:
Scope = 'https://graph.microsoft.com/.default'
in the body to automatically claim all permissions available to that identity.

PowerShell 5.1 What is wrong with my New-PSSession syntax

Environment:
PowerShell 5.1
Windows 2016 Standard
Windows 10 Pro
Just asking here if syntax is fundamentally correct...
$hostSession = New-PSSession -ComputerName $hostName -Credential $cred
$versionFolder = "c:\temp"
$sspLatestVer = Invoke-Command -Session $hostSession -ScriptBlock { param($path) (Get-ChildItem $path | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name } -ArgumentList $versionFolder
Update:
The following works on one machine but not on another:
$versionFolder = "\\COMPUTER01\c$\temp"
$sspLatestVer = (Get-ChildItem $versionFolder | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name
Error Message for machine that doesn't work
Get-ChildItem : Cannot find path '\\COMPUTER01\c$\temp' because it does not exist.
At C:\temp\candidate2.ps1:24 char:18
+ $sspLatestVer = (Get-ChildItem $versionFolder | Sort-Object LastWrite ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (\\COMPUTER01\c$\temp:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
OP Error Message:
New-PSSession : [COMPUTER01] Connecting to remote server COMPUTER01 failed with the following error message : WinRM cannot process the request. The following error with errorcode 0x80090311 occurred while using
Kerberos authentication: We can't sign you in with this credential because your domain isn't available. Make sure your device is connected to your organization's network and try again. If you previously signed in on
this device with another credential, you can sign in with that credential.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does not exist.
-The client and remote computers are in different domains and there is no trust between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
At C:\Users\RSTEST\Documents\candidate2.ps1:17 char:16
+ ... hostSession = New-PSSession -ComputerName $hostName -Credential $cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : AuthenticationFailed,PSSessionOpenFailed
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:\Users\RSTEST\Documents\candidate2.ps1:19 char:41
+ $sspLatestVer = Invoke-Command -Session $hostSession -ScriptBlock { p ...
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Invoke-Command], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.InvokeCommandCommand
Remove-PSSession : Cannot validate argument on parameter 'Name'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Users\RSTEST\Documents\candidate2.ps1:20 char:24
+ Remove-PSSession -Name $hostSession
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand
Two issues here:
First, see WinRM cannot process the request. Error 0x80090311
If the remote system is in the same domain, and you are already logged in with a domain account that is an administrator on that system, then there would be no need to specify a credential for New-PSSession
If the systems are in different forests that have a trust with each other, note that there is a need to use the fully qualified domain name (FQDN) of the remote host for Kerberos authentication to function correctly.
Second, regarding:
$versionFolder = "\\COMPUTER01\c$\temp"
Note that remote sessions normally do not have access to network shares, even when presumably running under the credentials of an administrative user.
This is known as the "second hop problem". There have been various posts about it:
https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/ps-remoting-second-hop?view=powershell-5.1
https://devblogs.microsoft.com/scripting/enable-powershell-second-hop-functionality-with-credssp/
This may work from COMPUTER01 itself, since it could be aliased to local drive access.

Is there a way to connect to New-CsOnlineSession using an oauth token?

I am looking for a way that I can run 'New-CsOnlineSession' from a web-app using an oauth token. The WebApp will be responsible for authenticating a user. This will use Microsoft Modern Authentication which will handle two factor authentication and consent.
I have registered an App in the Azure Portal and given the User Impersonation permission for Skype For Business Powershell Server Application.
How ever when I connect with a token that is obtained using the WebApp I get an error that the wrong audience is being used.
Below is the transcript from my powershell session. Once I have this working in powershell, the idea is that the WebApp will execute the powershell commands, so any way of doing this where PowerShell prompts for the credentials will not work.
PS C:\WINDOWS\system32> $token = ConvertTo-SecureString -String $oauthtoken -AsPlainText -Force
PS C:\WINDOWS\system32> $session = New-CsOnlineSession -OAuthAccessToken $token -Verbose
VERBOSE: OAuthAccessToken is provided.
VERBOSE: Determining domain to administer
VERBOSE: AdminDomain = 'mydomain.onmicrosoft.com'
VERBOSE: Discovering PowerShell endpoint URI
VERBOSE: TargetUri = 'https://admin2e.online.lync.com/OcsPowershellOAuth'
VERBOSE: AuthUri = 'https://login.windows.net/common/oauth2/authorize', ClientId = 7716031e-6f8b-45a4-b82b-922b1af0fbb4
VERBOSE: Validating authentication token.
New-CsOnlineSession : OAuthAccessToken has invalid audience https://teamsconfigapi-int.trafficmanager.net, expected https://admin2e.online.lync.com/OcsPowershellOAuth.
At line:1 char:12
+ $session = New-CsOnlineSession -OAuthAccessToken $token -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,New-CsOnlineSession
Could you try setting the -OverrideAccessTokenResourceUri to the specified URL.

powershell returned an error:(403) WebException using New-pnpList

I had my PS script running the other day and created a new list with a single field with no issues. Was able to view the list in the Site Contents lib.
Today, it's not working. I tried running the PS code below and then resorted to running the new-pnplist code at the command line...got the same error which is shown below.
I'm using the Global admin account. Using version 3.13.19 SharePointPNPPowerShellOnline. Executed the commands from Powershell ISE which is what I did the other day when it worked. And, I was able to connect successfully using the Connect-sposervice command.
Error:
new-pnplist -Template GenericList -Title 'TestPNP2'
new-pnplist : The remote server returned an error: (403) Forbidden.
At line:1 char:1
+ new-pnplist -Template GenericList -Title $ListName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [New-PnPList], WebException
+ FullyQualifiedErrorId : EXCEPTION,SharePointPnP.PowerShell.Commands.Lists.NewList
Code:
$TargetListURL="https://<my sharepoint.com>/sites/CKCDemo"
$ListName="TESTPNP2"
Connect-PnPOnline -url $TargetListURL -CurrentCredentials
New-PnPList -Template GenericList -Title $ListName
Add-PnPField -List $ListName -DisplayName "MyTEST" -InternalName "MyTEST" -Type Text -AddToDefaultView
Get-PnPList`
Make sure you have enough permission to create a list in this site. You could try to go to the site directly, check whether you could create a list through ui.
Note: A global admin will not automatically have access to individual sites unless explicitly granted.

Azure runbook powershell script to copy all webapp settings

I am trying to run the following script as a runbook to copy all settings from one webapp to another but I get the following error.
try
{
$acct = Get-AzureRmSubscription
}
catch
{
Login-AzureRmAccount
}
$fromResourceGroup = 'resourceG1'
$fromSite = 'website1'
$toResourceGroup = 'resourceG2'
$toSite = 'website2'
$props = (Invoke-AzureRmResourceAction -ResourceGroupName $fromResourceGroup -ResourceType Microsoft.Web/sites/Config -Name $fromSite/appsettings -Action list -ApiVersion 2015-08-01 -Force).Properties
$hash = #{}
$props | Get-Member -MemberType NoteProperty | % { $hash[$_.Name] = $props.($_.Name) }
Set-AzureRMWebApp -ResourceGroupName $toResourceGroup
-Name $toSite -AppSettings $hash
exception:
Get-Member : You must specify an object for the Get-Member cmdlet.
At line:18 char:10
+ $props | Get-Member -MemberType NoteProperty | % { $hash[$_.Name] = $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-Member], InvalidOperationException
+ FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand
Set-AzureRMWebApp : The term 'Set-AzureRMWebApp' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At line:20 char:1
+ Set-AzureRMWebApp -ResourceGroupName $toResourceGroup
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Set-AzureRMWebApp:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
-Name : The term '-Name' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:21 char:9
+ -Name $toSite -AppSettings $hash
+ ~~~~~
+ CategoryInfo : ObjectNotFound: (-Name:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
An Automation Runbook use a different strategy for login, so you should not just copy a PowerShell script to a Runbook and expect it run exactly the same way as you run locally.
You see that the command Login-AzureRmAccount will popup a window asking for user name and password. But, in an Automation Runbook, it can't. Hence, you need to do something else in order to properly login.
Create a new Active Direcotry User for your automation.
a. Log into the Azure Classic Portal.
b. Select Active Directory, and click your default Active Directory.
c. Click User, and click Add User. For Type of User, choose New user in your organization. It cannot be User with an existing Microsoft account, because it will fail when trying to login in a Runbook.
d. On the User Profile, for Roles, a Service administrator is good enough, but if you want, you can choose Global administrator. Do not Enable Multi-Factor Authentication. If you do, again, it will fail when trying to login in a Runbook.
e. Note the user’s full name and temporary password.
f. Back to the Classic Portal, Click Settings > Administrators > Add. Type in the user name you got above, and select your subscription.
g. Log out of Azure and then log back in with the account you just created. You will be prompted to change the user’s password.
Note: If you already have a "non-Microsoft" and MFA-disabled user account, you can skip this step. For more information, see Configuring Azure Automation
Create a PS credential asset for your Runbook.
a. Log into the Azure Portal, and choose your automation.
b. In your automation account setting blade, click Assets > Credential.
c. Click Add a credential, enter Name, User name, and Password (the user name and password you create in the previous step), and click Create.
Instead of simply using Login-AzureRmAccount, you should us the following to login.
$cred = Get-AutomationPSCredential -Name "<your credential name>"
Login-AzureRmAccount -Credential $cred
This error:
Get-Member : You must specify an object for the Get-Member cmdlet.
means that $props is null, since you are passing it to Get-Member. So
$props = (Invoke-AzureRmResourceAction -ResourceGroupName $fromResourceGroup -ResourceType Microsoft.Web/sites/Config -Name $fromSite/appsettings -Action list -ApiVersion 2015-08-01 -Force).Properties
is evaluating to null for some reason.
This is probably because you are not authenticating to Azure correctly. Please see https://azure.microsoft.com/en-us/blog/azure-automation-authenticating-to-azure-using-azure-active-directory/ and https://azure.microsoft.com/en-us/blog/announcing-azure-resource-manager-support-azure-automation-runbooks/ for more info.