I am new to the elastic search concept and I am exposed to this concept because of a tool. This tool has now introduced Elasticsearch for fetching the license usage details of the tool user.
The version of elastic search installed is 6.4.3. The product by default provides a Powershell script which i have tried to add few filters to fetch the license consumption by dates and feature.
I would require to publish a report with the license consumption details every month. The below Powershell script does not finish executing even after 12 hours and the output file size is greater than 2 GB and still growing.
Any help in fine tuning this script would be of great help.
I use a batch file with the below content:
powershell.exe -File .\query.ps1 -hostname "<XXX>" -port 9200 -outputFilePath D:\LicenseUsageTracker\OutputFile.json -startDate 2019-12-10 -endDate 2019-12-11 -featureName XXX
The content of query.ps1 is as follows
param( [String]$hostname, [Int32]$port, [String]$outputFilePath, [STRING]$startDate, [STRING]$endDate ,$featureName)
function CheckStatusCode {
param( [Microsoft.PowerShell.Commands.HtmlWebResponseObject]$response )
if ($response.StatusCode -ne 200) {
Write-host ("ERROR RESPONSE: STATUS: " + ($response.StatusCode) + "; CONTENT: " + ($response.Content | ConvertFrom-Json | ConvertTo-Json))
return $false;
}
return $true;
}
function AddHits {
param( [System.Object[]]$hits, [String]$path )
If (-not (Test-Path $path -PathType Leaf)) {
New-Item $path -ItemType file -Force
}
$comma = "";
Write-host ("Writing " + $hits.length + " search results...")
ForEach ($hit In $hits) {
Add-Content -Path $path -Value ($comma + ($hit._source | ConvertTo-Csv -NoTypeInformation))
$comma = "";
}
Write-host ("done.")
}
If (Test-Path $outputFilePath -PathType Leaf) {
$overwrite = read-host ("File '" + $outputFilePath + "' exists already. Overwrite? (yes/no)");
If ($overwrite -ne "yes") {
Write-host ("Exiting script.")
return;
} else {
Write-host ("Overwriting file '" + $outputFilePath + "'");
Remove-Item -Path $outputFilePath
}
} else {
Write-host ("Writing to file '" + $outputFilePath + "'");
}
$response = Invoke-WebRequest -Uri "http://${hostname}:${port}/usageinfo/_search?scroll=2m&filter_path=_scroll_id,hits.hits._source" -ContentType "application/json" -Method POST -Body ('{
"query": {
"bool": {
"must": [
{
"range": {
"timeStamp": {
"gte": "' + $startDate + '",
"lte": "' + $endDate + '"
}
}
},
{
"match": {
"featureName":"' + $featureName + '"
}
}
]
}
},
"size": 10000
}');
if (-not (CheckStatusCode($response))) {
return;
}
$jsonContent = ($response.Content | ConvertFrom-Json);
$scrollId = $jsonContent._scroll_id;
$hits = $jsonContent.hits.hits;
AddHits $hits $outputFilePath;
while ($hits.length -gt 0) {
$response = Invoke-WebRequest -Uri "http://${hostname}:${port}/_search/scroll?filter_path=_scroll_id,hits.hits._source" -ContentType "application/json" -Method POST -Body ('{ "scroll" : "2m", "scroll_id" : "' + $scrollId + '"}');
if (-not (CheckStatusCode($response))) {
return;
}
$scrollId = ($response.Content | ConvertFrom-Json)._scroll_id;
$hits = ($response.Content | ConvertFrom-Json).hits.hits;
If ($hits.Length -ne 0) {
AddHits $hits $outputFilePath;
}
};
Related
I'm retrieving records using Codeigniter and datatables. Removing $sOrder and $sLimit loads the data but on filtering, there's a database error:
"You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near ''desc' LIMIT '0', '10'' at line 5
SELECT SQL_CALC_FOUND_ROWS id, FName, LName, status, authorizedby, userName
FROM users
ORDER BY id 'desc'
LIMIT '0', '10'"
Here's the code:
if (isset($_REQUEST['iSortCol_0'])) {
$sOrder = "ORDER BY ";
for ($i = 0; $i < intval($_REQUEST['iSortingCols']); $i++) {
if ($_REQUEST['bSortable_' . intval($_REQUEST['iSortCol_' . $i])] == "true") {
$sOrder .= $aColumns[intval($_REQUEST['iSortCol_' . $i])] . "
" . $this->db->escape($_REQUEST['sSortDir_' . $i]) . ", ";
}
}
$sOrder = substr_replace($sOrder, "", -2);
if ($sOrder == "ORDER BY") {
$sOrder = "";
}
}
$sWhere = "";
// this for search code
if ($_REQUEST['sSearch'] != "") {
$sWhere = "WHERE (";
for ($i = 0; $i < count($aColumns); $i++) {
$sWhere .= $aColumns[$i] . " LIKE '%" . $this->db->escape($_REQUEST['sSearch']) . "%' OR ";
}
$sWhere = substr_replace($sWhere, "", -3);
$sWhere .= ')';
}
for ($i = 0; $i < count($aColumns); $i++) {
if ($_REQUEST['bSearchable_' . $i] == "true" && $_REQUEST['sSearch_' . $i] != '') {
if ($sWhere == "") {
$sWhere = "WHERE ";
} else {
$sWhere .= " AND ";
}
$sWhere .= $aColumns[$i] . " LIKE '%" . $this->db->escape($_REQUEST['sSearch_' . $i]) . "%' ";
}
}
// generate sql query
$sQuery = "SELECT SQL_CALC_FOUND_ROWS " . str_replace(" , ", " ", implode(", ", $aResultColumns)) . "
FROM $sTable
$sWhere
$sOrder
$sLimit
";
Now, removing the last two lines ($sOrder and $sLimit) works for loading the data but error on filtering. How is this fixable.
This is how I solved it:
$sWhere = "";
// this for search code
if ($_REQUEST['sSearch'] != "") {
$sWhere = "WHERE (";
for ($i = 0; $i < count($aColumns); $i++) {
$sWhere .= $aColumns[$i] . " LIKE '*%" . $this->db->escape($_REQUEST['sSearch']) . "%*' OR ";
}
$sWhere = substr_replace($sWhere, "", -3);
$sWhere .= ')';
}
for ($i = 0; $i < count($aColumns); $i++) {
if ($_REQUEST['bSearchable_' . $i] == "true" && $_REQUEST['sSearch_' . $i] != '') {
if ($sWhere == "") {
$sWhere = "WHERE ";
} else {
$sWhere .= " AND ";
}
$sWhere .= $aColumns[$i] . " LIKE '*%" . $this->db->escape($_REQUEST['sSearch_' . $i]) . "%*' ";
}
}
$sOrder = str_replace("'", "", $sOrder);
$sLimit = str_replace("'", "", $sLimit);
$sWhere = str_replace("'", "", $sWhere);
$sWhere = str_replace("*", "'", $sWhere);
// generate sql query
$sQuery = "SELECT SQL_CALC_FOUND_ROWS " . str_replace(" , ", " ", implode(", ", $aResultColumns)) . "
FROM $sTable
$sWhere
$sOrder
$sLimit
";```
I have a page which is used to search the users. If I searched an existing user, the page will redirect to my wanted page. If the user is not existing, a message must be shown. But for me the message is not showing. I know may be this is a simple error, but it's not working for me. I am using Laravel 5.8.
Error is:
Undefined offset: 0
in ClientsController.php (line 344)
at HandleExceptions->handleError.
Here is my controller:
public function getMerchantDetails() {
$user = $_GET['user'];
$mid = $_GET['mid'];
$activity = "User $user has searched this merchant";
//This is for Activity Log Capturing. Added user variable
DB::insert("INSERT INTO activitylog (mid,activity) values ('$mid','$activity')");
//Activity ends here
$mobile = $_GET['mobile'];
$email = $_GET['email'];
$m = '';
if ($mobile != '') {
$m = " AND primary_number = '" . $mobile . "' ";
}
$e = '';
if ($email != '') {
$e = " AND email = '" . $email . "' ";
}
$i = '';
if ($mid != '') {
$i = " AND mid = '" . $mid . "' ";
}
if ($m == '' && $e == '' && $i == '') {
// print_r($m);
// die();
return response()->json(array('data' => ''), 200);
} else {
$res = DB::select(DB::raw("SELECT * FROM clients WHERE 1=1 " . $m . $e . $i . " LIMIT 1"));
if (!$res) {
//$res_config = DB::select( DB::raw("SELECT * FROM configuration WHERE code = 'PERL_SEARCH_MERCHANT'") );
$perl_path = DB::select(DB::raw("SELECT * FROM configuration WHERE code = 'PERL_PATH'"));
$perl_output = exec($perl_path[0]->description . ' -merchant_id ' . $mid . ' -mobile ' . $mobile . ' -email ' . $email);
$r = json_decode($perl_output, true);
if ($r['status'] == 'success') {
if ($r['id'] != '') {
$res = DB::select(DB::raw("SELECT * FROM clients WHERE id = " . $r['id']));
} else {
$res[0]['id'] = '';
}
}
}
return response()->json(array('data' => $res[0]), 200); (line 344)
}
}
My Ajax code:
$.ajax({
"url": '{!! route('clients.fetchMerchantDetails') !!}',
async: true,
type: "GET",
data: {
mobile: mobile,
email: email,
mid: mid,
user:userid
},
success: function (response) {
var data = response.data
if(data.id!=''){
clientEditUrl = clientEditUrl.replace(':id', data.id);
window.location = clientEditUrl;
}else{
$('.searchOutputDiv').html('<h3>No merchant found!</h3>');
}
}
});
I found this blog on how to get all users with REST however I am receiving an error:
PS C:\windows\system32> C:\Temp\YammerUsers.ps1
https://www.yammer.com/api/v1/users.json?page=1
https://www.yammer.com/api/v1/users.json?page=1 System.Collections.ArrayList
The '++' operator works only on numbers. The operand is a 'System.Object[]'.
At C:\Temp\YammerUsers.ps1:34 char:16
+ return Get-YamUsers($page++, $allUsers)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : OperatorRequiresNumber
Code is as follows:
$baererToken = "TOKEN REMOVED"
$yammerBaseUrl = "https://www.yammer.com/api/v1"
Function Get-BaererToken() {
$headers = #{ Authorization=("Bearer " + $baererToken) }
return $headers
}
Function Get-YamUsers($page, $allUsers) {
if ($page -eq $null) {
$page = 1
}
if ($allUsers -eq $null) {
$allUsers = New-Object System.Collections.ArrayList($null)
}
$urlToCall = "$($yammerBaseUrl)/users.json"
$urlToCall += "?page=" + $page
$headers = Get-BaererToken
Write-Host $urlToCall
$webRequest = Invoke-WebRequest –Uri $urlToCall –Method Get -Headers
$headers
if ($webRequest.StatusCode -eq 200) {
$results = $webRequest.Content | ConvertFrom-Json
if ($results.Length -eq 0) {
return $allUsers
}
$allUsers.AddRange($results)
}
if ($allUsers.Count % 50 -eq 0) {
return Get-YamUsers($page++, $allUsers)
}
else {
return $allUsers
}
}
$users = Get-YamUsers
$users | Select-Object id, email
$page isn't an integer so can't be incremented but I am unable to find how to edit this code to make it work. Any thoughts?
You can use this API to get all the users in Yammer Network.
https://www.yammer.com/api/v1/users.json
Try dynamic casting in PowerShell to increment $Page.
Replace:
return Get-YamUsers($page++, $allUsers)
With:
return Get-YamUsers(([int]$page)++, $allUsers)
The correct code is here
$baererToken = "put your api token here"
$yammerBaseUrl = "https://www.yammer.com/api/v1"
Function Get-BaererToken() {
$headers = #{ Authorization=("Bearer " + $baererToken) }
return $headers
}
Function Get-YamUsers($page, $allUsers) {
if ($page -eq $null) {
$page = 1
}
if ($allUsers -eq $null) {
$allUsers = New-Object System.Collections.ArrayList($null)
}
$urlToCall = $yammerBaseUrl + "/users.json?page=" + $page
Write-Host $urlToCall
$headers = Get-BaererToken
$webRequest = Invoke-WebRequest –Uri $urlToCall –Method Get -Headers $headers
if ($webRequest.StatusCode -eq 200) {
$results = $webRequest.Content | ConvertFrom-Json
if ($results.Length -eq 0) {
return $allUsers
}
$allUsers.AddRange($results)
}
if ($allUsers.Count % 50 -eq 0) {
write-host $page
return Get-YamUsers -page ($page+1) -allUsers $allUsers
}
else {
return $allUsers
}
}
$users = Get-YamUsers
$users | Select-Object id, email, state, jobtitle, location, full_name, first_name, lastname, network_name | Export-Csv -Path C:\exported_users.csv -NoTypeInformation -Encoding UTF8
I am writing a web app and I need to pass some url parameters as command line arguments to another script. What should I do to avoid security problems? I am using Sympfony's Process to execute the bash command and Laravel to build the app.
Here is some of the code, look into the buildScreenshotCommand to see how I am building the command string and also note that the $urlRequest is filled in using the Laravel's Request $request class:
<?php
namespace App\Logic;
use App\Logic\TimeHelper;
use App\UrlRequest;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
class Screenshot {
static function take(UrlRequest $urlRequest)
{
$name = self::generateName($urlRequest);
$command = self::buildScreenshotCommand($name, $urlRequest);
$startTime = TimeHelper::milliseconds();
$process = new Process($command);
$process->run();
$endTime = TimeHelper::milliseconds();
if (!$process->isSuccessful())
{
throw new ProcessFailedException($process);
}
$output = $process->getOutput();
if (trim($output) === '')
{
$urlRequest->successful = 1;
$file = self::uploadToS3($name);
$urlRequest->image_url = $file['url'];
$urlRequest->file_size = $file['size'];
$urlRequest->file_name = $name;
$urlRequest->time_it_took_to_take_screenshot_ms = $endTime - $startTime;
if ($urlRequest->save())
{
return $urlRequest;
}
}
else
{
$urlRequest->error = $output;
$urlRequest->save();
}
return false;
}
static function uploadToS3($name)
{
$name = 'screenshots/' . $name;
Storage::disk('s3')->put($name, Storage::disk('local')->get($name), ['visibility' => 'public']); // upload to S3
$fileSize = Storage::disk('local')->size($name);
Storage::disk('local')->delete($name);
return [
'url' => Storage::disk('s3')->url($name),
'size' => $fileSize
];
}
static function generateName($urlRequest)
{
$name = time() . rand(10000, 99999);
$extension = '.png';
if (isset($urlRequest->pdf) AND $urlRequest->pdf == 1)
{
$extension = '.pdf';
}
while (UrlRequest::where('file_name', '=', $name . $extension)->first())
{
$name = time() . rand(10000, 99999);
}
return $name . $extension;
}
static function buildScreenshotCommand($name, $urlRequest)
{
$command = 'cd ' . base_path() . ' && node puppeteer-screenshots-init.js ';
$command .= "--url={$urlRequest->url} ";
$fullPath = storage_path('app') . '/screenshots/' . $name;
$command .= "--path={$fullPath} ";
if (isset($urlRequest->pdf))
{
$command .= "--pdf=true ";
}
if (isset($urlRequest->viewport_width))
{
$command .= "--viewportWidth={$urlRequest->viewport_width} ";
}
if (isset($urlRequest->mobile))
{
$command .= '--mobile=true ';
}
if (isset($urlRequest->media_type_print))
{
$command .= '--mediaTypePrint=true ';
}
if (isset($urlRequest->user_agent))
{
$command .= '--userAgent="' . $urlRequest->user_agent . '" ';
}
$command .= '2>&1 &';
return $command;
}
}
I think this is a really bad idea. What if $urlRequest->url was:
// urlencoded
http%3A%2F%2Fgoogle.com%3F%3Brm+-Rf+%2F%3B
http://google.com?;rm -Rf /;
What kind of input sanitization are you doing?
Created a build definition using TFS 2013 to run a scheduled build.
And using SetupSiteForPublish.ps1(see below) in post-build script process to deploy the site on iis on a remote server.
I am referring following 2 articles:
Article1
Article2
Now When i use /P:CreatePackageOnPublish=True /P:DeployOnBuild=True
in MSBuild Arguments, getting following error message:
C:\Program Files
(x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.targets
(3739): Package/Publish task
Microsoft.Web.Publishing.Tasks.IsCleanMSDeployPackageNeeded failed to
load Web Deploy assemblies. Microsoft Web Deploy is not correctly
installed on this machine. Microsoft Web Deploy v3 or higher is
recommended.
param(
[parameter(Mandatory = $false)]
$siteName,
[parameter(Mandatory = $false)]
$sitePhysicalPath,
[parameter(Mandatory = $false)]
$siteAppPoolName,
[parameter(Mandatory = $false)]
[int]$sitePort,
[parameter(Mandatory = $false)]
$deploymentUserName,
[parameter(Mandatory = $false)]
$deploymentUserPassword,
[parameter(Mandatory = $false)]
$managedRunTimeVersion,
[parameter(Mandatory = $false)]
$publishSettingSavePath,
[parameter(Mandatory = $false)]
$publishSettingFileName
)
##Import-LocalizedData -BindingVariable Resources -FileName Resources.psd1
# ==================================
#constants
$SCRIPTERROR = 0
$WARNING = 1
$INFO = 2
$logfile = ".\HostingLog-$(get-date -format MMddyyHHmmss).log"
$template = #"
<?xml version="1.0" encoding="utf-8"?>
<publishData>
<publishProfile
publishUrl=""
msdeploySite=""
destinationAppUrl=""
mySQLDBConnectionString=""
SQLServerDBConnectionString=""
profileName="Default Settings"
publishMethod="MSDeploy"
userName=""
userPWD=""
savePWD="True"
/>
</publishData>
"#
#the order is important. Check for apppool name first. Its possible that
#the user gave just a sitename to set permissions. In this case leave apppool emtpy.
#else give a default name to the apppool.
if(!$siteAppPoolName)
{
if(!$siteName)
{
$siteAppPoolName = "AvailabilityServiceAgent"
}
}
else
{
$siteAppPoolName = $siteAppPoolName.Trim()
}
#now the sitename check. If its empty give it a default name
if(!$siteName)
{
$siteName = "AvailabilityServiceAgent"
}
else
{
$siteName = $siteName.Trim()
}
if(!$sitePhysicalPath)
{
$sitePhysicalPath= $ENV:TF_BUILD_DROPLOCATION+"\_PublishedWebsites\AvailabilityServiceHost"
}
else
{
$sitePhysicalPath = $sitePhysicalPath.Trim()
}
#global variable. Because we need to return two values from MWA from one function. [REF] has bugs. Hence global
$global:sitePath = $sitePhysicalPath
$global:publishURL = $null
# this function does logging
function write-log([int]$type, [string]$info){
$message = $info -f $args
$logMessage = get-date -format HH:mm:ss
Switch($type){
$SCRIPTERROR{
$logMessage = $logMessage + "`t" + $Resources.Error + "`t" + $message
write-host -foregroundcolor white -backgroundcolor red $logMessage
}
$WARNING{
$logMessage = $logMessage + "`t" + $Resources.Warning + "`t" + $message
write-host -foregroundcolor black -backgroundcolor yellow $logMessage
}
default{
$logMessage = $logMessage + "`t" + $Resources.Info + "`t" + $message
write-host -foregroundcolor black -backgroundcolor green $logMessage
}
}
$logMessage >> $logfile
}
function GetPublishSettingSavePath()
{
if(!$publishSettingFileName)
{
$publishSettingFileName = "WDeploy.PublishSettings"
}
if(!$publishSettingSavePath)
{
$publishSettingSavePath = [System.Environment]::GetFolderPath("Desktop")
}
if((test-path $publishSettingSavePath) -eq $false)
{
write-log $SCRIPTERROR $Resources.FailedToAccessScriptsFolder $publishSettingSavePath
return $null
}
return Join-Path $publishSettingSavePath $publishSettingFileName
}
# returns false if OS is not server SKU
function NotServerOS
{
$sku = $((gwmi win32_operatingsystem).OperatingSystemSKU)
$server_skus = #(7,8,9,10,12,13,14,15,17,18,19,20,21,22,23,24,25)
return ($server_skus -notcontains $sku)
}
# gives a user access to an IIS site's scope
function GrantAccessToSiteScope($username, $websiteName)
{
trap [Exception]
{
write-log $SCRIPTERROR $Resources.FailedToGrantUserAccessToSite $username $websiteName
return $false
}
foreach($mInfo in [Microsoft.Web.Management.Server.ManagementAuthorization]::GetAuthorizedUsers($websiteName, $false, 0,[int]::MaxValue))
{
if($mInfo.Name -eq $username)
{
write-log $INFO $Resources.UserHasAccessToSite $username $websiteName
return $true
}
}
[Microsoft.Web.Management.Server.ManagementAuthorization]::Grant($username, $websiteName, $FALSE) | out-null
write-log $INFO $Resources.GrantedUserAccessToSite $username $websiteName
return $true
}
# gives a user permissions to a file on disk
function GrantPermissionsOnDisk($username, $type, $options)
{
trap [Exception]
{
write-log $SCRIPTERROR $Resources.NotGrantedPermissions $type $username $global:sitePath
}
$acl = (Get-Item $global:sitePath).GetAccessControl("Access")
$accessrule = New-Object system.security.AccessControl.FileSystemAccessRule($username, $type, $options, "None", "Allow")
$acl.AddAccessRule($accessrule)
set-acl -aclobject $acl $global:sitePath
write-log $INFO $Resources.GrantedPermissions $type $username $global:sitePath
}
function AddUser($username, $password)
{
if(-not (CheckLocalUserExists($username) -eq $true))
{
$comp = [adsi] "WinNT://$env:computername,computer"
$user = $comp.Create("User", $username)
$user.SetPassword($password)
$user.SetInfo()
write-log $INFO $Resources.CreatedUser $username
}
}
function CheckLocalUserExists($username)
{
$objComputer = [ADSI]("WinNT://$env:computername")
$colUsers = ($objComputer.psbase.children | Where-Object {$_.psBase.schemaClassName -eq "User"} | Select-Object -expand Name)
$blnFound = $colUsers -contains $username
if ($blnFound){
return $true
}
else{
return $false
}
}
function CheckIfUserIsAdmin($username)
{
$computer = [ADSI]("WinNT://$env:computername,computer")
$group = $computer.psbase.children.find("Administrators")
$colMembers = $group.psbase.invoke("Members") | %{$_.GetType().InvokeMember("Name",'GetProperty',$null,$_,$null)}
$bIsMember = $colMembers -contains $username
if($bIsMember)
{
return $true
}
else
{
return $false
}
}
function CreateLocalUser($username, $password, $isAdmin)
{
AddUser $username $password
if($isAdmin)
{
if(-not(CheckIfUserIsAdmin($username) -eq $true))
{
$group = [ADSI]"WinNT://$env:computername/Administrators,group"
$group.add("WinNT://$env:computername/$username")
write-log $INFO $Resources.AddedUserAsAdmin $username
}
else
{
write-log $INFO $Resources.IsAdmin $username
}
}
return $true
}
function Initialize
{
trap [Exception]
{
write-log $SCRIPTERROR $Resources.CheckIIS7Installed
break
}
$inetsrvPath = ${env:windir} + "\system32\inetsrv\"
[System.Reflection.Assembly]::LoadFrom( $inetsrvPath + "Microsoft.Web.Administration.dll" ) > $null
[System.Reflection.Assembly]::LoadFrom( $inetsrvPath + "Microsoft.Web.Management.dll" ) > $null
}
function GetPublicHostname()
{
$ipProperties = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
if($ipProperties.DomainName -eq "")
{
return $ipProperties.HostName
}
else
{
return "{0}.{1}" -f $ipProperties.HostName, $ipProperties.DomainName
}
}
function GenerateStrongPassword()
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Web") > $null
return [System.Web.Security.Membership]::GeneratePassword(12,4)
}
function GetPublishURLFromBindingInfo($bindingInfo, $protocol, $hostname)
{
$port = 80
trap [Exception]
{
#return defaults
return "http://$hostname"
}
if(($bindingInfo -match "(.*):(\d*):([^:]*)$") -and
($Matches.Count -eq 4 ))
{
$port = $Matches[2]
$header = $Matches[3]
$ipaddress = $Matches[1]
if($header)
{
$hostname = $header
}
elseif(($ipaddress) -AND (-not($ipaddress -eq "*")))
{
$bracketsArray = #('[',']')
$hostname = $ipaddress.Trim($bracketsArray)
}
if(-not($port -eq 80))
{
$hostname = $hostname + ":" + $port
}
}
return $protocol + "://" + $hostname
}
function GetUnusedPortForSiteBinding()
{
[int[]] $portArray = $null
$serverManager = (New-Object Microsoft.Web.Administration.ServerManager)
foreach($site in $serverManager.Sites)
{
foreach($binding in $site.Bindings)
{
if($binding.IsIPPortHostBinding)
{
if($binding.Protocol -match "https?")
{
if(($binding.BindingInformation -match "(.*):(\d*):([^:]*)$") -and
($Matches.Count -eq 4 ))
{
$portArray = $portArray + $Matches[2]
}
}
}
}
}
if(-not($portArray -eq $null))
{
$testPortArray = 8081..8200
foreach($port in $testPortArray)
{
if($portArray -notcontains $port)
{
return $port
}
}
}
return 8081 #default
}
function CreateSite($name, $appPoolName, $port, $dotnetVersion)
{
trap [Exception]
{
write-log $SCRIPTERROR $Resources.SiteCreationFailed
return $false
}
$hostname = GetPublicHostName
$global:publishURL = "http://$hostname"
if(-not($port -eq 80))
{
$global:publishURL = $global:publishURL + ":" + $port
}
$configHasChanges = $false
$serverManager = (New-Object Microsoft.Web.Administration.ServerManager)
#appPool might be empty. WHen the user gave just a site name to
#set the permissions on. As long as the sitename is not empty
if($appPoolName)
{
$appPool = $serverManager.ApplicationPools[$appPoolName]
if ($appPool -eq $null)
{
$appPool = $serverManager.ApplicationPools.Add($appPoolName)
$appPool.Enable32BitAppOnWin64 = $true
if( ($dotnetVersion) -and
(CheckVersionWithinAllowedRange $dotnetVersion) )
{
$appPool.ManagedRuntimeVersion = $dotnetVersion
}
$configHasChanges = $true
write-log $INFO $Resources.AppPoolCreated $appPoolName
}
else
{
write-log $WARNING $Resources.AppPoolExists $appPoolName
}
}
$newSite = $serverManager.Sites[$name]
if ($newSite -eq $null)
{
$newSite = $serverManager.Sites.Add($name,$global:sitePath, $port)
$newSite.Applications[0].ApplicationPoolName = $appPool.Name
if((test-path $global:sitePath) -eq $false)
{
[System.IO.Directory]::CreateDirectory($global:sitePath)
}
else
{
write-log $WARNING $Resources.SiteVirtualDirectoryExists $global:sitePath
}
$newSite.ServerAutoStart = $true
$configHasChanges = $true
write-log $INFO $Resources.SiteCreated $name
}
else
{
#get virtual directory and siteport
$global:sitePath = [System.Environment]::ExpandEnvironmentVariables($newSite.Applications["/"].VirtualDirectories["/"].PhysicalPath)
foreach($binding in $newSite.Bindings)
{
if($binding.IsIPPortHostBinding)
{
if($binding.Protocol -match "https?")
{
$global:publishURL = GetPublishURLFromBindingInfo $binding.BindingInformation $binding.Protocol $hostname
}
}
}
if($appPoolName)
{
if (-not($newSite.Applications[0].ApplicationPoolName -eq $appPool.Name ))
{
$newSite.Applications[0].ApplicationPoolName = $appPool.Name
write-log $INFO $Resources.SiteAppPoolUpdated $name $appPoolName
}
else
{
write-log $INFO $Resources.SiteExists $name $appPoolName
}
}
else
{
write-log $INFO $Resources.SiteExists $name $newSite.Applications[0].ApplicationPoolName
}
}
if ($configHasChanges)
{
$serverManager.CommitChanges()
}
return $true
}
function CheckUserViaLogon($username, $password)
{
$signature = #'
[DllImport("advapi32.dll")]
public static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
'#
$type = Add-Type -MemberDefinition $signature -Name Win32Utils -Namespace LogOnUser -PassThru
[IntPtr]$token = [IntPtr]::Zero
$value = $type::LogOnUser($username, $env:computername, $password, 2, 0, [ref] $token)
if($value -eq 0)
{
return $false
}
return $true
}
function CheckUsernamePasswordCombination($user, $password)
{
if(($user) -AND ($password))
{
if(CheckLocalUserExists($user) -eq $true)
{
if(CheckUserViaLogon $user $password)
{
return $true
}
else
{
write-Log $SCRIPTERROR $Resources.FailedToValidateUserWithSpecifiedPassword $user
return $false
}
}
}
return $true
}
function CreateProfileXml([string]$nameofSite, [string]$username, $password, [string]$hostname, $pathToSaveFile)
{
trap [Exception]
{
write-log $SCRIPTERROR $Resources.FailedToWritePublishSettingsFile $pathToSaveFile
return
}
$xml = New-Object xml
if(Test-Path $pathToSaveFile)
{
$xml.Load($pathToSaveFile)
}
else
{
$xml.LoadXml($template)
}
$newProfile = (#($xml.publishData.publishProfile)[0])
$newProfile.publishUrl = $hostname
$newProfile.msdeploySite = $nameofSite
$newProfile.destinationAppUrl = $global:publishURL.ToString()
$newProfile.userName = $username
if(-not ($password -eq $null))
{
$newProfile.userPWD = $password.ToString()
}
else
{
write-log $WARNING $Resources.NoPasswordForExistingUserForPublish
}
$xml.Save($pathToSaveFile)
write-log $INFO $Resources.SavingPublishXmlToPath $pathToSaveFile
}
function CheckVersionWithinAllowedRange($managedVersion)
{
trap [Exception]
{
return $false
}
$KeyPath = "HKLM:\Software\Microsoft\.NETFramework"
$key = Get-ItemProperty -path $KeyPath
$path = $key.InstallRoot
$files = [System.IO.Directory]::GetFiles($path, "mscorlib.dll", [System.IO.SearchOption]::AllDirectories)
foreach($file in $files)
{
if($file -match "\\(v\d\.\d).\d*\\")
{
if($Matches[1] -eq $managedVersion)
{
return $true
}
}
}
return $false
}
#================= Main Script =================
if(NotServerOS)
{
write-log $SCRIPTERROR $Resources.NotServerOS
break
}
Initialize
if(CheckUsernamePasswordCombination $deploymentUserName $deploymentUserPassword)
{
if(!$sitePort)
{
$sitePort = GetUnusedPortForSiteBinding
}
if(CreateSite $siteName $siteAppPoolName $sitePort $managedRunTimeVersion)
{
if(!$deploymentUserName)
{
$idx = $siteName.IndexOf(' ')
if( ($idx -gt 0) -or ($siteName.Length -gt 16))
{
$deploymentUserName = "WDeployuser"
}
else
{
$deploymentUserName = $siteName + "user"
}
}
if( (CheckLocalUserExists($deploymentUserName) -eq $true))
{
$deploymentUserPassword = $null
}
else
{
if(!$deploymentUserPassword)
{
$deploymentUserPassword = GenerateStrongPassword
}
}
if(CreateLocalUser $deploymentUserName $deploymentUserPassword $false)
{
GrantPermissionsOnDisk $deploymentUserName "FullControl" "ContainerInherit,ObjectInherit"
if(GrantAccessToSiteScope ($env:computername + "\" + $deploymentUserName) $siteName)
{
$hostname = GetPublicHostName
$savePath = GetPublishSettingSavePath
if($savePath)
{
CreateProfileXml $siteName $deploymentUserName $deploymentUserPassword $hostname $savePath
}
}
}
}
}
Write-Host “Post-build script succeeded!”