I'm very new to Powershell. Only have been using it for about 2 weeks.
I have a file that is structured like this:
Service name: WSDL
Service ID: 14234321885
Service resolution path: /gman/wsdlUpdte
Serivce endpoints:
--------------------------------------------------------------------------------
Service name: DataService
Service ID: 419434324305
Service resolution path: /widgetDate_serv/WidgetDateServ
Serivce endpoints:
http://servername.company.com:1012/widgetDate_serv/WidgetDateServ
--------------------------------------------------------------------------------
Service name: SearchService
Service ID: 393234543546
Service resolution path: /ProxyServices/SearchService
Serivce endpoints:
http://servername.company.com:13010/Services/SearchService_5_0
http://servername2.company.com:13010/Services/SearchService_5_0
--------------------------------------------------------------------------------
Service name: Worker
Service ID: 14187898547
Service resolution path: /ProxyServices/Worker
Serivce endpoints:
http://servername.company.com:131009/Services/Worker/v9
--------------------------------------------------------------------------------
I'd like to parse the file and have Service name, Service ID, Service Resolution Path and Service Endpoints (which sometimes contain multiple or no values) in individual columms (CSV).
Beyond using Get-Content and looping through the file, I have no idea even where to start.
Any help will be appreciated.
Thanks
with PowerShell 5 you can use the fabulous command 'convertfrom-string'
$template=#'
Service name: {ServiceName*:SearchService}
Service ID: {serviceID:393234543546}
Service resolution path: {ServicePath:/ProxyServices/SearchService}
Serivce endpoints:
http://{ServiceEP*:servername.company.com:13010/Services/SearchService_5_0}
http://{ServiceEP*:servername2.tcompany.tcom:13011/testServices/SearchService_45_0}
--------------------------------------------------------------------------------
Service name: {ServiceName*:Worker}
Service ID: {serviceID:14187898547}
Service resolution path: {ServicePath:/ProxyServices/Worker}
Serivce endpoints:
http://{ServiceEP*:servername3.company.com:13010/Services/SearchService}
--------------------------------------------------------------------------------
Service name: {ServiceName*:WSDL}
Service ID: {serviceID:14234321885}
Service resolution path: {ServicePath:/gman/wsdlUpdte}
Serivce endpoints:
http://{ServiceEP*:servername4.company.com:13010/Services/SearchService_5_0}
--------------------------------------------------------------------------------
'#
#explode file with template
$listexploded=Get-Content -Path "c:\temp\file1.txt" | ConvertFrom-String -TemplateContent $template
#export csv
$listexploded |select *, #{N="ServiceEP";E={$_.ServiceEP.Value -join ","}} -ExcludeProperty ServiceEP | Export-Csv -Path "C:\temp\res.csv" -NoTypeInformation
Give this a try:
Read the file content as one string
Split it by 81 hyphens
Split each splited item on the colon char and take the last array item
Create new object for each item
$pattern = '-'*81
$content = Get-Content D:\Scripts\Temp\p.txt | Out-String
$content.Split($pattern,[System.StringSplitOptions]::RemoveEmptyEntries) | Where-Object {$_ -match '\S'} | ForEach-Object {
$item = $_ -split "\s+`n" | Where-Object {$_}
New-Object PSobject -Property #{
Name=$item[0].Split(':')[-1].Trim()
Id = $item[1].Split(':')[-1].Trim()
ResolutionPath=$item[2].Split(':')[-1].Trim()
Endpoints=$item[4..($item.Count)]
} | Select-Object Name,Id,ResolutionPath,Endpoints
}
Try this:
Get-Content | ? { $_ -match ': ' } | % { $_ -split ': ' } | Export-Csv Test.csv;
Basically it boils down to:
Get all text content as an array
Filter for lines that contain ': '
For each line left over, split it on ': '
Export object arrays to a CSV file named test.csv
Hope this points you in the right direction.
Note: Code is untested.
Here is a general way parsing files with records and records of records (and so on), it use the powerfull PowerShell switch instruction with regular expressions and the begin(), Process(), end() function template.
Load it, debug it, correct it ...
function Parse-Text
{
[CmdletBinding()]
Param
(
[Parameter(mandatory=$true,ValueFromPipeline=$true)]
[string]$ficIn,
[Parameter(mandatory=$true,ValueFromPipeline=$false)]
[string]$ficOut
)
begin
{
$svcNumber = 0
$urlnum = 0
$Service = #()
$Service += #{}
}
Process
{
switch -regex -file $ficIn
{
# End of a service
"^-+"
{
$svcNumber +=1
$urlnum = 0
$Service += #{}
}
# URL, n ones can exist
"(http://.+)"
{
$urlnum += 1
$url = $matches[1]
$Service[$svcNumber]["Url$urlnum"] = $url
}
# Fields
"(.+) (.+): (.+)"
{
$name,$value = $matches[2,3]
$Service[$svcNumber][$name] = $value
}
}
}
end
{
#$service[3..0] | % {New-Object -Property $_ -TypeName psobject} | Export-Csv c:\Temp\ws.csv
# Get all the services except the last one (empty -> the file2Parse is teerminated by ----...----)
$tmp = $service[0..($service.count-2)] | Sort-Object #{Expression={$_.keys.count };Descending=$true}
$tmp | % {New-Object -Property $_ -TypeName psobject} | Export-Csv $ficOut
}
}
Clear-Host
Parse-Text -ficIn "c:\Développements\Pgdvlp_Powershell\Apprentissage\data\Text2Parse.txt" -ficOut "c:\Temp\ws.csc"
cat "c:\Temp\ws.csv"
Related
Consider that CSV file:
Node Name,Client Name,Job Directory,Policy Name
server1,test.domain.com,"vmware:/?filter= VMHostName AnyOf "server2.domain.com", "server3.domain.com"",TEST
My code:
$events = Import-Csv "C:\file.csv" | foreach {
New-Object PSObject -prop #{
Server = $_.{Node Name};
Client = $_.{Client Name};
{JobDirectory/Script} = $_.{Job Directory};
Policy = $_.{Policy Name};
}
}
I have some problems when I try to parse the third field. I am not sure if its because the comma, or the double quote.
This is the object I would like to have:
Node Name : server1
Client Name : test.domain.com
JobDirectory/Script : vmware:/?filter= VMHostName AnyOf "server2.domain.com", "server3.domain.com"
Policy Name : TEST
Can someone help me?
Ok, so the easiest way to approach this is to read the file in with Get-Content and then split each line where the commas are not inside quotes. I borrowed the regex from this solution for this.
Using your current input data I would do something like this
$filedata = Get-Content C:\temp\test.csv
$asObject = ForEach($singlerow in ($filedata | Select-Object -Skip 1)){
$props = #{}
$singlerow = $singlerow -split ',(?=(?:[^"]*"[^"]*")*[^"]*$)'
[pscustomobject][ordered]#{
Server = $singlerow[0]
Client = $singlerow[1]
"JobDirectory/Script" = $singlerow[2]
Policy = $singlerow[3]
}
}
Sample Output from $asObject | Format-List
Server : server1
Client : test.domain.com
JobDirectory/Script : "vmware:/?filter= VMHostName AnyOf "server2.domain.com", "server3.domain.com""
Policy : TEST
Another way using your starting code
$obj = gc c:\temp\test.csv |
% { $_ -replace '"(\b[^"]*\b)"','$1' } |
convertfrom-csv | % { [pscustomobject][ordered] #{
Server = $_.{Node Name}
Client = $_.{Client Name}
{JobDirectory/Script} = $_.{Job Directory}
Policy = $_.{Policy Name} }
}
How can I get user list from a local group? I only have PS 2.0 and it does not have Get-ADGroup command.
I can get local groups:
$adsi = [ADSI]"WinNT://$env:COMPUTERNAME"
$groups = $adsi.Children | Where { $_.SchemaClassName -eq 'Group' }
$group | ft Name
What I need is to list all the members for each group.
You can try the following
$obj = [ADSI]"WinNT://$env:COMPUTERNAME"
$admingroup = $obj.Children | Where { $_.SchemaClassName -eq 'group'} | where {$_.name -eq 'Administrators'}
$admingroup.Invoke('Members') | % {$_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)}
$admingroup.Invoke('Members') | % {$_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)}
Here are the common properties
String :
Description, FullName, HomeDirectory, HomeDirDrive, Profile, LoginScript, ObjectSID
Integer :
UserFlags, PasswordExpired, PrimaryGroupID
Time :
PasswordAge
You'll find more in Microsoft documentation.
Try this
$computer = [ADSI]"WinNT://$env:COMPUTERNAME"
$computer.psbase.children | where { $_.psbase.schemaClassName -eq 'group' } | foreach {
write-host $_.name
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
write-host
}
This doesn't give the domain though, hence i had to look for other ways, like:
If you want to see members of a local group quickly:
PS C:\> net localgroup USERS
Alias name USERS
Comment Users are prevented from making accidental or intentional system-wide changes and can run most applications
Members
-------------------------------------------------------------------------------
NT AUTHORITY\Authenticated Users
NT AUTHORITY\INTERACTIVE
The command completed successfully.
Now you can manipulate this output a bit to get what you need:
$computer = [ADSI]"WinNT://$env:COMPUTERNAME"
$groups = $computer.psbase.children | where { $_.psbase.schemaClassName -eq 'group' } | select -ExpandProperty Name
Foreach($group in $groups)
{
write-host $group
write-host "------"
net localgroup $group | where {$_ -notmatch "command completed successfully"} | select -skip 6
Write-host
}
I have a script that works properly when run as an administrator but gives a Parse error when run as a normal user. Any Ideas?;
SCRIPT
`NeverExpires = 9223372036854775807;
$ExpireMin = (Get-Date).AddDays(4);
$ExpireMax = (Get-Date).AddDays(9);
$Userlist = Get-ADUser -Filter * -Properties name, samaccountname, accountexpirationdate, enabled, distinguishedname, accountExpires | Where-object {($_.DistinguishedName -notlike "*OU=Terminated,OU=Users,OU=Home Office,DC=Domain,DC=com")} |
Where-Object {$_.accountExpires -ne $NeverExpires `
-and [datetime]::FromFileTime([int64]::Parse($_.accountExpires)) -lt $ExpireMax `
-and [datetime]::FromFileTime([int64]::Parse($_.accountExpires)) -gt $ExpireMin }
$Userlist | select name, samaccountname, accountexpirationdate, enabled, distinguishedname | export-csv $ReportName -notypeinformation
Send-MailMessage -To $To -From $From -Subject $Subject -Body $Body -SMTPServer $SMTPServer -Attachments $ReportName
Get-ADUser -Filter * -Properties accountExpires |
Where-Object {$_.accountExpires -ne $NeverExpires `
-and [datetime]::FromFileTime([int64]::Parse($_.accountExpires)) -lt $ExpireMax `
-and [datetime]::FromFileTime([int64]::Parse($_.accountExpires)) -gt $ExpireMin } | ForEach {
$account = $_
$manager = Get-ADUser -Identity $account -Properties EmailAddress,Manager | %{(Get-AdUser $_.Manager -Properties EmailAddress).EmailAddress}`
I would say that $_.accountExpires is null either because the property could not be retrieved or $_ is itself null. Powershell will quietly convert null to the empty string resulting an invalid format for parsing. Note that the Parse call is completely unnecessary because powershell will automatically try to coerce the string for you and will likely give you a much better error message. Although null will be coerced to 0 as a long.
I'm using the following to query the firewall rules of a list of servers.
$servers = Get-Content fw_servers.txt
foreach($serv in $servers) {
$fw = New-Object -ComObject hnetcfg.fwpolicy2
$fw.rules |
Where-Object { $_.enabled -and $_.LocalPorts -like 3389 } |
Select-Object -Property direction,protocol, localports,name
}
I would like to export this information to a csv file. Can someone please let me know how I can use Export-CSV for this? I've tried making it into an array but it's not working for me. I'm using 2.0
I'd also like the exported data to look like the following
Server Direction Protocol LocalPorts Name
testsrv1 1 6 3389 Remote Desktop (TCP-In)
testsrv2 1 6 3389 Research Remote Desktop Policy
Thank you for your help.
Amelia
I had an epiphany and somehow figured it out. The following, although not pretty, works for me.
$servers = Import-CSV fw_servers.csv
$servers | Foreach {
$serv = $_.serv
foreach-object {
$name = $_."Server"
$fw = New-Object -ComObject hnetcfg.fwpolicy2
$fw.rules |
Where-Object { $_.enabled -and $_.LocalPorts -like 3389 } |
Select-Object #{Name="Server"; Expression={$name}}, direction, protocol, localports, name
}
} | Export-CSV C:\Users\trankaa\desktop\fw_res.csv -NoTypeInformation -Force
I am parsing text output from a disk array that lists information about LUN snapshots in a predictable format. After trying every other way to get this data out of the array in a useable manner, the only thing I can do is generate this text file and parse it. The output looks like this:
SnapView logical unit name: deleted_for_security_reasons
SnapView logical unit ID: 60:06:01:60:52:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
Target Logical Unit: 291
State: Inactive
This repeats all through the file with one line break between each group. I want to identify a group, parse each of the four lines, create a new PSObject, add the value for each line as a new NoteProperty, and then add the new object to a collection.
What I can figure out is, once I identify the first line in the block of four lines, how to then process the text from lines two, three, and four. I'm looping through each line, finding the start of a block, and then processing it. Here's what I have so far, with comments where the magic goes:
$snaps = get-content C:\powershell\snaplist.txt
$snapObjects = #()
foreach ($line in $snaps)
{
if ([regex]::ismatch($line,"SnapView logical unit name"))
{
$snapObject = new-object system.Management.Automation.PSObject
$snapObject | add-member -membertype noteproperty -name "SnapName" -value $line.replace("SnapView logical unit name: ","")
#Go to the next line and add the UID
#Go to the next line and add the TLU
#Go to the next line and add the State
$snapObjects += $snapObject
}
}
I have scoured the Google and StackOverflow attempting to figure out how I can reference the line number of the object I'm iterating through, and I can't figure it out. I may rely on foreach loops too much and so that's affecting my thinking, I don't know.
As you say, I think you're thinking too much foreach when you should be thinking for. The below modification should be more along the lines of what you're looking for:
$snaps = get-content C:\powershell\snaplist.txt
$snapObjects = #()
for ($i = 0; $i -lt $snaps.length; $i++)
{
if ([regex]::ismatch($snaps[$i],"SnapView logical unit name"))
{
$snapObject = new-object system.Management.Automation.PSObject
$snapObject | add-member -membertype noteproperty -name "SnapName" -value ($snaps[$i]).replace("SnapView logical unit name: ","")
# $snaps[$i+1] Go to the next line and add the UID
# $snaps[$i+2] Go to the next line and add the TLU
# $snaps[$i+3] Go to the next line and add the State
$snapObjects += $snapObject
}
}
A while loop may be even cleaner because then you can increment $i by 4 instead of 1 when you hit this case, but since the other 3 lines won't trigger the "if" statement... there's no danger, just a few wasted cycles.
Another possibility
function Get-Data {
$foreach.MoveNext() | Out-Null
$null, $returnValue = $foreach.Current.Split(":")
$returnValue
}
foreach($line in (Get-Content "C:\test.dat")) {
if($line -match "SnapView logical unit name") {
$null, $Name = $line.Split(":")
$ID = Get-Data
$Unit = Get-Data
$State = Get-Data
New-Object PSObject -Property #{
Name = $Name.Trim()
ID = ($ID -join ":").Trim()
Unit = $Unit.Trim()
State = $State.Trim()
}
}
}
Name ID Unit State
---- -- ---- -----
deleted_for_security_reasons 60:06:01:60:52:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX 291 Inactive
switch -regex -file C:\powershell\snaplist.txt {
'^.+me:\s+(\S*)' {$SnapName = $Matches[1]}
'^.+ID:\s+(\S*)' {$UID = $Matches[1]}
'^.+it:\s+(\S*)' {$TLU = $Matches[1]}
'^.+te:\s+(\S*)' {
New-Object PSObject -Property #{
SnapName = $SnapName
UID = $UID
TLU = $TLU
State = $Matches[1]
}
}
}
try this
Get-Content "c:\temp\test.txt" | ConvertFrom-String -Delimiter ": " -PropertyNames Intitule, Value
if you have multiple packet try this
$template=#"
{Data:SnapView logical unit name: {UnitName:reasons}
SnapView logical unit ID: {UnitId:12:3456:Zz}
Target Logical Unit: {Target:123456789}
State: {State:A State}}
"#
Get-Content "c:\temp\test.txt" | ConvertFrom-String -TemplateContent $template | % {
[pscustomobject]#{
UnitName=$_.Data.UnitName
UnitId=$_.Data.UnitId
Target=$_.Data.Target
State=$_.Data.State
}
}