Powershell - combining multiple for each into a single output - powershell

Good morning everyone,
I am still learning powershell and have a script that my company run's. I have adjusted it slightly and it works well. however...
Overview
Script pulls in a CSV file and then for each device on the CSV it logs in and grabs all of the VIP information and then outputs it to a CSV that is dated and titled with the device name.
Ask
I would like adjust the script so that instead of having 50+ CSV files I could have a single CSV file with an extra column that would like the device name that all the VIPS are on. How do I do that?
Current Script
$user = "user"
$pass1 = Read-Host "Enter Netscaler Password"
$Devicelist = Import-Csv'C:\Users\user\Documents\20221110\20221109_Citrix_inventory_Master1.csv'
foreach ($device in ($Devicelist | ? { $_.fqdn -match "nsr" -and $_.State -match "Primary" -and $_.Configuration_viewable_with_Techops_login -match "Yes" })) {
Write-Host "Attempting to connect to $($device.fqdn)"
$SecurePassword = ConvertTo-SecureString $pass1 -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($user, $SecurePassword)
$session = Connect-NetScaler -Hostname $device."IP address" -Credential $Credential -PassThru
$nsVIPs = Get-NSLBVirtualServer | select name, ipv46, port, curstate
$nsVIPs | Out-File C:\Users\user\Documents\20221110\VIPS\$(get-date -f yyyyMMdd)"_"$($device.fqdn)-"vips.csv"
}
Current CSV Input File format
Current output file format
What I would like to out file format to be
**
What have I tried
**
At the moment nothing except for research, I am guessing that I will need to hold of of the info in an array and then output it at the end. I just don't have a clue how to do that.
Thanks for looking and helping
Neil

You can change the code to first collect all data in one single variable $result and after the loop write all that out in a single CSV file.
To write csv, you need to use Export-Csv, not Out-File, which is intended to write simple text, not objects.
$user = "user"
$pass1 = Read-Host "Enter Netscaler Password"
$SecurePassword = ConvertTo-SecureString $pass1 -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($user, $SecurePassword)
$today = '{0:yyyyMMdd}' -f (Get-Date)
$Devicelist = Import-Csv -Path 'C:\Users\user\Documents\20221110\20221109_Citrix_inventory_Master1.csv' |
Where-Object { $_.fqdn -match "nsr" -and
$_.State -match "Primary" -and
$_.Configuration_viewable_with_Techops_login -match "Yes" }
$result = foreach ($device in $Devicelist) {
Write-Host "Attempting to connect to $($device.fqdn)"
$session = Connect-NetScaler -Hostname $device.'IP address' -Credential $Credential -PassThru
Get-NSLBVirtualServer |
Select-Object name, ipv46, port, curstate, #{Name = 'Device Name'; Expression = {$device.fqdn}}
}
# now write out the csv file just once
$result | Export-Csv -Path "C:\Users\user\Documents\20221110\VIPS\$($today)_vips.csv" -NoTypeInformation

Related

Powershell variable script

Another week another powershell question. First off thank you all for your help I am learning a lot and I am thinking that I know the answer but can't seem to get it out of my head into the script today.
I currently have this.
$user = "user"
$pass1 = Read-Host "Enter Techops Password"
$SecurePassword = ConvertTo-SecureString $pass1 -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($user, $SecurePassword)
$querylist = (Import-Csv -Path 'C:\Users\user\Documents\20221110\VIPS\20221115_vips1.csv').ip
$today = '{0:yyyyMMdd}' -f (Get-Date)
Import-Module tm-device42
Connect-D42 -Credential $Credential
$results = foreach ($ip in ($querylist)) {
Get-vServerPrdFromPim {$_.ip}
}
$results | Write-Output
The $results | Write-output wont be staying I'm just using it whilst building the script.
The $querylist = (Import-Csv -Path 'C:\Users\user\Documents\20221110\VIPS\20221115_vips1.csv').ip returns the correct info, currently a single IP address 10.10.10.1 (example)
However I get a result of product not found on the Get-vServerPrdFromPim (this is an internal custom made module) but if I do
Get-vServerPrdFromPim 10.10.10.1 in powershell I get the answers that I would expect.
user> (Import-Csv -Path 'C:\Users\user\Documents\20221110\VIPS\20221115_vips1.csv').ip
10.75.230.74
So I am assuming it is an issue with my foreach statement.
I am just wanting to pull the IP's from a large sheet and check them against a database and then output the data.
Am I correct in thinking that I haven't correctly formatted my foreach statement? If so how do I make $ip reference the info from $querylist?
Kind regards
-------------UPDATE --------------------
I have adjusted the following code as suggested
Get-vServerPrdFromPim $ip
So now the foreach loop looks like
$results = foreach ($ip in ($querylists)) {
Get-vServerPrdFromPim $ip | select Name, ProductCode, NetAddr, InfrastructureOwner, OperatingSystemOwner
}
This seems to work fine for a file with a single IP address but when I add additional IP's to the CSV it only processes the first IP.
Will need to dig in further.
Further Update. As requested this is what the excel sheet looks like. This is just an extract.
Found the mistake in my code. Thanks to #mathias and also other research. Code ended up being
$user = "user"
$pass1 = Read-Host "Enter Techops Password"
$SecurePassword = ConvertTo-SecureString $pass1 -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($user, $SecurePassword)
$ips = (Import-Csv -Path 'C:\Users\user\Documents\20221110\VIPS\20221115_vips.csv').ip
$today = '{0:yyyyMMdd}' -f (Get-Date)
Import-Module device42
Connect-D42 -Credential $Credential
$results = foreach ($ip in $ips){
Get-vServerPrdFromPim $ip | select Name, ProductCode, NetAddr, InfrastructureOwner, OperatingSystemOwner
}
$results | Export-Csv C:\Users\user\Documents\20221110\D42_test.csv

Importing CSV and using Get-Hotfix to export to CSV

So, I'm having some difficulty with some code I'm trying to use to get hotfixes from a lot of computers (which are listed in a CSV file under the column "IP Address") and export that result to a csv. They each require a local computer account to log in (in the same CSV under the column "CPU Name"). I don't really care if it's one csv for the whole thing or a csv for each result. Here's the code so far:
$ipaddress = [What do I put here?]
$cpuname = [What do I put here?]
$OutputFile = 'MyFolder\Computer.csv'
$Username = '$cpuname\MyUsername' [Is this ok?]
$Password = 'MyPassword'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$SecureString = $pass
$MySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username,$SecureString
$Computers = Import-CSV "C:\MyFolder\Computers.csv"
ForEach ($ipaddress in $Computers) {
}
try
{
Get-HotFix -Credential $MySecureCreds -ipaddress $IPAddress | Select-Object PSComputerName,HotFixID,Description,InstalledBy,InstalledOn | export-csv $OutputFile
}
catch
{
Write-Warning "System Not reachable:$ipaddress"
}
Am I close?
The IP Address and the Computer Name are coming from the CSV, so you don't need to statically define them.
Regarding the username, a couple things:
You need to use double quotes to expand.
Also you'll need to read the 'CPU Name' property one way to do this
would be using a subexpression inside of the double quoted larger expression e.g. "$($variable.property)more text". Or you could concatenate the string $variable.property + 'more text'
Since CPU Name has a space in the column name you'll need to enclose that in quotes.
Since the User name comes from the Computer name which comes from the
CSV, defining the User name variable needs to be in the foreach loop.
The security practices in this script are questionable, but outside the scope of the question. e.g. Saving passwords in scripts, especially a local account with administrative privileges to a large number of networked machines that all have that same password...
$InputFile = 'C:\MyFolder\Input.csv'
$OutputFile = 'C:\MyFolder\Output.csv'
$Password = Read-Host | ConvertTo-SecureString -AsPlainText -Force
$Computers = Import-CSV $InputFile
$HotfixOutput = foreach ($Computer in $Computers) {
$Username = "$($Computer.'CPU Name')\MyUsername"
$MySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username,$Password
try {
Get-HotFix -Credential $MySecureCreds -ipaddress $Computer.'IP Address' | Select-Object PSComputerName, HotFixID, Description, InstalledBy, InstalledOn
}
catch {
Write-Warning "System Not reachable: $($Computer.'IP Address')"
}
}
$HotfixOutput | Export-Csv $OutputFile -NoTypeInformation
Remove-Variable Password
Remove-Variable MySecureCreds

Having trouble writing Powershell output to csv file

I'm a PowerShell newbie trying to write a simple script to look up the number of times a specific user has logged into a workstation, and export that information in a useful way to a CSV file so it can be easily manipulated. The CSV file only really needs to contain the time of login and the username mentioned in the "Message" section of the Security log entry.
My problem is it seems I can either get a CSV file with a truncated "Message" no containing the username, or I get all the information I want printed to host instead of exporting to CSV. I'm sure the solution is probably very basic, but like I said I'm a newbie.
In the code posted here I get everything I need printed to host, but I can't seem to get it into a CSV file. Any help would be appreciated.
New-Item -Name "UserLoginHistory" -Path C:\ -ItemType Directory -Force | Out-Null
$UserName = Read-Host -Prompt 'Which user are you searching for?'
$a =Get-EventLog -LogName Security -Message "*$UserName*" | Where-Object {$_.EventID -eq 4624}
foreach($item in $a)
{
$timeLog = $item.TimeGenerated
$item = $item.Message.Split(":")
$subject = $item[3].split()
#$subject[2]
$NewLogin = $item[14].split()
#$NewLogin[2]
$WorkstationName = $item[26].split()
#$WorkstationName[1]
$SourceNetworkAddress = $item[27].split()
#$SourceNetworkAddress[1]
"Time: $timeLog Subject: $($subject[2]) NewLogin: $($NewLogin[2]) WorkstationName $($WorkstationName[1]) SourceNetworkAddress $($SourceNetworkAddress[1])"
}
Export-Csv -Path C:\UserLoginHistory\LoginHistory.csv
Don't reuse the variable $item of the foreach inside the {scrript block} for other purposes.
create a [PSCustomObject] and emit it to a gathering variable for the whole foreach
Untested template:
New-Item -Name "UserLoginHistory" -Path C:\ -ItemType Directory -Force | Out-Null
$UserName = Read-Host -Prompt 'Which user are you searching for?'
$Events = Get-EventLog -LogName Security -Message "*$UserName*" | Where-Object {$_.EventID -eq 4624}
$Data = foreach($Event in $Events){
$item = $Event.Message.Split(":")
[PSCustomObject]#{
Time = $Event.TimeGenerated
Subject = $item[3].split()[2]
NewLogin = $item[14].split()[2]
WorkstationName = $item[26].split()[1]
SourceNetworkAddress = $item[27].split()[1]
}
}
$Data | Format-Table -Autosize *
$Data | Out-Gridview
$Data | Export-Csv -Path C:\UserLoginHistory\LoginHistory.csv -NoTypeInformation
Try stuffing your results into an array like this untested code.
New-Item -Name "UserLoginHistory" -Path C:\ -ItemType Directory -Force | Out-Null
$UserName = Read-Host -Prompt 'Which user are you searching for?'
$a =Get-EventLog -LogName Security -Message "*$UserName*" | Where-Object {$_.EventID -eq 4624}
$ReportOutPut = #() # An array to hold your output.
foreach($item in $a)
{
$timeLog = $item.TimeGenerated
$item = $item.Message.Split(":")
$subject = $item[3].split()
#$subject[2]
$NewLogin = $item[14].split()
#$NewLogin[2]
$WorkstationName = $item[26].split()
#$WorkstationName[1]
$SourceNetworkAddress = $item[27].split()
#$SourceNetworkAddress[1]
"Time: $timeLog Subject: $($subject[2]) NewLogin: $($NewLogin[2]) WorkstationName $($WorkstationName[1]) SourceNetworkAddress $($SourceNetworkAddress[1])"
$ReportOutput += [pscustomobject] #{
Time = $timeLog;
Subject = $subject[2];
NewLogin = $NewLogin[2];
WorkstationName = $WorkstationName[1];
SourceNetworkAddress = $SourceNetworkAddress[1]
} # Custom objec to be exported via csv
}
Export-Csv -InputObject $ReportOutPut -NoTypeInformation -Path C:\UserLoginHistory\LoginHistory.csv

automate sitecollection administrator assignment in sharepoint online with powershell for backup purposes

I was asked to create a powershell script to automate the assignment for new sitecollection administrator in SharePoint-Online for BackUp purposes NetApp CloudControl.
This is my firsttime ever in PowerShell and now I got stucked and don't know where to look anymore or least don't understand what I'm looking at.
The script is supposed to do the following:
Get Microsoft-tenant and password
Create a new ps-script where the credentials are already filled in
Connect to sharepoint-online and lookup personal space for every user(onedrive for business sites)
cut the log and create a second one if more than 200 lines were written
read the log and make the service-account a sitecollectionadmin
create task to run the created script once per week
At the moment I got it to do this:
Get Microsoft-tenant and password
Save Credentials
Connect to sharepoint-online and lookup personal space for every user(onedrive for business sites)
read the log and make the service-account a sitecollectionadministrator
Can anyone of you please help me out on how to proceed with the next steps?
P.S. Please excuse that I'm posting the script as a whole, I just didn't know what I should cut out.
$TenantName = $null0
$TenantPassword = $null1
if($TenantName -eq $null0){
$TenantName = Read-Host "Enter Office 365 - Tenant Name."
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$TenantName = \$null0$',"`$TenantName = '$TenantName'"}
$NewScript | Out-File $PSCommandPath -Force
}
if($TenantPassword -eq $null1){
$TenantPassword = Read-Host "Enter Password for netapp-service#$($TenantName).onmicrosoft.com."
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$TenantPassword = \$null1$',"`$TenantPassword = '$TenantPassword'"}
$NewScript | Out-File $PSCommandPath -Force
}
$username = "netapp-service#$($TenantName).onmicrosoft.com"
$cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $userName, $(convertto-securestring $TenantPassword -asplaintext -force)
Connect-SPOService -Url https://$($TenantName)-admin.sharepoint.com/ -Credential $cred
$AdminURI = "https://$($TenantName)-admin.sharepoint.com"
$AdminAccount = "netapp-service#$($TenantName).onmicrosoft.com"
$AdminPass = $TenantPassword
$eDiscoveryUser = "netapp-service#$($TenantName).onmicrosoft.com"
$MySitePrefix = "https://$($TenantName)-my.sharepoint.com"
$LogFile = '.\$TenantName\$TenantName-MySites.txt'
$MySiteListFile = '.\$TenantName\$TenantName-MySites.txt'
Connect-SPOService -Url $AdminURI -Credential $cred
$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")
$sstr = ConvertTo-SecureString -string $AdminPass -AsPlainText –Force
$AdminPass = ""
$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminAccount, $sstr)
$proxyaddr = "$AdminURI/_vti_bin/UserProfileService.asmx?wsdl"
$UserProfileService= New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False
$UserProfileService.Credentials = $creds
$strAuthCookie = $creds.GetAuthenticationCookie($AdminURI)
$uri = New-Object System.Uri($AdminURI)
$container = New-Object System.Net.CookieContainer
$container.SetCookies($uri, $strAuthCookie)
$UserProfileService.CookieContainer = $container
$UserProfileResult = $UserProfileService.GetUserProfileByIndex(-1)
Write-Host "Starting- This could take a while."
Out-File $LogFile -Force
$NumProfiles = $UserProfileService.GetUserProfileCount()
$i = 1
While ($UserProfileResult.NextValue -ne -1)
{
Write-Host "Examining profile $i of $NumProfiles"
$Prop = $UserProfileResult.UserProfile | Where-Object { $_.Name -eq "PersonalSpace" }
$Url= $Prop.Values[0].Value
if ($Url) {
$Url | Out-File $LogFile -Append -Force
}
$UserProfileResult = $UserProfileService.GetUserProfileByIndex($UserProfileResult.NextValue)
$i++
}
Write-Host "Done!"
$reader = [System.IO.File]::OpenText($MySiteListFile)
try {
for(;;) {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$fullsitepath = "$MySitePrefix$line"
Write-Host "Operating on $fullsitepath "
$fullsitepath = $fullsitepath.trimend("/")
Write-Host "Making $eDiscoveryUser a Site Collection Admin"
Set-SPOUser -Site $fullsitepath -LoginName $eDiscoveryUser -IsSiteCollectionAdmin $true
}
}
finally {
$reader.Close()
}
Disconnect-SPOService
Write-Host "Done!"

Reading values from CSV files and storing in local variable in PowerShell

I am stuck at one point, the requirement is I have to store the Username, Password, Hostname & hostkey in a CSV file and I have to read & store the values in local variable which can be used for establishing SFTP connection.
My CSV looks like this:
HostName,Username,Password,SshHostKeyFingerprint
abc.com,Lear,qwert,ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx...
The code which I am using to read and store the different columns values is:
Add-Type -Path "WinSCPnet.dll"
$csv = Import-Csv c:\test\output.csv
$csv | ForEach-Object
{
$Hostname = $_.hostname
$username = $_.username
$Password = $_.Password
"$Hostname - $username -$Password"
}
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = $Hostname
UserName = $username
Password = $Password
SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
}
Nothing is getting displayed, when trying to display the values.
The script block after the ForEach-Object cmdlet has to start on the same line. Otherwise PowerShell won't connect them together.
$csv | ForEach-Object {
$HostName = $_.HostName
$Username = $_.Username
$Password = $_.Password
"$HostName - $Username - $Password"
}
Another problem, that your will face eventually, is that your code does process only the last line in the CSV file.
You most probably actually want to process the parsed out values within the ForEach-Object script block. Like this:
$csv | ForEach-Object {
$HostName = $_.HostName
$Username = $_.Username
$Password = $_.Password
"$HostName - $Username - $Password"
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = $HostName
UserName = $Username
Password = $Password
SshHostKeyFingerprint = ...
}
# ...
}