Showing posts with label powershell. Show all posts
Showing posts with label powershell. Show all posts

Thursday, 22 September 2016

How to pass named parameters with Invoke-Command




-ArgumentList is based on use with scriptblock commands, like:
Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True
When you call it with a -File it still passes the parameters like a dumb splatted array. I've submitted a feature request to have that added to the command (please vote that up).
So, you have two options:
If you have a script that looked like this, in a network location accessible from the remote machine (note that -Debug is implied because when I use the Parameter attribute, the script gets CmdletBinding implicitly, and thus, all of the common parameters):
param(
   [Parameter(Position=0)]
   $one
,
   [Parameter(Position=1)]
   $two
,
   [Parameter()]
   [Switch]$Clear
)

"The test is for '$one' and '$two' ... and we $(if($DebugPreference -ne 'SilentlyContinue'){"will"}else{"won't"}) run in debug mode, and we $(if($Clear){"will"}else{"won't"}) clear the logs after."
Without getting hung up on the meaning of $Clear ... if you wanted to invoke that you could use either of the following Invoke-Command syntaxes:
icm -cn (gc Servers.txt) { 
    param($one,$two,$Debug=$False,$Clear=$False)
    C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 @PSBoundParameters
} -ArgumentList "uno", "dos", $false, $true
In that one, I'm duplicating ALL the parameters I care about in the scriptblock so I can pass values. If I can hard-code them (which is what I actually did), there's no need to do that and use PSBoundParameters, I can just pass the ones I need to. In the second example below I'm going to pass the $Clear one, just to demonstrate how to pass switch parameters:
icm -cn $Env:ComputerName { 
    param([bool]$Clear)
    C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $(Test-Path $Profile)

The other option

If the script is on your local machine, and you don't want to change the parameters to be positional, or you want to specify parameters that are common parameters (so you can't control them) you will want to get the content of that script and embed it in your scriptblock:
$script = [scriptblock]::create( @"
param(`$one,`$two,`$Debug=`$False,`$Clear=`$False)
&{ $(Get-Content C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -delimiter ([char]0)) } @PSBoundParameters
"@ )

Invoke-Command -Script $script -Args "uno", "dos", $false, $true

PostScript:

If you really need to pass in a variable for the script name, what you'd do will depend on whether the variable is defined locally or remotely. In general, if you have a variable $Script or an environment variable $Env:Script with the name of a script, you can execute it with the call operator (&): &$Script or &$Env:Script
If it's an environment variable that's already defined on the remote computer, that's all there is to it. If it's a local variable, then you'll have to pass it to the remote script block:
Invoke-Command -cn $Env:ComputerName { 
    param([String]$Script, [bool]$Clear)
    &$Script "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $ScriptPath, $(Test-Path $Profile)


from: Stack overflow

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

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

<#  #>

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/

Thursday, 19 September 2013

PowerShell - Usefull commands


Update help definition  from online.

You need to run this command under administrator rights.

PS C:\Windows\system32> Update-Help
(I have read, that it gets updated almost every week)


PowerShell can run with wildcards : *

PS C:\Windows\system32> help *service*


Name                              Category  Module                    Synopsis                                                                                                               
----                              --------  ------                    --------                                                                                                               
Get-Service                       Cmdlet    Microsoft.PowerShell.M... Gets the services on a local or remote computer.                                                                       
New-Service                       Cmdlet    Microsoft.PowerShell.M... Creates a new Windows service.                                                                                         
New-WebServiceProxy               Cmdlet    Microsoft.PowerShell.M... Creates a Web service proxy object that lets you use and manage the Web service in Windows PowerShell.                 
Restart-Service                   Cmdlet    Microsoft.PowerShell.M... Stops and then starts one or more services.                                                                            
Resume-Service                    Cmdlet    Microsoft.PowerShell.M... Resumes one or more suspended (paused) services.                                                                       
Set-Service                       Cmdlet    Microsoft.PowerShell.M... Starts, stops, and suspends a service, and changes its properties.                                                     
Start-Service                     Cmdlet    Microsoft.PowerShell.M... Starts one or more stopped services.                                                                                   
Stop-Service                      Cmdlet    Microsoft.PowerShell.M... Stops one or more running services.                                                                                    
Suspend-Service                   Cmdlet    Microsoft.PowerShell.M... Suspends (pauses) one or more running services.         


Get full help information about command including examples


PS C:\Windows\system32> help Get-Service -full

What version of PowerShell do I have Installed

  1. $PSVersionTable
  2. $host.version

Get gui for command

PS C:\Windows\system32> Show-Command Start-Process

Get members of commands:

This command shows all information what all I can get get.

PS D:\Scripts> get-service | get-member

PowerShell function parameters
If you are using parameters use param definition in function instead in bracets of the function name:

function WebConfig-SetAppConfigValueForKey{
    param(
         [Parameter(Mandatory=$true)]
         [xml]$doc,
         [Parameter(Mandatory=$true)]
         [string]$key,
         [Parameter(Mandatory=$true)]
         [string]$value
    )


Executing script path

If you are executing script you will be able to get path of the script which gets executed.

function Test(){
    $scriptpath = $MyInvocation.MyCommand.Path
    write-host $scriptpath
}

Test

If you execute the script without file you will get null