This question already has an answer here:
Dynamically create variables in PowerShell
(1 answer)
Closed 7 years ago.
I am trying to assign / divide a string out to assign them to variables. The length of each row is random so I am kinda at a loss. Thanks for the help.
-String-
Company 1
Employee 1
Employee 2
Employee 3
Company 2
Employee 1
Employee 2
Employee 3
I want to assign each line to a variable. $a = "company 1" $b = "employee 1" ect. The only stable variable in this string is each line of data is a different variable. The length of each line is unknown.
Thanks again!
If you really need to create a distinct variable for each row of your string, then use New-Variable in a loop:
$str = 'Company 1
Employee 1
Employee 2
Employee 3
Company 2
Employee 1
Employee 2
Employee 3'
# to know how many variables were created we will put them into array
$variables = #()
$i = 0
foreach ($row in ($str -split [Environment]::NewLine)) {
# create new variable from row's value
New-Variable -Name "row$i" -Value $row
# and create a member of array
$variables += [pscustomobject]#{Name = "row$i"; Value = $row}
$i++
}
Write-Host "Total: $i"
foreach ($var in $variables) {
Write-Host $var.Name $var.Value
}
# now we can get value from a variable
Write-Host $row1
# or from array
Write-Host $variables[1].Name $variables[1].Value
But to operate on a collection of items it is really simplier to use arrays and other collection types without creating a variable per item:
$rows = #()
foreach ($row in ($str -split [Environment]::NewLine)) {
$rows += $row
}
Write-Host "Total rows: $rows.Count"
# get the first row
$rows[0]
Related
I need to get the occurrence of "failure" in a logfile.
The thing is I need to get the occurrence of "failure" for each session block.
What the log looks like:
---Session 1
check
check
failure
failure
check
----Session 2
check
failure
check
check
----Session 3
failure
failure
What I've got so far is this:
$rows = Get-Childitem -Path E:\shell\lot.log |
Select-String -Pattern failure
$i = 0
foreach ($row in $rows) {
$i++
}
echo $i
With that script I only get the total of the occurrences.
I would start a new counter whenever a line beginning with 3 or more consecutive hyphens occurs and collect the results in a hashtable.
$failcount = #{}
Get-Content 'E:\shell\lot.log' | ForEach-Object {
if ($_ -match '^-{3,}(.*)') {
$section = $matches[1].Trim()
$failcount[$section] = 0
} elseif ($_ -like '*failure*') {
$failcount[$section]++
}
}
I believe this will do it. Key part is to reset your counter after each session.
$rows = Get-Childitem -Path E:\shell\lot.log
$i = 0 # failure counter
$j = 1 # session counter
foreach($row in $rows){
if($row -like "*Session 1"){
# skip the first line. Edit: removed * as would skip session 10, 11 etc. assumes line ends with "session 1"
continue
}elseif($row -eq "failure){
# if the row is equal to failure, count it
$i++
}elseif($row -like "*Session*"){
# when you get to the end of a session, print the number of failures
Write-Host "Session $j had $i failures"
# ... and reset the failure counter
$i = 0
# increment the session counter
$j++
}
}
I'll add another option. Read the whole log file in with -Raw to get a multi-line string. Remove the ---- from the first line, and then split on 3 or more hyphens at the beginning of a line, this gets you each session as a multi-line string, then you could just output text or custom objects, or whatever you wanted with it. Split the multi-line string on new line characters, filter for 'failure', and do a count to get failures per session.
(GC E:\shell\lot.log -Raw) -replace '^-+' -split '(?<=[\r\n])---+'|%{
'{0} had {1} failure(s)' -f ($_.split("`n")[0].Trim()),($_ -split '[\r\n]+'|?{$_ -match 'failure'}).Count
}
That would (given the sample provided) output:
Session 1 had 2 failure(s)
Session 2 had 1 failure(s)
Session 3 had 2 failure(s)
I currently have a spreadsheet with the following display:
+------------+---------+---------+
| Site | UserP |UserName |
+------------+---------+---------+
| Site A | Read | user1 |
| | | |
+------------+---------+---------+
| Site A | Write | user2 |
| | | |
+------------+---------+---------+
The problem is that sometimes the UserName field brings a Group and then I have to open this group and create a new row for each user in this group with the same information.
So if I had this:
Site A | Read | Group 1
It would become this:
Site A | Read | Group 1
Site A | Read | Group 1 User A
Site A | Read | Group 1 User B
Site A | Read | Group 1 User C
I can manually pull the information from the group, the thing is that I don't know how to read a specific column from excel and then create a new row in that excel sheet.
I didn't post any code cause I barely have one. I don't know how to loop to the cells.
This is what I have.
$file = "\Desktop\AccessReviewReportPRE.csv"
$sheetName = "AccessReviewReportPRE"
$objExcel = New-Object -ComObject Excel.Application
$workbook = $objExcel.Workbooks.Open($file)
$sheet = $workbook.Worksheets.Item($sheetName)
Now, I know how to access individual cells, like this:
$worksheet.cells.Item(3, 3).text
Just not sure how to loop trough all rows, check what is in the third column and do a action on that.
Following #BenH tip, I did this:
$file = "\Desktop\AccessReviewReportPRE.csv"
$fileContent = Import-csv $file -header "URL", "Site/List/Folder/Item", "Title/Name", "PermissionType", "Permissions", "LoginName"
$newRow = New-Object PsObject -Property #{"URL" = 'sdfs'; "Site/List/Folder/Item" = 'dsfd'; "Title/Name" = 'sdf'; "PermissionType" = 'dsf'; "Permissions" = 'sdfs'; "LoginName" = 'sdf'}
$fileContent += $newRow
$fileContent | Export-Csv -NoTypeInformation -Path "\Desktop\AccessReviewReportAFTER.csv"
But it is duplicating the header. Any ideas why?
To loop through each Row you need a loop.
I recommend a do-while.
#My Code to find a groupname
$WorkBook=$Excel.Workbooks.Open($strPath)
#Selcet the first Tabelle
$mappe = $workbook.sheets.item(1)
$Target = $mappe.Range("A1").Find($Grouname)
$start = $Target.Row
end, $middle, $counter = 0
do {
#assigning
$middle = $end
#Search Funktion
$nextFind = $mappe.Range("A1:A150000").FindNext($Target)
#Old Range assinging to $find
$Target = $nextFind
#Assign the Rownumber
$end = $nextFind.Row
#Check if the Value is correct
if ($mappe.cells.Item($nextFind.Row,1).Value() -eq $Groupname)
{
$counter++
}else{
break
}
}while($end -gt $start)
#The FindNext function only works when there are at least 2 of the groups
#but in some cases there is only 1 group. To fix the issue a counter counts
#the passages and if it is 1, $middle will be assigned the start row.
if($counter -eq 1)
{
$middle= $start
}
#Because a line must be added after the last one, $row needs be increased by 1
$row = $middle + 1
#Column stays the same, later it will be increased
$column = $Target.Column
# ADD ROW
$eRow = $mappe.cells.item($row,1).entireRow
$active = $eRow.activate()
$active = $eRow.insert()
With this Code, I'm looking for a Group. The Finde function which I use helps me to locate the group. The finde function does not work in a loop, that's why you must use the FindeNext function.
$middle contains the last row number to add a row it must be increased.
In order to add data into multiple columns, the row has to stay the same, but the column must be increased.
$mappe.Cells.Item($row, $column) = Text
$column++
If you wanna check the 3 column and based on its value you wanna make an action, make a if-statment.
I know the Code ain't perfect, but I hope it helped.
I want to write a script that renames all NICs on a Server 2012 R2.
Currently it looks like this with each one:
$NIC = Get-WMIObject -Class Win32_NetworkAdapter -Filter "NetconnectionID='Embedded LOM 1 Port 1'"
$NIC.NetconnectionID = 'Physical 1'
$NIC.Put()
Now I want to use this for different Servers and therefore I have to get the NetconnectionID from a variable.
So far I have put the NICs into a variable:
$NICS = Get-NetAdapter | select name
Now when just issuing the command $NICS it shows the list of names, but since I want to rename however many of NICs I have individually I have to break the variable down into different strings. It would be awesome if it would even count the amount and then implement my script with an if statement or foreach!
But for now I would be happy with a solution to rename a specific amount (in my case it's four).
$NICS = Get-NetAdapter | select name
for ($i = 0; $i -lt $NICS.Count; $i++) {
Write-Host (($NICS[$i]) -replace("#{name=","") -replace("}",""))
}
That is a good starting point I think.
Use foreach for that:
$NICS = Get-NetAdapter | select name
foreach ($n in $nics)
{
write-host "Nick name " $n.name
}
I am novice programmer of powershell, I am trying to do excel search and change of format and font option. Here is the snippet were I am trying to search for the word "PASSED" and change the color to green and bold, currently the code does exits out without changing as expected what is wrong in this which I could not figure out, need help in this regards.
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $False
$workbook = $excel.Workbooks.Open("C:\test.xlsx")
$sheet = $workbook.ActiveSheet
$xlCellTypeLastCell = 11
$used = $sheet.usedRange
$lastCell = $used.SpecialCells($xlCellTypeLastCell)
$row = $lastCell.row # goes to the last used row in the worksheet
for ($i = 1; $i -lt $row.length; $i++) {
If ($sheet.cells.Item(1,2).Value() = "PASSED") {
$sheet.Cells.Item(1,$i+1).Font.ColorIndex = 10
$sheet.Cells.Item(1,$i+1).Font.Bold = $true
}
}
$workbook.SaveAs("C:\output.xlsx")
$workbook.Close()
Input(test.xlsx) file has the following
Module | test | Status
ABC a PASSED
Its quiet a huge file with different status of each unit test.
$row is a string containing the last row number, comparing to it's Length property in the for loop will land you in trouble since it'll give you the length of the string itself.
Change it to:
for ($i = 1; $i -lt $row; $i++) {
In the if statement inside the loop, there's another problem: =
In order to compare two values for equality, use the -eq operator instead of = (= is only for assignment):
if ($sheet.cells.Item($i,2).Value() -eq "PASSED") {
$sheet.Cells.Item(1,$i+1).Font.ColorIndex = 10
$sheet.Cells.Item(1,$i+1).Font.Bold = $true
}
Lastly, Excel cell references are not zero-based, so Item(1,2) will refer to the cell that in your example has the value "test" (notice how it takes a row as the first parameter, and a column as the second). Change it to Item(2,3) to test against the correct cell, and transpose the cell coordinates inside the if block as well.
You may want to update the for loop to reflect this as well:
for ($i = 2; $i -le $row; $i++) {
if ($sheet.cells.Item($i,3).Value() = "PASSED") {
$sheet.Cells.Item($i,3).Font.ColorIndex = 10
$sheet.Cells.Item($i,3).Font.Bold = $true
}
}
I'm trying to set up a script to monitor IIS 7.5 logs fro 500 errors. Now I can get it to do that OK but I would like it to check every 30 minutes. Quite naturally I don't want it to warn me about the previous 500 errors it has already reported.
As you can see from the script below I have added a $time variable to take this into account, however I can't seem to find a way to use this variable. Any help would be appreciated.
#Set Time Variable -30
$time = (Get-Date -Format hh:mm:ss (Get-Date).addminutes(-30))
# Location of IIS LogFile
$File = "C:\Users\here\Documents\IIS-log\"+"u_ex"+(get-date).ToString("yyMMdd")+".log"
# Get-Content gets the file, pipe to Where-Object and skip the first 3 lines.
$Log = Get-Content $File | where {$_ -notLike "#[D,S-V]*" }
# Replace unwanted text in the line containing the columns.
$Columns = (($Log[0].TrimEnd()) -replace "#Fields: ", "" -replace "-","" -replace "\(","" -replace "\)","").Split(" ")
# Count available Columns, used later
$Count = $Columns.Length
# Strip out the other rows that contain the header (happens on iisreset)
$Rows = $Log | where {$_ -like "*500 0 0*"}
# Create an instance of a System.Data.DataTable
#Set-Variable -Name IISLog -Scope Global
$IISLog = New-Object System.Data.DataTable "IISLog"
# Loop through each Column, create a new column through Data.DataColumn and add it to the DataTable
foreach ($Column in $Columns) {
$NewColumn = New-Object System.Data.DataColumn $Column, ([string])
$IISLog.Columns.Add($NewColumn)
}
# Loop Through each Row and add the Rows.
foreach ($Row in $Rows) {
$Row = $Row.Split(" ")
$AddRow = $IISLog.newrow()
for($i=0;$i -lt $Count; $i++) {
$ColumnName = $Columns[$i]
$AddRow.$ColumnName = $Row[$i]
}
$IISLog.Rows.Add($AddRow)
}
$IISLog | select time,csuristem,scstatus
OK With KevinD's help and PowerGUI with a fair bit of trial and error, I got it working as I expected. Here's the finished product.
#Set Time Variable -30
$time = (Get-Date -Format "HH:mm:ss"(Get-Date).addminutes(-30))
# Location of IIS LogFile
$File = "C:\Users\here\Documents\IIS-log\"+"u_ex"+(get-date).ToString("yyMMdd")+".log"
# Get-Content gets the file, pipe to Where-Object and skip the first 3 lines.
$Log = Get-Content $File | where {$_ -notLike "#[D,S-V]*" }
# Replace unwanted text in the line containing the columns.
$Columns = (($Log[0].TrimEnd()) -replace "#Fields: ", "" -replace "-","" -replace "\(","" -replace "\)","").Split(" ")
# Count available Columns, used later
$Count = $Columns.Length
# Strip out the other rows that contain the header (happens on iisreset)
$Rows = $Log | where {$_ -like "*500 0 0*"}
# Create an instance of a System.Data.DataTable
#Set-Variable -Name IISLog -Scope Global
$IISLog = New-Object System.Data.DataTable "IISLog"
# Loop through each Column, create a new column through Data.DataColumn and add it to the DataTable
foreach ($Column in $Columns) {
$NewColumn = New-Object System.Data.DataColumn $Column, ([string])
$IISLog.Columns.Add($NewColumn)
}
# Loop Through each Row and add the Rows.
foreach ($Row in $Rows) {
$Row = $Row.Split(" ")
$AddRow = $IISLog.newrow()
for($i=0;$i -lt $Count; $i++) {
$ColumnName = $Columns[$i]
$AddRow.$ColumnName = $Row[$i]
}
$IISLog.Rows.Add($AddRow)
}
$IISLog | select #{n="Time"; e={Get-Date -Format "HH:mm:ss"("$($_.time)")}},csuristem,scstatus | ? { $_.time -ge $time }
Thanks again Kev you're a good man. Hope this code helps someone else out there.
Here's
Try changing your last line to:
$IISLog | select #{n="DateTime"; e={Get-Date ("$($_.date) $($_.time)")}},csuristem,scstatus | ? { $_.DateTime -ge $time }
In the select, we're concatenating the date and time fields, and converting them to a date object, then selecting rows where this field is greater than your $time variable.
You'll also need to change your $time variable:
$time = (Get-Date).AddMinutes(-30)
You want a DateTime object here, not a string.