Bulk Change SSRS Data Sources using Powershell - powershell

I'm trying to alter a data source for a set of Reporting Services reports, but I can't get the Powershell to work for them. I'd appreciate any help :)
$server = "http://My/ReportServer/"
$dataSource = Get-RsDataSource -Path "/Data Sources/NewDataSource" -
ReportServerUri $server
$reports = Get-RsCatalogItems -RsFolder "/Testing/NewDataSOurce" -ReportServerUri $server -Recurse | Where-Object {$_.TypeName -eq "Report"}
$reports | ForEach-Object {
$reportDataSource = Get-RsItemDataSource -RsItem $_.Path -ReportServerUri $server
$reportPath = $_.Path
if ($reportDataSource.Name -eq "OldDataSource") {
Set-RsItemDataSource -RsItem $reportPath -DataSource $dataSource -ReportServerUri $server
}
}

I wrote a function to do what you are talking about for setting data sources. Here is what I have... Unfortunately I don't have a SSRS instance any longer. The full script / module is on a gist on my GitHub account. I'll paste my gist urls at the bottom on this thread.
The function that I'm pulling the snippet out of is called Deploy-NativeSSRS. I used this module + a driver script to push items that had been checked out of TFS. So they could in turn be parsed and then pushed to SSRS during CI activities.
$reports = New-ReportObject -files (Get-ChildItem -Path $reportPath -Filter $reportExtension)
foreach($report in (($reports | Where-Object{$_.datasourcename -eq $datasourceName}).filename))
{
$fileExt = $reportExtension.trim('*')
$status = Set-SSRSDataSourceInfoNative -ReportName ($report.trim($fileext)) -reportPath $documentLibrary -DataSourceName $datasourceName -DataSourcePath "$dataSourceTarget/$datasourceName" -reportWebService $webservice
write-output "The following $report datasource was updated to $datasourcename"
}
function set-SSRSDataSourceInfoNative
{
param
(
[parameter(mandatory)]
[string]$Reportname, #with no extension SSRS has no name for the file in native mode
[parameter(mandatory)]
[string]$reportPath,
[parameter(mandatory)]
[string]$DataSourceName,
[parameter(mandatory)]
[string]$DataSourcePath,
[parameter(mandatory)]
[uri]$reportWebService,
[System.Management.Automation.PSCredential]$Credentials
)
if ($Credentials)
{$reportProxy = new-webserviceproxy -uri $reportWebService -Credential $credentials -namespace 'SSRSProxy' -class 'ReportService2010'}
else
{$reportProxy = new-webserviceproxy -uri $reportWebService -UseDefaultCredential -namespace 'SSRSProxy' -class 'ReportService2010'}
$f = $ReportName.ToLower()
try
{
$dataSources = $reportProxy.GetItemDataSources("$reportpath/$reportname")
}
catch
{
"Error was $_"
$line = $_.InvocationInfo.ScriptLineNumber
"Error was in Line $line"
"ReportName: $reportname"
"ReportPath: $reportpath"
}
$proxyNameSpace = $dataSources.gettype().Namespace
$dc = $reportProxy.GetDataSourceContents($DataSourcePath)
if ($dc)
{
$d = $dataSources | Where-Object {$_.name -like $DataSourceName }
$newDataSource = New-Object ("$proxyNameSpace.DataSource")
$newDataSource.Name = $datasourcename
$newDataSource.Item = New-Object ("$proxyNamespace.DataSourceReference")
$newDataSource.Item.Reference = $DatasourcePath
$d.item = $newDataSource.item
$reportProxy.SetItemDataSources("$reportpath/$f", $d)
$set = ($reportproxy.GetItemDataSources("$reportPath/$f")).name
write-verbose "$reportname set to data source $set"
$returnobj = 'success'
}
$returnobj
}
https://gist.github.com/crshnbrn66/40c6be436e7c2e69b4de5cd625ce0902
https://gist.github.com/crshnbrn66/b10e43ef0dadf7f4eeae620428b2cdd9

Here something that works with Power BI Report Server Rest API:
[string] $uri = "https://xxx/Reports"
$session = New-RsRestSession -ReportPortalUri $uri
$reports = Get-RsRestFolderContent -WebSession $session -RsFolder / -Recurse | Where-Object {$_.Type -eq "PowerBIReport"}
$reports | ForEach-Object {
$dataSources = Get-RsRestItemDataSource -WebSession $session -RsItem $_.Path | Where-Object {$_.ConnectionString -eq "yyy;zzz"}
#$dataSources[0].DataModelDataSource.AuthType = 'Windows'
$dataSources[0].DataModelDataSource.Username = 'domain\user'
$dataSources[0].DataModelDataSource.Secret = 'password'
Set-RsRestItemDataSource -WebSession $session -RsItem $_.Path -RsItemType 'PowerBIReport' -DataSources $dataSources
}

Related

Cannot get a powershell function i created to clear is argument so that it can be called with a different value?

Function Get-SQLAPICred($user)
{
$inputname = $user + "-name"
$PasswordFile = "\\location\$inputname.txt"
$KeyFile = "\\location\$inputname.key"
$key = Get-Content $KeyFile
return $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)
}
# This is the start of the first pull, using PSCredential object grabbed from first call to Get-APICred
$GetRecentCSV = Get-ChildItem "\\CSVLocation\" -Name -Filter Report*.CSV | Sort-Object LastWriteTime -Descending | Select-Object -First 1
$PathToCSV = "\\CSVLocation\" + $GetRecentCSV
$PathToOutputCSV = "\\OutputLocation\Output.csv"
$InputArray = Get-Content -Path $PathToCSV | Select-Object -Skip 1 | ConvertFrom-Csv
$InputArray = $InputArray | Where-Object {$_.column1 -ne 'XFR'}
$FilterValues = "'$($InputArray.ID -join "','")'"
$SQLCred = Get-SQLAPICred -user "username1"
$Query = "SELECT * FROM database
WHERE Field IN ("+$FilterValues+")
"
$UserCSV = Invoke-Sqlcmd -ServerInstance server\instance -Credential $SQLCred -Database ExtCopy -Query $Query
# This is the start of the Second pull, using PSCredential object grabbed from first call to Get-APICred
$Uri = 'https://url.to.otherthingapi'
$APICred = Get-SQLAPICred -user "username2"
$RESTTest = Invoke-RestMethod -Credential $DCCred -Uri $Uri
The issue I'm having is that the user values stays as "username1" even though I've passed a new argument onto the function. I have toyed with Clear-Variables both inside and outside the function and cannot seem to figure out how to have my function work with ONLY one value passed to it at a time.

PS: Dynamic parameter to be used if existing parameter value is set to a particular value

I would like to make the token parameter required ONLY when the runType parameter is set to download. I believe something like this can be done with dynamicparam, but I'm stuggling to find out how it works. As you can see, I have a basic Write-Error to catch the missing value, but perhaps can anyone give an example/how-to for use of something smart with dynamicparam?
[CmdletBinding()]
param (
[Parameter(Position=1, Mandatory=$true)]
[ValidateSet('download', 'update')]
[string]$runType,
[Parameter(Position=2)]
[ValidateNotNullOrEmpty()]
[string]$token
)
if (($runType -eq "download") -and (!$token)){
Write-Error "Personal Access Token parameter required: '-token'"
exit 1
}
$mainDir = (Get-Location).Path
$subDir = (Get-ChildItem -Path $mainDir | Where-Object { $_.PSIsContainer }).Name
foreach ($dir in $subDir) {
Write-Host "`n`n **** Directory $dir"
if ($runType -eq "download") {
$base64token = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(":$token"))
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $base64token")
$url = "https://dev.azure.com/ASDF/$dir/_apis/git/repositories?api-version=6.1-preview.1"
$response = Invoke-RestMethod $url -Method 'GET' -Headers $headers
$sortResponse = $response.value | Sort-Object -Property "name"
foreach ($item in $sortResponse) {
$name = $item.name
if (Test-Path -Path "$mainDir\$dir\$name" -PathType "Container") {
if (Test-Path -Path "$mainDir\$dir\$name\.git" -PathType "Container") {
Set-Location -Path "$mainDir\$dir\$name"
Write-Host "`n`t **** Updating Git $name"
Write-Host "$mainDir\$dir\$name"
# git pull
}
} else {
Set-Location -Path "$mainDir\$dir"
Write-Host "`n`t **** Cloning $name"
Write-Host "$mainDir\$dir\$name"
$clone = "git#ssh.dev.azure.com:v3/ASDF/$dir/$name"
# git clone $clone
}
}
}
if ($runType -eq "update") {
$repos = (Get-ChildItem -Path "$mainDir\$dir" | Where-Object { $_.PSIsContainer }).FullName
foreach ($item in $repos) {
if (Test-Path -Path "$item\.git" -PathType "Container") {
Write-Host "`n`t **** Updating Git $($item.split("\")[-1])"
Set-Location -Path "$item"
# git pull
}
}
}
}
Set-Location -Path $mainDir
Found that -> Microsoft Docs
Worked for me.
[CmdletBinding()]
Param(
[Parameter(Position=1, Mandatory=$true)]
[ValidateSet('download', 'update')]
[string]$runType
)
DynamicParam
{
if ($runType -eq 'download')
{
$attributes = New-Object -Type System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = "token"
$attributes.Mandatory = $true
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("token", [string],
$attributeCollection)
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("token", $dynParam1)
return $paramDictionary
}
}

Testing and reporting Invoke-command execution

I have the following PowerShell script that creates a session with Windows server administrator account.I want to report in case of failure of Invoke-command the error and save it in a file
Below is the code that I wrote but if i tamper for example .json file(set a wrong username),execution fails and error_report.txt is not created
#Param(
$user = "lamda"
#)
$user_domain = (Get-WmiObject Win32_ComputerSystem).Domain
$user_computer = (Get-WmiObject Win32_ComputerSystem).Name
$file = "error_report.txt"
If ((Test-Path "creds.json") -eq $True)
{
$jsonfile = Get-ChildItem creds.json
if ($jsonfile.Length -eq 0)
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:The file 'creds.json' is empty"
break
}
else
{
$creds= (Get-Content creds.json | Out-String | ConvertFrom-Json)
$admin = $creds.username
$passwd = $creds.password
if (($admin) -and ($passwd))
{
$Password = ConvertTo-SecureString -String $passwd -AsPlainText -Force
$credential = [pscredential]::new($admin,$Password)
$command = Invoke-Command -ComputerName Server.$user_domain -FilePath
C:\SECnology\Data\Utilities\Updating.ps1 -ArgumentList
$user,$admin,$user_computer -Credential $credential
If ($command -eq $false)
{
$file = "error_report.txt"
Set-Content -Path $file -Value "Error:Session between user and server
could not be created,please check your Credentials"
}
break
}
elseif (([string]::IsNullOrEmpty($admin)) -or ([string
]::IsNullOrEmpty($passwd)))
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:One object of 'creds.json' seems
to be empty.Please check your file "
}
}
break
}
else
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:The file 'creds.json' does not exist"
}
I think the issue is the way you are defining the condition on your if statement.
You use -eq $false however if you connections fails it does not set the vale of command to $false it will leave command as a null as it return no value (it errorred).
What you can try is either use the null operator (!) in your if statement so:
If (!$command){Do stuff}
Or you can give you invoke command an error variable and check if that has a value when run.
$command = Invoke-Command -ComputerName Server.$user_domain -FilePath
C:\SECnology\Data\Utilities\Updating.ps1 -ArgumentList
$user,$admin,$user_computer -Credential $credential -ErrorVariable TheError
If ($TheError)
{Do stuff}

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!"

How to output from a Powershell hashtable to a output file

I am trying to get the .NetFramwork version from all the windows servers. I am using powershell script. I can get the output displayed but unable to get the output from the hashtable to a output file. Also how would I get rid of the "..." from VersionDetails : {1.0.3705, 1.1.4322, 2.0.50727, 3.0...} and show the full content.
Any help will be greatly appreciated
here is the code I am using:
$username = "username"
$password = "Password"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
$query = "select name from win32_directory where name like 'c:\\windows\\microsoft.net\\framework\\v%'"
$ComputerNames = Get-Content "d:\Scripts\serverList.txt"
foreach ($ComputerName in $ComputerNames)
{
write-host "ComputerName = $ComputerName"
$ComputerName | ForEach-Object {
$res = Get-WmiObject -query $query -Credential $cred -ComputerName $ComputerName | ForEach-Object {
Split-Path $_.name -Leaf } | # returns directories
Where-Object { $_ -like 'v*' } | # only include those that start with v
ForEach-Object { [system.version]( $_ -replace "^v" ) }
# remove "v" from the string and convert to version object
# Create hashtable with computername and version details
$prop = #{
ComputerName = $ComputerName
#V1_Present = &{ if ( $res | Where-Object { $_.Major -eq 1 -and $_.Minor -eq 0 } ) { $true } }
#V1_1Present = &{ if ( $res | Where-Object { $_.Major -eq 1 -and $_.Minor -eq 1 } ) { $true } }
V2_Present = &{ if ( $res | Where-Object { $_.Major -eq 2 -and $_.Minor -eq 0 } ) { $true } }
V3_Present = &{ if ( $res | Where-Object { $_.Major -eq 3 -and $_.Minor -eq 0 } ) { $true } }
V3_5Present = &{ if ( $res | Where-Object { $_.Major -eq 3 -and $_.Minor -eq 5 } ) { $true } }
V4_Present = &{ if ( $res | Where-Object { $_.Major -eq 4 -and $_.Minor -eq 0 } ) { $true } }
VersionDetails = $res
}
# Create and output PSobject using hashtable
New-Object PSObject -Property $prop
}
=========================================================
Output dispalys
PS D:\Scripts> .\GetDotNetFrameworkver.ps1
in for loop ComputerName = XXXXXXX
V4_Present : True
V3_5Present : True
V2_Present : True
V3_Present : True
ComputerName : XXXXX
VersionDetails : {1.0.3705, 1.1.4322, 2.0.50727, 3.0...}
Based on the answer of link there is a "simpler" (and faster) solution to fetch the versions.
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -recurse | Get-ItemProperty -name Version,Release -ErrorAction Ignore | Where { $_.PSChildName -match '^(?!S)\p{L}'} | Select PSChildName, Version, Release
If you want to get the versions of different remote machines you can use PowerShell remoting. Be aware that you've to enable PS remoting .If your OS version is WIN10/WIN2012R2 it is enabled per default. If you're using an older OS you've to call Enable-PSRemoting on the remote machine. See this link for details.
Example:
$result = Invoke-Command -ComputerName computer1.domain, computer1.domain -Credential (Get-Credential ) -ScriptBlock {
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -recurse | Get-ItemProperty -name Version,Release -ErrorAction Ignore | Where { $_.PSChildName -match '^(?!S)\p{L}'} | Select PSChildName, Version, Release
}
$hash = $result | group PSComputerName -AsHashTable # Group the .Net versions by computername
$hash.'computer1.domain' # Print all .Net version of computer1
$hash.'computer1.domain'.Version # Only print the version
Hope that helps.