SetEnvironmentVariable from integer held in a csv cell - powershell

I have a use case where i want to be able to write a port number to the system environment variable that matches the PC name that the script is being run on.
To do this i have a script that looks for the Computername in a 2 column csv file and writes the corresponding port number of the device to the system environment variable. The problem is that i am unable to get the script to add the port number to the environment variable.
If i put brackets around the $port in the last line. an entry is added but instead of the port number it adds the string $port.
If any one could provide some assistance i'd greatly appreciate it. Thanks in advance.
$COMPUTERNAME = "$env:COMPUTERNAME"
$data = import-csv "C:\PS stuff\Port assign.csv" | Where-Object
{$_."computer" -eq "$COMPUTERNAME"}
$data | Select -ExpandProperty "port" $port
[System.Environment]::SetEnvironmentVariable('TCP_PORT', "$port",
[System.EnvironmentVariableTarget]::User)

$port=Import-Csv -Path 'C:\PS stuff\Port assign.csv'| Where-Object {$_.computer -eq "$COMPUTERNAME"}|Select -ExpandProperty "port"

It seems that the variable $port wasn't being written to due to the way i had structured my code. It has now been changed to the following and all works as required. Thanks for all the assistance.
$COMPUTERNAME = "$env:COMPUTERNAME"
$data = import-csv "C:\PS stuff\Port assign.csv" | Where-Object
{$_."computer" -eq "$COMPUTERNAME"}
$port = $data | Select -ExpandProperty "port"
[System.Environment]::SetEnvironmentVariable('TCP_PORT', "$port",
[System.EnvironmentVariableTarget]::User)

Related

Powershell import-csv $variable properly is null

I have a weird issues with Powershell Version 2.0.
The following works on newer versions but its not working as expected on this version. Any help is appreciated.
$DB = Import-Csv -Path "$($path)\DBExtrat.csv"
which is fine.
Headers in DBExtrat.csv ('hostname','hostip','name','type')
all 4 headers are reorganized and show up if i run
$DB
But if I try
$DB.name or $DB.hostname it returns noting. I need to be able to call it like this because my whole logic is tied to those specific variables names.
I've already tried adding the -header option:
$DB = Import-Csv -Path "$($path)\DBExtrat.csv" -Header 'hostname','hostip','name','type'
but it doesn't work and also creates unnecessary extra row with header data.
With an expression such as $DB.name, you're trying to get the name property values of all elements of collection $DB, by performing the property access on the collection as a whole.
This feature is called member-access enumeration, and it is only available in PowerShell v3+.
The PowerShell v2 equivalent requires use of either Select-Object or ForEach-Object:
# Note the use of -ExpandProperty to ensure that only the property *value*
# is returned (without it, you get a *custom object* with a 'name' property).
$DB | Select-Object -ExpandProperty name
# Slower alternative, but can provide more flexibility
$DB | ForEach-Object { $_.name }
I'd recommend going with #mklement0 answer; short and simple. Alternatively, going off the question you asked in the comments, you may try working with a custom object and seeing if the below works.
$import = Import-Csv -Path "$($path)\DBExtrat.csv"
$Object = New-Object psobject -Property #{
'hostname' = $import | Select-Object -ExpandProperty hostname
'hostip' = $import | Select-Object -ExpandProperty hostip
'name' = $import | Select-Object -ExpandProperty name
'type' = $import | Select-Object -ExpandProperty type
}
"$Object.hostname - $Object.hostip"

powershell how do I Create/format a dynamic list from a group membership to use in a for each loop

bit of a noob question.
I have the following cmd which grabs the server members of a group which I can copy into a text list. however as the group changes I need to modify the text list manually.
Get-AdGroupMember -identity "Reboot 7pm" | Sort-Object | select name
when I have that output in a text list, the following works fine.
$listpath = "C:\Scripts\servers.txt"
[System.Collections.ArrayList]$list = #(Get-content $listpath)
foreach($ComputerName in $list)
{
Get-Uptime -ComputerName $ComputerName
I want to know if it is possible to use a variable that I can use again in a for each loop. I've tried to do so, however the format of the list is not the same when is goes into a variable, thus the function (get-uptime) against the server doesn't work, anyone know what I can do to format the output so I only get the server name?
EG.
$WSUS_7PM = Get-AdGroupMember -identity "Reboot 7pm" | Sort-Object | select name
PS C:\Windows\system32> $WSUS_7PM
name
----
AXXXXX003
BXXXXX005
CXXXXX006
DXXXXX007
PS C:\Windows\system32> foreach($Name in $WSUS_7PM) {Write-Host $Name}
#{name=AXXXXX003}
#{name=BXXXXX005}
#{name=CXXXXX006}
#{name=DXXXXX007}
so when I run the same cmds as above modified with the variable instead of the text list, I get the following as the server name is obviously incorrect.
$listpath = $WSUS_7PM
[System.Collections.ArrayList]$list = #(Get-content $WSUS_7PM)
foreach($ComputerName in $list)
{
Get-Uptime -ComputerName $ComputerName
WARNING: Unable to connect to #{name=AXXXXX003}
WARNING: Unable to connect to #{name=BXXXXX005}
I hope that makes sense to someone, appreciate the help in understanding what the difference is in the object output.
Thanks
Alzoo
When you use Select-Object name you are creating a list of objects with a name property. You can either expand it ahead of time
$WSUS_7PM = Get-AdGroupMember -identity "Reboot 7pm" | Sort-Object | Select-Object -ExpandProperty name
or reference the name property later
foreach($Name in $WSUS_7PM.name) {Write-Host $Name}

PowerShell Script to implement ipsec rule

I am troubleshooting an issue in our local IT infrastructure. Some time ago a GPO was pushed that blocked traffic from our IT administration program to our production devices.
Long story short the big company made a decision which wrongly affects our very specific IT needs/design in our department.
Due to sheer coincidence we managed to resolve the issue by manually adding an IPSEC security exception on a device to solve a different issue.
Now the below dodgy attempt by me to make a PS command is just a base as the correct parameters are still to be decided after meeting with multiple sides of the business and IT.
But to reduce the time I need to implement the solution on hundreds of our devices I would like to get a script working where I just have to add or adjust the parameters when I receive the word "go"
I would need the command below to be useable with an input (list/array) of all our devices. I am looking into the CimSession cmdlet but I struggle to come up with a solution to loop through a list/array and add both the target computer and its IP address to the script.
Thank you in advance for your tips on how to proceed.
With the responses below I have expanded the script to the following:
```Powershell
# Ask for the csv file
$CsvLocation = Read-Host -Prompt 'input the location of the csv file (for
example c:\Users\USERNAME\Documents\workstations.csv)'
$CsvFile = Import-CSV -Path $CsvLocation
# Create empty Hash Table
$Machines = #{Workstation = "Test" ; IP = "123"}
# create a hashtable to store the parameters in for splatting
$ruleParams = #{
Confirm = $false
Enabled = $true
Description = 'This rule is instated to allow MobiControl
Administration to be performed on this device.'
DisplayName = 'MobiControl connection'
IPsecRuleName = 'Mobicontrol connection'
OutboundSecurity = 'None'
InboundSecurity = 'None'
Platform = '6.1+'
PolicyStore = 'PersistentStore'
Profile = 'Any'
RemoteAddress = '10.133.120.207'
RequireAuthorization = $false
Protocol = 'any'
}
# For each Element in the csv file add name and ip address to the hash
table
$CsvFile | ForEach-Object {
$Workstation = $_.Workstation
$IpAddress = [System.Net.Dns]::GetHostAddresses($Workstation) |
Where-Object { $_.AddressFamily -eq 'InterNetwork' } | Select-Object -
ExpandProperty IpAddressToString
$Machines.add($Workstation, $IpAddress)
# fill in the two remaining parameters with the IP address and computer
name
<# test print contents
Read-Host "press enter to see the values for hostname and ip address"
Echo $Machines.keys
Read-Host "press enter to continue"
#>
$ruleParams['LocalAddress'] = $_.Value # IP Address
$ruleParams['CimSession'] = $_.Key # HostName
# execute using the ruleParams splat
Write-Host "Creating IPsecRule on computer $() with IP address $()"
# New-NetIPsecRule #ruleParams
}
This looks to be more in the direction I want. Any obvious flaws?
the input csv file would just be a list of workstation names.
Testing the code all seems to be in working order up until the execution of the New-NetIPsecRule. The values inside the hashtable $Machines are non valid inputs for their related parameters.
The way you add the parameters to the cmdlet is incorrect and would require the much hated backticks at the end of each line, preceeded with a space.
Similar that, but much better is to use Splatting
# create a hashtable to store the parameters in for splatting
$ruleParams = #{
Confirm = $false
Enabled = $true
Description = 'This rule is instated to allow MobiControl Administration to be performed on this device.'
DisplayName = 'MobiControl connection'
IPsecRuleName = 'Mobicontrol connection'
OutboundSecurity = 'None'
InboundSecurity = 'None'
Platform = '6.1+'
PolicyStore = 'PersistentStore'
Profile = 'Any'
RemoteAddress = '10.133.120.207'
RequireAuthorization = $false
# I'm not sure about the Protocol parameter..
# The docs say it is a String, but also refer to the Get-NetFirewallPortFilter
# cmdlet where this parameter is a string array (String[])
Protocol = 'TCP,UDP'
}
# now iterate over the $machines hashtable, fill in the two missing parameters in the hash and execute
$machines.GetEnumerator() | ForEach-Object {
$CimSession = Get-CimSession -ComputerName $_.Key
# fill in the two remaining parameters with the IP address and computer name
$ruleParams['LocalAddress'] = $_.Value # IP Address
$ruleParams['CimSession'] = $CimSession
# execute using the ruleParams splat
Write-Host "Creating IPsecRule on computer $($_.Key) with IP address $($_.Value)"
New-NetIPsecRule #ruleParams
$CimSession | Remove-CimSession
}
Disclaimer.. I cannot try this myself, and as I'm not sure the Protocol parameter should be a single comma separated string or a string array, please try this on a limited test set of machines first.
P.S. When creating the $machines hashtable, change this line
$IpAddress = [System.Net.Dns]::GetHostAddresses($Workstation) |
Where-Object { $_.AddressFamily -eq 'InterNetwork' } | select IpAddressToString
into
$IpAddress = [System.Net.Dns]::GetHostAddresses($Workstation) |
Where-Object { $_.AddressFamily -eq 'InterNetwork' } | Select-Object -ExpandProperty IpAddressToString

Powershell function returning an array instead of string

i'm importing a csv and i would like to add a column to it (with the result based off of the previous columns)
my data looks like this
host address,host prefix,site
10.1.1.0,24,400-01
i would like to add a column called "sub site"
so I wrote this module but the problem is, the actual ending object is an array instead of string
function site {
Param($s)
$s -match '(\d\d\d)'
return $Matches[0]
}
$csv = import-csv $file | select-object *,#{Name='Sub Site';expression= {site $_.site}}
if I run the command
PS C:\>$csv[0]
Host Address :10.1.1.0
host prefix :24
site :400-01
sub site : {True,400}
when it should look like
PS C:\>$csv[0]
Host Address :10.1.1.0
host prefix :24
site :400-01
sub site : 400
EDIT: I found the solution but the question is now WHY.
If I change my function to $s -match "\d\d\d" |out-null I get back the expected 400
Good you found the answer. I was typing this up as you found it. The reason is because the -match returns a value and it is added to the pipeline, which is all "returned" from the function.
For example, run this one line and see what is does:
"Hello" -match 'h'
It prints True.
Since I had this typed up, here is another way to phrase your question with the fix...
function site {
Param($s)
$null = $s -match '(\d\d\d)'
$ret = $Matches[0]
return $ret
}
$csv = #"
host address,host prefix,site
10.1.1.1,24,400-01
10.1.1.2,24,500-02
10.1.1.3,24,600-03
"#
$data = $csv | ConvertFrom-Csv
'1 =============='
$data | ft -AutoSize
$data2 = $data | select-object *,#{Name='Sub Site';expression= {site $_.site}}
'2 =============='
$data2 | ft -AutoSize

Extracting part of a host name with select-object

I have a simple powershell function where I provide the log type and event and it scans all of our SQL servers. it works except the host name is returned as hostname.domain.local. I want it to return just the host name. I've tried machinename.split('.') and substring and it won't work. I've tried putting the select-object into a separate variable and was going to join it with the rest of the columns, but it takes too long to run.
Here is my sample scrap code i'm testing with before I change my function along with the commented out parts that didn't work. Looked around and found lots of resources about the commands, but they don't work when I try to use them in my script.
The error I keep getting is A positional parameter cannot be found that accepts argument '. '.
$servers = Get-Content -literalpath "C:\temp\sql_servers3.txt"
#$server
#$result =
ForEach($box in $servers) {Get-Eventlog -ComputerName $box -LogName
application -After 1-4-2018 -Entrytype Error | Where {$_.source -notin
'Perfnet','Perflib', 'ntfs', 'vss'}| select-object -property MachineName}
#$result_Host_name = select-object -inputobject $result -property
'MachineName'
#'TimeGenerated', 'MachineName'.Split('.')[1], 'EventID','message'}
#| Where {$_.source -notin 'Perfnet','Perflib', 'ntfs', 'vss'} 0
#return $result_Host_name
What you are looking for is a "Calculated Property" when using Select-Object.
| Select-Object #{n='HostName';e={($_.MachineName -split '\.')[0]}}