I am about to create a detailed report of all site collections on a tenant.
One part of the report is the usage data such as hits & visits. The report always returns 0 for these properties. I thought there might be a delay between the actual hit/visit and the report, so I tried it several times.
Here is my script:
$adminSiteUrl = "https://tenant-admin.sharepoint.com";
Connect-PnPOnline -Url $adminSiteUrl -Credentials 'O365Dev'
$sites = Get-PnPTenantSite -Detailed
Write-Host "Site Collections found: " $sites.Count
$siteDirectory = #()
foreach ($site in $sites)
{
$tenantSite = $sites | Where-Object {$_.Url -eq $site.Url}
$siteDirectoryEntry = New-Object psobject
Connect-PnPOnline -Url $site.Url -Credentials 'O365Dev'
$siteDetails = Get-PnPSite -Includes RootWeb.Created, RootWeb.SiteUsers, RootWeb.Webs, GeoLocation, IsHubSite, LockIssue, Owner, SecondaryContact, Usage; $siteDetails
$siteDirectoryEntryProperties = #{
URL = $siteDetails.Url
Title = $tenantSite.Title
Description = $tenantSite.Description
...
UsageBandwidth = $siteDetails.Usage.Bandwidth
UsageHits = $siteDetails.Usage.Hits
UsageVisits = $siteDetails.Usage.Visits
}
$siteDirectoryEntry = New-Object psobject -Property $siteDirectoryEntryProperties
$siteDirectory += $siteDirectoryEntry
}
$siteDirectory | Export-Csv .\SiteDirectory.csv
I also tried to add "Usage.Hits" to the "Includes" argument of Get-PnPSite as I would do with other properties such as RootWeb. While it works for the latter, it throws the following error for any UsageInfo Properties:
Get-PnPSite : The query expression is not supported.
At C:\Users....\SPO_Reports.ps1:19 char:20
+ ... teDetails = Get-PnPSite -Includes RootWeb.Created, RootWeb.SiteUsers, ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Get-PnPSite], InvalidQueryExpressionException
+ FullyQualifiedErrorId : EXCEPTION,SharePointPnP.PowerShell.Commands.Site.GetSite
I know I can get some usage statistics like storage through Get-PnPTenantSite but when it comes to hits and visits, it seems like this would be the only way.
Any ideas what I am doing wrong?
Reply by MS Support-
At this time, the only supported method to display usage data for SharePoint Online is through the GUI. You can find more information about this here: https://support.office.com/en-us/article/view-usage-data-for-your-sharepoint-site-2fa8ddc2-c4b3-4268-8d26-a772dc55779e
The information above is not acceptable
Related
i'm new to ps scripting , i want to export certain data from event logs. I tried following
$Myexcel = New-Object -ComObject excel.application
$Myexcel.visible = $true
$Myworkbook = $Myexcel.workbooks.add()
$Sheet1 = $Myworkbook.worksheets.item(1)
$Sheet1.name = "summary"
$Sheet1.cells.item(1,1) = 'BootDevice'
$events = Get-WinEvent -FilterHashtable #{logname="Microsoft-Windows-Storage-Storport/Health"; id=511}
# get the first event raw XML
$event = [xml]$events[0].ToXml()
# display its content
#$event.Event.EventData.Data
$BootDevice=$event.Event.EventData.Data | Where-Object {$_.name -eq "BootDevice"}
write-output $BootDevice
$Sheet1.cells.item(2,1) = $BootDevice
$Sheet1.Columns.AutoFit()
$Myfile = 'E:\tmp\test.xlsx'
$Myworkbook.Saveas($Myfile)
$Myexcel.displayalerts = $true
But its giving error
Exception from HRESULT: 0x800A03EC
At line:16 char:1
+ $Sheet1.cells.item(2,1) = $BootDevice
And a blank excel is generated.
Any help will be thankfull.
I am able to deploy the ssrs report (.rdl file) to the target server using an azure extension successfully. However now if I have to deploy them to different environments like preprod,prod. I need to manually change the connection string in the .rdl file. How can I automate this process.
In our environments, we set up a DataSource per environment, and then after creating/deploying the report, we set its DataSource to the DataSource for that environment (Note, this is using the legacy SOAP API, this example would need to change if you're using the REST API):
param(
[string]$environment = "",
[string]$reportServerUri = "https://localhost:443/SSRS"
)
$rs = New-WebServiceProxy -Uri $reportServerUri -UseDefaultCredential
$targetFolderPath = ("/ChangeThisRootFolderToWhereverYouWantItToBe/Reports/{0}" -f $environment)
$newDataSourcePath = ("/ChangeThisRootFolderToWhereverYouWantItToBe/DataSources/{0}/ChangeThisDataSource" -f $environment)
$newDataSourceName = "ChangeThisDataSource"
$warnings = $null
Get-ChildItem *.rdl | Foreach-Object {
$reportName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
$bytes = [System.IO.File]::ReadAllBytes($_.FullName)
Write-Output "Uploading report ""$reportName"" to ""$targetFolderPath""...`r`n"
$warnings = $rs.CreateReport(
$reportName, # Report name
$targetFolderPath,# Destination folder
$true, # Overwrite report if it exists?
$bytes, # .rdl file contents
$null) # Properties to set.
$warnings | ForEach-Object {
Write-Output ("Warning: {0}" -f $_.Message)
}
$reportPath = "$($targetFolderPath)/$($reportName)"
$dataSources = $rs.GetItemDataSources($reportPath)
$dataSources | ForEach-Object {
$proxyNamespace = $_.GetType().Namespace
$myDataSource = New-Object ("$proxyNamespace.DataSource")
$myDataSource.Name = $newDataSourceName
$myDataSource.Item = New-Object ("$proxyNamespace.DataSourceReference")
$myDataSource.Item.Reference = $newDataSourcePath
$_.item = $myDataSource.Item
$rs.SetItemDataSources($reportPath, $_)
Write-Output "Changing report's DataSource reference ($($_.Name)) to: $($_.Item.Reference)";
}
Write-Output ""
}
I'm using the following script to enable MFA methods for a user in Azure Active Directory (snippet taken from this article):
Connect-MsolService
$UserPrincipalName = "j.brown#exchangelabs.nl"
$SMS = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$SMS.IsDefault = $true
$SMS.MethodType = "OneWaySMS"
$Phone = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$Phone.IsDefault = $false
$Phone.MethodType = "TwoWayVoiceMobile"
$PrePopulate = #($SMS, $Phone)
Set-MsolUser -UserPrincipalName $UserPrincipalName -StrongAuthenticationMethods $PrePopulate
It works great, but this means that I'll have to run this anytime a new user is created.
Is there a way I can set it as a default for new users?
Edit:
Here is a previous question that might shed some more light on the issue:
Enforcing phone number in azure active directory MFA
Have you tried the below snippet at the end,
Connect-MsolService
$UserPrincipalName = "email#email.com"
$SMS = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$SMS.IsDefault = $true
$SMS.MethodType = "OneWaySMS"
$Phone = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationMethod
$Phone.IsDefault = $false
$Phone.MethodType = "TwoWayVoiceMobile"
$PrePopulate = #($SMS, $Phone)
Get-MsolUser -All | foreach{set-msoluser -UserPrincipalName $_.UserPrincipalName -StrongAuthenticationMethods $PrePopulate}
my sharepoint site list is having too many items and i need to delete 10000 files from it.How to do that using powershell script.
Create the query:
$list = (Get-Spweb http://devmy101).GetList("http://devmy101/Lists/smarEnteredTerritorialWaters")
$query = New-Object Microsoft.SharePoint.SPQuery;
$query.ViewAttributes = "Scope='Recursive'";
$query.RowLimit = 2000;
$query.Query = '<Where><Gt><FieldRef Name="Created"/><Value Type="DateTime" IncludeTimeValue="TRUE">2013-07-10T14:20:00Z</Value></Gt></Where>';
Build the command (note the query is limited to returning 2000 items at a time, and uses the ListItemCollectionPosition property to continue retrieving items in batches of 2000 until all the items have been queried. See this MSDN documentation for more info.)
$itemCount = 0;
$listId = $list.ID;
[System.Text.StringBuilder]$batchXml = New-Object "System.Text.StringBuilder";
$batchXml.Append("<?xml version=`"1.0`" encoding=`"UTF-8`"?><Batch>");
$command = [System.String]::Format( "<Method><SetList>{0}</SetList><SetVar Name=`"ID`">{1}</SetVar><SetVar Name=`"Cmd`">Delete</SetVar></Method>", $listId, "{0}" );
do
{
$listItems = $list.GetItems($query)
$query.ListItemCollectionPosition = $listItems.ListItemCollectionPosition
foreach ($item in $listItems)
{
if($item -ne $null){$batchXml.Append([System.String]::Format($command, $item.ID.ToString())) | Out-Null;$itemCount++;}
}
}
while ($query.ListItemCollectionPosition -ne $null)
$batchXml.Append("</Batch>");
$itemCount;
And lastly (and most importantly!), run the query
$web = Get-Spweb http://inceweb/HKMarineDB;
$web.ProcessBatchData($batchXml.ToString()) | Out-Null;
You will want to run this in SharePoint Management Shell as Admin.
This is verbatim takin from a blog post by Matthew Yarlett. I posted the majority of the post here incase his blog ever goes away. http://matthewyarlett.blogspot.com/2013/07/well-that-was-fun-bulk-deleting-items.html
I am working on a GUI script and I ran into a problem with my TreeView object. The problem occurs when I try to display the SelectedNode property or try to use the GetNodeAt() method of a TreeView that is displayed in another thread. I am able to display the TreeView object itself though. This is a sample of what I'm trying to do:
$form = new-object system.windows.forms.form
$treeview = new-object system.windows.forms.treeview
$treeview.name = "tree view"
$treeview.add_afterselect({write-host $this.selectednode})
$treenode = new-object system.windows.forms.treenode
$treenode.name = "tree node"
$treenode.text = "tree node"
$treenode2 = new-object system.windows.forms.treenode
$treenode2.name = "second tree node"
$treenode2.text = "second tree node"
$treeview.nodes.addrange(#($treenode,$treenode2))
$form.controls.add($treeview)
$thread = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
$thread.Open()
$thread.SessionStateProxy.SetVariable("form",$form)
$thepipe = $thread.CreatePipeline({$form.Showdialog()})
$thepipe.Input.Close()
$thepipe.InvokeAsync()
The issue comes with the line $treeview.add_afterselect({write-host $this.selectednode}) When I click a node in the treeview the form will hang and I have to kill the Powershell process. The weird thing is I can display the TreeView object with no issue. Like this: $treeview.add_afterselect({write-host $this}). This will return the TreeView Object with no issues. I have also tried to use this instead $treeview.add_nodemouseclick({write-host $this.getnodeat($_.x,$_.y)}). This will also hang the form.
The problem comes from the form being displayed in another thread because when I do the same code but keep the form in the same thread I have no issues with displaying the selected node. like this:
$form = new-object system.windows.forms.form
$treeview = new-object system.windows.forms.treeview
$treeview.name = "tree view"
$treeview.add_afterselect({write-host $this.selectednode})
$treenode = new-object system.windows.forms.treenode
$treenode.name = "tree node"
$treenode.text = "tree node"
$treenode2 = new-object system.windows.forms.treenode
$treenode2.name = "second tree node"
$treenode2.text = "second tree node"
$treeview.nodes.addrange(#($treenode,$treenode2))
$form.controls.add($treeview)
$form.Showdialog()
Any help will be greatly appreciated. Thank you!
If you take a look at the TreeViewEventHandler method signature, you'll find that it takes two arguments, a sender and a TreeViewEventArgs object.
You can either "intercept" these by declaring your own named parameters, like so:
$treeview.add_AfterSelect({
param($s,$e)
# $e now refers to the TreeViewEventArgs
Write-Host $e.Node
})
Or you can rely on the automatic event variables $Sender and $EventArgs:
$treeview.add_AfterSelect({
Write-Host $EventArgs.Node
})
You may want to have a look at the help files for Register-ObjectEvent and about_Automatic_Variables
Don't use $this inside an event action - it's meant to be used as an instance reference in script method definitions, like so:
PS C:\> $obj = New-Object psobject -Property #{ Number = 3 }
PS C:\> $obj |Add-Member -Type ScriptMethod -Name GetSquare -Value { return $this.Number * $this.Number }
PS C:\> $obj.GetSquare()
9
PS C:\> $obj.Number = 4
PS C:\> $obj.GetSquare()
16