Thursday, 3 October 2013

Executing scripts / files using powershell

Note: PS refers to PowerShell

Powershell has 2 main ways I have tested how to execute scripts.
  1.        Start-Process
  2.        Invoke-Command

Start-Process

       After research, and using in example i have found it is ill-suited to run commands with arguments, unless you construct everything in one command and then execute. You can get only one set of results and you need to add additional logic in order to pass messages to parent window.

Example:

$ScriptPath = "D:\Scripts\script.ps1"
$WebSiteName = 'MyWebSite'
$PathToDirectory ="D:\site"


#Definition of AllArguments (keep in mind the quotes) 
$AllArgument = '-ExecutionPolicy Unrestricted -file "' + $ScriptPath + '" 
-IsRunAsAdmin -args ' + "$WebSiteName, $PathToDirectory" 

$AdminProcess = Start-Process "$PsHome\PowerShell.exe" -WindowStyle Maximized  -Verb RunAs -ArgumentList $AllArgument -PassThru 
      
# Access the process by ID and wait for its end
Wait-Process $AdminProcess.Id 

Invoke-Command

       Is used mosty of running command as part of a script where there is no need for user interaction. All output is directed into one window unless specified otherwise.
Example
$ScriptPath = "D:\Scripts\script.ps1"
$WebSiteName = 'MyWebSite'
$PathToDirectory ="D:\site\"

Executing option script 1

$script = [scriptblock]::create( @"
param(`$PathToDirectory,`$WebSiteName,`$Debug=`$False)
&{ $(Get-Content $ScriptPath -delimiter ([char]0)) } @PSBoundParameters
"@ )

Invoke-Command -Script $script -Args $PathToDirectory,$WebSiteName, $false

Executing option script 2

icm { 
    param($PathToDirectory,$WebSiteName,$Debug=$False)
    D:\Scripts\script.ps1 @PSBoundParameters
} -ArgumentList $PathToDirectory,$WebSiteName, $false
NOTE: icm is same as Invoke-Command

Executing option script 3

Invoke-Command { 
    param($PathToDirectory,$WebSiteName,$Debug=$False)
    &$ScriptPath @PSBoundParameters
} -ArgumentList $PathToDirectory,$WebSiteName, $false 

Wednesday, 2 October 2013

Umbraco Links


 Slowly I am getting loads of articles about Umbraco

Here are some I have found usefull


Publishing events using V4 code base in V6 
http://our.umbraco.org/forum/developers/api-questions/38101-V6-ContentService-Publish-Event


MVC

 Custom routing
http://shazwazza.com/category/Umbraco


MVC Umbraco testing
http://dipunm.wordpress.com/2013/06/16/creating-testable-controllers-in-umbraco/


Code UI Automation
http://watin.org/

Restart IIS Site using powershell script with credentials

I need to reset iis site using team city build.
I have decided to use PowerShell as I have been using it for everything else to do with the build.

When I have attempted to run this under my normal credentials, it did not work and I got error:

 System.InvalidOperationException: Process should have elevated status to access IIS configuration data.
    at Microsoft.IIs.PowerShell.Provider.ConfigurationPr
 ovider.Start(ProviderInfo providerInfo)
    at System.Management.Automation.SessionStateInternal
 .NewProvider(ProviderInfo provider)
    at System.Management.Automation.SessionStateInternal
 .AddProvider(Type implementingType, String name,
 String helpFileName, PSSnapInInfo psSnapIn,
 PSModuleInfo module)



Not to be beaten, I have proceeded on trip how to run this with elevated permissions.






Code:

# ============================== #
#     Definition of variables    #
# ============================== #
$UserName = "Domain\UserName"  
$UserPassword = 'password'
$computer = 'ServerName'
$WebSiteName = 'Site-Build'

# ============================== #
#   Generic setup                                              #
# ============================== #
$SecurePassword = ConvertTo-SecureString -AsPlainText -Force -String $UserPassword
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $UserName , $SecurePassword

# ========================== #
#   Option 1                                            #
# ========================== #
$a = {
  function foo([string]$WebSiteName){

    Write-Host "Restarting website $WebSiteName"
    Import-Module WebAdministration
    Stop-WebSite $WebSiteName
    Start-Sleep -Milliseconds 5000
    Start-WebSite $WebSiteName
    return "$WebSiteName"
  }
 
  foo($args)
}
$rv = Invoke-Command -Credential $Credential -ComputerName $computer -ScriptBlock  $a -ArgumentList $WebSiteName
Write-Host $rv1

# ========================== #
#   Option 2 - preffered by me                #
# ========================== #
Start-Sleep -Milliseconds 15000

function foo([string] $WebSiteName){
   
    Write-Host "Restarting website $WebSiteName"
    Import-Module WebAdministration
    Stop-WebSite $WebSiteName
    Start-Sleep -Milliseconds 5000
    Start-WebSite $WebSiteName

    return "$WebSiteName"
}


$rv1 = Invoke-Command -Credential $Credential -ComputerName $computer -ScriptBlock ${function:foo} -ArgumentList $WebSiteName
Write-Host $rv1

<#  #>

Wednesday, 25 September 2013

PowerShell creating database and associating login

I have been working on droping new database as part of my continuous deployment implementation.
For this I have needed to create couple powerhsell scripts.

Here is one example (prototype how it works)

Note: it needs tidy up.







$Instance   = ".\SQLEXPRESS"
$LoginName  = "Login name"
$Password   = "loginPassword"
$DBName     = "Database"

#Get the server object
$srv = New-Object ("Microsoft.SqlServer.Management.SMO.Server") $instance

        $varDBUser = "Usern"
        $varDBPassword = "password"
        $srv.ConnectionContext.LoginSecure = $false
        $srv.ConnectionContext.Login = $varDBUser
        $srv.ConnectionContext.Password = $varDBPassword

#Get the login object if it exists
$Login = $srv.Logins.Item($LoginName)

IF (!($Login))  #check to see if login already exists
{
   Write-Host " login does not exists, creating"

 #it doesn't, so instantiate a new login object
    $Login = New-Object ("Microsoft.SqlServer.Management.SMO.Login") ($Server, $LoginName)

    #make it a SQL Login
    $Login.LoginType = [Microsoft.SqlServer.Management.Smo.LoginType]::SqlLogin

    #Create it on the server with the specified password
    $Login.Create($Password)



}

#Get the database object
$DB = $srv.Databases[$DBName]
 
#Get the user object if it exists
$User = $DB.Users[$LoginName]

if (!($User)) # check to see if the user is already in the database
{
    #it doesn't, so add it
    $User = New-Object ("Microsoft.SqlServer.Management.SMO.User") ($DB, $LoginName)
    $User.Login = $LoginName
    $User.Create()
}

Monday, 23 September 2013

Running referenced powershell scripts from teamcity build.

I have been tasked  with creating automation for build process using PowerShell and TeamCity.

I have had multiple functions that I wanted to call in multiple steps, but the one issue had problem with was error:

[15:50:43][Step 7/8] .\ExecuteScripts.ps1 : The term '.\ExecuteScripts.ps1' is not recognized
[15:50:43][Step 7/8] as the name of a cmdlet, function, script file, or operable program. Check the
[15:50:43][Step 7/8] spelling of the name, or if a path was included, verify that the path is
[15:50:43][Step 7/8] correct and try again.
[15:50:43][Step 7/8] At \Path\RunUmbracoInstallation.ps1:5 char:1
[15:50:43][Step 7/8] + .\ExecuteScripts.ps1


This is so helpfull that I had to find way around it.
I have created basic file (test.ps1 - first version) that I have been able to execute from team build process.

After this step have been executing correctly though TeamCity.
I have set up permissions on powershell for user account under which teamcity agent run to FullControl.






File: test.ps1 - first version


 param(
        [Parameter(Mandatory=$True)] [string] $arg1,
        [Parameter(Mandatory=$True)] [string] $arg2
    )

function PowerShellTest{
  
    Write-Host -fore Magenta "Executing function powershell test with arguments:"
    Write-host -fore Cyan "arg1:$arg1  arg2:$arg2"
}

  
PowerShellTest


File: test.ps1 - final version

 param(
        [Parameter(Mandatory=$True)] [string] $arg1,
        [Parameter(Mandatory=$True)] [string] $arg2
    )


 &lt;# ========== Loading required files ============ #&gt;
$commons =Join-Path (Get-ScriptDirectory)"test2.ps1"
.$commons;

&lt;# ========== Loading required files ============ #&gt;

function PowerShellTest{
  

    Write-Host -fore Magenta "Executing function powershell test with arguments:"
    Write-host -fore Cyan "arg1:$arg1  arg2:$arg2"

    PowerShellTest2 -arg1 $arg1 -arg2 $arg2
}


function Get-ScriptDirectory
{
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    Split-Path $Invocation.MyCommand.Path
}

  
PowerShellTest


File: test2.ps1



function PowerShellTest2{  

 param(
        [Parameter(Mandatory=$True)] [string] $arg1,
        [Parameter(Mandatory=$True)] [string] $arg2
    )

    Write-Host -fore Magenta "Executing function powershell test2:"
    Write-host -fore Cyan "arg1:$arg1  arg2:$arg2"
}



Now build configuration



Note:
  1. that script arguments do not have staring - before and value is in quotes.
  2. Powershell run mode: is defined as to what version of my PS and x64 is as my server version


After running agent again I do get results as:



 Execute PS Test script (Powershell)
[18:14:36][Step 8/8] Starting: Path\powershell.exe -NoProfile -NonInteractive -ExecutionPolicy ByPass -File PathToWorkDirectory\test.ps1 arg1="Test1" arg2="2Test2"
[18:14:36][Step 8/8] in directory: PathToWorkDirectory\
[18:14:37][Step 8/8] Executing function powershell test with arguments:
[18:14:37][Step 8/8] arg1:arg1=Test1 arg2:arg2=2Test2
[18:14:37][Step 8/8] Executing function powershell test2:
[18:14:37][Step 8/8] arg1:arg1=Test1 arg2:arg2=2Test2
[18:14:37][Step 8/8] Process exited with code 0


I have managed to do this thanks to this blog article.
http://leftlobed.wordpress.com/2008/06/04/getting-the-current-script-directory-in-powershell/