How to get all Web Applications with Content DB names from SharePoint 2013/2016 Farm using PowerShell CSOM?
simple one:
#Get all web applications sharepoint using powershell
$WebAppColl = Get-SPWebApplication
#Iterate through each web application
Foreach ($WebApp in $WebAppColl)
{
$Webapp.Url
}
#Or a one liner to loop through web applications
#Get-SPWebApplication | Select URL
#Read more: https://www.sharepointdiary.com/2016/01/get-all-web-applications-in-sharepoint-using-powershell.html#ixzz7JoRyZrx8
with more data:
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
#Configuration Parameters
$ReportOutput= "C:\WebApplications-Report.csv"
$DataCollection = #()
#Get all web applications sharepoint using powershell
$WebAppColl = Get-SPWebApplication
Foreach ($WebApp in $WebAppColl)
{
#Determine the Authentication Type of the web application
if ($WebApp.UseClaimsAuthentication) { $AuthticationTYpe = "Claims"} else {$AuthticationTYpe = "Classic" }
#Get All Managed Paths of the web application
$ManagedPaths =(Get-SPManagedPath -WebApplication $WebApp | Select -ExpandProperty Name) -join ","
$WebAppData = new-object PSObject
$WebAppData | add-member -membertype NoteProperty -name "Web Application Name" -Value $WebApp.Name
$WebAppData | add-member -membertype NoteProperty -name "URL" -Value $WebApp.URL
$WebAppData | add-member -membertype NoteProperty -name "No.of Content Databases" -Value $WebApp.ContentDatabases.Count
$WebAppData | add-member -membertype NoteProperty -name "Authentication Type" -Value $AuthticationTYpe
$WebAppData | add-member -membertype NoteProperty -name "Application Pool" -Value $WebApp.ApplicationPool.DisplayName
$WebAppData | add-member -membertype NoteProperty -name "Outgoing E-mail" -Value $WebApp.OutboundMailServiceInstance[0].Server.Address
$WebAppData | add-member -membertype NoteProperty -name "Managed Paths" -Value $ManagedPaths
$DataCollection += $WebAppData
}
#Export Results to a CSV File
$DataCollection | Export-csv $ReportOutput -notypeinformation
Write-Host "Web Application Audit Report has been Generated!" -f Green
#Read more: https://www.sharepointdiary.com/2016/01/get-all-web-applications-in-sharepoint-using-powershell.html#ixzz7JoSCM4YG
more info - https://www.sharepointdiary.com/2016/01/get-all-web-applications-in-sharepoint-using-powershell.html
Related
I am stuck in the following script. The script below works fine to locate the user's team's group, email, and URL. We have recently discovered that some MS Teams contain MS Team Private Channels. We would also like to know if any of those teams (ms teams users are members of) have private channels, and download the name of the channel and the URL.
The following site shows how to find those private channels' URLs from the whole company.
https://pnp.github.io/script-samples/report-private-teams-excel/README.html?tabs=pnpps
But I only need the private channel URL from specific sites.
Can anyone help me please?
Thank you
Connect-ExchangeOnline
Connect-MicrosoftTeams
$CustodianTeams = Read-Host -Prompt "Enter the user ID and #domain. i.e, UserID#Microsoft.com"
$Custodianteams = $CustodianTeams -replace '(^\s+|\s+$)','' -replace '\s+',' '
$TeamIDs = Get-Team -User $CustodianTeams
foreach ($TeamID in $TeamIDs) {
Get-UnifiedGroup -Identity $TeamID.GroupID | select DisplayName, PrimarySmtpAddress, SharePointSiteUrl | Export-Csv .\$CustodianTeams.csv -Append
}
Please refer below steps:
First install and connect:
Install-Module PowerShellGet -RequiredVersion 2.2.4.1
Install-Module -Name MicrosoftTeams -RequiredVersion 3.0.0
Connect-MicrosoftTeams
Then:
1. Copy the ps1 file to your downloads folder
2. cd C:\Users\username\Downloads
3. .\TeamsChannelMemberReport.ps1
Choose option 2 to export all and it will export to downloads.
Save this as TeamsChannelMemberReport.ps1:
<#
.Requires -version 2 - Connect-MicrosoftTeams and then Run the script in Powershell
.SYNOPSIS
.\TeamsChannelMemberReport.ps1 - It Can Display all the Teams and its Channels and its members on a List
Or It can Export to a CSV file
With Export of Specific teams
Example 1
PS C:\Scripts> .\TeamsChannelMemberReportv1.0.ps1
Teams Channel Member Report
----------------------------
1.Display in Microsoft Teams Shell
2.Export to CSV File
3.Display Specific Microsoft Team in Shell
4.Export Specific Microsoft Team to CSV File
Choose The Task: 1
User SMTP Address Role Channel DisplayName Team DisplayName
----------------- ---- ------------------- ----------------
Email address removed Owner General Teams_Azure365pro
Email address removed Member General Teams_Azure365pro
Email address removed Member General Teams_Azure365pro
Email address removed Owner General Teams_Azure365pro
Email address removed Member General Teams_Azure365pro
Email address removed Member General Teams_Azure365pro
Email address removed Owner General InformationTec...
Email address removed Member General InformationTec...
Email address removed Owner ServiceDesk Team InformationTec...
Email address removed Owner Infrastructure Team InformationTec...
Example 2
PS C:\Scripts> .\TeamsChannelMemberReportv1.0.ps1
Teams Channel Member Report
----------------------------
1.Display in Microsoft Teams Shell
2.Export to CSV File
3.Display Specific Microsoft Team in Shell
4.Export Specific Microsoft Team to CSV File
Choose The Task: 2
Enter the Path of CSV file (Eg. C:\Teams.csv): c:\teams.csv
#>
Write-host "
Teams Channel Member Report
----------------------------
1.Display in Microsoft Teams Shell
2.Export to CSV File
3.Display Specific Microsoft Team in Shell
4.Export Specific Microsoft Team to CSV File"-ForeGround "Cyan"
#----------------
# Script
#----------------
Write-Host " "
$number = Read-Host "Choose The Task"
$output = #()
switch ($number)
{
1 {
$i = 0
$AllTeams = Get-Team
Foreach ($Team in $AllTeams)
{
$AllChannels = Get-TeamChannel -GroupID $Team.GroupID
Foreach ($Channel in $AllChannels)
{
$AllMembers = Get-TeamChannelUser -GroupId $Team.GroupID -DisplayName $channel.DisplayName
Foreach ($member in $AllMembers)
{
$userObj = New-Object PSObject
$userObj | Add-Member NoteProperty -Name "User SMTP Address" -Value $member.User
$userObj | Add-Member NoteProperty -Name "Role" -Value $member.role
$userObj | Add-Member NoteProperty -Name "Channel DisplayName" -Value $Channel.DisplayName
$userObj | Add-Member NoteProperty -Name "Team DisplayName" -Value $Team.DisplayName
$output += $UserObj
}
}
# update counters and write progress
$i++
Write-Progress -activity "Scanning Teams . . .Channels . . . Members" -status "Scanned: $i of $($AllTeams.Count)" -percentComplete (($i / $AllTeams.Count) * 100)
Write-Output $Output
}
;Break}
2 {
$i = 0
$CSVfile = Read-Host "Enter the Path of CSV file (Eg. C:\Teams.csv)"
$AllTeams = Get-Team
Foreach ($Team in $AllTeams)
{
$AllChannels = Get-TeamChannel -GroupID $Team.GroupID
Foreach ($Channel in $AllChannels)
{
$AllMembers = Get-TeamChannelUser -GroupId $Team.GroupID -DisplayName $channel.DisplayName
Foreach ($member in $AllMembers)
{
$userObj = New-Object PSObject
$userObj | Add-Member NoteProperty -Name "DisplayName" -Value $member.Name
$userObj | Add-Member NoteProperty -Name "UserId" -Value $member.UserId
$userObj | Add-Member NoteProperty -Name "User SMTP Address" -Value $member.User
$userObj | Add-Member NoteProperty -Name "Role" -Value $member.role
$userObj | Add-Member NoteProperty -Name "Channel DisplayName" -Value $Channel.DisplayName
$userObj | Add-Member NoteProperty -Name "Channel Description" -Value $Channel.Description
$userObj | Add-Member NoteProperty -Name "Channel MembershipType" -Value $Channel.MembershipType
$userObj | Add-Member NoteProperty -Name "Team GroupID" -Value $Team.GroupId
$userObj | Add-Member NoteProperty -Name "Team DisplayName" -Value $Team.DisplayName
$userObj | Add-Member NoteProperty -Name "Team Description" -Value $Team.Description
$userObj | Add-Member NoteProperty -Name "Team Visibility" -Value $Team.Visibility
$userObj | Add-Member NoteProperty -Name "Team MailNickName" -Value $Team.MailNickName
$userObj | Add-Member NoteProperty -Name "Team Classification" -Value $Team.Classification
$userObj | Add-Member NoteProperty -Name "Team Archived" -Value $Team.Archived
$userObj | Add-Member NoteProperty -Name "Team AllowGiphy" -Value $Team.AllowGiphy
$userObj | Add-Member NoteProperty -Name "Team GiphyContentRating" -Value $Team.GiphyContentRating
$userObj | Add-Member NoteProperty -Name "Team AllowStickersAndMemes" -Value $Team.AllowStickersAndMemes
$userObj | Add-Member NoteProperty -Name "Team AllowGuestCreateUpdateChannels" -Value $Team.AllowGuestCreateUpdateChannels
$userObj | Add-Member NoteProperty -Name "Team AllowGuestDeleteChannels" -Value $Team.AllowGuestDeleteChannels
$userObj | Add-Member NoteProperty -Name "Team AllowCreateUpdateChannels" -Value $Team.AllowCreateUpdateChannels
$userObj | Add-Member NoteProperty -Name "Team AllowCreatePrivateChannels" -Value $Team.AllowCreatePrivateChannels
$userObj | Add-Member NoteProperty -Name "Team AllowDeleteChannels" -Value $Team.AllowDeleteChannels
$userObj | Add-Member NoteProperty -Name "Team AllowAddRemoveApps" -Value $Team.AllowAddRemoveApps
$userObj | Add-Member NoteProperty -Name "Team AllowCreateUpdateRemoveTabs" -Value $Team.AllowCreateUpdateRemoveTabs
$userObj | Add-Member NoteProperty -Name "Team AllowCreateUpdateRemoveConnectors" -Value $Team.AllowCreateUpdateRemoveConnectors
$userObj | Add-Member NoteProperty -Name "Team AllowUserEditMessages" -Value $Team.AllowUserEditMessages
$userObj | Add-Member NoteProperty -Name "Team AllowUserDeleteMessages " -Value $Team.AllowUserDeleteMessages
$userObj | Add-Member NoteProperty -Name "Team AllowOwnerDeleteMessages" -Value $Team.AllowOwnerDeleteMessages
$userObj | Add-Member NoteProperty -Name "Team AllowTeamMentions" -Value $Team.AllowTeamMentions
$userObj | Add-Member NoteProperty -Name "Team AllowChannelMentions" -Value $Team.AllowChannelMentions
$userObj | Add-Member NoteProperty -Name "Team ShowInTeamsSearchAndSuggestions" -Value $Team.ShowInTeamsSearchAndSuggestions
$output += $UserObj
}
}
# update counters and write progress
$i++
Write-Progress -activity "Scanning Teams . . .Channels . . . Members" -status "Scanned: $i of $($AllTeams.Count)" -percentComplete (($i / $AllTeams.Count) * 100)
$output | Export-csv -Path $CSVfile -NoTypeInformation -Encoding UTF8
}
;Break}
3 {
$i = 0
$Teamname = Read-Host "Enter the Team Display name or Range (Eg. Teamname , Team*,*Team)"
$AllTeams = Get-Team | Where-object {$_.DisplayName -like $Teamname}
Foreach ($Team in $AllTeams)
{
$AllChannels = Get-TeamChannel -GroupID $Team.GroupID
Foreach ($Channel in $AllChannels)
{
$AllMembers = Get-TeamChannelUser -GroupId $Team.GroupID -DisplayName $channel.DisplayName
Foreach ($member in $AllMembers)
{
$userObj = New-Object PSObject
$userObj | Add-Member NoteProperty -Name "User SMTP Address" -Value $member.User
$userObj | Add-Member NoteProperty -Name "Role" -Value $member.role
$userObj | Add-Member NoteProperty -Name "Channel DisplayName" -Value $Channel.DisplayName
$userObj | Add-Member NoteProperty -Name "Team DisplayName" -Value $Team.DisplayName
$output += $UserObj
}
}
# update counters and write progress
$i++
Write-Progress -activity "Scanning Teams . . .Channels . . . Members" -status "Scanned: $i of $($AllTeams.Count)" -percentComplete (($i / $AllTeams.Count) * 100)
Write-Output $Output
}
;Break}
4 {
$i = 0
$CSVfile = Read-Host "Enter the Path of CSV file (Eg. C:\Teams.csv)"
$Teamname = Read-Host "Enter the Team Display name or Range (Eg. Teamname , Team*,*Team)"
$AllTeams = Get-Team | Where-object {$_.DisplayName -like $Teamname}
Foreach ($Team in $AllTeams)
{
$AllChannels = Get-TeamChannel -GroupID $Team.GroupID
Foreach ($Channel in $AllChannels)
{
$AllMembers = Get-TeamChannelUser -GroupId $Team.GroupID -DisplayName $channel.DisplayName
Foreach ($member in $AllMembers)
{
$userObj = New-Object PSObject
$userObj | Add-Member NoteProperty -Name "DisplayName" -Value $member.Name
$userObj | Add-Member NoteProperty -Name "UserId" -Value $member.UserId
$userObj | Add-Member NoteProperty -Name "User SMTP Address" -Value $member.User
$userObj | Add-Member NoteProperty -Name "Role" -Value $member.role
$userObj | Add-Member NoteProperty -Name "Channel DisplayName" -Value $Channel.DisplayName
$userObj | Add-Member NoteProperty -Name "Channel Description" -Value $Channel.Description
$userObj | Add-Member NoteProperty -Name "Channel MembershipType" -Value $Channel.MembershipType
$userObj | Add-Member NoteProperty -Name "Team GroupID" -Value $Team.GroupId
$userObj | Add-Member NoteProperty -Name "Team DisplayName" -Value $Team.DisplayName
$userObj | Add-Member NoteProperty -Name "Team Description" -Value $Team.Description
$userObj | Add-Member NoteProperty -Name "Team Visibility" -Value $Team.Visibility
$userObj | Add-Member NoteProperty -Name "Team MailNickName" -Value $Team.MailNickName
$userObj | Add-Member NoteProperty -Name "Team Classification" -Value $Team.Classification
$userObj | Add-Member NoteProperty -Name "Team Archived" -Value $Team.Archived
$userObj | Add-Member NoteProperty -Name "Team AllowGiphy" -Value $Team.AllowGiphy
$userObj | Add-Member NoteProperty -Name "Team GiphyContentRating" -Value $Team.GiphyContentRating
$userObj | Add-Member NoteProperty -Name "Team AllowStickersAndMemes" -Value $Team.AllowStickersAndMemes
$userObj | Add-Member NoteProperty -Name "Team AllowGuestCreateUpdateChannels" -Value $Team.AllowGuestCreateUpdateChannels
$userObj | Add-Member NoteProperty -Name "Team AllowGuestDeleteChannels" -Value $Team.AllowGuestDeleteChannels
$userObj | Add-Member NoteProperty -Name "Team AllowCreateUpdateChannels" -Value $Team.AllowCreateUpdateChannels
$userObj | Add-Member NoteProperty -Name "Team AllowCreatePrivateChannels" -Value $Team.AllowCreatePrivateChannels
$userObj | Add-Member NoteProperty -Name "Team AllowDeleteChannels" -Value $Team.AllowDeleteChannels
$userObj | Add-Member NoteProperty -Name "Team AllowAddRemoveApps" -Value $Team.AllowAddRemoveApps
$userObj | Add-Member NoteProperty -Name "Team AllowCreateUpdateRemoveTabs" -Value $Team.AllowCreateUpdateRemoveTabs
$userObj | Add-Member NoteProperty -Name "Team AllowCreateUpdateRemoveConnectors" -Value $Team.AllowCreateUpdateRemoveConnectors
$userObj | Add-Member NoteProperty -Name "Team AllowUserEditMessages" -Value $Team.AllowUserEditMessages
$userObj | Add-Member NoteProperty -Name "Team AllowUserDeleteMessages " -Value $Team.AllowUserDeleteMessages
$userObj | Add-Member NoteProperty -Name "Team AllowOwnerDeleteMessages" -Value $Team.AllowOwnerDeleteMessages
$userObj | Add-Member NoteProperty -Name "Team AllowTeamMentions" -Value $Team.AllowTeamMentions
$userObj | Add-Member NoteProperty -Name "Team AllowChannelMentions" -Value $Team.AllowChannelMentions
$userObj | Add-Member NoteProperty -Name "Team ShowInTeamsSearchAndSuggestions" -Value $Team.ShowInTeamsSearchAndSuggestions
$output += $UserObj
}
}
# update counters and write progress
$i++
Write-Progress -activity "Scanning Teams . . .Channels . . . Members" -status "Scanned: $i of $($AllTeams.Count)" -percentComplete (($i / $AllTeams.Count) * 100)
$output | Export-csv -Path $CSVfile -NoTypeInformation -Encoding UTF8
};
Break
}
Default {Write-Host "No matches found, Enter Options 1 or 2" -ForeGround "red"}
}
I have a Powershell program which runs on a schedule in an Azure Functions app. It connects to Office 365 to download audit logs, make some changes and then export a CSV to an Azure Data Lake Storage account. To avoid hard-coded credentials, an Azure Key Vault stores the secrets. I created a managed identity in the Azure Function along with the required application settings and URL to point to Azure Key Vault. The code references the application secrets (APPSETTING) and all seemed to be running well, until I noticed today that since yesterday afternoon the exported CSV files were empty.
So I opened up the Function app, hit Run manually and I could see a CSV file exported with data. When I took a look at the execution log however, I spotted these error messages which despite not affecting the execution this time, makes me wonder whether this is what caused the problem with the empty CSV files. The program is now running on a schedule as normal and the error messages appear to be intermittent.
Not sure why it's complaining about the username and password, when it is clearly able to access the data source (Office audit logs), export the CSV and transfer it to the file destination (Azure Data Lake Storage) successfully.
Any idea what is going on? Any tips or suggestions welcome! Code provided below. Many thanks!
# Input bindings are passed in via param block.
param($Timer)
# Get the current universal time in the default string format.
$currentUTCtime = (Get-Date).ToUniversalTime()
# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
if ($Timer.IsPastDue) {
Write-Host "PowerShell timer is running late!"
}
# Write an information log with the current time.
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime"
<#
Title: Power BI Audit Logging
Client:
Description: Connects to Azure audit logs using admin credentials (secrets via Azure Key Vault). Opens a session to iterate through the Audit Log ($currentrResults) and aggregate
the logs into a single object ($aggregateResults). A for-each loop then iterates through the $aggregateResults and assigns each data piece (datum)
to a PowerShell object to which properties are added to hold the audit data. A CSV file is created and exported, and then transferred to a Data Lake storage account (using SAS secret via Azure Key Vault).
Last Revision: 06/09/2020 #>
Set-ExecutionPolicy RemoteSigned
Set-Item ENV:\SuppressAzurePowerShellBreakingChangeWarnings "true"
# Better for scheduled jobs
$uSecret = $ENV:APPSETTING_SecretUsername
$pSecret = $ENV:APPSETTING_SecretPassword
$sasSecret = $ENV:APPSETTING_SecretSAS
$securePassword = ConvertTo-SecureString -String $pSecret -AsPlainText -Force
$UserCredential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $uSecret, $securePassword
# This will prompt the user for credential (optional)
# $UserCredential = Get-Credential
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $session
$startDate=(get-date).AddDays(-10)
$endDate=(get-date)
$scriptStart=(get-date)
$sessionName = (get-date -Format 'u')+'pbiauditlog'
# Reset user audit accumulator
$aggregateResults = #()
$i = 0 # Loop counter
Do {
$currentResults = Search-UnifiedAuditLog -StartDate $startDate -EndDate $enddate -SessionId $sessionName -SessionCommand ReturnLargeSet -ResultSize 1000 -RecordType PowerBIAudit
if ($currentResults.Count -gt 0) {
Write-Host ("Finished {3} search #{1}, {2} records: {0} min" -f [math]::Round((New-TimeSpan -Start $scriptStart).TotalMinutes,4), $i, $currentResults.Count, $user.UserPrincipalName )
# Accumulate the data.
$aggregateResults += $currentResults
# No need to do another query if the # records returned <1000 - should save around 5-10 seconds per user.
if ($currentResults.Count -lt 1000) {
$currentResults = #()
} else {
$i++
}
}
} Until ($currentResults.Count -eq 0) # End of Session Search Loop.
$data=#()
foreach ($auditlogitem in $aggregateResults) {
$datum = New-Object -TypeName PSObject
$d = ConvertFrom-json $auditlogitem.AuditData
$datum | Add-Member -MemberType NoteProperty -Name Id -Value $d.Id
$datum | Add-Member -MemberType NoteProperty -Name CreationTDateTime -Value $d.CreationDate
$datum | Add-Member -MemberType NoteProperty -Name CreationTime -Value $d.CreationTime
$datum | Add-Member -MemberType NoteProperty -Name RecordType -Value $d.RecordType
$datum | Add-Member -MemberType NoteProperty -Name Operation -Value $d.Operation
$datum | Add-Member -MemberType NoteProperty -Name OrganizationId -Value $d.OrganizationId
$datum | Add-Member -MemberType NoteProperty -Name UserType -Value $d.UserType
$datum | Add-Member -MemberType NoteProperty -Name UserKey -Value $d.UserKey
$datum | Add-Member -MemberType NoteProperty -Name Workload -Value $d.Workload
$datum | Add-Member -MemberType NoteProperty -Name UserId -Value $d.UserId
$datum | Add-Member -MemberType NoteProperty -Name ClientIPAddress -Value $d.ClientIPAddress
$datum | Add-Member -MemberType NoteProperty -Name UserAgent -Value $d.UserAgent
$datum | Add-Member -MemberType NoteProperty -Name Activity -Value $d.Activity
$datum | Add-Member -MemberType NoteProperty -Name ItemName -Value $d.ItemName
$datum | Add-Member -MemberType NoteProperty -Name WorkSpaceName -Value $d.WorkSpaceName
$datum | Add-Member -MemberType NoteProperty -Name DashboardName -Value $d.DashboardName
$datum | Add-Member -MemberType NoteProperty -Name DatasetName -Value $d.DatasetName
$datum | Add-Member -MemberType NoteProperty -Name ReportName -Value $d.ReportName
$datum | Add-Member -MemberType NoteProperty -Name WorkspaceId -Value $d.WorkspaceId
$datum | Add-Member -MemberType NoteProperty -Name ObjectId -Value $d.ObjectId
$datum | Add-Member -MemberType NoteProperty -Name DashboardId -Value $d.DashboardId
$datum | Add-Member -MemberType NoteProperty -Name DatasetId -Value $d.DatasetId
$datum | Add-Member -MemberType NoteProperty -Name ReportId -Value $d.ReportId
$datum | Add-Member -MemberType NoteProperty -Name OrgAppPermission -Value $d.OrgAppPermission
# Option to include the below JSON column however for large amounts of data it may be difficult for PBI to parse
$datum | Add-Member -MemberType NoteProperty -Name Datasets -Value (ConvertTo-Json $d.Datasets)
# Below is a simple PowerShell statement to grab one of the entries and place in the DatasetName if any exist
foreach ($dataset in $d.datasets) {
$datum.DatasetName = $dataset.DatasetName
$datum.DatasetId = $dataset.DatasetId
}
$data+=$datum
}
$dateTimestring = $startDate.ToString("yyyyMMdd") + "_" + (Get-Date -Format "yyyyMMdd") + "_" + (Get-Date -Format "HHmm")
$fileName = ($dateTimestring + ".csv")
Write-Host ("Writing to file {0}" -f $fileName)
$filePath = "$Env:temp/" + $fileName
$data | Export-csv -Path $filePath
# File transfer to Azure storage account
Get-AzContext #Connect-AzAccount -Credential $UserCredential
Get-AzVM -ResourceGroupName "Audit" -status
$Context = New-AzStorageContext -StorageAccountName "auditingstorage" -StorageAccountKey $sasSecret
Set-AzStorageBlobContent -Force -Context $Context -Container "auditlogs" -File $filePath -Blob $filename
# Close PowerShell session
Remove-PSSession -Id $Session.Id
Your error state
ERROR: Connect-AzAccount : Username + Password authentication is not
supported in PowerShell Core. Please use device code authentication
for interactive log in, or Service Principal authentication for script
log in.
The problem come from using the credential authentication scheme in Powershell Core
Connect-AzAccount -Credential $UserCredential
Instead, in your app, enable the System Managed Identity and grant it the permissions to access what you need.
You can do that by going into the Identity pane and turning the status to On in the System assigned tab.
From there, add the required access through the Azure role assignments button.
Once this is done, you don't need to use Connect-AzAccount, your app is connected automatically to the managed identity at runtime. You can use Object ID from the Identity pane to find it afterward in Azure Active Directory / App Registration and assign it additional API access if needed.
Additional note
You could always continue to use Connect-AzAccount with a service principal account but unless you have requirements for that, I'd go the Managed Identity route.
References
How to use managed Identities for App Service and Azure Functions
Create an Azure service principal with Azure Powershell
I am writing a small program in Powershell which connects to Office 365 to download audit logs, make some changes and then export a CSV to an Azure Data Lake Storage account. To run this process on a schedule, I have created an Azure Function app (timer template) to run the program. To avoid hard-coded credentials, I created an Azure Key Vault to store the credential secrets. I created a managed identity in the Azure Function, created the secrets in Azure Key Vault with the credentials and then created three application settings in Azure Function under "Configuration" with the URL to point at the secrets stored in Azure Key Vault.
The three application settings are called "SecretUsername", "SecretPassword" (to point to the Office 365) and "SecretSAS" (to store the CSV in ADLS).
How do I refer to these variables in my Powershell script? I have tried different variations in my code, but none appear to work. Examples:
$uSecret = $SecretUsername
$uSecret = $ENV:SecretUsername
$uSecret = ENV:SecretUsername
$uSecret = (Get-ChildItem ENV:SecretUsername).SecretValueText
# Input bindings are passed in via param block.
param($Timer)
# Get the current universal time in the default string format.
$currentUTCtime = (Get-Date).ToUniversalTime()
# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
if ($Timer.IsPastDue) {
Write-Host "PowerShell timer is running late!"
}
# Write an information log with the current time.
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime"
Set-ExecutionPolicy AllSigned
Set-Item ENV:\SuppressAzurePowerShellBreakingChangeWarnings "true"
$uSecret = (Get-ChildItem ENV:SecretUsername).SecretValueText
$pSecret = (Get-ChildItem ENV:SecretPassword).SecretValueText
$sasSecret = (Get-ChildItem ENV:SecretSAS).SecretValueText
$securePassword = ConvertTo-SecureString -String $pSecret -AsPlainText -Force
$UserCredential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $uSecret, $securePassword
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $session
$startDate=(get-date).AddDays(-10)
$endDate=(get-date)
$scriptStart=(get-date)
$sessionName = (get-date -Format 'u')+'pbiauditlog'
$aggregateResults = #()
$i = 0 # Loop counter
Do {
$currentResults = Search-UnifiedAuditLog -StartDate $startDate -EndDate $enddate -SessionId $sessionName -SessionCommand ReturnLargeSet -ResultSize 1000 -RecordType PowerBIAudit
if ($currentResults.Count -gt 0) {
Write-Host ("Finished {3} search #{1}, {2} records: {0} min" -f [math]::Round((New-TimeSpan -Start $scriptStart).TotalMinutes,4), $i, $currentResults.Count, $user.UserPrincipalName )
# Accumulate the data.
$aggregateResults += $currentResults
# No need to do another query if the # records returned <1000 - should save around 5-10 seconds per user.
if ($currentResults.Count -lt 1000) {
$currentResults = #()
} else {
$i++
}
}
} Until ($currentResults.Count -eq 0) # End of Session Search Loop.
$data=#()
foreach ($auditlogitem in $aggregateResults) {
$datum = New-Object -TypeName PSObject
$d = ConvertFrom-json $auditlogitem.AuditData
$datum | Add-Member -MemberType NoteProperty -Name Id -Value $d.Id
$datum | Add-Member -MemberType NoteProperty -Name CreationTDateTime -Value $d.CreationDate
$datum | Add-Member -MemberType NoteProperty -Name CreationTime -Value $d.CreationTime
$datum | Add-Member -MemberType NoteProperty -Name RecordType -Value $d.RecordType
$datum | Add-Member -MemberType NoteProperty -Name Operation -Value $d.Operation
$datum | Add-Member -MemberType NoteProperty -Name OrganizationId -Value $d.OrganizationId
$datum | Add-Member -MemberType NoteProperty -Name UserType -Value $d.UserType
$datum | Add-Member -MemberType NoteProperty -Name UserKey -Value $d.UserKey
$datum | Add-Member -MemberType NoteProperty -Name Workload -Value $d.Workload
$datum | Add-Member -MemberType NoteProperty -Name UserId -Value $d.UserId
$datum | Add-Member -MemberType NoteProperty -Name ClientIPAddress -Value $d.ClientIPAddress
$datum | Add-Member -MemberType NoteProperty -Name UserAgent -Value $d.UserAgent
$datum | Add-Member -MemberType NoteProperty -Name Activity -Value $d.Activity
$datum | Add-Member -MemberType NoteProperty -Name ItemName -Value $d.ItemName
$datum | Add-Member -MemberType NoteProperty -Name WorkSpaceName -Value $d.WorkSpaceName
$datum | Add-Member -MemberType NoteProperty -Name DashboardName -Value $d.DashboardName
$datum | Add-Member -MemberType NoteProperty -Name DatasetName -Value $d.DatasetName
$datum | Add-Member -MemberType NoteProperty -Name ReportName -Value $d.ReportName
$datum | Add-Member -MemberType NoteProperty -Name WorkspaceId -Value $d.WorkspaceId
$datum | Add-Member -MemberType NoteProperty -Name ObjectId -Value $d.ObjectId
$datum | Add-Member -MemberType NoteProperty -Name DashboardId -Value $d.DashboardId
$datum | Add-Member -MemberType NoteProperty -Name DatasetId -Value $d.DatasetId
$datum | Add-Member -MemberType NoteProperty -Name ReportId -Value $d.ReportId
$datum | Add-Member -MemberType NoteProperty -Name OrgAppPermission -Value $d.OrgAppPermission
# Option to include the below JSON column however for large amounts of data it may be difficult for PBI to parse
$datum | Add-Member -MemberType NoteProperty -Name Datasets -Value (ConvertTo-Json $d.Datasets)
# Below is a simple PowerShell statement to grab one of the entries and place in the DatasetName if any exist
foreach ($dataset in $d.datasets) {
$datum.DatasetName = $dataset.DatasetName
$datum.DatasetId = $dataset.DatasetId
}
$data+=$datum
}
$dateTimestring = $startDate.ToString("yyyyMMdd") + "_" + (Get-Date -Format "yyyyMMdd") + "_" + (Get-Date -Format "HHmm")
$fileName = ($dateTimestring + ".csv")
Write-Host ("Writing to file {0}" -f $fileName)
$filePath = "$Env:temp/" + $fileName
$data | Export-csv -Path $filePath
Connect-AzAccount -Credential $UserCredential
Get-AzVM -ResourceGroupName "Audit" -status
$Context = New-AzStorageContext -StorageAccountName "auditingstorage" -StorageAccountKey $sasSecret
Set-AzStorageBlobContent -Force -Context $Context -Container "auditlogs" -File $filePath -Blob $filename
Remove-PSSession -Id $Session.Id
How do I reference the application settings in Azure Function so that I can use the stored secrets in my program?
Please assist! Many thanks!
To access the app settings, keyvault or not, you must retrieve it trhough : $env:APPSETTING_YourSettingName
Thus, for your keyvault referenced secret, you would access it through the following variables.
$env:APPSETTING_SecretUserName
$env:APPSETTING_SecretPassword
$env:APPSETTING_SecretSAS
And if ever you need to produce a list of them.
Get-ChildItem env:APPSETTING_*
Note, the values returned will plain text unencrypted string.
Therefore, in your code, this:
$uSecret = (Get-ChildItem ENV:SecretUsername).SecretValueText
becomes that:
$uSecret = $env:APPSETTING_SecretUserName
Additional note
Since it was pointed out in the comments, I'll mention it.
I am not advocating the use of clear text secret in app settings at all.
App settings should be a keyvault referene for any sensitive data.
I am simply stating that it can be retrieved within the function at runtime as clear-text through the $env:APPSETTING_YourSettingName variable.
Example:
AppSetting name : MySecretUser
AppSetting value: #Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)
Actual secret value (In the keyvault) : I_AM_Secret
At runtime, getting the value of $env:APPSETTING_MySecretUser will return a String Object with the value I_AM_Secret
I am using the following to connect to my SPO tenant and pull a report, however I am finding that the WebsCount parameter is not populating any subsites, has anyone encountered similar behavior and how to fix this bulk query?
Import-Module Microsoft.Online.SharePoint.Powershell -DisableNameChecking
#Config Parameters
$AdminSiteURL="https://SPTenant-admin.sharepoint.com"
$ReportOutput="C:\Temp\SPOStorage.csv"
#Get Credentials to connect to SharePoint Admin Center
$Cred = Get-Credential
#Connect to SharePoint Online Admin Center
Connect-SPOService -Url $AdminSiteURL –Credential $Cred
#Get all Site collections details and Export to CSV
Get-SPOSite -Limit ALL -Detailed | Export-Csv -Path $ReportOutput -NoTypeInformation
The following PowerShell for your reference.
Import-Module Microsoft.Online.SharePoint.Powershell -DisableNameChecking
#Config Parameters
$AdminSiteURL="https://tenant-admin.sharepoint.com"
$ReportOutput="C:\Temp\SPOStorage.csv"
#Get Credentials to connect to SharePoint Admin Center
$Cred = Get-Credential
#Connect to SharePoint Online Admin Center
Connect-SPOService -Url $AdminSiteURL –Credential $Cred
#Get All site collections
$SiteCollections = Get-SPOSite -Limit All
Write-Host "Total Number of Site collections Found:"$SiteCollections.count -f Yellow
#Array to store Result
$ResultSet = #()
#Loop through each site collection and retrieve details
Foreach ($Site in $SiteCollections)
{
Write-Host "Processing Site Collection :"$Site.URL -f Yellow
$Site=Get-SPOSite -identity $Site.Url -Limit ALL -Detailed
#Get site collection details
$Result = new-object PSObject
$Result | add-member -membertype NoteProperty -name "Title" -Value $Site.Title
$Result | add-member -membertype NoteProperty -name "Url" -Value $Site.Url
$Result | add-member -membertype NoteProperty -name "WebsCount" -Value $Site.WebsCount
$Result | add-member -membertype NoteProperty -name "LastContentModifiedDate" -Value $Site.LastContentModifiedDate
$Result | add-member -membertype NoteProperty -name "Status" -Value $Site.Status
$Result | add-member -membertype NoteProperty -name "LocaleId" -Value $Site.LocaleId
$Result | add-member -membertype NoteProperty -name "LockState" -Value $Site.LockState
$Result | add-member -membertype NoteProperty -name "StorageQuota" -Value $Site.StorageQuota
$Result | add-member -membertype NoteProperty -name "StorageQuotaWarningLevel" -Value $Site.StorageQuotaWarningLevel
$Result | add-member -membertype NoteProperty -name "Used" -Value $Site.StorageUsageCurrent
$Result | add-member -membertype NoteProperty -name "CompatibilityLevel" -Value $Site.CompatibilityLevel
$Result | add-member -membertype NoteProperty -name "Template" -Value $Site.Template
$Result | add-member -membertype NoteProperty -name "SharingCapability" -Value $Site.SharingCapability
$ResultSet += $Result
}
#Export Result to csv file
$ResultSet | Export-Csv $ReportOutput -notypeinformation
Write-Host "Site Quota Report Generated Successfully!" -f Green
Check the similar thread here: SiteProperties.WebsCount property is returning zero (CSOM)?
I have problems to list lists permissions using CSOM/PowerShell.
Variables / filters
$spSiteUrl = "https://mytenant.sharepoint.com"
Getting credentials
if($cred -eq $null)
{
$cred = Get-Credential
}
Loading Assemblies
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
Connecting into SharePoint and showing site title
Write-Host "Connecting to SharePoint"
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($spSiteUrl)
$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName, $cred.Password)
$web = $ctx.Web
$ctx.Load($web)
$ctx.ExecuteQuery()
Write-host "Site Name : $($web.Title)"
Function listing "useful" applications
function getApps($web)
{
$appsArray = #()
$apps = $web.Lists
$ctx.Load($apps)
$ctx.ExecuteQuery()
Write-Host "List of aplications : "
foreach($app in $apps){
if($app.Hidden -eq $false)
{
$item = New-Object PSObject
$item | Add-Member -MemberType NoteProperty -Name 'Col1' -Value $($app.Title)
$item | Add-Member -MemberType NoteProperty -Name 'Col2' -Value $($app.HasUniqueRoleAssignments)
$item | Add-Member -MemberType NoteProperty -Name 'Col3' -Value $($app.RoleAssignments)
$item | Add-Member -MemberType NoteProperty -Name 'Col4' -Value $($app.BrowserFileHandling)
$item | Add-Member -MemberType NoteProperty -Name 'Col5' -Value $($app.EffectiveBasePermissions)
$item | Add-Member -MemberType NoteProperty -Name 'Col6' -Value $($app.Fields)
$item | Add-Member -MemberType NoteProperty -Name 'Col7' -Value $($app.WorkflowAssociations)
$appsArray += $item
}
}
$appsArray | Format-Table
}
Calling the function
getApps($web)
My problem is that :
$app.HasUniqueRoleAssignments
$app.RoleAssignments
$app.BrowserFileHandling
$app.EffectiveBasePermissions
$app.Fields
$app.WorkflowAssociations
Return me errors
The collection has not been initialized. It has not been requested or
the request has not been executed. It may need to be explicitly
requested..
The exception
The collection has not been initialized. It has not been requested or
the request has not been executed. It may need to be explicitly
requested.
Typically means that the property you are trying to work with (e.g. HasUniqueRoleAssignments) was not retrieved from the server yet.
You probably need an additional ExecuteQuery to load each app
foreach($app in $apps){
if($app.Hidden -eq $false)
{
$ctx.Load($app)
$ctx.ExecuteQuery()
You will eventually notice that some properties can't be retrieved with regular csom api (such as HasUniqueRoleAssignments) and for those you can use Gary's powershell, giving you the possibility to do what you otherwise would use linq
foreach($app in $apps){
if($app.Hidden -eq $false)
{
$ctx.Load($app)
Load-CSOMProperties -object $app -propertyNames #("HasUniqueRoleAssignments")
$ctx.ExecuteQuery()
https://gist.github.com/glapointe/cc75574a1d4a225f401b#file-load-csomproperties-ps1
https://sharepoint.stackexchange.com/questions/126221/spo-retrieve-hasuniqueroleassignements-property-using-powershell