So, to continue my lovely journey through powershell from here:
Loop for two variables
I have a ps1 that runs a loop for a bunch of transactions and a bunch of nodes and sends them over to a csv file.
$url = "https://someserver/trans="
$transactions = '1','2','3','4' #There are 4 transactions
$nodes = 'node1','node2','node3','node4','node5','node6' #There are 10 nodes
Remove-Item ATM.csv -Force
# So far so good
# Below is what I'd use as a function in bash. No sure what/how to do in PS:
#OUTPUT:
foreach($transaction in $transactions)
{
foreach($node in $nodes)
{
"$transaction;$node" |out-file -Append ATM.csv
curl -k -u user#pass $url$transaction$node | findstr "<value>" | out-file -Append ATM.csv
}
}
Opening the file in excel, I end up with this output under column A:
transaction1;node1 (in the first row, left-most cell)
value1 (from the curl. It's actually a number and it sits in the row right under the first entry)
and so on and so forth for 2,3, and the rest. only the left most column (column A) gets populated.
What I'd like to get is a way to place the values in three columns, such that the csv will look like:
Column A | Column B | Column C
transaction1| node1 | valueX
transaction2| node2 | valueY
and so on. The script or another will have to do this, the end user for this job who'll run the script will not open excel every day and start running macros, he needs the final csv ready from the script.
Whatever shall I do?
Something like this will fix your issues, the only bit that's not included is selecting the value itself from Invoke-WebRequest (curl) as that will change depending on what's returned.
foreach($transaction in $transactions)
{
foreach($node in $nodes)
{
$value = Invoke-WebRequest -Uri $url$transaction$node -UseBasicParsing | Select-Object -Expand Content
Add-Content -Path ATM.csv -Value "$transaction,$node,$value"
}
}
You are currently writing your output in two different lines. One solution could be to use the NoNewLine parameter in the Out-File:
"$transaction;$node" |out-file -Append ATM.csv -nonewline
curl -k -u user#pass $url$transaction$node | findstr "<value>" | out-file -Append ATM.csv
Personally I would create a Powershell Object and create the csv at the end:
$array = #()
foreach($node in $nodes) {
$obj = New-Object psobject
$obj | Add-Member -MemberType NoteProperty -Name 'Transaction' -Value $transaction
$obj | Add-Member -MemberType NoteProperty -Name 'Node' -Value $node
$obj | Add-Member -MemberType NoteProperty -Name 'Value' -Value (curl -k -u user#pass $url$transaction$node | findstr "<value>")
$array += $obj
}
Related
I used the below one it gives somewhat different in excel ,please help me on this
#Disk Space
Get-Volume
$results = Get-Volume | Export-Csv -Path C:\temp\software1.csv
Note: I need health check , Drive Name, Free space , size, disk type in excel
Thanks in advance friends :)
Generally speaking, when you run a powershell command it only shows what sections are deemed as important. If you take the same command and pipe it to format-list (or "ft" for short) you will get everything.
Get-Volume | ft
When exporting it exports everything.
Also, you need to add the paramater -NoTypeInformation to get rid of the first row.
To only get certain values, you will just pipe it using select.. something like this:
Get-Volume | select HealthStatus, DriveLetter, SizeRemaining,DriveType | Export-Csv -NoTypeInformation -Path C:\temp\software1.csv
Also, there is no need to do $results = get-volume... This pushes the output into the variable $results. This would be applicable if you wanted to recall the variable later. So, you could also do something like this..
$results = Get-Volume
$results | select HealthStatus, DriveLetter, SizeRemaining, DriveType | Export-Csv -NoTypeInformation -Path C:\temp\software1.csv
Keep in mind you need to have the Import-Excel Module loaded but you should be able to use this to output to Excel.
#check-DiskSpace_FSs.ps1
import-module activedirectory
$dc = "domainController09"
$currentDate = get-date -Format yyyyMMdd_HHmm
$path = "\\UNC\export\FileServer_DiskSpace\FileServer_DiskSpace_$currentDate.xlsx"
$smtpServer = "10.10.10.10"
$from = "me#somewhere.com"
$to = "me#somewhere.com"
$subject = "Server FS diskspace - $date"
$ServerFSs = get-adcomputer -Server $dc -SearchBase "OU=fs,OU=Server,DC=somewhere,DC=com" -filter * | select name | sort Name
$DriveSize = foreach ($FS in $somewhereFSs)
{
get-WmiObject win32_logicaldisk -ComputerName $FS.name -Filter "Drivetype=3" | select SystemName,DeviceID,#{n="TotalSize(GB)";e={$_.Size / 1gb -as [int] }}`
,#{n="FreeSize(GB)";e={$_.freespace / 1gb -as [int] }}`
,#{n="FreeSize(%)";e={[int]($_.Freespace*100/$_.Size)}},VolumeName | Export-Excel -Path $path -append -FreezeTopRow -BoldTopRow -AutoSize -AutoFilter
}
Send-Mailmessage -smtpServer $smtpServer -from $from -to $to -subject $subject -Attachments $path -priority High
I'm trying to split a URL into an object.
$url = "https://api.somedomain.com/v2/direct-access/producing-entities-details?entity_id=104194825&format=json&page=1
The desired result would be
PS C:\WINDOWS\system32> $url.api
https://api.somedomain.com/v2/direct-access
PS C:\WINDOWS\system32> $url.dataset
producing-entities-details
PS C:\WINDOWS\system32> $url.params
entity_id=104194825&format=json&page=1
I'm sure this can be done in combination with regex, but I am also wondering if this can be done just using built in PowerShell functionality.
No need to mess around with regex. The [uri] type accelerator would do some of that work for you. The other parts seem specific to how you choose to interpret the data and not how URL anatomy works.
PS C:\Users\matt> $url = [uri]"https://api.somedomain.com/v2/direct-access/producing-entities-details?entity_id=104194825&format=json&page=1"
PS C:\Users\matt> $url.Query
?entity_id=104194825&format=json&page=1
You can explore the other properties and see how they will help you. For instance, you might need to build the Segments to get the other parts you are looking for.
PS C:\Users\matt> $url.Segments
/
v2/
direct-access/
producing-entities-details
$url = "https://api.somedomain.com/v2/direct-access/producing-entities-details?entity_id=104194825&format=json&page=1"
$uri = [System.Uri]$url
$ParsedQueryString = [System.Web.HttpUtility]::ParseQueryString($uri.Query)
$i = 0
$queryParams = #()
foreach($QueryStringObject in $ParsedQueryString){
$queryObject = New-Object -TypeName psobject
$queryObject | Add-Member -MemberType NoteProperty -Name Query -Value $QueryStringObject
$queryObject | Add-Member -MemberType NoteProperty -Name Value -Value $ParsedQueryString[$i]
$queryParams += $queryObject
$i++
}
$queryParams
Output:
Query Value
----- -----
entity_id 104194825
format json
page 1
I previously had asked a question regarding adding together files and folders with a common name and having them summed up with a total size (Sum of file folder size based on file/folder name). This was successfully answered with the PS script below:
$root = 'C:\DBFolder'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = (Get-ChildItem "$root\$_*\*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum ) / 1GB
}
}
This now leaves me with a list that is ordered by the 'Database' Property by default. I have attempted to use a Sort-Object suffix to use the 'Size' property with no joy. I have also attempted to use Export-Csv with confounding results.
Ideally, if I could pass the results of this script to Excel/CSV so I can rinse/repeat across multiple SQL Servers and collate the data and sort within Excel, I would be laughing all the way to the small dark corner of the office where I can sleep.
Just for clarity, the output is looking along the lines of this:
Database Size
-------- ----
DBName1 2.5876876
DBName2 4.7657657
DBName3 3.5676578
Ok, it was one pipe character that I had missed when using the Export-csv function. This resolved my problem.
$root = 'C:\DB\Databases'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = (Get-ChildItem "$root\$_*\*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum ) / 1GB
}
} | Export-Csv 'C:\Test\test.csv'
Ok heres what I have code wise:
$a = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\*.csv"
$b = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
(get-content $a) | set-content $b
This pulls all the data of all the files into one merged file, but I need one additional item, I need to pull the name of the individual files and append it to the first column of the file for multiple files, several hundred at a time.
Not tested but something like this should do it:
$a = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\*.csv"
$b = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
Get-ChildItem $a | % {
Import-Csv $_.Fullname | Add-Member -MemberType NoteProperty -Name 'File Name' -Value $_.Name
} | Export-Csv $b
Assuming the CSV files each have the same column headings, I would lean toward using Import-CSV instead of Get-Content so that you can work with the CSV contents as arrays of objects with named properties.
Then all you need to do is iterate through each item of the array and append a property containing the file path, which you can do using the Add-Member cmdlet. Once that's done, export the array of objects using the Export-CSV cmdlet.
$directory = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\"
$search = $directory + "*.csv"
$exportpath = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
$paths = get-childitem $search
$objectArrays = #()
$paths | %{
$filepath = $_.fullname;
$objectArray = Import-CSV $filepath;
$objectArray | %{
Add-Member -inputobject $_ -Name "SourceFile" -Value $filepath -MemberType NoteProperty};
$objectArrays += $objectArray}
$objectArrays | export-csv -path $exportpath -notype
This puts the SourceFile property as the last column in the outputted CSV file
Ok, simplification... Search target folder, pipe to a ForEach-Object loop (shorthand % used), capture the file name as variable, import the CSV, add the sourcefile using the Select-Object cmdlet, convert it back to a CSV, end loop, pipe to destination file.
$a = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\*.csv"
$b = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
GCI $a | %{$FileName=$_.Name;Import-CSV $_|Select #{l='SourceFile';e={$FileName}},*|ConvertTo-CSV -NoType} | set-content $b
I have part of the code: at the moment its coming empty in the CSV file. But i need a command to specify the path/folders to look at, how do i modify this for that purpose.
Param(
[String]$path,
[String]$outfile = ".\outfile.csv"
)
$output = #()
ForEach ($item in (Get-ChildItem -Path $path -Recurse -Directory)) {
ForEach ($acl in ($item.GetAccessControl().Access)){
$output += $acl |
Add-Member `
-MemberType NoteProperty `
-Name 'Folder' `
-Value $item.FullName `
-PassThru
}
}
$output | Export-Csv -Path $outfile -NoTypeInformation
Ok, let's do this. I've made it into a function, and removed the OutFile part of it. If you want to output it to a file, pipe it to Export-CSV. If you want it saved as a variable, assign it to a variable. Just simpler this way.
Function Get-RecursiveACLs{
Param(
[String]$Path=$(Throw "You must specify a path")
)
$Output = GCI $Path -Recurse -Directory|%{
$PathName=$_.FullName
$_.GetAccessControl().Access|%{
Add-Member -InputObject $_ -NotePropertyName "Path" -NotePropertyValue $PathName -PassThru
}
}
}
Then it's a simple matter of storing it in a variable like:
$ACLList = Get-RecursiveACLs "C:\Example\Path"
Or piping it to output to a CSV if you would prefer:
Get-RecursiveACLs "C:\Example\Path" | Export-CSV "C:\Results.csv" -NoType
Put the function at the top of your script and call it as needed.