I am getting below error while installing the packages in Sitecore through Powershell.
We had a similar question reported on the community https://community.sitecore.net/developers/f/7/t/1173
The issue is that the web service we built encounters a timeout with the long running process of the installation wizard. We provide a solution in which you can create a background ScriptSession job that you can later retrieve.
In our gitbook we provide this example.
Import-Module -Name SPE
$session = New-ScriptSession -Username admin -Password b -ConnectionUri http://remotesitecore
$job = Invoke-RemoteScript -Session $session -ScriptBlock {
Start-ScriptSession -ScriptBlock {
# Replace the contents of this scriptblock with your installation steps.
# I just put $true there so something would come back.
Start-Sleep -Seconds 10
[PSCustomObject]#{"IsComplete"=$true}
}
}
$keepRunning = $true
while($keepRunning) {
$done = Invoke-RemoteScript -Session $session -ScriptBlock {
$scriptSession = Get-ScriptSession -Id $params.JobId
$scriptSession.State -ne "Busy"
} -Arguments #{"JobId" = $job.ID}
if($done) {
$keepRunning = $false
Invoke-RemoteScript -Session $session -ScriptBlock {
$scriptSession = Get-ScriptSession -Id $params.JobId
if($scriptSession.State -ne "Busy") {
$scriptSession | Receive-ScriptSession
}
} -Arguments #{"JobId" = $job.ID}
} else {
Start-Sleep -Milliseconds 500
}
}
Expect to see updates to the book for simplified a usage with the release of SPE 4.
This is sample code
Import-Module -Name "C:\Scripts_31DEC\SPE Remoting-3.3\SPE"
$session = New-ScriptSession -Username admin -Password b -ConnectionUri http://quuintranet
$job = Invoke-RemoteScript -Session $session -ScriptBlock {
Start-ScriptSession -ScriptBlock {
# Replace the contents of this scriptblock with your installation steps.
# I just put $true there so something would come back.
Install-Package -Path "C:\Scripts_31DEC\quutest_ow.zip" -InstallMode Overwrite
[PSCustomObject]#{"IsComplete"=$true}
}
}
$keepRunning = $true
while($keepRunning) {
$done = Invoke-RemoteScript -Session $session -ScriptBlock {
$scriptSession = Get-ScriptSession -Id $params.JobId
$scriptSession.State -ne "Busy"
} -Arguments #{"JobId" = $job.ID}
if($done) {
$keepRunning = $false
Invoke-RemoteScript -Session $session -ScriptBlock {
$scriptSession = Get-ScriptSession -Id $params.JobId
if($scriptSession.State -ne "Busy") {
$scriptSession | Receive-ScriptSession
}
} -Arguments #{"JobId" = $job.ID}
} else {
Start-Sleep -Milliseconds 500
}
}
Related
I have written a script which works fine on the local server. However I would like to run the script block on a remote server. Here's the script block that's that runs fine locally. Can I use Invoke-Command to embed the below script block and run it on a remote server?
$Folder = Read-Host "Enter the folder name"
$FilePath = "E:\$Folder\capture.bat"
$Session = New-PSSession -ComputerName "qtestwest01"
Invoke-Command -Session $Session -ScriptBlock {$pt = New-Object System.Diagnostics.ProcessStartInfo;}
Invoke-Command -Session $Session -ScriptBlock {$pt.FileName = $using:FilePath;}
Invoke-Command -Session $Session -ScriptBlock {$pt.UseShellExecute = $false;}
Invoke-Command -Session $Session -ScriptBlock {$pt.RedurectStandardInput = $true;}
Invoke-Command -Session $Session -ScriptBlock {$e = [System.Diagnostics.Process]::Start($pt);}
Invoke-Command -Session $Session -ScriptBlock {$e.StandardInput.WriteLie("`n")}
Yes, it's pretty straight forward:
$Session = New-PSSession -ComputerName "qtestwest01"
$SB =
{
$pt = New-Object System.Diagnostics.ProcessStartInfo;
$pt.FileName = "E:\testscripts\capture.bat";
$pt.UseShellExecute = $false;
$pt.RedirectStandardInput = $true;
$e = [System.Diagnostics.Process]::Start($pt);
$e.StandardInput.WriteLine("`n")
}
Invoke-Command -Session $Session -ScriptBlock $SB
An aside: You may want to look at Start-Process -PassThru. Though I'm not sure you can set UseShellExecute using that pattern. There are some details about that here , but I didn't give it a thorough reading.
Update
Responding to your implementation and the parameter question, repeatedly calling Invoke-Command is unnecessary. You're calling into the same session so it's functionally the same thing, but everything you need is available so you can run a single command. The $Using: modifier can be used in a prefabricated ScriptBlock so long as the script block is used with certain cmdlets, including and maybe primarily Invoke-Command.
A new example:
$FilePath = "C:\windows\System32\notepad.exe"
$Session = New-PSSession -ComputerName "Server1"
$SB =
{
$pt = New-Object System.Diagnostics.ProcessStartInfo;
$pt.FileName = $Using:FilePath;
$pt.UseShellExecute = $false;
$pt.RedirectStandardInput = $true;
$e = [System.Diagnostics.Process]::Start($pt);
$e.StandardInput.WriteLine("`n")
}
Invoke-Command -Session $Session -ScriptBlock $SB
A second method of passing parameters into a script block is to use the Invoke-Command -ArgumentList parameter:
Example:
$FilePath = "C:\windows\System32\notepad.exe"
$Session = New-PSSession -ComputerName "Server1"
$SB =
{
$pt = New-Object System.Diagnostics.ProcessStartInfo;
$pt.FileName = $args[0] ;
$pt.UseShellExecute = $false;
$pt.RedirectStandardInput = $true;
$e = [System.Diagnostics.Process]::Start($pt);
$e.StandardInput.WriteLine("`n")
}
Invoke-Command -Session $Session -ScriptBlock $SB -ArgumentList $FilePath
And, Either approach, $Using or $args[0] will work even if cite the script block inline with the command:
Example:
$FilePath = "C:\windows\System32\notepad.exe"
$Session = New-PSSession -ComputerName "Server1"
Invoke-Command -Session $Session -ArgumentList $FilePath -ScriptBlock {
$pt = New-Object System.Diagnostics.ProcessStartInfo;
$pt.FileName = $args[0] ;
$pt.UseShellExecute = $false;
$pt.RedirectStandardInput = $true;
$e = [System.Diagnostics.Process]::Start($pt);
$e.StandardInput.WriteLine("`n")
}
Notes:
-ComputerName argument name and $FilePath value were changed in these examples just so I could test in my environment.
The use of $FilePath instead of $Folder. So far as I can tell $pt.FileName property needs a the full path. This was either mis-typed or in error in your last sample. $FilePath because of the -FilePath parameter on Start-Process.
$folder = 'testscripts'
$Session = New-PSSession -ComputerName "qtestwest01"
Invoke-Command -Session $Session -ScriptBlock {$pt = New-Object System.Diagnostics.ProcessStartInfo;}
Invoke-Command -Session $Session -ScriptBlock {$pt.FileName = $using:folder;}
Invoke-Command -Session $Session -ScriptBlock {$pt.UseShellExecute = $false;}
Invoke-Command -Session $Session -ScriptBlock {$pt.RedurectStandardInput = $true;}
Invoke-Command -Session $Session -ScriptBlock {$e = [System.Diagnostics.Process]::Start($pt);}
Invoke-Command -Session $Session -ScriptBlock {$e.StandardInput.WriteLie("`n")}
I wrote a script to restart a few ASP.NET websites on a remote server:
$computerName = #...
$password = #...
$secureStringPassword = ConvertTo-SecureString -AsPlainText -Force -String $password
$userName = #...
$credential= New-Object System.Management.Automation.PSCredential ($userName, $secureStringPassword)
$websiteNames = #..., #..., #...
Get-PSSession -ComputerName $computerName -Credential $credential | Remove-PSSession
$psSession = New-PSSession -ComputerName $computerName -Credential $credential
Invoke-Command -Session $psSession -ScriptBlock { $websiteNames | foreach{ Stop-Website -Name $_ } }
Invoke-Command -Session $psSession -ScriptBlock { $websiteNames | foreach{ Start-Website -Name $_ } }
$psSession | Remove-PSSession
For some reasons my Invoke-Command do not run properly, I have the following error message:
Cannot validate argument on parameter 'Name'. The argument is null. Provide a valid value for the argument, and then try running the command again.
When the commands are run after an Enter-PSSession it works fine within a -ScriptBlock it kinda mess up the -Name parameter, any idea how to fix that up?
The remote session cannot access the variables you have defined locally. They can be referenced with $using:variable
Invoke-Command -Session $psSession -ScriptBlock { $using:websiteNames | foreach{ Stop-Website -Name $_ } }
Invoke-Command -Session $psSession -ScriptBlock { $using:websiteNames | foreach{ Start-Website -Name $_ } }
More information in the about_remote_variables help:
get-help about_remote_variables -Full
Actually just needed to pass the arguments to the -ArgumentList of the -ScriptBlock and use $args to reference to it within the function block:
Invoke-Command -Session $psSession -ScriptBlock { $args | foreach{ Stop-Website -Name $_ } } -ArgumentList $websiteNames
Invoke-Command -Session $psSession -ScriptBlock { $args | foreach{ Start-Website -Name $_ } } -ArgumentList $websiteNames
Using invoke-parallel in Powershell, I'm trying to get a list of hosts where a certain command works vs. does not. How can I write to a global variable inside of invoke-parallel?
$creds = Get-Credential -UserName $username -Message 'Password?'
$servers = get-content .\hosts.txt
$success = #()
$failure = #()
Invoke-Parallel -InputObject $servers -throttle 20 -runspaceTimeout 30 -ImportVariables -ScriptBlock {
try
{
$result = Invoke-Command $_ -Credential $creds -Authentication "Negotiate" -ErrorAction Stop {hostname}
$success += $result
}
catch
{
$failure += $_
}
}
write-host $success
write-host $failure
Try this:
$Results = Invoke-Parallel -InputObject $servers -throttle 20 -runspaceTimeout 30 -ImportVariables -ScriptBlock {
try
{
$Output = Invoke-Command $_ -Credential $creds -Authentication "Negotiate" -ErrorAction Stop {hostname}
}
catch
{
$Output = $_
}
#($Output)
}
Final code sample for what I ended up using.
$username = "myuser"
$creds = Get-Credential -UserName $username -Message 'Password?'
$servers = get-content .\hosts.txt
$Results = Invoke-Parallel -InputObject $servers -throttle 20 -runspaceTimeout 30 -ImportVariables -ScriptBlock {
$arr = #{}
try
{
$Output = Invoke-Command $_ -Credential $creds -Authentication "Negotiate" {hostname} -ErrorAction Stop
$arr[$_] = "successful"
}
catch
{
$arr[$_] = "failed"
}
$arr
}
$Results
I am writing a PowerShell script for multithreading NUnit tests. My problem is that I take test categories from the file category.txt, and I have to write which categories have been done into my output file file 1.txt. I also need to output an XML report after all tests have been performed. How can I do this in NUnit?
$Groups=Get-Content d:\test\category.txt | Select-Object -Last 10
Write-Host $Groups
if ($Groups -ne $null)
{Write-Host "true"}
else
{write-host "false"}
###Multithreading###
$ThreadNumber =$Groups.Count
$ScriptBlock = {
function Nunit {
$Connection = #{"server" = ""; "username" = ""; "password" = ""}
write-verbose $Connection
$serv = $connection.Get_Item("server")
$user = $connection.Get_Item("username")
$pass = $connection.Get_Item("password")
$securePassword = ConvertTo-SecureString -AsPlainText $pass -Force
#Create connection credentials object for Invoke-Command
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $user, $securePassword
$Output = "C:\"
$scriptBlock = {
CMD.EXE /C "C:\testNunit\bin\nunit-console.exe /xml:c:\console-test.xml C:\testNunit\dll\Tests.dll /include:TestTypeSmoke> c:\1.txt"
}
Invoke-Command -ComputerName $serv -ScriptBlock $scriptBlock -credential $cred
}
Nunit
}
I will try to get back to you on NUnit after trying some things at my end, but as a suggestion you could also try PowerShell Workflow for Multi-Threading. They work like functions.
Workflow NUnit
{
Param
(
$server,
$username,
$password,
)
foreach -parallel -throttlelimit 2($group in $groups)
try{
//NUnit Code here
}
}
Catch
{
$_.Exception.Message
}
}
}
NUnit-server "" -username "" -password ""
I am trying to read strings in a remote registry. When I run the script I am working on, it connects to the workstation in the list, but it only reads the local computer when running, not the remote. any Ideas?
#create open dialog box
Function Get-FileName($initialDirectory)
{
[void] [Reflection.Assembly]::LoadWithPartialName( 'System.Windows.Forms' );
$d = New-Object Windows.Forms.OpenFileDialog;
$d.ShowHelp = $True;
$d.filter = "Comma Separated Value (*.csv)| *.csv";
$d.ShowDialog( ) | Out-Null;
$d.filename;
}
# Set Variables with arguments
$strFile = Get-FileName;
$strComputer = Get-Content $strFile;
$date = Get-Date -Format "MM-dd-yyyy";
$outputFile = "C:\PowerShell\Reports";
$cred = Get-Credential
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
..
..
}
The above code won't work. Enter-PSSession is not for using in a script. Anything written after that in a script won't run.
Instead, use Invoke-Command and pass rest of the script block as a parameter value. For example,
foreach ($computer in $strComputer) {
Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
}
As the comments already explained, Enter-PSSession is for interactive use. To read remote registry entries, there are several ways.
Use plain reg.exe, it works well enough. Like so,
foreach($computer in $strComputers) {
reg query \\$computer\hklm\software\Microsoft\Windows\CurrentVersion\Reliability /v LastComputerName
}
Use PSSessions. Create a session and Invoke-Command to read registry. Like so,
function GetRegistryValues {
param($rpath, $ivalue)
Set-Location $rpath
$systemInfo = (Get-ItemProperty .).$ivalue
Write-Host $systemInfo
}
$session = New-PSSession -ComputerName $computer
Invoke-Command -Session $session -Scriptblock ${function:GetRegistryValues} `
-argumentlist "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability",`
"LastComputerName"
Remove-PSSession $session
Use .Net classes, Microsoft.Win32.RegistryKey. Like so,
$sk = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $server)
$k = $sk.opensubkey("SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability", $false)
write-host $k.getvalue("LastComputerName")