Powershell: Function Prompt In Ps1 Script - powershell

Want to pull off something similar to " set /p variable = x " from batch.
How can we make this happen in PS1?
Script example that im using
Function Prompt { 'PS' + $x + '>' }

The equivalent to set /p in PowerShell would be Read-Host:
$value = Read-Host "Give me some input"
The host application (eg. powershell.exe) will now prompt the user for input with the caption Give me some input:, and the result will be stored in $value

Related

How to pass powershell hashtable from one script to another script in Jenkins Pipeline

In the local system I am able to execute powershell script by passing hashtable but the same is not working in Jenkins pipeline . I tried in Multiple ways but none of them working. Could you please help me on this.
I need solutions for couple of things
How can I pass a powershell hashtable to a groovy command
If above can't work how can I execute powershell script from powershell script block
stage('Passing Hashtable Test')
{
steps{
script{
powershell '''
write-host "hello Passing Hashtable "
$dict = #{
"firstKey" = "abc";
"User" = "Robot"
}
Write-host "Keys are present here : " + $dict.Keys
$env:WORKSPACE\PassingDictonary.ps1 -param1 "ThisIsStringValuePassed" -myHashTable $dict
'''
echo "priting outside script1 $dict" //how to get Powershell $dict variable here ?
//Atleast If I can send hashtable to ps1 file then its good . I tried this but not working
//OR At least If I can get Powershell variable outside of the block .. so that I would like to use a bat command by using -file parameter but I am not able to get value here.
}
}
}
This is my PassingDictionary.ps1 file code (this is working locally)
param (
[string]$param1 = "something",
[hashtable]$myHashTable
)
Write-host "Param1 value is : " + $param1
write-host "length of my Passed Hashtable is :" + $myHashTable.Count
foreach($k in $myHashTable.Keys)
{
Write-Host "Prining myHashTable Key is : => " + $k
Write-Host "Prining myHashTable Value is : => " + $myHashTable[$k]
}
At last I am able to execute powershell script from powershell block in Jenkins pipeline like below (this gives solution for my 2nd problem which mentioned above )
script {
powershell '''
PowerShell(. '.\\PassingDictonary.ps1' -param1 "ThisIsStringValuePassed"
-myHashTable $dict)
'''
}

Change currently running script

Is there any way to add text to specific part of script to the currently running script?
If i have a menu with options:
Install All
Add item
Quit
Could the Add item be possible?
Learning to use powershell (heavy user of batches).
When entering Add item, then a read-host would pop up, adding a row between the long row of ### addwifi -wnm $USERINPUT afterwards 'restarting' the script.
Current script:
#cmd: title Add****
$host.ui.RawUI.WindowTitle = "Add Wi-Fi networks"
#When Show-Menu –Title 'SetupWi-Fi' is called
function Show-Menu
{
# NOTE if changing warible from somewhere else (Show-Menu -WARIBLE VALUE) then param part must be included
param (
[string]$Title = 'SetupWi-Fi'
)
Clear-Host
#cls and echo on #echo off
Write-Host "================ $Title ================"
Write-Host "a: Add Wi-Fi networks."
Write-Host "q: Quit."
}
#Do this until x
#For future shortening purposes
function addwifi
{
param (
[string]$wnm
#wnm= wifi name
)
netsh wlan add profile filename="$wnm.xml"
#for some reason (nice for this script) . stops the warible name
}
do
{
# call Show-Menu and optionally change varible: –Title 'Warible' changes the $title varible
Show-Menu
# makin varible chaase equal user input, placing Selection before it
$chaase = Read-Host "Selection:"
#switch according to the varible chaase
switch ($chaase)
{
'a' {
#'single quote' acts as echo, now executing commands of 'a' varible
'Adding Wi-Fi networks.'
$host.ui.RawUI.WindowTitle = "Adding Wi-Fi networks"
#note the upper function is called with warible
#add below here! #####################################################################
addwifi -wnm laptopidee
#add above here! #####################################################################
}
#close a execution
#close switch
}
#close do
}
#until x: selection == input q
until ($chaase -eq 'q')
One possibility is to use placeholders that you replace at runtime, though I'm not sure how well it will hold up for more complex scripts.
For example, if you have the following script:
$scriptPath = "$PsScriptRoot\$($MyInvocation.MyCommand.Name)"
$scriptContent = Get-Content "$PsScriptRoot\$($MyInvocation.MyCommand.Name)" -Raw
$newItem = Read-Host "Please enter new command"
##Placeholder
$scriptContent -replace "$([char]0x0023)$([char]0x0023)Placeholder", "$([char]0x0023)$([char]0x0023)Placeholder$([char]0x000D)$([char]0x000A)$newItem" |
Set-Content -Path $scriptPath
Each time you run it, you will be prompted for a new command, which will be added below the ##Placeholder. So, if you enter Get-Process when prompted, the script would end up on-disk like this:
$scriptPath = "$PsScriptRoot\$($MyInvocation.MyCommand.Name)"
$scriptContent = Get-Content "$PsScriptRoot\$($MyInvocation.MyCommand.Name)" -Raw
$newItem = Read-Host "Please enter new command"
##Placeholder
Get-Process
$scriptContent -replace "$([char]0x0023)$([char]0x0023)Placeholder", "$([char]0x0023)$([char]0x0023)Placeholder$([char]0x000D)$([char]0x000A)$newItem" |
Set-Content -Path $scriptPath
Next time you run the script you will be prompted for a new command, which is added to the list, and all commands already on the list will be executed.
Yes. Use external files as sources to be pulled in. The Add Item menu option creates another file to be read in at next execution.
Many people did this with batch files using .ini files to hold parameters. Similar construct.

Pass arguments from one powershell script to another

I have one powershell script, like this one:
$ErrorActionPreference = "Stop"
$WORKDIR=$args[0]
Write-Host "Num of arguments given: " $args.Count
$AllArguments = ""
for ($i = 1; $i -lt $args.Count; $i += 2) {
$AllArguments = '$AllArguments $args[$i] "$($args[$i+1])"'
}
Write-Host "AllArguments: $($AllArguments)"
Write-Host "Starting .\someotherscript.ps1 in directory $($WORKDIR)"
pushd "$WORKDIR"
& Powershell -File .\someotherscript.ps1 $AllArguments
popd
Basically, this powershell script shoud start another powershell script, but without the first argument. So, e.g. when this script is started with .\firstscript.ps1 C:\some\dir -GiveMeParameter param1, then it should call the other script with the following parameters .\someotherscript.ps1 -GivMeParameter param1.
How to achieve that? At the moment I do not know how to solve this problem.
You can use multiple assignment to extract the first and remaining arguments by doing
$WORKDIR, $RemainingArgs = $args
I'm not sure why you're calling PowerShell again to run the script. You can just run the script directly and use splatting to pass the remaining args to the child script.
.\someotherscript.ps1 #RemainingArgs

Executing Powershell script from command line with quoted parameters

I am automating the build of a legacy MS Access application, and in one of the steps, I am trying to make an Access executable (.ADE). I have come up with the following code, which is stored in a file (PSLibrary.ps1):
Add-Type -AssemblyName Microsoft.Office.Interop.Access
function Access-Compile {
param (
[Parameter(Mandatory=$TRUE,Position=1)][string]$source,
[Parameter(Mandatory=$TRUE,Position=2)][string]$destination
)
Write-Output "Starting MS Access"
$access = New-Object -ComObject Access.Application
$access.Visible = $FALSE
$access.AutomationSecurity = 1
if (!(Test-Path $source)) { Throw "Source '$source' not found" }
if ((Test-Path $destination)) {
Write-Output "File '$destination' already exists - deleting..."
Remove-Item $destination
}
Write-Output "Compiling '$source' to '$destination'"
$result = $access.SysCmd(603, $source, $destination)
$result
Write-Output "Exiting MS Access"
$access.quit()
}
If I go into the PowerShell ISE and run the command below, then everything works fine, and the expected output is created:
PS C:>& "C:\Temp\PSLibrary.ps1"
PS C:>Access-Compile "C:\Working\Project.adp" "C:\Working\Project.ade"
However, I can't seem to generate the right hocus-pocus to get this running from the command line, as I would in an automated build. For instance,
powershell.exe -command "& \"C:\\Temp\\PSLibrary.ps1\" Access-Compile \"C:\\Temp\\Project.adp\" \"C:\\Temp\\Project.ade\""
What am I doing wrong?
For complex parameters, you can use Powershell's -EncodedCommand parameter. It will accept a Base64 encoded string. No escaping is needed for quotes, slashes and such.
Consider a test function that will print its parameters. Like so,
function Test-Function {
param (
[Parameter(Mandatory=$TRUE,Position=1)][string]$source,
[Parameter(Mandatory=$TRUE,Position=2)][string]$destination
)
write-host "src: $source"
write-host "dst: $destination"
}
Create command to load the script and some parameters. Like so,
# Load the script and call function with some parameters
. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
After the command syntax is OK, encode it into Base64 form. Like so,
[System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes('. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""'))
You'll get a Base64 string. Like so,
LgAgAEMAOgBcAFQAZQBtAHAAXABDAGEAbABsAGkAbgBnAC0AVABlAHMAdAAuAHAAcwAxADsAIAAgAFQAZQBzAHQALQBGAHUAbgBjAHQAaQBvAG4AIAAiAHMAbwBtAGUAXABzAHAAZQBjAGkAYQBsADoAYwBoAGEAcgBhAGMAdABlAHIAcwA/ACIAIAAiAGAAIgBjADoAXABtAHkAIABwAGEAdABoAFwAdwBpAHQAaABcAHMAcABhAGMAZQBzACAAdwBpAHQAaABpAG4ALgBlAHgAdABgACIAIgA=
Finally, start Powershell and pass the encoded string as a parameter. Like so,
# The parameter string here is abreviated for readability purposes.
# Don't do this in production
C:\>powershell -encodedcommand LgAgA...
Output
src: some\special:characters?
dst: "c:\my path\with\spaces within.ext"
Should you later want to reverse the Base64 encoding, pass it into decoding method. Like so,
$str = " LgAgA..."
[Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($str))
# Output
. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
PowerShell like Bash can take single or double quotes
PS C:\Users\Steven> echo "hello"
hello
PS C:\Users\Steven> echo 'hello'
hello
this can alleviate some of the headache, also I think you can use the literal backslashes without escaping.
To run PowerShell, choose
Start Menu Programs Accessories
Windows Powershell Windows Powershell

Strange order of variables written from Write-Host within function

With my following code seems Write-Host puts out variables in a strange way (for me coming from C# at least).
Code is here
function Run(
[string] $command,
[string] $args
)
{
Write-Host 'from function - command is:' $command '.args is: ' $args
}
$cmd = "ping"
$args = "208.67.222.222"
Write-Host 'from main - command is:' $cmd '.args is: ' $args
Run("ping","208.67.222.222")
Output is here
from main - command is: ping .args is: 208.67.222.222
from function - command is: ping 208.67.222.222 .args is:
How come Write-Host from main works as I expect, but within the function it outputs all variables at the same time? How can I correct this behaviour?
$args in the function is an automatic variable. It is an array that contains all the arguments passed to the function.
Use something besides $args for your IP address variable.