none
Deployment package using Powershell to run in multiple servers RRS feed

  • Question

  • Hi .

    I am using a command line prompt, to install my application on multiple server, after logging into each server.

    what the existing script does is  -  Navigate to a specific path using command prompt , execute two commands to install the application. This same step I need to perform in multiple servers, by first logging into the server, opening command prompt, using cd to navigate to the directory and run those commands.   

    I have created a configuration XML file, which contains all the information to be executed . Is there a way to achieve this in powershell without logging into the server and executing the command ? My config file is as below:

    <?xml version="1.0"?>
    <Config>   
      <Action Name="Deploy">
                <CommandPath>path to navigate</CommandPath>
                <PackagePath>path of Application package</PackagePath>
    			<ModelName>Name of model to be deployed</ModelName>
    			<ServiceName>Name of Service</ServiceName>
                <DeploymentServer>
                    <Server Name = 'Server1'></Server>
                    <Server Name = 'Server2'></Server>
                </DeploymentServer>
      </Action>
      <Action Name="Update">
                <CommandPath>path to navigate</CommandPath>
                <PackagePath>path of Application package</PackagePath>
    			<ModelName>Name of model to be updated</ModelName>
    			<ServiceName>Name of Service</ServiceName>
                <DeploymentServer>
                    <Server Name = 'Server1'></Server>
                    <Server Name = 'Server2'></Server>
                </DeploymentServer>
      </Action>     
    </Config>

    I want to get the type of installation -  deploy or update from user and then update the commands.

    I am aware of reading the data from user , but need the help to run the other commands by reading from the config xml and exceuting in the servers defined in the DeploymentServer tag.

    How to achieve this deployment in multiple servers using Powershell ?

    Thanks


    • Edited by Venkatzeus Friday, July 10, 2020 3:50 PM
    Friday, July 10, 2020 3:26 PM

Answers

  • Please skip the unnecessary variables to avoid confusion and errors.

    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            Set-Location $args[0].CommandPath
            & $args[0].Deployscript1.Name
            & $args[0].Deployscript2.Name
        } -ArgumentList $selectedNode

    This is evenbetter.

    $sb = {
        param(
            $Configuration
        )
        Set-Location $Configuration.CommandPath
        & $Configuration.Deployscript1.Name
        & $Configuration.Deployscript2.Name
    }
    Invoke-Command -ComputerName $ServerName -ScriptBlock $sb  -ArgumentList $selectedNode

    Either makes the code understandable with explicit names.  "$args" is a relic from PS1 that was used before PS2 refined the language.


    \_(ツ)_/

    • Marked as answer by Venkatzeus Friday, July 24, 2020 6:07 PM
    Thursday, July 23, 2020 6:50 PM
    Moderator

All replies

  • The following contains all of the information you need to manipulate XML files with PowerShell.

    It is free and complete.  


    \_(ツ)_/


    • Proposed as answer by jrvModerator Saturday, July 11, 2020 6:17 AM
    • Edited by jrvModerator Saturday, July 11, 2020 6:18 AM
    • Unproposed as answer by Venkatzeus Saturday, July 11, 2020 7:05 AM
    Friday, July 10, 2020 4:42 PM
    Moderator
  • what's the problem? i cannot get in which plase you have misunderstadnig/ideas

    if you know your data structure - you can hardcoded navigate in your file

    if you do not knot datastructure inside - you can create some interactive menu for your users


    The opinion expressed by me is not an official position of Microsoft

    Friday, July 10, 2020 6:25 PM
  • Hi.

    Thanks for the reply. I need the PowerShell help for below

    1) How to get each of the values in the config depending on whether it s Deploy or Update

    2) How to loop through for each of the server ( windows server )

    3) How to connect to those servers and move to the path available in CommandPath

    Thanks



    • Edited by Venkatzeus Saturday, July 11, 2020 7:09 AM
    Saturday, July 11, 2020 5:27 AM
  • Hi.

    Thanks for the reply. I need the PowerShell help for below

    1) How to get each of the values in the config depending on whether it s Deploy or Update

    2) How to loop through for each of the server ( windows server )

    3) How to connect to those servers and move to the path available in CommandPath

    Thanks

    Here, I already answered 1st and 2nd questions

    you have XPath where you can provide one value or another. Did you try that?

    3 Have no idea what do you mean when you say bold fragment. Can you show your code and place where you have a problem?


    The opinion expressed by me is not an official position of Microsoft

    Saturday, July 11, 2020 11:39 AM
  • HI.

    For 3 -  

    I need to connect to each of the server. Navigate to the path in the command prompt or powershell defined in <CommandPath>path to navigate</CommandPath>

    Then excute the commands

    Thanks.

    Sunday, July 12, 2020 6:42 AM
  • HI.

    For 3 -  

    I need to connect to each of the server. Navigate to the path in the command prompt or powershell defined in <CommandPath>path to navigate</CommandPath>

    Then excute the commands

    Thanks.

    $XML = Select-Xml -Path $PSScriptRoot\Test.xml -XPath 'Config' | Select-Object -ExpandProperty Node
    do {
        $Answer = Read-Host -Prompt "Select required action ""$($XML.Action.Name -join '", "')"" "
    } Until ($Answer -in ($XML.Action.Name))
    
    $SelectedAnswer = $XML.Action | Where-Object {$_.Name -eq $Answer}
    $SelectedAnswer.DeploymentServer.Server | ForEach-Object {
        $ServerName = $_.Name
    
        Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0]
            # U can use this on the remote server
            $Configuration.CommandPath
            $Configuration.PackagePath
            $Configuration.ModelName
            $Configuration.ServiceName
        } -ArgumentList $SelectedAnswer
    }



    The opinion expressed by me is not an official position of Microsoft

    Sunday, July 12, 2020 1:20 PM
  • Hi.

    Should the Invoke command be used multiple times, if there are multiple scripts which needs to be run ?

    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0]
            # U can use this on the remote server
            $Configuration.CommandPath
            $Configuration.PackagePath
            $Configuration.ModelName
            $Configuration.ServiceName
        } -ArgumentList $SelectedAnswer

    Apologies, if I had not put the information properly.

    1) Connect to remote server  - able to do now

    2) navigate to path as defined in command path

    3) run the scripts as listed below in the xml:

    <Action Name="Deploy"> <CommandPath>C:\Program Files\Microsoft Sql server\110\</CommandPath> <PackagePath>path of Application package</PackagePath> <ModelName>Name of model to be deployed</ModelName> <ServiceName>Name of service</ServiceName> <DeploymentServer> <Server Name = 'Server1'></Server> <Server Name = 'Server2'></Server> </DeploymentServer> <Deployscript1 Name = 'listservices' > </Deployscript1> <Deployscript2 Name = 'Updateservices' > </Deployscript2>



    • Edited by Venkatzeus Wednesday, July 15, 2020 4:06 PM
    Wednesday, July 15, 2020 4:06 PM
  • it depends :)

    if scripts should be executed on the same remote host 1 by 1 than you can place all you need into code block and execute it (or store all needed inside some script(s) > copy script files onto remote host > execute scripts remotelly)

    if you need execute same code on more then 1 servers simultaneously you can provide list of those servers into the -Computername param (arrays supported) or use loop (like foreach in this discussion).

    Note that loop not so quick


    The opinion expressed by me is not an official position of Microsoft


    • Edited by Vector BCO Wednesday, July 15, 2020 4:15 PM
    Wednesday, July 15, 2020 4:14 PM
  • Hi.

    I am looking at execution as below.

    1) Connect to remote server 1

    2) navigate to path specified , run the first second. On completion of first command, run the second command

    3) Exit from remote server 1

    4) connect to remote server 2 .. like this

    In this block, what should be changed ?

    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0]
            # U can use this on the remote server
            $Configuration.CommandPath
            $Configuration.PackagePath
            $Configuration.ModelName
            $Configuration.ServiceName
        } -ArgumentList $SelectedAnswer
    Thanks

    Thursday, July 16, 2020 6:52 AM
  • yes, this is right place 

    Invoke-Command -ComputerName $ServerName -ScriptBlock { $Configuration = $args[0] # U can use this on the remote server

    #Navigate somewhere Set-Location $Configuration.CommandPath

    #Execute first command & $Configuration.PackagePath -ModelName $Configuration.ModelName

    #Execute second command Get-Service $Configuration.ServiceName | Stop-Service } -ArgumentList $SelectedAnswer


    The opinion expressed by me is not an official position of Microsoft


    • Edited by Vector BCO Thursday, July 16, 2020 7:07 AM
    Thursday, July 16, 2020 7:07 AM
  • Hi.

    I am trying to use the Invoke-Command to run a script in the remote server.

    I am getting the below errors:

    Error 1 : You cannot call a method on a null-valued expression

    Error 2 : The expression after '&' in a pipeline element produced an object that was not valid. It must result in a command name, a script block, or a CommandInfo object.

    The code I have tried is:

    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0]
      
    #Navigate to location
            Set-Location $scriptPath.ToString()
    
    #Execute first command
    
            & $ScriptCode
    
    #Execute second command
    
            $ScriptCode1    
        } -ArgumentList $SelectedAnswer

    Before this line, I am able to get the values of scriptpath  and scriptcode in the writehost.

    How to fix this?

    Thanks

    • Merged by jrvModerator Thursday, July 23, 2020 8:37 AM DUPLICATE
    Thursday, July 23, 2020 6:57 AM
  • What is $scriptPath?  It does not exist in the code.

    Here is your code without all of the useless comments.

    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0]
            Set-Location $scriptPath.ToString()
            & $ScriptCode
            $ScriptCode1    
        } -ArgumentList $SelectedAnswer

    No variables in the script block are defined anywhere.


    \_(ツ)_/

    Thursday, July 23, 2020 7:05 AM
    Moderator
  • Hi.

    The values in the variables defined and are got from configuration xml. Those are working.

    I have used the above code only, but still getting those error

    Error 1 : You cannot call a method on a null-valued expression

    Thursday, July 23, 2020 8:18 AM
  • Hi.

    The values in the variables defined and are got from configuration xml. Those are working.

    I have used the above code only, but still getting those error

    Error 1 : You cannot call a method on a null-valued expression

    please take a look on sample once again

    you are doing something diferrent that we discessed before

    btw, what the reasone create new topic every 3-5 days if your question related to the previous one, and hard understandable without previous context?


    The opinion expressed by me is not an official position of Microsoft

    • Edited by Vector BCO Thursday, July 23, 2020 8:29 AM
    • Proposed as answer by jrvModerator Thursday, July 23, 2020 8:34 AM
    Thursday, July 23, 2020 8:27 AM
  • Without correct and complete information it is impossible to answer your question.


    \_(ツ)_/

    Thursday, July 23, 2020 8:33 AM
    Moderator
  • Hi.

    Below is the complete code used:

    // XML
    
    <?xml version="1.0"?>
    <Config>   
      <Action Name="Deploy">
                <CommandPath>C:\Program Files\Microsoft Sql server\110\</CommandPath>            
                <DeploymentServer>
                    <Server Name = 'Server1'></Server>
                    <Server Name = 'Server2'></Server>  
                </DeploymentServer>
                <Deployscript1 Name = 'listservices' > </Deployscript1>
                <Deployscript2 Name = 'script2' > </Deployscript2>
      </Action>
      <Action Name="Update">
        //few more nodes
      </Action>     
    </Config>


    // Powershell
    
    Set-ExecutionPolicy RemoteSigned
    
    function RunConfiguration()
    {
    
    # get an array of 'Action' XmlElements
    $actionNodes = (Select-Xml -Path $configFile -XPath '//Action').Node
    
    do {
        $Answer = Read-Host -Prompt "Select required action '$($actionNodes.Name -join "', '")'"
    } Until ($Answer -in ($actionNodes.Name))
    
    $selectedNode = $actionNodes | Where-Object {$_.Name -eq $Answer}
    Write-Host $selectedNode.Name
    
    $selectedNode.DeploymentServer.Server | ForEach-Object {
        $ServerName = $_.Name
        Write-Host $ServerName
        
    if($selectedNode.Name -ieq "deploy")
    {
    $ScriptCode  = $selectedNode.Deployscript1.Name
    $ScriptCode2  = $selectedNode.Deployscript2.Name
    }
    Write-Host $ScriptCode
    Write-Host $selectedNode.CommandPath
    
    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0]
      
    #Navigate to location
            Set-Location $scriptPath.ToString()
    
    #Execute first command
    
            & $ScriptCode
    
    #Execute second command
    
            $ScriptCode1    
        } -ArgumentList $SelectedAnswer
      }
    }
    
    
    $spAdminServiceName = "SPAdminV4"
    $currentDir=(split-path $myinvocation.mycommand.path -parent)
    $configFile = $currentDir
    $configFile += "\DeployConfig.xml"
    Execute-Commands $configFile
    
    RunConfiguration
    
    Write-Host -f White "Press Enter key to exit..."
    Read-Host

    I am getting the error as -

    Error 1 : You cannot call a method on a null-valued expression

    Error 2 : The expression after '&' in a pipeline element produced an object that was not valid. It must result in a command name, a script block, or a CommandInfo object. 

    Thursday, July 23, 2020 10:17 AM
  • 1 Setting up execution policy inside the script have no sence because if execution policy will block script execution that line also will not be executed

    2 previously i show you how to provide variables inside Invoke-Command script block, correct? For that you have $configuration & $SelectedAswer variables, and there was a samle how to get values from $configuration. Please read once again previous samples. You need to catch the idea

    3 For some reasone SelectedAnswer variable you renamed in one place but not in the another

    4 For some reasone you defining $ScriptCode and $ScriptCode2, but tries to use $ScriptCode and $ScriptCode1. At the same time you are defining those vars only when SelectedNode.Name -ieq deploy but you use that vars without any if statements. So here you have combo - broken logic and mechanical mistakes

    start from the simple thing and move forward with small and understandable steps (for you first of all)

    as a bonus, current folder can be trigerred in easyer way - $PSScriptRoot


    The opinion expressed by me is not an official position of Microsoft

    • Edited by Vector BCO Thursday, July 23, 2020 11:36 AM
    Thursday, July 23, 2020 11:33 AM
  • Thanks for the reply.

    I corrected those parameters, as below :

    $actionNodes = (Select-Xml -Path $configFile -XPath '//Action').Node
    
    do {
        $Answer = Read-Host -Prompt "Select required action '$($actionNodes.Name -join "', '")'"
    } Until ($Answer -in ($actionNodes.Name))
    
    $selectedNode = $actionNodes | Where-Object {$_.Name -eq $Answer}
    Write-Host $selectedNode.Name
    
    $selectedNode.DeploymentServer.Server | ForEach-Object {
        $ServerName = $_.Name
        Write-Host $ServerName
    
    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0]
    Set-Location $selectedNode.CommandPath.ToString()
    
    #Execute first command
    
          & $selectedNode.Deployscript1.Name.ToString()
    
    #Execute second command
    
        $selectedNode.Deployscript2.Name.ToString()
        
    } -ArgumentList $selectedNode
    
    }

    Error 1: You cannot call a method on a null-valued expression.
        + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull
        + PSComputerName        : ServerName

    Thursday, July 23, 2020 1:21 PM
  • ок, take a look on this

    your $selectedNode parameter provided to ArgumentList goes to $args[0] (red arrow), which saved in $Configuration variable. So if you need to use something from $SelectedNode (outside variable) you should use $Configuration (inside variable)

    At the same time you do not need to use .ToString() method because yours inputs already should be strings


    The opinion expressed by me is not an official position of Microsoft

    Thursday, July 23, 2020 1:57 PM
  • Hi ,

    Could you please verify if this is correct:

     Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $selectedNode
    
            Set-Location $Configuration.CommandPath
    
    #Execute first command      
            & $Configuration.Deployscript1.Name
    #Execute second command
    
      & $Configuration.Deployscript2.Name
        } -ArgumentList $selectedNode
     

    I am still getting this error -

    You cannot call a method on a null-valued expression.
        + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull
        + PSComputerName        : ServerName

    Press Enter key to exit...

    Thursday, July 23, 2020 4:36 PM
  • Invoke-Command -ComputerName $ServerName -ScriptBlock {
            $Configuration = $args[0] # <<<<< $args[0] here should not be replaced\renamed
    
            Set-Location $Configuration.CommandPath
    
    #Execute first command      
            & $Configuration.Deployscript1.Name
    #Execute second command
    
      & $Configuration.Deployscript2.Name
        } -ArgumentList $selectedNode

    The opinion expressed by me is not an official position of Microsoft

    Thursday, July 23, 2020 5:50 PM
  • Please skip the unnecessary variables to avoid confusion and errors.

    Invoke-Command -ComputerName $ServerName -ScriptBlock {
            Set-Location $args[0].CommandPath
            & $args[0].Deployscript1.Name
            & $args[0].Deployscript2.Name
        } -ArgumentList $selectedNode

    This is evenbetter.

    $sb = {
        param(
            $Configuration
        )
        Set-Location $Configuration.CommandPath
        & $Configuration.Deployscript1.Name
        & $Configuration.Deployscript2.Name
    }
    Invoke-Command -ComputerName $ServerName -ScriptBlock $sb  -ArgumentList $selectedNode

    Either makes the code understandable with explicit names.  "$args" is a relic from PS1 that was used before PS2 refined the language.


    \_(ツ)_/

    • Marked as answer by Venkatzeus Friday, July 24, 2020 6:07 PM
    Thursday, July 23, 2020 6:50 PM
    Moderator
  • Hi.

    Apologies, but I am not able to get it right.

    Below is the updated code:

    // XML Config
    
    <?xml version="1.0"?>
    <Config>   
      <Action Name="Deploy">
                <CommandPath>C:\Program Files\Microsoft Sql server\110\</CommandPath>            
                <DeploymentServer>
                    <Server Name = 'Server1'></Server>
                    <Server Name = 'Server2'></Server>  
                </DeploymentServer>
                <Deployscript1 Name = 'list services' > </Deployscript1>
                <Deployscript2 Name = 'script2 test -deploy' > </Deployscript2>
      </Action>
      <Action Name="Update">
        //few more nodes
      </Action>     
    </Config>
    
    
    // Powershell
    function RunConfiguration()
    {
    $actionNodes = (Select-Xml -Path $configFile -XPath '//Action').Node
    
    do {
        $Answer = Read-Host -Prompt "Select required action '$($actionNodes.Name -join "', '")'"
    } Until ($Answer -in ($actionNodes.Name))
    
    $selectedNode = $actionNodes | Where-Object {$_.Name -eq $Answer}
    Write-Host $selectedNode.Name
    
    $selectedNode.DeploymentServer.Server | ForEach-Object {
        $ServerName = $_.Name
        Write-Host $ServerName
    
    $sb = {
        param(
            $Configuration
        )
        Set-Location $Configuration.CommandPath
        & $Configuration.Deployscript1.Name
        & $Configuration.Deployscript2.Name
    }
    Invoke-Command -ComputerName $ServerName -ScriptBlock $sb  -ArgumentList $selectedNode
      }
     }

    Friday, July 24, 2020 1:53 PM
  • ok, so now everything working fine?

    if so please vote for helpfull posts (left side arrow up), and mark comments as an answer that was fully covered your problem


    The opinion expressed by me is not an official position of Microsoft

    Friday, July 24, 2020 3:42 PM
  • Hi Vector,

    No , the above code is not working

    Friday, July 24, 2020 4:07 PM
  • Hi Vector,

    No , the above code is not working

    ok, so what the problem in last edition?

    if you have some old machine/server with old powershell version try my sample with $args[0]


    The opinion expressed by me is not an official position of Microsoft

    Friday, July 24, 2020 4:17 PM
  • Hi.

    The error is -

    The term 'list services' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
        + CategoryInfo          : ObjectNotFound: (Mdsmodeldeploy listservices:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException
        + PSComputerName        : ServerName

    The syntax - list services -  is correct. Is there any quotes which need to be added when the script is having spce

    Friday, July 24, 2020 5:06 PM
  • for now your code working fine and you need modify your xml, because its true that powershell does'nt have such command as list services

    my guess that second command also invalid if you did not place any script2 in location storred in CommandPath, which was descussed more or less month ago in one of the previous yours topics


    The opinion expressed by me is not an official position of Microsoft

    Friday, July 24, 2020 5:32 PM
  • Hi.

    The commands are available here - https://docs.microsoft.com/en-us/sql/master-data-services/deploy-a-model-deployment-package-by-using-mdsmodeldeploy?view=sql-server-ver15

    I had shown the deploy script as an example.

    I am trying to run the commands:

    1) MDSModelDeploy listservices 

    2) MDSModelDeploy deploynew -package PackageName -model ModelName -service ServiceName

    Thanks



    • Edited by Venkatzeus Friday, July 24, 2020 5:47 PM
    Friday, July 24, 2020 5:42 PM
  • Hi.

    The commands are available here - https://docs.microsoft.com/en-us/sql/master-data-services/deploy-a-model-deployment-package-by-using-mdsmodeldeploy?view=sql-server-ver15

    I had shown the deploy script as an example.

    I am trying to run the commands:

    1) MDSModelDeploy listservices 

    2) MDSModelDeploy deploynew -package PackageName -model ModelName -service ServiceName

    Thanks

    your error message say that you run list services not mdsmodeldeploy listservices, so please double check your commands

    for debug purpose you can try run needed commands locally and then correct one place into your xml


    The opinion expressed by me is not an official position of Microsoft

    Friday, July 24, 2020 5:52 PM
  • I gave that command as an example. I had used the right command only
    Friday, July 24, 2020 5:55 PM
  • I gave that command as an example. I had used the right command only

    ok, next time if you will provide correct issue you will get correct recommendation.

    check that on your remote machine that mdsmodeldeploy util exists and working as expected

    mb you need something like & .\mdsmodeldeploy.exe listservices or something like that


    The opinion expressed by me is not an official position of Microsoft

    Friday, July 24, 2020 6:03 PM