Issue with Start-ThreadJob ScriptBlock Unable to find powershell script - multithreading

I am using Start-ThreadJob and ScriptBlock to execute a powershell script in a new thread. It works fine on my local but on the preprod server, I am getting an error.
Code Block where I am initiating a new thread
Start-ThreadJob -InputObject $fileType -ScriptBlock {
./Functions/Download-FilesFromFTP.ps1 $args[0] $args[1] $args[2] $args[3] $args[4] $args[5]
} -ArgumentList $ftpServer,$user,$password,$completeSourceFolder,$completeStagingFolderPath,$completeLogFolderPath
As mentioned earlier, this code block works perfectly on my local. On Preprod env I get the following error when I display jobs using Get-Jobs command.
Powershell version on my local
Powershell version on preprod server
The version of the module ThreadJob is same on both servers

Start-ThreadJob runs the new thread with the same current location as the caller, which is unrelated to where the executing script is located.
If you want to refer to a file relative to the script's own location, use the automatic $PSScriptRoot variable, and refer to it in the thread script block via the $using: scope:
Start-ThreadJob -InputObject $fileType -ScriptBlock {
& "$using:PSScriptRoot/Functions/Download-FilesFromFTP.ps1" #args
} -ArgumentList $ftpServer,$user,$password,$completeSourceFolder,$completeStagingFolderPath,$completeLogFolderPath
Note the use of #args in order to also pass all positional arguments, reflected in the automatic $args array, through as individual arguments to the target script via splatting.

Related

Cross talk threads to allow for file system access in powershell

Reference: Runspace for button event in powershell
https://www.foxdeploy.com/blog/part-v-powershell-guis-responsive-apps-with-progress-bars.html
So, I believe my issue is that PowerShell is unable to access the memory space of the file system, from within the memory block, of my thread, is there a way to solve this, to access the file system, from a multi-threaded application?
Back Story:
So, I run a program, that calls upon "code"/command, from the command prompt, (*.exe) (Robocopy) to copy files from a server, to a group of computers, at a time. We have a classroom environment, at my work, so I have my setup, in a way, that I have a folder, per room. I keep a list of all our addresses (static), for each room, in their perspective folders. We have an update, from our developers, that we need to push to all of the rooms. We need to run a slow push, as to not disturb the production environment. It's proprietary, so we can't use a/any typical solution(s), like Microsoft SCCM. So, I created a script to push to the rooms. while it does work, it's not a smooth operation. I'm not actually the one pushing the update, because of the slow process, of updating. I'm just trying to make a stable smooth-running package, for the person, who is going to be doing it. My code works, outside of the thread, (I) tested it, I know it works.
So how I came my conclusion of knowing, that my code works outside of the thread. (The picture) I followed the same setup, with my code, (A button click event inside of a thread, running the form). Placed the actual working code, (tried, and tested, before making a Thread, for the interface, after completing backend operation code testing.)
("Region Boe's Addition") referring to Boe Prox, (from the link)
In his, he is updating from a command line/powershell window, via a function run inside a thread. I'm running an event from a button, inside of a thread and trying to run a separate thread, for the click event(s). Outside of the thread. The event works fine, but inside, it doesn't work, at all..
Basic Code:
// Multi thread, thread for the $form, and thread for the event (as per referenced link)
$var = [PowerShell]::Create().AddScript({ button.Add_Click{
$var = [PowerShell]::Create().AddScript{<Thread><Robocopy></Thread>}
})
Needed the "Start-Process" -Wait command to allow for the listbox, to be updated in-between copies, to confirm installation, through each step in the loop.
$choice = $comboBox.SelectedItem
# $drive = Get-Location
if(!(Test-Path -PathType Container -Path "L:\$choice"))
{
# New-Item -ItemType "container" -Path . -Name $choice
New-Item -ItemType "Directory" -Path . -Name $choice
}
# $folder = $_
# Where is it being stored at?
[System.IO.File]::ReadLines("Y:\$choice\IPs.txt") | foreach {
ping -a -n 2 -w 2000 $_ | Out-Null
Test-Connection -Count 2 -TimeToLive 2 $_ | Out-Null
if($?)
{
RoboCopy /Log:"L:\$folder\$_.log" $source \\$_\c$\tools
RoboCopy /Log+:"L:\$folder\$folder-MovementLogs.log" $source \\$_\c$\tools
Start-Process -Wait "P:\psexec.exe" -ArgumentList "\\$_ -d -e -h -s cmd /c reg import C:\tools\dump.reg"
# Copy-Item -LiteralPath Y:\* -Destination \\$_\c$\tools
$listBox.Items.Add($_)
}
}

Azure Pipeline Extract Task 7zip

Unable to extract zip to destination with default usage of Extract Task its fails with error:
##[error]Unable to locate executable file: 'C:\azagent\A5\_work\_tasks\ExtractFiles_5e1e3830-fbfb-11e5-aab1-090c92bc4988\1.200.0\7zip\7z.exe'. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.
Stating its fails to locate default 7zip path. Tried to use custom PATH setting but also fails with the same error.
UPDATE
Issue seem to be caused by permissions of agent. Still haven't been able to execute Release with Admin privileges in service mode. When run in interactive mode as Admin the release executes successfully.
Task fails whenever admin permission is required.
From the error message, 7zip seems not installed on your self-hosted agent. Try to install the 7zip before you use the Extract Task.
Take Bash Task as an example:
brew install p7zip
For Windows, use the below PowerShell script to install:
$dlurl = 'https://7-zip.org/' + (Invoke-WebRequest -UseBasicParsing -Uri 'https://7-zip.org/' | Select-Object -ExpandProperty Links | Where-Object {($_.outerHTML -match 'Download')-and ($_.href -like "a/*") -and ($_.href -like "*-x64.exe")} | Select-Object -First 1 | Select-Object -ExpandProperty href)
# modified to work without IE
# above code from: https://perplexity.nl/windows-powershell/installing-or-updating-7-zip-using-powershell/
$installerPath = Join-Path $env:TEMP (Split-Path $dlurl -Leaf)
Invoke-WebRequest $dlurl -OutFile $installerPath
Start-Process -FilePath $installerPath -Args "/S" -Verb RunAs -Wait
Remove-Item $installerPath

Passing parameter to script from Invoke-AzVMRunCommand

I trying to execute the Invoke-AzVMRunCommand to execute a PS function that accept parameters. The code below shows call to the Invoke-AzVMRunCommand
$runcmdparameters=#{
"VolumeLable"="sdsd";
"azurelun"="1,3,4"
}
Invoke-AzVMRunCommand -ResourceGroupName $ServerResourceGroupName -VMName $VMVame -ScriptPath "c:\Configurestorage.ps1" -CommandId 'RunPowerShellScript' -Parameter $runcmdparameters -Verbose
The PS Script that I need to execute on the server is
function Configure-Storage
{
Param(
[parameter(Mandatory=$true)][String]$VolumeLable,
[parameter(Mandatory=$true)][String[]]$azurelun
)
#create a storage pool for user databases.
Out-File "C:\Temp\log.txt" -InputObject $VolumeLable -Append
}
Configure-Storage -VolumeLable $VolumeLable -azurelun $azurelun
The script fail with Cannot bind argument to parameter 'VolumeLable'
because it is an empty string.
Microsoft documentation on Invoke-AzVMRunCommand is not very helpful.
How can I pass the parameter to the script?
I think you need to do this:
Param(
[parameter(Mandatory=$true)][String]$VolumeLable,
[parameter(Mandatory=$true)][String[]]$azurelun
)
#create a storage pool for user databases.
Out-File "C:\Temp\log.txt" -InputObject $VolumeLable -Append
Because what happens now: your script doesnt really accept parameters, you function does, but you are calling the script, not the function. and then you call the function inside the script. another way of fixing this - add parameters to the script itself

How to hide console output from Select-AzureRmSubscription

Does anyone know how to hide output from command Select-AzureRmSubscription inside azure workbook which runs as powershell workflow
Thanks
You can use Out-Null. Works for any PowerShell cmdlet.
Select-AzureRmSubscription | Out-null
The Out-Null cmdlet sends its output to NULL, in effect, removing it
from the pipeline and preventing the output to be displayed at the
screen.
https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/out-null
Select-AzSubscription -SubscriptionId $s.Id | Out-Null + ~~~~~~~~ Cannot call the 'Out-Null' command. Other commands from this module have been packaged as workflow activities, but this command was specifically excluded. This is likely because the command requires an interactive Windows PowerShell session, or has behavior not suited for workflows. To run this command anyway, place it within an inline-script (InlineScript { Out-Null }) where it will be invoked in isolation

PowerShell Start-Process loses precision on number passed as a string to a function

I have some code that edits the registry, so it needs to run as admin. To do this, I start up a new PowerShell process from my running PowerShell script, and pass in part of the registry key path, which happens to be a version number, e.g. "12.0". The function in the new PowerShell process receives the string as "12" though, not "12.0", and so I'm getting errors that it can't find the registry key.
I've created a little sample powershell script that reproduces the problem. Here's the snippet:
$ScriptBlock = {
function Test([string]$VisualStudioVersion)
{
$VisualStudioVersion # This always displays 12, instead of 12.0
$Host.UI.RawUI.ReadKey()
}
}
# Run the script block's function.
Start-Process -FilePath PowerShell -ArgumentList "-Command & {$ScriptBlock Test(""12.0"")}"
Here I've hardcoded "12.0", but in practice I want to pass in a variable.
Any ideas on what I'm doing wrong? Thanks in advance.
Ok, after some experimenting the following seems to work correctly:
Start-Process -FilePath PowerShell -ArgumentList "-Command & {$ScriptBlock Test('12.0')}"
and it even works when using a variable:
$version = "12.0"
Start-Process -FilePath PowerShell -ArgumentList "-Command & {$ScriptBlock Test('$version')}"
I'm still not sure why using double quotes causes it to lose the precision and single quotes keeps it, but at least I solved my problem.
Update
So it turns out I'm a dummy and the problem was that I was using C# syntax of Test(""$version"") to call the function, instead of the proper PowerShell syntax Test ""version"". With this change it now works as expected.

Resources