PowerShell: Exception calling "GetListItems" with "7" argument(s) - powershell

Attempting to Get List Items from SharePoint using PowerShell.
I used the example from here Windows PowerShell Blog, modified it to use with my site. Now I get the following error:
Exception calling "GetListItems" with "7" argument(s): "Exception of type 'Microsoft.SharePoint.SoapServer.SoapServerException' was thrown."
At line:30 char:1
+ $list = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $qu ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SoapException
Script I am using:
# The uri refers to the path of the service description, e.g. the .asmx page
$uri = "http://SITE/sites/DefaultCollection/Engineering/Subsite%20(UK)/_vti_bin/lists.asmx"
# Create the service
$service = New-WebServiceProxy -Uri $uri -Namespace SpWs -UseDefaultCredential
# The name of the list
$listName = "Test1"
# Create xml query to retrieve list.
$xmlDoc = new-object System.Xml.XmlDocument
$query = $xmlDoc.CreateElement("Query")
$viewFields = $xmlDoc.CreateElement("ViewFields")
$queryOptions = $xmlDoc.CreateElement("QueryOptions")
$query.set_InnerXml("FieldRef Name='Text1'")
$rowLimit = "10"
$list = $null
$service = $null
try
{
$service = New-WebServiceProxy -Uri $uri -Namespace SpWs -UseDefaultCredential
}
catch
{
Write-Error $_ -ErrorAction:'SilentlyContinue'
}
$list = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $queryOptions, "")
if($service -ne $null)
{
try
{
$list = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $queryOptions, "")
}
catch
{
Write-Error $_ -ErrorAction:'SilentlyContinue'
}
}
Anyone tried this before? How can I resolve this issue?

Here's the solution worked for me..
Add "?WSDL" to the end of $uri string
$uri = "http://SITE/sites/DefaultCollection/Engineering/Subsite%20(UK)/_vti_bin/lists.asmx?WSDL"
According to this link:To return a service description of a Web service that was created by using ASP.NET, append "?WSDL" to the URL of the Web service (for example, http://www.ss64.com/MyWebService.asmx?WSDL)

The line it is throwing the error at is:
$list = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $queryOptions, "")
That line is not caught, but here is a similar issue throwing the same error. If you want to try and get a better exception, wrap the line in another try catch:
try{
$list = $service.GetListItems($listName, "", $query, $viewFields, $rowLimit, $queryOptions, "")
}
catch{
[System.Exception]
write-host ($_.Exception).Message
}

Please make sure to add "?WSDL" to your URI which is why the code breaks. Pretends like it doesn't know the definition of the function (atleast I guess)...
Like the one below. I was surprised to see this made my code work. Weird..
$uri = "http://<>/sites/DefaultCollection/Engineering/Subsite%20(UK)/_vti_bin/lists.asmx?WSDL"

Related

Change Credential Retrieval in SSRS with powershell

I want to change SSRS data source credential retrieval from using the following credentials to without any credentials with powershell and script fails.
I want to change value 'Store' to 'None' according to this article:
https://learn.microsoft.com/en-us/dotnet/api/reportservice2010.credentialretrievalenum?view=sqlserver-2016#ReportService2010_CredentialRetrievalEnum_None
This is my code:
$uri ='http://ServerName/ReportServer/ReportService2010.asmx?wsdl'
$reporting = New-WebServiceProxy -uri $uri -UseDefaultCredential -namespace "ReportingWebService"
$DataSources = $reporting.ListChildren('/', $true) | Where-Object {$_.Name -eq "DataSourceName"}
foreach($Object in $DataSources) {
$dataSource =$reporting.GetDataSourceContents($Object.path)
#$dataSource.CredentialRetrieval="None"
$dataSource.CredentialRetrieval=[ReportingWebService.CredentialRetrievalEnum]::None
$reporting.SetDataSourceContents($Object.path,$dataSource)
}
This is the error:
Exception calling "SetDataSourceContents" with "2" argument(s): "The combination of values for the fields UserName and CredentialRetrieval are not valid. --->
Microsoft.ReportingServices.Diagnostics.Utilities.InvalidElementCombinationException: The combination of values for the fields UserName and CredentialRetrieval are not valid."
At line:13 char:4
+ $reporting.SetDataSourceContents($Object.path,$dataSource)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SoapException
The issue was that i actually did not change existent credential retrieval settings 'Store' with required Username parameter.
To resolve it i should create new data source definition with new credential retrieval settings and apply it to my data source:
$uri ='http://servername/ReportServer/ReportService2010.asmx?wsdl'
$reporting = New-WebServiceProxy -uri $uri -UseDefaultCredential
$type=$reporting.GetType().Namespace
$DataSources = $reporting.ListChildren('/', $true) | Where-Object {$_.Name -eq "Data source name"}
foreach($Object in $DataSources) {
$dataSource =$reporting.GetDataSourceContents($Object.path)
$dataSourceDefinitionType = ($type + '.DataSourceDefinition');
$dataSourceDefinition = New-Object ($dataSourceDefinitionType);
$dataSourceDefinition.Extension = $dataSource.Extension; #get data from existent data source definition
$dataSourceDefinition.ConnectString = $dataSource.ConnectString #get data from existent data source definition
$credentialRetrievalDataType = ($type + '.CredentialRetrievalEnum');
$credentialRetrieval = new-object ($credentialRetrievalDataType);
$credentialRetrieval.value__ = 3;
$dataSourceDefinition.CredentialRetrieval = $credentialRetrieval;
$dataSourceDefinition.WindowsCredentials = $dataSource.WindowsCredentials; #get data from existent data source definition
$dataSourceDefinition.Enabled = $dataSource.Enabled; #get data from existent data source definition
$dataSourceDefinition.EnabledSpecified = $dataSource.EnabledSpecified; #get data from existent data source definition
$reporting.SetDataSourceContents($Object.path,$dataSourceDefinition)
}

% : You cannot call a method on a null-valued expression

I think I've found unexplainable in PowerShell scripting. Let me describe the problem below:
I created a function that will query VSTS and will output back the amount of bugs that contain specific tags.
function GetBugsFromVSTS($applicationName, $first_url, $second_url, $query) {
#Building the body of the HTTP request to VSTS endpoint
$bodyOfRequest = $query | ConvertTo-Json
#Building headers of the HTTP request to VSTS endpoint
$headers = #{
'Content-Type'='application/json'
'Accept'='application/json'
'Authorization' = '' + $vsts_access_token + ''
}
$getBugs = Invoke-RestMethod -Uri $first_url `
-Method Post `
-Body $bodyOfRequest `
-Headers $headers | ConvertTo-Json -Depth 100
$json_decoded = $getBugs | ConvertFrom-Json
if ($json_decoded.workItems -eq $null) {
Write-Host "$applicationName Json decoded workitems are equal null" -ForegroundColor Red
} else {
Write-Host "$applicationName Json decoded workitems are not null" -ForegroundColor Green
$json_decoded.workItems | % {
$bug_id = $_.id
Write-Host $bug_id
}
}
$json_decoded.workItems | % {
$bug_id = $_.id
$url = ($second_url +$bug_id)
$getVstsBugState = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
[PSCustomObject]#{
"Application Name" = $applicationName
"Id" = $bug_id;
"State" = $getVstsBugState.fields.'System.State';
"Reason" = $getVstsBugState.fields.'System.Reason';
"Severity" = $getVstsBugState.fields.'Microsoft.VSTS.Common.Severity'.Substring(4);
"AssignedTo" = $getVstsBugState.fields.'System.AssignedTo'.displayName
}
}
}
When I try to run it
$application = "MyBeautifulApp"
$application_first_url = "https://test.visualstudio.com/72L80E4b-1583-45c1-b669-d8de6133V895/_apis/wit/wiql?api-version=1.0"
$application_second_url = "https://test.visualstudio.com/72L80E4b-1583-45c1-b669-d8de6133V895/_apis/wit/workItems/"
$application_query = #{"query" = "SELECT [System.Id],[System.WorkItemType],[System.Title],[System.AssignedTo],[System.State] FROM WorkItems WHERE [System.TeamProject] = #project AND [System.WorkItemType] = 'Bug' AND [System.Title] CONTAINS 'Test' AND [System.TAGS] CONTAINS 'Test'"}
GetBugsFromVSTS $application $application_first_url $application_second_url $application_query
} catch {
Write-Warning "##vso[task.logissue type=warning;]Some problem occured querying MyBeautifulApp application. Please see below for error details"
$_
}
The most interesting part here is that I'm getting this really weird error message
WARNING: ##vso[task.logissue type=warning;]Some problem occured
querying MyBeautifulApp application. Please see below for error
details
% : You cannot call a method on a null-valued expression.
For the sake of test I added if..else clause to test that $json_decoded.workItems are not equal null, and that verification passes. If I run the code, full output will be
MyBeautifulApp Json decoded workitems are not null
9805
10330
10331
10371
10372
10373
10374
WARNING: ##vso[task.logissue type=warning;]Some problem occured querying MyBeautifulApp application. Please see below for error details
% : You cannot call a method on a null-valued expression. line 29
+ $json_decoded.workItems | % {
+ ~~~
+ CategoryInfo : InvalidOperation: (:) [ForEach-Object], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull,Microsoft.PowerShell.Commands.ForEachObjectCommand
How is it possible that the first verification for $json_decoded.workItems (line 23) is not indicating that variable equals null, whereas the second statement (line 29) shows that it's null?
The problem isn't $json_decoded.workItems, the problem happens inside the script block passed to % / ForEach-Object:
Since you're using an enclosing try / catch handler, the offending individual statement inside the block is, unfortunately, not pinpointed in the error message.
However, given that there's only one method call in your block, the offending line can be inferred:
"Severity" = $getVstsBugState.fields.'Microsoft.VSTS.Common.Severity'.Substring(4);
In other words: $getVstsBugState.fields.'Microsoft.VSTS.Common.Severity' evaluates to $null, which is why the .Substring() method call fails.

Bad request(error #400) in streaming dataset

I am using Powershell script to upload data every minute into streaming dataset in PowerBI(It's scheduled with Windows Task Scheduler).
I'm struggling with strange error, that appeared without changing anything.
This is my code:
function invokeRest()
{
$endpoint = "https://api.powerbi.com/beta/..."
$query = #(Invoke-Sqlcmd -Query "select * from LS.dbo.live_Holdbacks;" -ServerInstance $env:computername)
$RetArray = #()
Foreach ($row in $query) {
$payload = #{
"id" = $row.LiveHoldbackID
"RefreshDate" = $row.RefreshDate.ToString("HH:mm")
"CreatedBy" = $row.CreatedBy
"Campaign Code" = $row.CampaignCode
"Campaign Description" = $row.CampaignDescription
"Comment" = $row.Comment
"Customer Number" = $row.CustomerNumber
"Country" = $row.Country
"holdback" = $row.holdback
"upselling" = $row.upselling
}
$RetArray += $payload
}
Write-Host (ConvertTo-Json #($RetArray));
Invoke-RestMethod -Method Post -Uri "$endpoint" -Body (ConvertTo-Json #($RetArray)) -Verbose
}
function ClearDataset([string]$authToken)
{
Clear-PBITableRows -authToken $authToken -dataSetName "DEV_live_holdbacks_no_History_1min" -tableName "RealTimeData" -Verbose
}
Import-Module -Name PowerBIPS
$authToken = Get-PBIAuthToken -ClientId "...." -Credential (new-object System.Management.Automation.PSCredential("......",(ConvertTo-SecureString -String "...." -AsPlainText -Force)))
$group = Get-PBIGroup -authToken $authToken -name "..."
Set-PBIGroup -id $group.id
$dataSets = Get-PBIDataSet -authToken $authToken -name "DEV_live_holdbacks_no_History_1min" -includeTables -Verbose
#ClearDataset $authToken
try {
ClearDataset $authToken
invokeRest
}
catch {
Write-Host 'Sth goes bad'
Write-Host $_
# do something with $_, log it, more likely
}
API info is taken directly from PowerBI, every URL is ok, and everything that I got in console is this:
The remote server returned an error: (400) Bad Request.
It just suddenly stopped working... Anyone got idea how to deal with it?
I figured this out! The problem was related to one of fields - it's type was set to Number and there was string passed into it.

Install windows update

I have following powershell script which should update my windows OS everytime I run it. Therefore I use the given windows API in order to search, download and install the updates. But somehow only searching for them actually works.
This is my script:
$global:scriptpath = $MyInvocation.MyCommand.Path
$global:dir = Split-Path $scriptpath
$global:logfile = "$dir\updatelog.txt"
write-host " Searching for updates..."
$session = New-Object -ComObject Microsoft.Update.Session
$searcher = $session.CreateUpdateSearcher()
$result = $searcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
if ($result.Updates.Count -eq 0) {
Write-Host "No updates to install"
} else {
$result.Updates | Select Title
}
$downloads = New-Object -ComObject Microsoft.Update.UpdateColl
foreach ($update in $result){
try {
$update.AcceptEula()
$Null = $downloads.Add($update)
} catch {}
}
$count = $result.Updates.Count
write-host ""
write-host "There are $($count) updates available."
write-host ""
read-host "Press Enter to download\install updates"
$downloader = $session.CreateUpdateDownLoader()
$downloader.Updates = $downloads
$downloader.Download()
$installs = New-Object -ComObject Microsoft.Update.UpdateColl
foreach ($update in $result.Updates){
if ($update.IsDownloaded){
$installs.Add($update)
}
}
$installer = $session.CreateUpdateInstaller()
$installer.Updates = $installs
$installresult = $installer.Install()
$installresult
But I get following error:
Exception calling "Download" with "0" argument(s): "Exception from HRESULT: 0x80240024"
+ $downloader.Download()
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
Somehow this line: $downloader.Updates = $downloads is not executed, but I don't know why. I also already tried running the script as an admin, didn't work either.
That error code is the WU_E_NO_UPDATE, described here. Basically it says that the Updates collection is not set or empty.

SSRS and PowerShell: Get report as Excel

I'm trying to make PowerShell send a web request to our SSRS server and capture the results. I've hit a wall using the rs:FORMAT=EXCEL parameter in the SSRS url string. I have the following:
First, init the credentials:
$User = "MYDOMAIN\MyUser"
$PWord = ConvertTo-SecureString -String "WooHooStringP$W0rd" -AsPlainText -Force
$c = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $User, $PWord
Now, request a report:
Invoke-WebRequest `
-UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer) `
-Credential $c `
-Uri "http://myserver/ReportServer_DEV/Pages/ReportViewer.aspx?/folder+path/report+name"
This works fine. I can even grab the results (enclosing this request and using ().Content).
Then, specify a format instead of plain rendering:
Invoke-WebRequest `
-UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer) `
-Credential $c `
-Uri "http://myserver/ReportServer_DEV/Pages/ReportViewer.aspx?/folder+path/report+name&rs:format=HTML4.0"
Note the rs:Format specification? Works like a charm.
Then, for the grande finale, give me an Excel file:
Invoke-WebRequest `
-UserAgent ([Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer) `
-Credential $c `
-Uri "http://myserver/ReportServer_DEV/Pages/ReportViewer.aspx?/folder+path/report+name&rs:format=EXCEL"
No can do, bud:
Invoke-WebRequest : The remote server returned an error: (401) Unauthorized.
At line:1 char:11
+ $bytez = (Invoke-WebRequest `
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Why does the rs:format=EXCEL option throw an Unauthorised exception where all the other URLs are served by SSRS?
I've figured it out! I went about this the wrong way: SSRS offers access through a webservice that PowerShell can consume without the need to hack the URL and capture a response. I found a script that did this and modified it to suit my purpose:
function GetRSConnection($server, $instance)
{
# Create a proxy to the SSRS server and give it the namespace of 'RS' to use for
# instantiating objects later. This class will also be used to create a report
# object.
$User = "DOMAIN\Username"
$PWord = ConvertTo-SecureString -String "Pa$$w0rd" -AsPlainText -Force
$c = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $User, $PWord
$reportServerURI = "http://" + $server + "/" + $instance + "/ReportExecution2005.asmx?WSDL"
$RS = New-WebServiceProxy -Class 'RS' -NameSpace 'RS' -Uri $reportServerURI -Credential $c
$RS.Url = $reportServerURI
return $RS
}
function GetReport($RS, $reportPath)
{
# Next we need to load the report. Since Powershell cannot pass a null string
# (it instead just passses ""), we have to use GetMethod / Invoke to call the
# function that returns the report object. This will load the report in the
# report server object, as well as create a report object that can be used to
# discover information about the report. It's not used in this code, but it can
# be used to discover information about what parameters are needed to execute
# the report.
$reportPath = "/" + $reportPath
$Report = $RS.GetType().GetMethod("LoadReport").Invoke($RS, #($reportPath, $null))
# initialise empty parameter holder
$parameters = #()
$RS.SetExecutionParameters($parameters, "nl-nl") > $null
return $report
}
function AddParameter($params, $name, $val)
{
$par = New-Object RS.ParameterValue
$par.Name = $name
$par.Value = $val
$params += $par
return ,$params
}
function GetReportInFormat($RS, $report, $params, $outputpath, $format)
{
# Set up some variables to hold referenced results from Render
$deviceInfo = "<DeviceInfo><NoHeader>True</NoHeader></DeviceInfo>"
$extension = ""
$mimeType = ""
$encoding = ""
$warnings = $null
$streamIDs = $null
# Report parameters are handled by creating an array of ParameterValue objects.
# Add the parameter array to the service. Note that this returns some
# information about the report that is about to be executed.
# $RS.SetExecutionParameters($parameters, "en-us") > $null
$RS.SetExecutionParameters($params, "nl-nl") > $null
# Render the report to a byte array. The first argument is the report format.
# The formats I've tested are: PDF, XML, CSV, WORD (.doc), EXCEL (.xls),
# IMAGE (.tif), MHTML (.mhtml).
$RenderOutput = $RS.Render($format,
$deviceInfo,
[ref] $extension,
[ref] $mimeType,
[ref] $encoding,
[ref] $warnings,
[ref] $streamIDs
)
# Determine file name
$parts = $report.ReportPath.Split("/")
$filename = $parts[-1] + "."
switch($format)
{
"EXCEL" { $filename = $filename + "xls" }
"WORD" { $filename = $filename + "doc" }
"IMAGE" { $filename = $filename + "tif" }
default { $filename = $filename + $format }
}
if($outputpath.EndsWith("\\"))
{
$filename = $outputpath + $filename
} else
{
$filename = $outputpath + "\" + $filename
}
$filename
# Convert array bytes to file and write
$Stream = New-Object System.IO.FileStream($filename), Create, Write
$Stream.Write($RenderOutput, 0, $RenderOutput.Length)
$Stream.Close()
}
$RS = GetRSConnection -server "DEVBOX" -instance "ReportServer_DEV"
$report = GetReport -RS $RS -reportPath "folder name/report name"
$params = #()
$params = AddParameter -params $params -name "Month" -val "201311"
GetReportInformat -RS $RS -report $report -params $params -outputpath "i:\test" -format "EXCEL"
Using web request:
[string]$Domain = "DomainUsername"
[string]$Username = "Username"
[string]$Password = "Password"
[string]$ReportServer = "http://ssrsreportserver/ReportServer/ReportExecution2005.asmx" #Report Server
[string]$ReportLocation = "/Report Location/Report Name" #Report Location ON SSRS
$ReportLocation = $ReportLocation.Replace("/", "%2f")
$ReportLocation = $ReportLocation.Replace(" ", "+")
[string]$outputFile = $PSScriptRoot + '\Report.xlsx' #Save location for the file
#If the report has any parameters
[string]$ParamString = "";
$ParamString += "&param1=paramvalue"
$ParamString += "&param2=paramvalue"
[string]$URL = $ReportServer + "?" + $ReportLocation + "&rs:Command=Render&rs:Format=" + "EXCELOPENXML" + "&rs:ParameterLanguage=en-GB" + $ParamString
Write-Host $URL
$Req = [System.Net.WebRequest]::Create($URL);
$Req.Credentials = new-object System.Net.NetworkCredential($Username, $Password, $Domain)
$Req.Timeout = 30000;
$WebStream = $Req.GetResponse().GetResponseStream();
$MemStream = New-Object System.IO.MemoryStream
$WebStream.CopyTo($MemStream);
[long]$Len = $MemStream.Length;
[byte[]]$outBytes = [System.Byte[]]::CreateInstance([System.Byte], $Len)
$MemStream.Seek(0, [System.IO.SeekOrigin]::Begin);
$MemStream.Read($outBytes, 0, [int]$Len);
$WebStream.Close();
$MemStream.Close();
$MemStream.Dispose();
$Stream = New-Object System.IO.FileStream($outputFile), Create, Write
$Stream.Write($outBytes, 0, $outBytes.Length)
$Stream.Close()
Invoke-Item $outputFile