Powershell and jenkins foreach loops - powershell

I have a function in Powershell and want to run this on many servers.
It's running from Jenkins via a Powershell step, the input param $env:servers is configured as a "Muli-line String".
Simple example:
function test {
param(
[string]$servername
)
#do somthing
}
$servers = $env:servers
foreach ($s in $servers) {
test -servername $s
}
But when I build it with parametrs, the foreach does not work - it treats $servers like a single string. What's wrong?

As your input param ($env:servers) is a multi-line string, $servers will also be a single multi-line string.
To use this with foreach it needs to be an array of strings, you will need to split $env:servers so $servers becomes an array of strings with each line an item. This is very simple to do using Split() (blog on this subject):
$servers = ($env:servers).Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries)
This will split on NewLine and deal with any blank lines by removing an empty entries from the final output.
Example code to show this behaviour for future reference to others:
$input_servers = #"
server1
server2
server3
"#
$servers = $input_servers.Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries)
foreach ($server in $servers) {
Write-Output "Server Name: $server"
}

Related

Convert comma seperated string from ARG into array in PowerShell

Is it possible to take an arg like "this, is, a, test" and create an array in powershell?
Something like
./myScript.ps1 -myStringArray 'this, is, a, test'
And in the code something like:
param (
[string[]] $myStringArray = #()
)
foreach($item in $myStringArray) {
Write-Host $item
}
I have tried a few way but they aren't very clean and either create a sentence with or without the commas but no new line per item.
How difficult would it be to support both:
'this, is, a, test'
And
'this,is,a,test'?
You could use the -split operator with a simple regex to archive that:
param (
[string[]] $myStringArray = #()
)
$myStringArray -split ',\s?' | ForEach-Object {
Write-Host $_
}

Foreach loop not running through list of entries

I've tried searching this multiple times but havent resolved the issue. I have a list of servers in $mediaagentlist, the foreach loop is supposed to run through each one and get the state of certain services:
$mediaagentlist = "cs0400ma01
cs0400ma02"
[string]$Commcell_Input = $args[0]
$MAChoice = $args[1]
if ($MAChoice -eq $null)
{
Write-Output "No media agent was specified, running against all MAs in the Commcell..."
#Run this loop for each MA which is stored in Mediaagentlist
foreach ($Mediaagent in $Mediaagentlist)
{
Write-Output $Mediaagent
$GxCLMgrS_State = Invoke-Command -ComputerName $Mediaagent {Get-Service -name "GxClMgrS(Instance001)"}
$GXMMM_State = Invoke-Command -ComputerName $Mediaagent {Get-Service -name "GXMMM(Instance001)"}
$GxCVD_State = Invoke-Command -ComputerName $Mediaagent {Get-Service -name "GxCVD(Instance001)"}
Write-Output "Client manager service state: " $GxCLMgrS_State.Status
Write-Output "Media manager mount service state: " $GXMMM_State.Status
Write-Output "Communications service state: " $GxCVD_State.Status
}
}
How do I correct this so the for each loop runs through the list of entries in $mediaagentlist and runs the code for each server?
Thanks in advance!
It looks like your issue is here
$mediaagentlist = "cs0400ma01
cs0400ma02"
It looks like your missing a closing qoute per word and a comma
try
$mediaagentlist = "cs0400ma01", "cs0400ma02"
or
$mediaagentlist = #("cs0400ma01", "cs0400ma02")
Or you can define a multi-line string, then split on new lines, if there's a reason you needed the input to be a single multi-line string:
$mediaagentlist = "cs0400ma01
cs0400ma02" -split '[\r\n]+'

Powershell script foreach ($x in $y) not working correctly

Just writing some basic scripts after avoiding PowerShell for too long and I'm getting kinda stuck here. Trying to pass multiple parameters to a single "argument" in a function but it will only ever return the first value in the string
#--------------------------------
# Returns logged on user of machine(s) given in parameter
#--------------------------------
function Get-UserLogged{
param($computerName)
foreach ($computer in $computerName) {
return (query user /server:$computerName)
}
}
Now if i call the function and run for example...
Get-UserLogged Server01 Server02 Server03
It will only return the output for server 1, so it seems that the foreach isn't working as expected
Different script same issue:
function p{
param($computerName)
foreach ($computer in $computerName) {
return (test-connection $computer -Count 1)
}
}
if I run:
p localhost, google.com, bbc.com
it will only attempt localhost
You're referencing the array $computerName inside the loop, not the "current item", $computer.
function Get-UserLogged{
param($computerName)
foreach ($computer in $computerName) {
query user /server:$computer
}
}
To pass an array of strings to a parameter, use a comma to separate the items:
Get-UserLogged -computerName Server01, Server02, Server03

Data Structure issues powershell

My end goal is to be able to enter several strings, then reference them in other commands, in this case, mapping a network drive.
I'm having issues with the 'several' part of that. I can work with one at a time, but when I try to do more it fails.
$Servers = #{"Server1" = "10.10.10.10";"Server2" = "10.10.10.11"}
$Sites = Read-Host "enter site codes"
$Sites.Split('.')
ForEach ($Site In Sites){
write-host $Servers[$Sites]
}
This in theory should output 10.10.10.10 and 10.10.10.11 on two lines, but it doesn't. It just outputs the value of $Sites, Server1,Server2
I don't know what I'm doing wrong.
I believe your mistake(s) is using $Sites (instead of $Site) as the key in your foreach loop, and not getting your split array into the foreach collection:
$Servers = #{"Server1" = "10.10.10.10";"Server2" = "10.10.10.11"}
$Sites = Read-Host "enter site codes"
ForEach ($Site In $Sites.Split(',')){
write-host $Servers[$Site]
}

Powershell: pass in multiline txt file values as an array in param statement

I have a text file containing a list of servers, one per line, like:
SERVER1
SERVER2
SERVER3
When I do a Get-Content on the file, I do see the output as:
SERVER1
SERVER2
SERVER3
So now I am writing a function that I want to take in the multiple servers as an array, and iterate over the array in the function. The function is currently like this:
function Get-LocalAdministrators
{
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[string[]]$computers
)
foreach ($computername in $computers)
{
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS)
{
$admin = $admin.replace("\\$computername\root\cimv2:Win32_UserAccount.Domain=","") # trims the results for a user
$admin = $admin.replace("\\$computername\root\cimv2:Win32_Group.Domain=","") # trims the results for a group
$admin = $admin.replace('",Name="',"\")
$admin = $admin.REPLACE("""","") # strips the last "
$objOutput = New-Object PSObject -Property #{
Machinename = $($computername)
Fullname = ($admin)
#DomainName =$admin.split("\")[0]
#UserName = $admin.split("\")[1]
}
$objReport+=#($objOutput)
}
return $objReport
}
}
Then I plan to call the function as:
Get-Content “C:\temp\computers.txt” | Get-LocalAdministrators
However, when I run the function, I can see that the value of $computers is {SERVER3} (i.e. only the last line in the file.) I have tried to find the answer to this via teh Google, and although there are a lot of array references/examples, I cannot find one where it combines reading the values from a file, into an array in a param statement. Please forgive my PS newb ignorance, and provide the clue that I need... Thanks.
UPDATE: Link to screenshot of script running in PowerGUI Script Editor showing the value of $computers during the run: debug run screenshot
When you pass objects via the pipeline into a function, only one is passed into your function at a time - not the whole array. So you don't need the foreach loop, nor do you need to make $computers an array in the function.
Also, when you have a pipeline function, you should be making use of the begin,process and end keywords. Each denotes a script block - begin is a scriptblock that is executed once (when the pipeline is "set up"), process is the scriptblock to be executed for each object passed via the pipeline, and end is just like begin only it runs after the last item has passed through.
So minimally, your function should be this:
function Get-LocalAdministrators
{
param(
[Parameter(Mandatory=$True,Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[string]$computer
)
process{
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
# Do other stuff here
}
}
The MSDN documentation says (this is in get-help about_functions - there's more to it than this):
Piping Objects to Functions
Any function can take input from the pipeline. You can control how a
function processes input from the pipeline using Begin, Process, and End
keywords. The following sample syntax shows the three keywords:
function <name> {
begin {<statement list>}
process {<statement list>}
end {<statement list>}
}
The Begin statement list runs one time only, at the beginning of
the function.
The Process statement list runs one time for each object in the pipeline.
While the Process block is running, each pipeline object is assigned to
the $_ automatic variable, one pipeline object at a time.
After the function receives all the objects in the pipeline, the End
statement list runs one time. If no Begin, Process, or End keywords are
used, all the statements are treated like an End statement list.
Edit: After seeing the full code added by the OP, this works. Note that I have made the changes to your code as I describe above.
function Get-LocalAdministrators
{
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[string]$computer
)
process{
$ADMINS = get-wmiobject -computername $computer -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computer',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS)
{
$admin = $admin.replace("\\$computername\root\cimv2:Win32_UserAccount.Domain=","") # trims the results for a user
$admin = $admin.replace("\\$computername\root\cimv2:Win32_Group.Domain=","") # trims the results for a group
$admin = $admin.replace('",Name="',"\")
$admin = $admin.REPLACE("""","") # strips the last "
$objOutput = New-Object PSObject -Property #{
Machinename = $($computer)
Fullname = ($admin)
#DomainName =$admin.split("\")[0]
#UserName = $admin.split("\")[1]
}
$objReport+=#($objOutput)
}
$objReport
}
}