SSRS How to Get Report Cache Options With Powershell? - web-services

In SSRS web interface, after clicking on a report and going to Manage --> Caching if a report is configured to "Always run this report against pregenerated snapshots" there is a Cache snapshots section with an option "Create cache snapshots on a schedule"
I have been messing around with PowerShell and trying to create a scriptthe finds all of the reports where this option is set, and output the schedule.
I have this script that iterates over each report with "Execution Type" of "Snapshot", but I believe I'm calling the wrong method (GetCacheOptions), as all it returns is False for each item:
Clear-Host 
$webServiceUrl = 'http://myReportServer.domain.com/reportserver/reportservice2010.asmx?WSDL'
$rs = New-WebServiceProxy -Class 'RS' -Namespace 'RS' -Uri $webServiceUrl -UseDefaultCredential
$reports = $rs.ListChildren("/Some Folder", $true) | Where-Object { $_.TypeName -eq "Report" }
$schedDef = New-Object RS.ScheduleDefinition
$expDef = New-Object RS.ExpirationDefinition
foreach ($report in $reports) {
$execType = $rs.GetExecutionOptions($report.Path, [ref]$schedDef.Item)
if($execType -eq "Snapshot") {
$rs.GetCacheOptions($report.Path, [ref]$expDef.Item)
}
}
Does anyone know what method needs to be called to get this information and how to call this method (i.e. what parameters needs to be supplied)?
EDIT:
Per guidance from accepted answer, I was able to make some edits (below) and I'm not getting the schedule information I desire:
.......
....
foreach ($report in $reports) {
$execResult = $rs.GetExecutionOptions($report.Path,
[ref]$ScheduleDefinitionOrReference)
if ($execResult -eq "Snapshot") {
if($ScheduleDefinitionOrReference.Item -is [RS.DailyRecurrence]) {
Write-Host "$($report.Name):" -f Green
Write-Host "`tSchedule Information:" -f Yellow
Write-Host "`t`tEvery $($ScheduleDefinitionOrReference.Item.Daysinterval) Day(s)"
Write-Host "`t`tStart Time: $($ScheduleDefinitionOrReference.StartDateTime)`n"
}
}

You can use ReportingService2010.GetItemHistoryOptions and pass the ItemPath, and out bool KeepExecutionSnapshots, and out ScheduleDefinitionOrReference to the method.
ScheduleDefinitionOrReference will contain the ScheduleDefinition if you check Create cache snapshots on a schedule, otherwise its value will be NoSchedule.
Example
$svcUrl = 'http://the-host-name/ReportServer/reportservice2010.asmx'
$svc = New-WebServiceProxy -Class 'RS' -Namespace 'RS' -Uri $svcUrl -UseDefaultCredential
$reports = $svc.ListChildren("/", $true) | Where-Object { $_.TypeName -eq "Report" }
$KeepExecutionSnapshots = $false
$ScheduleDefinitionOrReference = New-Object RS.ScheduleDefinitionOrReference
foreach ($report in $reports) {
$svc.GetItemHistoryOptions($report.Path,
[ref]$KeepExecutionSnapshots,
[ref]$ScheduleDefinitionOrReference)
$report.Path
$ScheduleDefinitionOrReference
}

Related

Is there any Powershell script to get/update term set navigation url

I am new to sharepoint and need help in updating a url in sharepoint site. can some one suggest is updating that through powershell is better or any other suggestions are appreciated. Thanks
The following PowerShell for your reference.
$siteURL="http://sp2013/sites/team"
$termStoreName="Managed Metadata Service"
$termGroupName="Global Navigation"
$termSetName="MyTermSet"
$oldUrl="/test"
$newUrl="/test1"
$site = Get-SPSite -Identity $siteURL
$taxSession = Get-SPTaxonomySession -Site $site
$tStore = $taxSession.TermStores[$termStoreName]
$tGroup = $tStore.Groups| Where-Object {$_.Name -eq $termGroupName}
$tSet = $tGroup.TermSets| Where-Object {$_.Name -eq $termSetName}
foreach( $term in $tSet.Terms)
{
$term.Name
$NavURL = $term.LocalCustomProperties["_Sys_Nav_SimpleLinkUrl"]
if($NavURL -match $oldUrl)
{
$NavURL = $NavURL -replace $oldUrl, $newUrl
$term.SetLocalCustomProperty("_Sys_Nav_SimpleLinkUrl",$NavURL)
}
$term.LocalCustomProperties["_Sys_Nav_SimpleLinkUrl"]
foreach ( $subTerm in $term.Terms)
{
$subTerm.Name
$NavURL = $subTerm.LocalCustomProperties["_Sys_Nav_SimpleLinkUrl"]
if($NavURL -match $oldUrl)
{
$NavURL = $NavURL -replace $oldUrl, $newUrl
$subTerm.SetLocalCustomProperty("_Sys_Nav_SimpleLinkUrl",$NavURL)
}
$subTerm.LocalCustomProperties["_Sys_Nav_SimpleLinkUrl"]
}
}
$tStore.CommitAll()
Refer to: SharePoint 2013 Managed Metadata Navigation with Site collection relative URLs

Registry - search child values to change parent value

I am looking to change a registry value based on a value found within its child key in powershell-v4.0. Please see the below diagram.
- scripts
- {ID}
+ ScriptState = 0 #This is the value I am looking to change
- properties
+ {ID},E = 'Activated' #based on the values of these registry values
+ {ID},V = 'Hard Drive' #based on the values of these registry values
Legend:
+ = Value
- = Key
All of the IDs are randomly generated, and I am having trouble looping through/getting a list of the randomly generated key IDs. Once I am able to loop through those key IDs then the rest should be fairly easy.
Below is the current script I am using that attempts to locate and filter the child keys (changing parent's parent's key value not yet implemented).
V1:
Get-ChildItem -Path $key -rec | foreach {
Get-ChildItem -Path $_.PSPath -rec } | foreach {
$CurrentKey = (Get-ItemProperty -Path $_.PsPath) } |
select-string "REGEX TO FIND VALUES" -input $CurrentKey -AllMatches |
foreach {($_.matches)| select-object Value
}
V2:
Get-ChildItem -Path $key -rec | foreach {
Get-ChildItem -Path $_.PSPath -rec | foreach {
$CurrentKey = (Get-ItemProperty -Path $_.PsPath)
if ($CurrentKey -match "REGEX TO FIND VALUES") {
$CurrentKey
}
}}
Neither of the above scripts produces any results and I'm hoping that someone can explain why they are not giving any result or point me towards a code that will accomplish the objective stated above.
Once you've done a Get-ChildItem -Recurse on the parent, you don't need to do an additional -Recurse on the ChildItem. All of the ChildItems are already in memory and ready to be used in your pipeline. I'm not sure if the below will help but this is how I'd go about finding a value somewhere in a list of keys.
$DebugPreference = 'Continue'
#Any Get-ChildItem with -Recurse will get all items underneath it, both childitems and their childitems.
$regKeySet = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -Recurse
foreach($childKey in $regKeySet)
{
Write-Debug -Message "Processing registry key $($childKey.Name)"
#You can pick any property you want, the -ErrorAction is set here to SilentlyContinue to cover the instances
#where the specific childitem does not contain the property you are looking for, the errors are typically non-terminating but it cleans up the red.
$publisherInfo = Get-ItemProperty $childKey.Name -Name Publisher -ErrorAction SilentlyContinue
if($publisherInfo.Publisher -ieq 'Microsoft Corporation')
{
#Do stuff here, you mention doing something to the parent, this is easily accomplished by
#just referecning the $childKey that is in this loop. If the publisher equals something you can then manipulate any property of the parent you would like.
Write-Host "Found the publisher I wanted: $($publisherInfo.Publisher)." -ForegroundColor Green
}
}

Unit Testing a Class-based DSC resource with Pester

I am having a problem with unit testing a class-based DSC resource. I am trying to Mock a couple of functions in the class and I get a cast error.
PSInvalidCastException: Cannot convert the "bool TestVMExists(string vmPath,
string vmName)" value of type "System.Management.Automation.PSMethod" to type
"System.Management.Automation.ScriptBlock".
My test code is this:
using module 'C:\Program Files\WindowsPowerShell\Modules\xVMWareVM\xVMWareVM.psm1'
$resource = [xVMWareVM]::new()
Describe "Set" {
Context "If the VM does not exist" {
Mock xVMWareVM $resource.TestVMExists {return $false}
Mock xVMWareVM $resource.CreateVM
It "Calls Create VM once" {
Assert-MockCalled $resource.CreateVM -Times 1
}
}
}
Does anyone know how to achieve this?
Thanks in advance
You currently won't be able to mock a class function using Pester. The current workaround is to use Add-Member -MemberType ScriptMethod to replace the function. This means you will not get the mock asserts.
I borrowed this for DockerDsc tests by #bgelens.
Without your class code, I haven't been able to test this, but it should give you the idea along with #bgelens code above.
using module 'C:\Program Files\WindowsPowerShell\Modules\xVMWareVM\xVMWareVM.psm1'
Describe "Set" {
Context "If the VM does not exist" {
$resource = [xVMWareVM]::new()
$global:CreateVmCalled = 0
$resource = $resource |
Add-Member -MemberType ScriptMethod -Name TestVMExists -Value {
return $false
} -Force -PassThru
$resource = $resource |
Add-Member -MemberType ScriptMethod -Name CreateVM -Value {
$global:CreateVmCalled ++
} -Force -PassThru
It "Calls Create VM once" {
$global:CreateVmCalled | should be 1
}
}
}

Create custom POST-request body in PowerShell

I am running into a bit of trouble. I am trying to do a POST-request with PowerShell. The problem is that the request-body uses the same key (you can upload multiple images), multiple times, so I can't build a hashtable to send the request. So the requestbody looks like this:
name value
image 1.jpg
image 2.jpg
subject this is the subject
message this is a message
A user with a similar problem (but not the same context) asked this before, and got as a response to use a List with KeyValuePair class. See https://stackoverflow.com/a/5308691/4225082
I cannot seem to create this. I found this https://bensonxion.wordpress.com/2012/04/27/using-key-value-pairs-in-powershell-2/
They use $testDictionary=New-Object “System.Collections.Generic.Dictionary[[System.String],[System.String]]”
to make the dictionary, but this doesn't translate to a list.
I managed to create (what I think is needed) by using $r = New-Object "System.Collections.Generic.List[System.Collections.Generic.KeyvaluePair[string,string]]"
and created a key by using $s = New-Object “System.Collections.Generic.KeyvaluePair[string,string]", but I can't set the values of that key.
I also tried creating a FormObject, but you also can't use the same key multiple times.
What is the best and/or easiest way to do this?
I am going to answer my own question. Because of the research, I managed to use better search terms, and found someone with exactly the same problem:
Does Invoke-WebRequest support arrays as POST form parameters?
I got rid of a bug (?) by changing [HttpWebResponse] to [System.Net.HttpWebResponse] and added the -WebSession parameter. I only needed it for the cookie, so I implemented that and didn't bother about the other stuff, it might need some tweaking for someone else!
This seemed to work at first glance, BUT for elements with the same key, it created an array, which messed up the order of the requestbody. Without the right order, the website won't accept it.
I messed around a bit more, and now I edited it to make use of multidimensional arrays.
So I ended up with this (all credits to the original writer!):
function Invoke-WebRequestEdit
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true)][System.Uri] $Uri,
[Parameter(Mandatory=$false)][System.Object] $Body,
[Parameter(Mandatory=$false)][Microsoft.PowerShell.Commands.WebRequestMethod] $Method,
[Parameter(Mandatory=$false)][Microsoft.PowerShell.Commands.WebRequestSession] $WebSession
# Extend as necessary to match the signature of Invoke-WebRequest to fit your needs.
)
Process
{
# If not posting a NameValueCollection, just call the native Invoke-WebRequest.
if ($Body -eq $null -or $body.GetType().BaseType -ne [Array]) {
Invoke-WebRequest #PsBoundParameters
return;
}
$params = "";
$i = 0;
$j = $body.Count;
$first = $true;
foreach ($array in $body){
if (!$first) {
$params += "&";
} else {
$first = $false;
}
$params += [System.Web.HttpUtility]::UrlEncode($array[0]) + "=" + [System.Web.HttpUtility]::UrlEncode($array[1]);
}
$b = [System.Text.Encoding]::UTF8.GetBytes($params);
# Use HttpWebRequest instead of Invoke-WebRequest, because the latter doesn't support arrays in POST params.
$req = [System.Net.HttpWebRequest]::Create($Uri);
$req.Method = "POST";
$req.ContentLength = $params.Length;
$req.ContentType = "application/x-www-form-urlencoded";
$req.CookieContainer = $WebSession.Cookies
$str = $req.GetRequestStream();
$str.Write($b, 0, $b.Length);
$str.Close();
$str.Dispose();
[System.Net.HttpWebResponse] $res = $req.GetResponse();
$str = $res.GetResponseStream();
$rdr = New-Object -TypeName "System.IO.StreamReader" -ArgumentList ($str);
$content = $rdr.ReadToEnd();
$str.Close();
$str.Dispose();
$rdr.Dispose();
# Build a return object that's similar to a Microsoft.PowerShell.Commands.HtmlWebResponseObject
$ret = New-Object -TypeName "System.Object";
$ret | Add-Member -Type NoteProperty -Name "BaseResponse" -Value $res;
$ret | Add-Member -Type NoteProperty -Name "Content" -Value $content;
$ret | Add-Member -Type NoteProperty -Name "StatusCode" -Value ([int] $res.StatusCode);
$ret | Add-Member -Type NoteProperty -Name "StatusDescription" -Value $res.StatusDescription;
return $ret;
}
}
The $body parameter is made like this:
$form=#()
$form+= ,#("value1",'somevalue')
$form+=,#("value2", 'somevalue')
$form+=,#("value2",'somevalue')
$form+=,#("value3",'somevalue')
Everything looks good now. It still doesn't work, but my original version with unique keys also doesn't work anymore, so there's probably something else going wrong.

Powershell matching TWO values in an array/object

I'll explain what I am trying to achieve first in case there is a better way than what I have wrote. I am trying to get a list of users (but in below example I am only querying one user to test the script) who have an Exchange plan set to disabled.
The filter I need to apply is on the licenses.servicestatus object. If you run and output of this object your get:
ServicePlan ProvisioningStatus
----------- ------------------
INTUNE_O365 PendingActivation
YAMMER_ENTERPRISE PendingInput
RMS_S_ENTERPRISE Success
OFFICESUBSCRIPTION Success
MCOSTANDARD Disabled
SHAREPOINTWAC Disabled
SHAREPOINTENTERPRISE Disabled
EXCHANGE_S_ENTERPRISE Success
What I need is the query to return true if it finds "disabled" in the provisioningstatus column and a matching "exchange" wildcard in the serviceplan column.
My script below does not do this, instead it returns true if it finds disabled and exchange in ANY order, IE it will always return true as long as disabled and Exchange are anywhere in the table, not where they both match on one row. This is as close as I can get as to what I want.
Get-MsolUser -UserPrincipalName "exampleuser#dom.com"| ? {"disabled" -in $_.licenses.servicestatus.provisioningstatus -and ($_.licenses.servicestatus| Out-String| ? {$_ -like "*exchange*"})}
I can see where I am going wrong, I just don't know how to fix it. The script is effectively running two separate searches rather than combining them together.
Also Note the reason I am using out-string is because the table above does not output serviceplan as a string.
If there is a better way of doing this then please advise otherwise I just need to know how to match two conditions in an array from the same row.
Get-MsolUser -UserPrincipalName "exampleuser#dom.com" |
ForEach-Object {
if( ($_.licenses.serviceplan.tostring() -match 'Exchange') -and ($_.licenses.ProvisioningStatus -eq 'Disabled') )
{
$true
}
Else
{
$false
}
}
examining your code :
"disabled" -in $_.licenses.servicestatus.provisioningstatus
wont work because
$_.licenses is an object with 2 properties Servicestatus & Provisioningstatus
so you can either use $_.licenses.servicestatus or $_.licenses.provisioningstatus not both together like $_.licenses.servicestatus.provisioningstatus because there is no such property.
Also -in is used to check if a value is contained in an array not suitable for what you are doing.
Your question got me to think about using Test-Any which i read about in an article written by #JaredPar. The basic idea is to evaluate if any item in an array of objects have a set of matching conditions.
I have put it into a module like this.
function Test-Any {
[CmdletBinding()]
param([scriptblock]$EvaluateCondition,
[Parameter(ValueFromPipeline = $true)] $ObjectToTest)
begin {
$any = $false
}
process {
if (-not $any -and (& $EvaluateCondition $ObjectToTest)) {
$any = $true
}
}
end {
$any
}
}
function Test-All {
[CmdletBinding()]
param([scriptblock]$EvaluateCondition,
[Parameter(ValueFromPipeline = $true)] $ObjectToTest)
begin {
$all = $true
}
process {
if ($all -and ((& $EvaluateCondition $ObjectToTest) -eq $false)) {
$all = $false
}
}
end {
$all
}
}
Export-ModuleMember -Function Test-Any, Test-All
Now as you might have noticed there is also a Test-All function. This is not used for this sample but may come in handy.
Now you can solve your task like this.
Notice i have replaced the call to Get-msoluser with some proper test data.
Import-Module AllAny
$testdata = #(
(new-object psobject -Property #{ServicePlan="ExchangePlan";licenses = new-object psobject -Property #{ProvisioningStatus="Disabled"}}),
(new-object psobject -Property #{ServicePlan="SomeOtherPlan";licenses = new-object psobject -Property #{ProvisioningStatus="Enabled"}}))
$userProp = $testdata #Get-MsolUser -UserPrincipalName "exampleuser#dom.com"
if ($userProp | Test-Any {$Args.serviceplan -match "Exchange" -and $Args.licenses.ProvisioningStatus -eq 'Disabled'})
{
echo "Do your thing!"
}
Hope that it makes sense.
I managed to fix this myself:
Get-MsolUser -UserPrincipalName "exampleuser#dom.com" | ? {$_.licenses.servicestatus| Out-String | ? {$_ -like "*exchange*disabled*"}}
This is fairly old, but here's a slightly neater solution I came up with, given the limitations of Azure queries.
First, create a list of the users that at least include the criteria you need to match on
$users = Get-Msoluser -EnabledFilter EnabledOnly |
Where { ($_.licenses.serviceplan.tostring() -match 'Exchange') `
-and ($_.licenses.ProvisioningStatus -eq 'Disabled') }
What you get is users that have both "Exchange" and "Disabled" somewhere within their Licenses attribute, but they may not be on the same row.
Just be cautious if you are looking for "unlicensed" users, because licenses can be reassigned. Here I'm using Get-AzureADUser and the AssignedPlans property instead. This user has been licensed for SfB twice, but one is still valid.
AssignedTimestamp CapabilityStatus Service ServicePlanId
----------------- ---------------- ------- -------------
2019-12-05 03:46:34 Enabled MicrosoftCommunicationsOnline 3e26ee1f-8a5f-4d52-aee2-b81ce45c8f40
2019-09-26 07:16:48 Deleted MicrosoftCommunicationsOnline 4828c8ec-dc2e-4779-b502-87ac9ce28ab7
After doing the first pass to populate the $users list, to get users where you have at least row that has an Exchange & Disabled value, check each user's Licenses attribute with a Where statement on both properties. The following dumps the UPN into $licensedUsers for later export.
$licensedUsers = #()
$users | Foreach {
$u = $_
if ($u.licenses | where { ($_.serviceplan.tostring() -match 'Exchange') `
-and ($_.ProvisioningStatus -eq 'Disabled') }) {
$licensedUsers += $u.userPrincipalName
#if you want more properties in the report, create a PSCustomObject here instead
}
}
If you only wanted to get the users that don't have any valid Exchange licenses at all, you'd want to reverse the logic to find accounts where all the licences are not enabled.
if (-not ($u.licenses | where { ($_.serviceplan.tostring() -match 'Exchange') `
-and ($_.ProvisioningStatus -eq 'Enabled')) })
There are a couple of things to do this in one line (as far as I can tell):
Use nested Where-Objects to check each object down the tree
No need to convert ServicePlan to a string if you use the 'servicename' property underneath it
So I think this should meet the original posters' requirements in a single command:
Get-MsolUser -UserPrincipalName "exampleuser#dom.com" | Where-Object { $_.Licenses.ServiceStatus | Where-Object { $_.ServicePlan.ServiceName -like "*exchange*" -and $_.ProvisioningStatus -eq "Disabled" } }
Or for a shorter command:
Get-MsolUser -UserPrincipalName "exampleuser#dom.com" | ? { $_.Licenses.ServiceStatus | ? { $_.ServicePlan.ServiceName -like "*exchange*" -and $_.ProvisioningStatus -eq "Disabled" } }