Powershell Script loop output to txt file - excel

I am using a Powershell script to write to a text file. A client showed me this Powershell script to use to replace a excel macro I used to use...
$computers= gc "C:\Users\Powershell\DeviceList.txt"
foreach ($computername in $computers)
{
write-output "<$computername>
active = yes
group =
interval = 5min
name = $computername
host = $computername
community =
version = 1
timeout = 0
retries = default
port = 161
qos_source = 1
</$computername>" | Out-File -filepath "C:\Users\Powershell\Cisco_Mon.txt" -append
}
It works great but now I wanted to build on it to add additional variables. In a perfect world I would like it to read from an excel spreadsheed grabbing each rowof data and each column being defined as a variable. For now using another text file is fine as well. Here is what I started with (it doesnt work) but you can see where I am going with it...
$computers= gc "C:\Users\Powershell\devicelist.txt"
$groups= gc "C:\Users\Powershell\grouplist.txt"
foreach ($computername in $computers) + ($groupname in $groups)
{
write-output "<$computername>
active = yes
group = $groupname
interval = 5min
name = $computername
host = $computername
community =
version = 1
timeout = 0
retries = default
port = 161
qos_source = 1
</$computername>" | Out-File -filepath "C:\Users\Powershell\Cisco_Mon.txt" -append
}
Of course it is not working. Essentially I would LOVE it if I could define each of the above options into a variable from an excel spreadsheet, such as $community, $interval, $active, etc.
Any help with this would be very much appreaciated. If someone could show me how to use an excel spreadsheet, have each column defined as a variable, and write the above text with the variables, that would be GREAT!!!.
Thanks,
smt1228#gmail.com
An Example of this would be the following...
Excel Data: (Colums seperated with "|"
IP | String | Group
10.1.2.3 | Public | Payless
Desired Output:
<10.1.2.3>
active = yes
group = Payless
interval = 5min
name = 10.1.2.3
host = 10.1.2.3
community =
version = 1
timeout = 0
retries = default
port = 161
qos_source = 1
</10.1.2.3>
Addition:
Pulling data from CSV for IP, String, Group where data is as follows in CSV...
10.1.2.3,public,group1
10.2.2.3,default,group2
10.3.2.3,public,group3
10.4.2.3,default,group4
to be writting into a .txt file as
IP = 10.1.2.3.
String = public
Group = Group1
and look for each line in the CSV

Ok, new answer now. The easiest way would be to save your Excel document as CSV so that it looks like this (i.e. very similar to how you presented your data above):
IP,String,Group
10.1.2.3,Public,Payless
You can still open that in Excel, too (and you avoid having to use the Office interop to try parsing out the values).
PowerShell can parse CSV just fine: with Import-Csv:
Import-Csv grouplist.csv | ForEach-Object {
"<{0}>
active = yes
group = {1}
interval = 5min
name = 10.1.2.3
host = 10.1.2.3
community =
version = 1
timeout = 0
retries = default
port = 161
qos_source = 1
</{0}>" -f $_.IP, $_.Group
}
I'm using a format string here where {0}, etc. are placeholders. -f then is the format operator which takes a format string on the left and arguments for the placeholders on the right. You can also see that you can access the individual columns by their name, thanks to Import-Csv.

Related

powershell: Multithreading to a Hash Table

I'm having some trouble with using multithreading in powershell. I've tried creating a synced hash table and doing ForEach-Object -Parallel -ThrottleLimit 3 -AsJob{...} but this just gives me errors.
A sample of what I'm trying to do is:
$index = [System.Collections.Hashtable]::Synchronized(#{})
Import-Csv -path .\csvfile.csv | ForEach-Object -Parallel -ThrottleLimit 3 -AsJob{
$nameKey = $_.($FILE_HEADER)
$dirKey = $_.($DIR_HEADER)
$extKey = $_.($EXTENSION_HEADER)
$nameLetter = $nameKey.Substring(0,1) #Retrieves the very first character of the name for indexing
#Confirm we are indexing into non-null array as we step through dimensions
if($null -eq $index[$dirKey])
{$index[$dirKey] = #{}}
if($null -eq $index[$dirKey][$extKey])
{$index[$dirKey][$extKey] = #{}}
if($null -eq $index[$dirKey][$extKey][$nameLetter])
{$index[$dirKey][$extKey][$nameLetter] = #{}}
if($null -eq $index[$dirKey][$extKey][$nameLetter][$nameKey])
{$index[$dirKey][$extKey][$nameLetter][$nameKey] = 0}
$index[$dirKey][$extKey][$nameLetter][$nameKey]++
}
In the result I would have a 4d hash table where I can call $index[$dirKey][$extKey][$nameLetter][$nameKey] to get a counter representing the number of times this name was added.
I am doing this because this CSV is half a million lines long and simply building my hash table linearly takes two hours. The next stage where I go through these entries takes even longer.
What I am looking for is the ability to run through all the entries of the CSV once and build my index file using as many threads as I want. What is the best way to go about this? Also how do I determine the most sensible number of threads?

Turn a formatted PowerShell hash table/array definition into a single line (and vice versa) via hot key in Visual Studio Code

In Visual Studio Code I am trying to work out a way to convert a piece of PowerShell (which defines a collection of hash tables and arrays) into a single line of code, and also a way to perform the same operation but the other way (i.e. take a single line and make it more readable). I need to do this because the YAML variable I am defining needs to be done on a single line (the PowerShell gets passed to another PowerShell script via this variable).
So, for example, I need to be able to turn:
#{
TestData = #{
Connections = #(
#{
ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01';
SourceVmName = 'D3ZUKS342APP01';
Targets = #(
#{
DestinationVmName = 'D3ZUKS342SQL01';
DestinationVmResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01';
DestinationPort = 1433;
Status = 'Reachable'
}
)
}
)
};
IPFlows = #(
#{
ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01';
TargetVmName = 'D3ZUKS342SQL01';
InboundFlows = #(
#{
Description = 'Application Server D3ZUKS342APP01';
Protocol = 'TCP';
LocalPorts = 1433;
RemoteIpAddress = '10.124.36.132';
RemotePort = 0;
}
);
OutboundFlows = #()
}
)
}
into:
#{TestData = #{Connections = #(#{ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01';SourceVmName= 'D3ZUKS342APP01';Targets = #(#{DestinationVmName= 'D3ZUKS342SQL01';DestinationVmResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01';DestinationPort= 1433;Status = 'Reachable' })});IPFlows = #(#{ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01';TargetVmName= 'D3ZUKS342SQL01';InboundFlows= #(#{Description = 'Application Server D3ZUKS342APP01';Protocol= 'TCP';LocalPorts= 1433;RemoteIpAddress = '10.124.36.132';RemotePort= 0;});OutboundFlows = #()})}}
And more importantly, do the same in reverse (i.e. take the single line and make it readable/editable). Ideally I'd love to be able to do both by mapping a hotkey to both operations.
The multi line > single line seems easier - a regex replace of \s+( ) with nothing, followed by a replace of carriage returns with nothing, but how can I map that to a hotkey?
The single line > multi line seems much harder :( I have searched for an extension that might help, but to no avail. Does anyone have any suggestions, either native Visual Studio Code functionality or an extension that I could use?
Although I do not understand why you need this either, specific to the request for a oneliner: you might use this ConvertTo-Expression cmdlet to rebuild your expression from an object using several expansion levels:
$Object = #{
TestData = #{ ...
# Oneliner
$Object | ConvertTo-Expression -Expand 0
#{IPFlows = ,#{ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01'; TargetVmName = 'D3ZUKS342SQL01'; InboundFlows = ,#{Description = 'Application Server D3ZUKS342APP01'; RemoteIpAddress = '10.124.36.132'; RemotePort = 0; Protocol = 'TCP'; LocalPorts = 1433}; OutboundFlows = #()}; TestData = #{Connections = ,#{ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01'; SourceVmName = 'D3ZUKS342APP01'; Targets = ,#{DestinationVmName = 'D3ZUKS342SQL01'; DestinationPort = 1433; DestinationVmResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01'; Status = 'Reachable'}}}}
# Compressed
$Object | ConvertTo-Expression -Expand -1
#{IPFlows=,#{ResourceGroup='d3zuks-bussvc-342-brimig-rgrp01';TargetVmName='D3ZUKS342SQL01';InboundFlows=,#{Description='Application Server D3ZUKS342APP01';RemoteIpAddress='10.124.36.132';RemotePort=0;Protocol='TCP';LocalPorts=1433};OutboundFlows=#()};TestData=#{Connections=,#{ResourceGroup='d3zuks-bussvc-342-brimig-rgrp01';SourceVmName='D3ZUKS342APP01';Targets=,#{DestinationVmName='D3ZUKS342SQL01';DestinationPort=1433;DestinationVmResourceGroup='d3zuks-bussvc-342-brimig-rgrp01';Status='Reachable'}}}}
# Expanded (to any level)
$Object | ConvertTo-Expression # -Expand to any level
#{
IPFlows = ,#{
ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01'
TargetVmName = 'D3ZUKS342SQL01'
InboundFlows = ,#{
Description = 'Application Server D3ZUKS342APP01'
RemoteIpAddress = '10.124.36.132'
RemotePort = 0
Protocol = 'TCP'
LocalPorts = 1433
}
OutboundFlows = #()
}
TestData = #{Connections = ,#{
ResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01'
SourceVmName = 'D3ZUKS342APP01'
Targets = ,#{
DestinationVmName = 'D3ZUKS342SQL01'
DestinationPort = 1433
DestinationVmResourceGroup = 'd3zuks-bussvc-342-brimig-rgrp01'
Status = 'Reachable'
}
}}
}

add entry in hashtable from string in Powershell

I have a string like this, retrieved from a txt file:
$txtindex = 5
$PRINTERNAME = get-content $txtPrinterfile | select -Index $txtindex
$PRINTERNAME = $PRINTERNAME.Trim()
$PRINTERNAME = $PRINTERNAME.Replace(" ","")
$Printername
NAME="W018"
So I thought I could easily add this to a hashtable:
$HashPrinter = #{}
$HashPrinter.Add($PRINTERNAME)
but this is not working.
Either this:
$HashPrinter = #{$PRINTERNAME}
If I type it manually:
$HashPrinter = #{NAME="W018"}
it works as expected.
What I am doing wrong?
PS C:\Users\alHaos> $HashTable = #{}
PS C:\Users\alHaos> $HashTable.Add("Name", "Pr001")
PS C:\Users\alHaos> $HashTable.Add("Manufacture", "Epson")
PS C:\Users\alHaos> $HashTable
Name Value
---- -----
Name Pr001
Manufacture Epson

Powershell - String Manipulation - getting dir from full file-path

Keep in mind I'm new to this and be gentle.
I have a full file path for a document "C:\folder1\folder2\01.03.2017 - FileName.csv" and I want to manipulate it to return the dir that the file is stored in (C:\folder1\folder2), minus the filename (01.03.2017 - FileName.csv).
I'm trying to make this modular so that it will work regardless of the amount of sub-folders a file sits in; we also won't know the FileName in advance, so again this needs to be modular and remove up to and including the last "\"
For background info on how this is currently built, I nicked a bit of code from a previous question I saw on StackOverflow:
Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”) |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = “All files (*.*)| *.*”
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
} #end function Get-FileName
# *** Entry Point to Script ***
$originalData = Get-FileName -initialDirectory “c:\” | Out-String
Write-Host $originalData
$originalDir = $originalData.Split('\')
$originalDir
Running this currently prompts for an "open dialog box" you would see in Windows. You select a folder and the output is currently:
C:\folder1\folder2\01.03.2017 - FileName.csv
C:
folder1
folder2
01.03.2017 - FileName.csv
I've tried a few different -join attempts but none successful.
We will have an input of C:\folder1\folder2\01.03.2017 - FileName.csv as a variable $originalData.
We want the output to be C:\folder1\folder2 as a variable $originalDir.
Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”) |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = “All files (*.*)| *.*”
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
} #end function Get-FileName
$originalData = Get-FileName -initialDirectory “c:\”
Write-Host $originalData
$originalDir = (Get-ChildItem $originalData).DirectoryName
you can use it like so, so take result or your function and use it with get-childitem.
edit: notice there's no | Out-String on the third to last line

Accessing Sharepoint UserProfile Properties with Powershell script

The following script spits out all UserProfile properties for users on Sharepoint 2007:
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")
# Function: Get-UserProfiles
# Description: return a UserProfileManager object containing all user profiles
# Parameters: SSPName SSPName
#
Function global:Get-UserProfiles($SSPName)
{
$ServerContext = [Microsoft.Office.Server.ServerContext]::GetContext($SSPName);
$UPManager = new-object Microsoft.Office.Server.UserProfiles.UserProfileManager($ServerContext);
return $UPManager.GetEnumerator();
}
$profiles = Get-UserProfiles("SharedServices");
$profiles | ForEach-Object { $_.GetEnumerator();}
However, what I want to do is be able to return a table, or csv file of specific values in the profile, e.g. Username, WorkEmail, WorkPhone. I have tried piping the output to |ft Username, WorkEmail, Workphone and | select Username, WorkEmail, WorkPhone but this just returns blanks.
I feel like I am so close. I don't want to replace the $_.GetEnumerator() call with lots of $_.Item("property") calls and it doesn't feel like I should have to. Any ideas?
I've further developed the code so that it now accepts a comma delimited list of properties and writes them to a delimited file.
# Outputs a delimited file with specified user profile properties for each user in Sharepoint
# Create array of desired properties
$arProperties = 'UserName','FirstName','LastName','Title','WorkEmail','WorkPhone','Manager','AlternateContact','RoleDescription','PictureURL';
# Specify output file
$outfile = 'UserProfiles.csv';
#Specify delimiter character (i.e. not one that might appear in your user profile data)
$delim = '^';
# Specify Shared Service Provider that contains the user profiles.
$SSP = "SharedServices";
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")
# Function: Get-UserProfiles
# Description: return a UserProfileManager object containing all user profiles
# Parameters: SSPName SSPName
#
Function global:Get-UserProfiles($SSPName)
{
$ServerContext = [Microsoft.Office.Server.ServerContext]::GetContext($SSPName);
$UPManager = new-object Microsoft.Office.Server.UserProfiles.UserProfileManager($ServerContext);
return $UPManager.GetEnumerator();
}
$profiles = Get-UserProfiles($SSP);
#Initialise Output file with headings
$header = [string]::join($delim,$arProperties);
Write-Output $header | Out-File $outfile
#Output the specified properties for each
$profiles | ForEach-Object {
foreach($p in $arProperties){
# Get the property name and add it to a new array, which will be used to construct the result string
$arProfileProps += $_.Item($p);
}
$results = [string]::join($delim,$arProfileProps);
# Get rid of any newlines that may be in there.
$CleanResults = $results.Replace("`n",'');
Write-Output $CleanResults
Remove-Variable -Name arProfileProps
} | Out-File -Append $outfile
This gets me a bit closer. I'd still really like a script that iterates through all the profile properties and puts them into a CSV or XML file more gracefully. This will do for now.

Resources