Powershell AzureAD App Registration Permissions New-AzureADApplication -RequiredResourceAccess - powershell

I am having a problem with the following code. I am trying to assign the following permissions to an App Registration in AzureAD using the -RequiredResourceAccess property from New-AzureADApplication. I keep getting an invalid value for $reqGraph?
Please help?
New-AzureADApplication : Error occurred while executing NewApplication
Code: Request_BadRequest Message: Invalid value specified for property
'resourceAppId' of resource 'RequiredResourceAccess'. RequestId:
5abf5ea5-8f94-4d14-8e8d-8f12a92bf3e5 DateTimeStamp: Mon, 17 May 2021
07:12:02 GMT Details: PropertyName - resourceAppId, PropertyErrorCode
InvalidValue HttpStatusCode: BadRequest HttpStatusDescription: Bad Request HttpResponseStatus: Completed
$appName = "Test" # Maximum 32 characters
$adalUrlIdentifier = "https://abc.dk/AADGuestLifecycleMgmt"
$appReplyUrl = "https://www.abc.dk"
$pwd = Read-Host -Prompt 'Enter a secure password for your certificate!'
$certStore = "Cert:\CurrentUser\My"
$currentDate = Get-Date
$endDate = $currentDate.AddYears(10) # 10 years is nice and long
$thumb = (New-SelfSignedCertificate -DnsName "abc.dk" -CertStoreLocation $certStore -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $endDate).Thumbprint
$thumb > cert-thumb.txt # Save to file
$pwd = ConvertTo-SecureString -String $pwd -Force -AsPlainText
Export-PfxCertificate -cert "$certStore\$thumb" -FilePath .\AzureADGuestLifecycleMgmt.pfx -Password $pwd
$path = (Get-Item -Path ".\").FullName
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("$path\AzureADGuestLifecycleMgmt.pfx", $pwd)
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
Install-Module AzureAD
Import-Module AzureAD
# Connect to Azure AD as an admin account
Connect-AzureAD
# Store tenantid
$tenant = Get-AzureADTenantDetail
$tenant.ObjectId > tenantid.txt
# Add AuditLog.Read.All access
$svcPrincipal = Get-AzureADServicePrincipal -All $true | ? { $_.DisplayName -match "Microsoft Graph" }
$appRole = $svcPrincipal.AppRoles | ? { $_.Value -eq "AuditLog.Read.All" }
$appPermission = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "$($appRole.Id)", "Role"
#Add Directory.ReadWrite.All access
$appRole2 = $svcPrincipal.AppRoles | ? { $_.Value -eq "Directory.ReadWrite.All" }
$appPermission2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "$($appRole2.Id)", "Role"
$reqGraph = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$reqGraph.ResourceAppId = $svcPrincipal.AppId
$reqGraph.ResourceAccess = $appPermission, $appPermission2
Write-Host $reqGraph
# Create Azure Active Directory Application (ADAL App)
$application = New-AzureADApplication -DisplayName "$appName" -IdentifierUris $adalUrlIdentifier -ReplyUrls $appReplyUrl -RequiredResourceAccess $reqGraph
New-AzureADApplicationKeyCredential -ObjectId $application.ObjectId -CustomKeyIdentifier "$appName" -Type AsymmetricX509Cert -Usage Verify -Value $keyValue -StartDate $currentDate -EndDate $endDate.AddDays(-1)

It seems that there are more than one app registration whose name includes "Microsoft Graph" in your tenant. It causes you to get the wrong $svcPrincipal.AppId (in this case, it may be a combination of multiple app ids).
Please directly set $reqGraph.ResourceAppId = "00000003-0000-0000-c000-000000000000".
00000003-0000-0000-c000-000000000000 is the app id of the Microsoft Graph app, which is a fixed value.

Here is the correct code with $_.DisplayName -eq "Microsoft Graph"
appName = "Test" # Maximum 32 characters
$adalUrlIdentifier = "https://abc.dk/AADGuestLifecycleMgmt"
$appReplyUrl = "https://www.abc.dk"
$pwd = Read-Host -Prompt 'Enter a secure password for your certificate!'
$certStore = "Cert:\CurrentUser\My"
$currentDate = Get-Date
$endDate = $currentDate.AddYears(10) # 10 years is nice and long
$thumb = (New-SelfSignedCertificate -DnsName "abc.dk" -CertStoreLocation $certStore -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $endDate).Thumbprint
$thumb > cert-thumb.txt # Save to file
$pwd = ConvertTo-SecureString -String $pwd -Force -AsPlainText
Export-PfxCertificate -cert "$certStore\$thumb" -FilePath .\AzureADGuestLifecycleMgmt.pfx -Password $pwd
$path = (Get-Item -Path ".\").FullName
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("$path\AzureADGuestLifecycleMgmt.pfx", $pwd)
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
Install-Module AzureAD
Import-Module AzureAD
# Connect to Azure AD as an admin account
Connect-AzureAD
# Store tenantid
$tenant = Get-AzureADTenantDetail
$tenant.ObjectId > tenantid.txt
# Add AuditLog.Read.All access
$svcPrincipal = Get-AzureADServicePrincipal -All $true | ? { $_.DisplayName -eq "Microsoft Graph" }
$appRole = $svcPrincipal.AppRoles | ? { $_.Value -eq "AuditLog.Read.All" }
$appPermission = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "$($appRole.Id)", "Role"
#Add Directory.ReadWrite.All access
$appRole2 = $svcPrincipal.AppRoles | ? { $_.Value -eq "Directory.ReadWrite.All" }
$appPermission2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "$($appRole2.Id)", "Role"
$reqGraph = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$reqGraph.ResourceAppId = $svcPrincipal.AppId
$reqGraph.ResourceAccess = $appPermission, $appPermission2
Write-Host $reqGraph
# Create Azure Active Directory Application (ADAL App)
$application = New-AzureADApplication -DisplayName "$appName" -IdentifierUris $adalUrlIdentifier -ReplyUrls $appReplyUrl -RequiredResourceAccess $reqGraph
New-AzureADApplicationKeyCredential -ObjectId $application.ObjectId -CustomKeyIdentifier "$appName" -Type AsymmetricX509Cert -Usage Verify -Value $keyValue -StartDate $currentDate -EndDate $endDate.AddDays(-1)

Related

Permissions error trying to download folder from GoDaddy Website via Powershell

Has to have something to do with GoDaddy and permissions. I can access files in that folder but get 403 when trying to access the folder itself (download):
$outputdir = 'C:\Windows10Upgrade'
$url = 'httx://www.mydomain.com/Windows10Upgrade/'
# enable TLS 1.2 and TLS 1.1 protocols
#[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12, [Net.SecurityProtocolType]::Tls11
$password = Microsoft.PowerShell.Security\ConvertTo-SecureString -String 'MYPASSWORD' -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'MYACCOUNTNUMBER', $password
$WebResponse = Invoke-WebRequest -Uri $url -Credential $credential
# get the list of links, skip the first one ("../") and download the files
$WebResponse.Links | Select-Object -ExpandProperty href -Skip 1 | ForEach-Object {
Write-Host "Downloading file '$_'"
$filePath = Join-Path -Path $outputdir -ChildPath $_
$fileUrl = '{0}/{1}' -f $url.TrimEnd('/'), $_
Invoke-WebRequest -Uri $fileUrl -OutFile $filePath
}
If you have a GoDaddy UserID and Password add a PSCredential object to your request:
$password = Microsoft.PowerShell.Security\ConvertTo-SecureString -String 'mypassword' -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'myuserid', $password
# Download a file
Invoke-WebRequest -Uri $source -OutFile $target -Credential $credential
Substitute your UserID with myuserid and your Password with mypassword in the code above which creates the PSCredential object (called $credential) you then pass into the Invoke-WebRequest cmdlet as seen in the last line.

PowerShell script that automatically uploads PowerBI report to list of Workspaces

I am trying to generate a script that automatically uploads a Power BI report to a list of workspaces, but since I'm not that experienced with PowerShell I feel a bit out of my depth.
Based on this post
https://dev.to/merill/powershell-script-to-generate-a-report-on-all-power-bi-workspaces-and-groups-in-your-microsoft-365-tenant-44pc
I have written a script that generates an array of workspaces:
Connect-PowerBIServiceAccount
$workspaces = Get-PowerBIWorkspace -Scope Organization -Include All
$wslist = #()
foreach ($ws in $workspaces) {
$item = [ordered] #{
Id = $ws.ID
Name = $ws.Name
}
$u = new-object PSObject -Property $item
$wslist += $u
}
Similarly, I have written a script that generates an array of report ID's uploaded to a given Workspace:
Connect-PowerBIServiceAccount
$workspaceid = "enter-id-here"
$reports = Get-PowerBIReport -WorkspaceId $workspaceid
$rlist = #()
foreach ($r in $reports) {
$r
$item = [ordered] #{
Id = $r.ID
Name = $r.Name
}
$u = new-object PSObject -Property $item
$rlist += $u
}
What I want to do is merge these arrays into one that only includes the rows where the report name is equal to some predefined name stored in a string var.
Finally, I want to iterate through the array, and for each row delete the old report and then upload a new version.
If I got your point correctly, you need something like this:
Import-Module MicrosoftPowerBIMgmt
$oldReportName = "Fancy Report"
$pbixFilePath = "C:\Power BI\Fancy Report.pbix"
$username = "user#example.com"
$password = "P#ssw0rd" | ConvertTo-SecureString -asPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
Connect-PowerBIServiceAccount -Credential $credential | Out-Null
# -All - Returns all results, not only top 100
$workspaces = Get-PowerBIWorkspace -All -Scope Organization -Include All
foreach($workspace in $workspaces) {
$report = Get-PowerBIReport -WorkspaceId $workspace.Id -Scope Organization -Name $oldReportName
if ($report) {
Write-Host "Report $oldReportName found in workspace $($workspace.Name)..."
New-PowerBIReport -Path $pbixFilePath -Workspace $workspace -ConflictAction CreateOrOverwrite
}
}
Disconnect-PowerBIServiceAccount
$oldReportName is the name of the report, that you are looking for. $pbixFilePath is where the new version that should be uploaded is. I've added -All, because otherwise Get-PowerBIWorkspace will return only the first 100 workspaces in the tenant. And because this is tenant-wise operation, $username and $password should be admin credentials (as of October 2020 service principal cannot be used for admin operations).
There is no need to construct an array. Just iterate through the workspaces and check is there a report with this name published there ($report = Get-PowerBIReport -WorkspaceId $workspace.Id -Scope Organization -Name $oldReportName). If such one exists, upload the new one there and replace it (New-PowerBIReport -Path $pbixFilePath -Workspace $workspace -ConflictAction CreateOrOverwrite).
The final, fully working PS script (with dummy names and paths) looks like this:
Connect-PowerBIServiceAccount
Import-Module MicrosoftPowerBIMgmt
# Report name here:
$ReportName = "AwesomeReport"
$FolderPath = "C:\Users\AwesomeUser\AwesomeReports"
$workspaces = Get-PowerBIWorkspace -All -Scope Organization -Include All
foreach($workspace in $workspaces) {
$report = Get-PowerBIReport -WorkspaceId $workspace.Id -Scope Organization -Name $ReportName
if ($report) {
Write-Host "Report $ReportName found in workspace $($workspace.Name)..."
$filePath = "$FolderPath\$($workspace.Name)\$ReportName.pbix"
New-PowerBIReport -Path $filePath -WorkspaceId $workspace.Id -Name $ReportName -ConflictAction CreateOrOverwrite
}
}
Disconnect-PowerBIServiceAccount

sharepoint powershell - Exception calling "ExecuteQuery" with "0" argument(s): "The underlying connection was closed:"

something is wrong and i don't know what's it ,the same script is working in my local machine but when i tried it in VM it just will not work and throw me exception
-the PowerShell is the same version
-the same PowerShell SDK
-i added rule to allowing PowerShell
-my user is admin
-all the parameters are correct and i can enter the SharePoint in browser
Import-Module 'C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll'
Import-Module 'C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll'
Clear-Host
# getting all argument before starting the process #
$SiteURL = "user"
$ListName = "list"
$Username ="email"
$Password ="pass"
if ($SiteURL -eq $null -or $ListName -eq $null -or $Username -eq $null -or $Password -eq $null)
{
Write-Output "Somthing went wrong!"
Write-Output "Some of the variables are not correct"
}
else
{
$outfile = $PSCommandPath | Split-Path -Parent
$outfile += '\items.txt'
Clear-Host
Write-Output "Getting Items"
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$securePassword=ConvertTo-SecureString $Password -AsPlainText -Force
$Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $securePassword)
$Web = $Context.Web
$List = $Web.get_lists().getByTitle($ListName)
$itemCreateInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
$ListItems = $List.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
$Context.Load($ListItems)
$Context.ExecuteQuery()
$ListItems | ForEach-Object {
$output=$_["Title"] + "~~"
$output | Out-File -FilePath $outfile -Append
}
Write-Output "Done!"
}
it's seems the security for the local machine has a SSL Certificate for my account by default but in the VM it was missing that Certificate, so i just invoked by using TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
to the first line of my power-shell code and everything worked nice
Works fine based on my testing.
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Clear-Host
# getting all argument before starting the process #
$SiteURL = "https://xxx.sharepoint.com/sites/lee"
$ListName = "testlist"
$Username ="user#xxx.onmicrosoft.com"
$Password ="password"
if ($SiteURL -eq $null -or $ListName -eq $null -or $Username -eq $null -or $Password -eq $null)
{
Write-Output "Somthing went wrong!"
Write-Output "Some of the variables are not correct"
}
else
{
$outfile = $PSCommandPath | Split-Path -Parent
$outfile += '\items.txt'
Clear-Host
Write-Output "Getting Items"
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$securePassword=ConvertTo-SecureString $Password -AsPlainText -Force
$Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $securePassword)
$Web = $Context.Web
$List = $Web.get_lists().getByTitle($ListName)
$itemCreateInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
$ListItems = $List.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
$Context.Load($ListItems)
$Context.ExecuteQuery()
$ListItems | ForEach-Object {
$output=$_["Title"] + "~~"
$output | Out-File -FilePath $outfile -Append
}
Write-Output "Done!"
}
Yes I confirm, it works, I had the same problem on a Windows 2012 R2 server

Powershell: Using send-mailmessage after PSFTP in script

I have written a small script that are using PSFTP to connect to a FTP server, download some files and conclude by sending an email with a summary of downloaded files.
I get a problem with the send-mailmessage part, which fails with this error:
Send-MailMessage : The remote certificate is invalid according to the validation procedure.
When running the send-mailmessage alone, it works flawlessly, it is only when using it combined with PSFTP, it fails. I am guessing, that it is the due to having made a session with the ftpserver, that somehow interferes, but that session should be ended when we come to the send mail. I can't figure this out, can anybody help?
My script:
#--------- FTP server variables here ------
$User = "XXX"
$Pass = "XXX"
$EncryptedPass = ConvertTo-SecureString -String $Pass -asPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential($User,$EncryptedPass)
$Server = "XXX"
#-------- Mail credentials here -----------
$User_ = "XXX"
$Pass_ = "XXX"
$EncryptedPass_ = ConvertTo-SecureString -String $Pass_ -asPlainText -Force
$Mailcredentials = New-Object System.Management.Automation.PSCredential($User_,$EncryptedPass_)
#$mailcredentials =
$Subject ="'bowkerdownload'"
$To = "XXX"
$From = "XXX"
$body = (get-content -path g:\resultout.txt) -join "`n"
$SMTP = "smtp.office365.com"
#---------File variables here --------------
$month = (Get-Date).AddMonths(-8).ToString('MMM')
$year = (Get-date).addyears(-1).ToString('yyyy')
$filesequential="_*_"
$filesize = "lc"
$filetype = ".txt"
$samlevar=($month + ''+$year + ''+$filesequential + ''+$filesize + ''+$filetype)
$filename = $samlevar.tostring()
#------ The script---------
Set-FTPConnection -Credentials $Credentials -Server $server -Session defaultftpsession -UsePassive
$Session = Get-FTPConnection -Session defaultftpsession
Get-FTPChildItem -Path /Download -filter "$filename" |
Get-FTPItem -session $Session -LocalPath g:\ -Overwrite |
Convertfrom-string -PropertyNames Kode, Status, Action, fil |
Select-Object -Property Status, action, Fil |
Out-file g:\resultout.txt;
Send-MailMessage -To $To -Subject $Subject -Body $Body -SmtpServer $SMTP -From $From -Credential $Mailcredentials -port 587 -UseSsl``

automate sitecollection administrator assignment in sharepoint online with powershell for backup purposes

I was asked to create a powershell script to automate the assignment for new sitecollection administrator in SharePoint-Online for BackUp purposes NetApp CloudControl.
This is my firsttime ever in PowerShell and now I got stucked and don't know where to look anymore or least don't understand what I'm looking at.
The script is supposed to do the following:
Get Microsoft-tenant and password
Create a new ps-script where the credentials are already filled in
Connect to sharepoint-online and lookup personal space for every user(onedrive for business sites)
cut the log and create a second one if more than 200 lines were written
read the log and make the service-account a sitecollectionadmin
create task to run the created script once per week
At the moment I got it to do this:
Get Microsoft-tenant and password
Save Credentials
Connect to sharepoint-online and lookup personal space for every user(onedrive for business sites)
read the log and make the service-account a sitecollectionadministrator
Can anyone of you please help me out on how to proceed with the next steps?
P.S. Please excuse that I'm posting the script as a whole, I just didn't know what I should cut out.
$TenantName = $null0
$TenantPassword = $null1
if($TenantName -eq $null0){
$TenantName = Read-Host "Enter Office 365 - Tenant Name."
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$TenantName = \$null0$',"`$TenantName = '$TenantName'"}
$NewScript | Out-File $PSCommandPath -Force
}
if($TenantPassword -eq $null1){
$TenantPassword = Read-Host "Enter Password for netapp-service#$($TenantName).onmicrosoft.com."
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$TenantPassword = \$null1$',"`$TenantPassword = '$TenantPassword'"}
$NewScript | Out-File $PSCommandPath -Force
}
$username = "netapp-service#$($TenantName).onmicrosoft.com"
$cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $userName, $(convertto-securestring $TenantPassword -asplaintext -force)
Connect-SPOService -Url https://$($TenantName)-admin.sharepoint.com/ -Credential $cred
$AdminURI = "https://$($TenantName)-admin.sharepoint.com"
$AdminAccount = "netapp-service#$($TenantName).onmicrosoft.com"
$AdminPass = $TenantPassword
$eDiscoveryUser = "netapp-service#$($TenantName).onmicrosoft.com"
$MySitePrefix = "https://$($TenantName)-my.sharepoint.com"
$LogFile = '.\$TenantName\$TenantName-MySites.txt'
$MySiteListFile = '.\$TenantName\$TenantName-MySites.txt'
Connect-SPOService -Url $AdminURI -Credential $cred
$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")
$sstr = ConvertTo-SecureString -string $AdminPass -AsPlainText –Force
$AdminPass = ""
$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminAccount, $sstr)
$proxyaddr = "$AdminURI/_vti_bin/UserProfileService.asmx?wsdl"
$UserProfileService= New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False
$UserProfileService.Credentials = $creds
$strAuthCookie = $creds.GetAuthenticationCookie($AdminURI)
$uri = New-Object System.Uri($AdminURI)
$container = New-Object System.Net.CookieContainer
$container.SetCookies($uri, $strAuthCookie)
$UserProfileService.CookieContainer = $container
$UserProfileResult = $UserProfileService.GetUserProfileByIndex(-1)
Write-Host "Starting- This could take a while."
Out-File $LogFile -Force
$NumProfiles = $UserProfileService.GetUserProfileCount()
$i = 1
While ($UserProfileResult.NextValue -ne -1)
{
Write-Host "Examining profile $i of $NumProfiles"
$Prop = $UserProfileResult.UserProfile | Where-Object { $_.Name -eq "PersonalSpace" }
$Url= $Prop.Values[0].Value
if ($Url) {
$Url | Out-File $LogFile -Append -Force
}
$UserProfileResult = $UserProfileService.GetUserProfileByIndex($UserProfileResult.NextValue)
$i++
}
Write-Host "Done!"
$reader = [System.IO.File]::OpenText($MySiteListFile)
try {
for(;;) {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$fullsitepath = "$MySitePrefix$line"
Write-Host "Operating on $fullsitepath "
$fullsitepath = $fullsitepath.trimend("/")
Write-Host "Making $eDiscoveryUser a Site Collection Admin"
Set-SPOUser -Site $fullsitepath -LoginName $eDiscoveryUser -IsSiteCollectionAdmin $true
}
}
finally {
$reader.Close()
}
Disconnect-SPOService
Write-Host "Done!"