Release Management 12 - Create Web Site with Host Header - ms-release-management

Is there a way to create a web site with Release Management v12 that will include a host header option?
My goal is to be able to host multiple sites on a single server, all binding to port 80 with different host headers. i.e. http://project1.development.local/, http://project2.development.local/
I'm able to create a web site with a host header from the AppCmd.exe, yet this requires an administration rights. Thought about using powershell, yet a UAC prompt will be triggered.
For right now, I'm having to manually create the server's web site to include the host header and I'd like to have a totally automated release process.
TIA!

There's nothing in-the-box for it, but as luck would have it, I've hacked something together to handle site bindings:
param(
$SiteName=$(throw "Site Name must be entered"),
$HostHeader,
$IpAddress,
$Port,
$RemoveDefault=$(throw "You must specify true or false")
)
Import-Module WebAdministration
try {
$bindingExists = (Get-WebBinding "$SiteName" -Port "$Port" -Protocol "http" -HostHeader "$HostHeader" -IPAddress "$IpAddress")
if (!$bindingExists) {
Write-host "Creating binding for $SiteName : Host header $HostHeader and IP Address $IpAddress"
New-WebBinding "$SiteName" -Port $Port -Protocol "http" -HostHeader "$HostHeader" -IPAddress "$IpAddress"
}
else {
Write-host "Site $SiteName already has binding for host header $HostHeader and IP Address $IpAddress"
}
if ($RemoveDefault -eq "true") {
$defaultBinding = Get-WebBinding "$SiteName" | where {$_.bindingInformation -eq "*:80:" }
if ($defaultBinding -ne $null) {
Write-Host "Default binding exists... removing."
$defaultBinding | Remove-WebBinding
}
else {
Write-Host "Default binding does not exist"
}
}
}
catch {
Write-host $_
exit 1
}
exit 0
You can create a custom tool in RM to leverage this script, just pass it the parameters specified in the param block.
You should never have to use AppCmd.exe... If the built-in tools don't meet your needs, the WebAdministration PowerShell module should be able to do everything else.

Related

AD users getting locked out every 20 seconds

I have been searching high and low for an answer, but I cannot seem to figure out why a few of our users keep getting locked out every 30 seconds. I unlock the account and then can watch the login attempts within seconds lock them out. I have tried tools like account lockout status and Netwrix, and I cannot find out what computer/service/task that is causing it. I did turn on netlogon logging, but it doesn't tell me which computer its coming from and it also doesn't say in the event viewer logs. Any help would be greatly appreciated!!!
I have put an example event, and netlogon line below:
Netlogon:
01/04 11:51:07 [LOGON] [20280] DOMAIN: SamLogon: Transitive Network logon of (null)\John Jones from (via WEB-SERVER) Returns 0xC000006A (there is nothing after from)
Event:
Failure Information:
Failure Reason: Unknown user name or bad password.
Status: 0xC000006D
Sub Status: 0xC0000064
Process Information:
Caller Process ID: 0x0
Caller Process Name: -
Network Information:
Workstation Name:
Source Network Address: -
Source Port: -
Do you use LDAP integrated applications?
Advise those end users to clear browser cache (if not already) - if Windows users, clear credentials in:
Credential Manager->Windows Credentials->Delete all entries under "Generic Credentials"
Does your organisation authenticate users who connect to corporate WiFi using AD? If so check that the end users mobiles/tablet devices have been configured with the new password, best way to do this is to forget the connection and re connect using new credentials.
We've had very similar issues in the past and resolved doing the above.
I have recently done this for myself.
The script can show you the timestamp, username, machine name where the lockout event is being originated.
Here is code:
# Set default parameters and variables
param (
[string]$DomainName = $env:USERDOMAIN,
[string]$UserName = "*",
[datetime]$StartTime = (Get-Date).AddDays(-3)
)
# check if current powershell version is 4 or higher
if ($Host.Version.Major -lt "4") {
Write-Host "`n`nError: You need at least version 4 PowerShell for logging to work, `nCurrent version:"$Host.Version.Major -BackgroundColor Red -ForegroundColor white
Write-Host "`nBefore you start using this script, please upgrade your PowerShell from Microsoft website!" -BackgroundColor Yellow -ForegroundColor Black
Read-Host "`n`nScript execution finished, press enter to exit!"
Exit
}
# Grab the information about your AD forest
$Forest = [system.directoryservices.activedirectory.Forest]::GetCurrentForest()
# Get list of all domain controllers in the forest
$DC = $Forest.domains | ForEach-Object {$_.DomainControllers} | ForEach-Object {$_.Name}
# Prompt user to enter a pacific username or accept default (which means look for all locked out events)
Write-Host "`n`nEnter a UserName to search user specific locked out events `n`nOR `n`nPress enter to search all locked out usernames!" -BackgroundColor Yellow -ForegroundColor Black
sleep 3
$TestName = Read-Host "`nPlease enter a UserName or Press enter"
if ($TestName -ne $null -and $TestName) {[string]$UserName = $TestName}
Write-Host "`nScript will search for locked out events on the following domain controllers..." -BackgroundColor Gray -ForegroundColor Black
$dc
# Search for locked out event of each DC and store them in variable
$dc | foreach {
Write-Host "`nChecking for locked out events on $_, please wait..." -BackgroundColor Gray -ForegroundColor Black
$OutPut = Invoke-Command ($_) {
$ErrorActionPreference = "SilentlyContinue"
Get-WinEvent -FilterHashtable #{LogName='Security';Id=4740;StartTime=$Using:StartTime} |
Where-Object {$_.Properties[0].Value -like "$Using:UserName"} |
Select-Object -Property TimeCreated,
#{Label='UserName';Expression={$_.Properties[0].Value}},
#{Label='ClientName';Expression={$_.Properties[1].Value}}
$ErrorActionPreference = "Continue"
} | Select-Object -Property TimeCreated, 'UserName', 'ClientName' |Out-Host
if ($OutPut -eq $null -and !$OutPut) {Write-Host "`nWarning: No lockout events were found!`nContinuing the search..." -BackgroundColor Yellow -ForegroundColor Black}
else {$OutPut}
}

Error catching mechanism in powershell

Just a broad question here - is there a generic error catching mechanism in powershell? I'm having issue where by connection to MSSSQL server times out randomly via a powershell script and then re-running it would be fine.
Just want to know if there is any try-catch or similar error capturing in powershell available. Or if any one has better solution to catch connection timeouts let me know.
Thank you.
Zulfiqar
Yes, you could use Try-Catch block.
Here is an example:
Write-Host "Disabling IP v6 - Reboot required after installation/update!"
$breboot = $True
try
{
New-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\" -Name "DisabledComponents" -Value 0xffffffff -PropertyType "DWord" -ErrorAction Stop
}
catch
{
Write-Host ("IPv6 already disabled - no reboot required!")
$breboot = $False
}
I recommend the blogpost by kevin marquette:
https://kevinmarquette.github.io/2017-04-10-Powershell-exceptions-everything-you-ever-wanted-to-know/.

Download all SSRS reports

I want to get a copy of all .rdl files in one server.
I can do the download manually one report at the time, but this is time consuming especially that this server has around 1500 reports.
Is there any way or any tool that allows me to download all the .rdl files and take a copy of them?
There is a complete & simpler way to do this using PowerShell.
This code will export ALL report content in the exact same structure as the Report server. Take a look at the Github wiki for other options & commands
#------------------------------------------------------
#Prerequisites
#Install-Module -Name ReportingServicesTools
#------------------------------------------------------
#Lets get security on all folders in a single instance
#------------------------------------------------------
#Declare SSRS URI
$sourceRsUri = 'http://ReportServerURL/ReportServer/ReportService2010.asmx?wsdl'
#Declare Proxy so we dont need to connect with every command
$proxy = New-RsWebServiceProxy -ReportServerUri $sourceRsUri
#Output ALL Catalog items to file system
Out-RsFolderContent -Proxy $proxy -RsFolder / -Destination 'C:\SSRS_Out' -Recurse
I've created this powershell script to copy them into a ZIP. You have to provide the SQL server database details.
Add-Type -AssemblyName "System.IO.Compression.Filesystem"
$dataSource = "SQLSERVER"
$user = "sa"
$pass = "sqlpassword"
$database = "ReportServer"
$connectionString = "Server=$dataSource;uid=$user; pwd=$pass;Database=$database;Integrated Security=False;"
$tempfolder = "$env:TEMP\Reports"
$zipfile = $PSScriptRoot + '\reports.zip'
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$allreports = $connection.CreateCommand()
$allreports.CommandText = "SELECT ItemID, Path, CASE WHEN Type = 2 THEN '.rdl' ELSE '.rds' END AS Ext FROM Catalog WHERE Type IN(2,5)"
$result = $allreports.ExecuteReader()
$reportable = new-object "System.Data.DataTable"
$reportable.Load($result)
[int]$objects = $reportable.Rows.Count
foreach ($report in $reportable) {
$cmd = $connection.CreateCommand()
$cmd.CommandText = "SELECT CAST(CAST(Content AS VARBINARY(MAX)) AS XML) FROM Catalog WHERE ItemID = '" + $report[0] + "'"
$xmldata = [string]$cmd.ExecuteScalar()
$filename = $tempfolder + $report["Path"].Replace('/', '\') + $report["Ext"]
New-Item $filename -Force | Out-Null
Set-Content -Path ($filename) -Value $xmldata -Force
Write-Host "$($objects.ToString()).$($report["Path"])"
$objects -= 1
}
Write-Host "Compressing to zip file..."
if (Test-Path $zipfile) {
Remove-Item $zipfile
}
[IO.Compression.Zipfile]::CreateFromDirectory($tempfolder, $zipfile)
Write-Host "Removing temporarly data"
Remove-Item -LiteralPath $tempfolder -Force -Recurse
Invoke-Item $zipfile
If you just need this for backup purposes or something similar, this might be useful: Where does a published RDL file sit?
The relevant query from that thread is:
select convert(varchar(max), convert(varbinary(max), content))
from catalog
where content is not null
The original answer was using 2005, and I've used it on 2016, so I imagine it should work for 2008 and 2012.
When I had to use this, I added in the Path to the query as well, so that I knew which report was which.
CAVEAT: prior to SSMS v18, Results to Grid is limited to 64KB per tuple and Results to Text are limited to 8,192 characters per tuple. If your report definition is larger than these limits you will not be able to get the entire definition.
In SSMS v18, those limits have been increased to 2MB per tuple for both Reports to Grid as well as Results to Text.
This is based on SQL2016/SSRS2016 but I think it should work for 2012.
SELECT 'http://mySQLServerName/reports/api/v1.0/catalogitems(' + cast(itemid as varchar(256))+ ')/Content/$value' AS url
FROM ReportServer.dbo.Catalog
This will give you a list of URL's, one for each report.
If the above did not work in SSRS 2012 then go to the report manager and do as if you were going to download the file from there. Check the URL on the download button and you'll probably see a URL with and item id embedded int it. Just adjust the above code to match that url structure.
What you do with then after this is up to you.
Personally I would use the Chrome extension called 'Tab Save' available in the Chrome store here. You can simply copy and paste all the URL's created above into it and hit the download button...
Found and used this without any issues. Nothing to install, just added my url, and pasted into Powershell.
https://microsoft-bitools.blogspot.com/2018/09/ssrs-snack-download-all-ssrs-reports.html
In case the link breaks, here's the code from the link:
###################################################################################
# Download Reports and DataSources from a SSRS server and create the same folder
# structure in the local download folder.
###################################################################################
# Parameters
###################################################################################
$downloadFolder = "c:\temp\ssrs\"
$ssrsServer = "http://myssrs.westeurope.cloudapp.azure.com"
###################################################################################
# If you can't use integrated security
#$secpasswd = ConvertTo-SecureString "MyPassword!" -AsPlainText -Force
#$mycreds = New-Object System.Management.Automation.PSCredential ("MyUser", $secpasswd)
#$ssrsProxy = New-WebServiceProxy -Uri "$($ssrsServer)/ReportServer/ReportService2010.asmx?WSDL" -Credential $mycreds
# SSRS Webserver call
$ssrsProxy = New-WebServiceProxy -Uri "$($ssrsServer)/ReportServer/ReportService2010.asmx?WSDL" -UseDefaultCredential
# List everything on the Report Server, recursively, but filter to keep Reports and DataSources
$ssrsItems = $ssrsProxy.ListChildren("/", $true) | Where-Object {$_.TypeName -eq "DataSource" -or $_.TypeName -eq "Report"}
# Loop through reports and data sources
Foreach($ssrsItem in $ssrsItems)
{
# Determine extension for Reports and DataSources
if ($ssrsItem.TypeName -eq "Report")
{
$extension = ".rdl"
}
else
{
$extension = ".rds"
}
# Write path to screen for debug purposes
Write-Host "Downloading $($ssrsItem.Path)$($extension)";
# Create download folder if it doesn't exist (concatenate: "c:\temp\ssrs\" and "/SSRSFolder/")
$downloadFolderSub = $downloadFolder.Trim('\') + $ssrsItem.Path.Replace($ssrsItem.Name,"").Replace("/","\").Trim()
New-Item -ItemType Directory -Path $downloadFolderSub -Force > $null
# Get SSRS file bytes in a variable
$ssrsFile = New-Object System.Xml.XmlDocument
[byte[]] $ssrsDefinition = $null
$ssrsDefinition = $ssrsProxy.GetItemDefinition($ssrsItem.Path)
# Download the actual bytes
[System.IO.MemoryStream] $memoryStream = New-Object System.IO.MemoryStream(#(,$ssrsDefinition))
$ssrsFile.Load($memoryStream)
$fullDataSourceFileName = $downloadFolderSub + "\" + $ssrsItem.Name + $extension;
$ssrsFile.Save($fullDataSourceFileName);
}
I'vr tried several permutations of this script and keep getting the "can't create proxy connection" error. Here's the one that "should" work:
#------------------------------------------------------
#Prerequisites
#Install-Module -Name ReportingServicesTools
#------------------------------------------------------
#Lets get security on all folders in a single instance
#------------------------------------------------------
#Declare SSRS URI
$sourceRsUri = "http://hqmnbi:80/ReportServer_SQL08/ReportService2010.asmx?wsdl"
#Declare Proxy so we dont need to connect with every command
$proxy = New-RsWebServiceProxy -ReportServerUri $sourceRsUri
#Output ALL Catalog items to file system
Out-RsFolderContent -Proxy $proxy -RsFolder / -Destination 'C:\Users\arobinson\source\Workspaces\EDW\MAIN\SSRS\HQMNBI' -Recurse
This is the error I'm getting:
Failed to establish proxy connection to http://hqmnbi/ReportServer_SQL08/ReportService2010.asmx : The HTML document does not contain
Web service discovery information.
At C:\Program Files\WindowsPowerShell\Modules\ReportingServicesTools\0.0.6.6\Functions\Utilities\New-RsWebServiceProxy.ps1:136 char:9
throw (New-Object System.Exception("Failed to establish proxy ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : OperationStopped: (:) [], Exception
FullyQualifiedErrorId : Failed to establish proxy connection to http://hqmnbi/ReportServer_SQL08/ReportService2010.asmx : The
HTML document does not contain Web service discovery information.
I've tried the URI with htttp:// and without, I've tried including the port number. etc. Still can't get this to actually work. We have two other SSRS instances that I was able to run this against no problem.
From this question: SQL Reporting Services - COPY reports to another folder
I found this tool can both download and upload reports. Plus it lists out folders and subfolders.
http://code.google.com/p/reportsync/

RM + DSC to node in untrusted domain

So I mention the untrusted domain aspect because I went through all the hoops around credential delegation and trusted hosts lists etc to allow me to successfully push a DSC configuration from my RM server to a target node (not using RM, just native DSC). I get that bit and it works, great.
Now when I use those same scripts in RM (with some minor edits for the format expected by RM), RM reports a successful deploy but all that has happened is the components bits have been copied to the target node to the default location for $applicationPathRoot (C:\Windows\DtlDownloads), there is no real evidence of an attempt to apply a mof file.
My RM server and target nodes are in different domains with no trust. Both servers are W2k8R2 (+ WMF4 of course). I'm running with Update 4 of RM server and client.
Here are the DSC scripts I'm running in RM:
CopyDSCResources.ps1
Configuration CopyDSCResource
{
param (
[Parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[String] $ModulePath = "$env:ProgramFiles\WindowsPowershell\Modules")
#[PSCredential] $credential = get-credential
Node VCTSCFDSMWEB01
{
File DeployWebDeployResource
{
Ensure = "Present"
SourcePath = "C:\test.txt"
DestinationPath = "D:\temp"
Force = $true
Type = "File"
}
}
}
CopyDSCResource -ConfigurationData $configData -Verbose
# test outside of RM
#CopyDSCResource -ConfigurationData CopyDSCResource.ConfigData.psd1
#Start-DscConfiguration -Path .\CopyDSCResource -Credential $credential -Verbose -Wait
CopyDSCResource.ConfigData.psd1
##{
$configData = #{
AllNodes = #(
#{
NodeName = "*"
PSDscAllowPlainTextPassword = $true
},
#{
NodeName = "VCTSCFDSWEB01.rlg.test"
Role = "WebServer"
}
)
}
I'm afraid I cant seem to upload screenshots from my current location but in terms of RM, I have a vNext environment with a single server linked, a vNext release path with a single 'Dev' stage and a vNext release template with a single 'Deploy PS/DSC' action. The configuration of the action is:
ServerName - VCTSCFDSMWEB01
ComponentName - COpyDSCResource vNext
PSScriptPath - copydscresources.ps1
PSConfigurationPath - copydscresource.configdata.psd1
UseCredSSP - true
When I run a new release, the deploy stage reports success and when I view the Deployment log files I get the following:
Upload components - Successfully uploaded to the normalized store.
Deploy Using PS/DSC - Copying recursively from \vcxxxxtfs03\Drops\CorrespondenceCI\CorrespondenceCI20150114.1\Scripts to C:\Windows\DtlDownloads\CopyDSCResource vNext succeeded.
Finally the DSC event log has the following:
Job {CD3BE350-4072-4C8B-835F-4B4D1C46D65D} :
Configuration is sent from computer NULL by user sid S-1-5-18.
This compares markedly to the same event log entry when run outside of RM:
Job {34F78498-CF18-4F2A-9874-EB54FDA2D990} :
Configuration is sent from computer VCXXXXTFS01 by user sid S-1-5-21-1034805355-1149422947-1317505720-10867.
Any pointers appreciated
It would be good if I could see evidence of a mof file being created on the RM server for example, anybody know where I can find this??
Turns out the crucial element was that my DSC script had to use an environment variable for naming the node. So:
Node $env:COMPUTERNAME
No idea why but it works!

How to run a scheduled task to stop and start SSRS service with elevated permissions?

I have this SSRS latency issues on my site. So I have googled it and found out that it is the common issues for so many people. Here it is:
I have created a powershell script as follows:
Stop-Service "SQL Server Reporting Services (MSSQLSERVER)"
Start-Service "SQL Server Reporting Services (MSSQLSERVER)"
$wc = New-Object system.net.webClient
$cred = [System.Net.CredentialCache]::DefaultNetworkCredentials
$wc.Credentials = $cred
$src = $wc.DownloadString("http://example.com/Reports/Pages/Folder.aspx")
When i run this script from poweshell cmd it is throwing me an error says cannot open/access sql report server service. It seems like permissions issue. Then I came with this online solution, which invokes/elevates admin permissions to run the script to that perticular user.
function Invoke-Admin() {
param ( [string]$program = $(throw "Please specify a program" ),
[string]$argumentString = "",
[switch]$waitForExit )
$psi = new-object "Diagnostics.ProcessStartInfo"
$psi.FileName = $program
$psi.Arguments = $argumentString
$psi.Verb = "runas"
$proc = [Diagnostics.Process]::Start($psi)
if ( $waitForExit ) {
$proc.WaitForExit();
}
}
But I dont know how to run this function before running that script. Please suggest. I have added this function also to the same script file and added function-Admin() call at the top of the script to to execute this function before running the script as follows:
function-Admin()
Stop-Service "SQL Server Reporting Services (MSSQLSERVER)"
Start-Service "SQL Server Reporting Services (MSSQLSERVER)"
$wc = New-Object system.net.webClient
$cred = [System.Net.CredentialCache]::DefaultNetworkCredentials
$wc.Credentials = $cred
$src = $wc.DownloadString("http://example.com/Reports/Pages/Folder.aspx")
But is throwing following error:
Please specify a program
At C:\SSRS_Script\SSRSScript.ps1:3 char:39
+ param ( [string]$program = $(throw <<<< "Please specify a program" ),
+ CategoryInfo : OperationStopped: (Please specify a program:String) [], RuntimeException
+ FullyQualifiedErrorId : Please specify a program
You are getting that error because the function Invoke-Admin() was designed to have parameters passed for the program you wanted to run with elevated privledges. If you want your powershell script SSRSScript.ps1 to use this Invoke-Admin() you could convert it to a standalone script.
Take the code without the function declartion and outer brackets. Save this a file called Invoke-Admin.ps1
param ( [string]$program = $(throw "Please specify a program" ),
[string]$argumentString = "",
[switch]$waitForExit )
$psi = new-object "Diagnostics.ProcessStartInfo"
$psi.FileName = $program
$psi.Arguments = $argumentString
$psi.Verb = "runas"
$proc = [Diagnostics.Process]::Start($psi)
if ( $waitForExit ) {
$proc.WaitForExit();
}
With that created then you could try to elevate your script with the following:
C:\*pathtoscript*\Invoke-Admin.ps1 -program "Powershell.exe" -argumentString "-file C:\SSRS_Script\SSRSScript.ps1"
You should get the elevation prompt at that point and then, once accepted, will run another window with your script using admin rights.
This is by no means the only way to accomplish this goal.
Scheduler
You have this in the title but dont really cover it in the question. Running this as a scheduled task will not work since it requires user input. You could however just make a task with your script as is assuming it works unattended.
General Tab
Run whether user is logged on or not
Run with highest privileges
Action > New...
Action: Start a program Program/script: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
Add arguments: -ExecutionPolicy Unrestricted -NoProfile -File C:\SSRS_Script\SSRSScript.ps1
Start in (optional): %SystemRoot%\system32\WindowsPowerShell\v1.0

Resources