how to run the powershell script with 2 foreach in c# - c#

This is the powershell script I want to run in c# :
ForEach ($Mailbox in Get-Mailbox) {Get-ActiveSyncDeviceStatistics -Mailbox
$Mailbox.Identity –ErrorAction SilentlyContinue |
SelectDeviceFriendlyName,Devicetype,DeviceUserAgent | ForEach-Object { $_ | Add-Member –
MemberType NoteProperty -Name "MailboxIdentity" -value $Mailbox}}
I could complete the c# coding upto first foreach loop in powershell script, but I do not know how implement the 2nd foreach that uses $mailbox variable along with the coding given below.
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("Get-Mailbox");
command.AddCommand("where-object");
command.AddParameter("Filterscript", ScriptBlock.Create("!$_.name.startswith \"DiscoverySearchMailbox\")"));
powershell.Commands = command;
powershell.Runspace = CreateRunSpace.GetRunSpace();
var result = powershell.Invoke();
 
PSCommand command1 = new PSCommand();
command1.AddCommand("write-output");
command1.AddParameter("InputObject", result);
command1.AddCommand("Foreach-Object");
command1.AddParameter("Process", ScriptBlock.Create("Get-ActiveSyncDeviceStatistics -Mailbox $_.Identity"));
powershell.Commands = command1;
powershell.Runspace =
CreateRunSpace.GetRunSpace();
var result1 = powershell.Invoke();
I'm stuck at 2nd foreach loop to add-member while adding the output of get-mailbox.
Appreciate your help and suggestions in advance. Thank you.

Related

how to identify query statement has a subquery in it?

Developing an C# project for SQL Training and giving different exercises based on training on each topic. One of the exercise is to write a query using Sub-Query. which needs to be evaluated whether the user has used/implemented Sub query in the Query Statment.
Q: Write a sql query to show the SalesOrderID,LineTotal,average LineTotal from the Sales.SalesOrderDetail table using Sub query
Select SalesOrderID,LineTotal [LineTotal],
(Select AVG(LineTotal) from Sales.SalesOrderDetail) as [AverageLineTotal]
from Sales.SalesOrderDetail
[AverageLineTotal] is an sub query.
Can we identify it by any means?? like execution plan Or SP to identify it has an sub query in the statement
Is there any way to identify it through execution Plans??
If this is a c# project you can parse the query with regex to find if the query contains (select {any other text}).
public static void Main()
{
var sql = #"Select SalesOrderID,LineTotal [LineTotal],(Select AVG(LineTotal) from Sales.SalesOrderDetail) as [AverageLineTotal] from Sales.SalesOrderDetail";
Console.WriteLine(DoesSqlContainSubquery(sql));
}
public bool DoesSqlContainSubquery(string sql)
{
var regexTest = new Regex(#"\( *Select .*\)", RegexOptions.IgnoreCase);
var containsSubquery = regexTest.IsMatch(sql);
return containsSubquery;
}
Parsing ad-hoc scripts is inherently complex due to the plethora T-SQL constructs and options. That being said, a robust method for targeted use cases is parsing scripts with the Microsoft.SqlServer.TransactSql.ScriptDom.
Below is an example PowerShell script that uses the script DOM assembly from the official Microsoft Dacfx NuGet package, downloading and extracting it if needed.
# Add TSqlScript DOM assembly reference, downloading and extracting to the specified location if needed
$scriptDomAssemblyPath = "C:\Temp\Microsoft.SqlServer.TransactSql.ScriptDom.dll"
$scriptDomNuGetUrl = "https://www.nuget.org/api/v2/package/Microsoft.SqlServer.DacFx.x64/150.4384.2"
if(![System.IO.File]::Exists($scriptDomAssemblyPath)) {
$response = Invoke-WebRequest -Uri $scriptDomNuGetUrl
if ($response.StatusCode -ne 200) {
throw "Unable to download Microsoft.SqlServer.TransactSql.ScriptDom NuGet package: $response.StatusCode : $response.StatusDescription"
}
$tempZipFilePath = "$([System.IO.Path]::GetTempPath())/$([System.IO.Path]::GetRandomFileName()).zip"
[System.IO.File]::WriteAllBytes($tempZipFilePath, $response.Content)
$response.BaseResponse.Dispose()
$tempUnzipFolderPath = "$([System.IO.Path]::GetTempPath())/$([System.IO.Path]::GetRandomFileName())"
Expand-Archive -Path $tempZipFilePath -DestinationPath $tempUnzipFolderPath
$tempZipFilePath | Remove-Item
Move-Item "$tempUnzipFolderPath\lib\net46\Microsoft.SqlServer.TransactSql.ScriptDom.dll" "$scriptDomAssemblyPath"
$tempUnzipFolderPath | Remove-Item -Recurse
}
Add-Type -Path $scriptDomAssemblyPath
# script to be parsed
$scriptText = #"
Select SalesOrderID,LineTotal [LineTotal],
(Select AVG(LineTotal) from Sales.SalesOrderDetail) as [AverageLineTotal]
from Sales.SalesOrderDetail
"#
#parse script
$parser = New-Object Microsoft.SqlServer.TransactSql.ScriptDom.TSql150Parser($true)
$parseErrors = New-Object System.Collections.Generic.List[Microsoft.SqlServer.TransactSql.ScriptDom.ParseError]
$scriptReader = New-Object System.IO.StringReader($scriptText)
$script = $parser.Parse($scriptReader, [ref]$parseErrors)
if($parseErrors.Count -gt 0) {
throw "$($parseErrors.Count) parsing errors"
}
# sanity check for expected SELECT query
if(($script.Batches.Count -ne 1) -or ($script.Batches[0].Statements.Count -ne 1) -or ($script.Batches[0].Statements[0].QueryExpression -eq $null)) {
throw "script with single SELECT statement expected"
}
# find scalar subquery expression in select list
$subQueryFound = $false
foreach($selectElement in $script.Batches[0].Statements[0].QueryExpression.SelectElements) {
if($selectElement.Expression.ToString() -eq "Microsoft.SqlServer.TransactSql.ScriptDom.ScalarSubquery") {
$subQueryFound = $true
break
}
}
# show if subquery was used
if($subQueryFound) {
Write-Host "A subquery is used"
}
else {
Write-Host "A subquery is not used"
}

finding duplicate rows in excel and export those rows to another sheet using power shell

How to find duplicate values in Excel and export rows to another sheet using power shell?
I had an Excel sheet with multiple rows and column lets say from "A" to "k". I need to find duplicate rows only if values in all the columns in a row are unique. And the script should ignore D,E,F columns even though those column's values are same.
The script should also copy all those duplicate rows and should paste in a new excel file.it should also copy header row and source of duplicate rows and Also attaching a sample image of input file(the output file should also be same as input in this input case because it should also copy source duplicate rows). I had tried a code but it is throwing an error..please look into that and give me a solution for the code.
code:
# The Text OleDB driver is only available in PowerShell x86. Start x86
shell if using x64.
# This has to be the first check this script performs.
if ($env:Processor_Architecture -ne "x86") {
Write-Warning "Switching to x86 shell"
&"$env:windir\syswow64\windowspowershell\v1.0\powershell.exe"
"$PSCommandPath $args"; return
}
# Change to your CSV file name, must end in .csv or .tsv
$csvfile = "C:\files\A01modcsv.csv"
# Does the first row contain column names?
$firstRowColumns = $True
# What's the delimiter? Use `t for tabbed.
$csvdelimter = "`t"
$firstRowColumns = $true
$checkColumns = "A"
$datasource = Split-Path $csvfile
$tablename = (Split-Path $csvfile -leaf).Replace(".","#")
switch ($firstRowColumns) {
$true { $firstRowColumns = "Yes" }
$false { $firstRowColumns = "No" }
}
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
[void][Reflection.Assembly]::LoadWithPartialName("System.Data")
# Setup OleDB using Microsoft Text Driver.
$connstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=$datasource;Extended Properties='text;HDR=$firstRowColumns;FMT=Delimited($csvdelimter)';"
$conn = New-Object System.Data.OleDb.OleDbconnection
$conn.ConnectionString = $connstring
$conn.Open()
$cmd = New-Object System.Data.OleDB.OleDBCommand
$cmd.Connection = $conn
# Perform select on CSV file, then add results to a datatable using ExecuteReader
$sql = "SELECT $checkColumns, COUNT(*) as DupeCount FROM [$tablename] GROUP BY $checkColumns HAVING COUNT(*) > 1"
$cmd.CommandText = $sql
$dt = New-Object System.Data.DataTable
$dt.BeginLoadData()
$dt.Load($cmd.ExecuteReader([System.Data.CommandBehaviour]::CloseConnection))
$dt.EndLoadData()
$totaltime = [math]::Round($elapsed.Elapsed.TotalSeconds,2)
# Get Total Row Count
$cmd.CommandText = "SELECT COUNT(*) as TotalRows FROM [$tablename]"
$totalrows = $cmd.ExecuteScalar()
$conn.Close()[enter image description here][1]
# Output some stats
$dupecount = $dt.Rows.Count
Write-Host "Total Elapsed Time: $totaltime seconds. $dupecount duplicates found out of $totalrows total rows. You can access these dupes using `$dt." -ForegroundColor Green
I am getting an error in the menctioned code at "$dt.Load($cmd.ExecuteReader([System.Data.CommandBehaviour]::CloseConnection))" command....can any help me in solving this error.Thank you.

How to execute multi-line powershell command

Trying to execute a PowerShell command in asp.net c# but it returns no results, where am I going wrong?
var shell = PowerShell.Create();
var script = $#"$Groups = Get-ADGroup {groupname}; $members = ForEach ($Group in $Groups) {{Get-AdGroupMember -Identity $Group -Recursive}} ; $members | Get-AdUser -Properties Department | Select-Object Name, Department | Sort Department, Name";
shell.Commands.AddScript(script);
var results = shell.Invoke();
foreach (var psObject in results)
{
dt.Rows.Add(new object[] { psObject.Members["Name"].Value, psObject.Members["Department"].Value });
}
Gridview2.DataSource = dt;
Gridview2.DataBind();
It executes perfectly in PowerShell. Separating the command over lines as per suggested answer does not work.
Edit - I took another look at my powershell and realised that it was unecessarily complicated. I changed it to the below and it now works. Still does not explain why something that returns results in powershell does not work when ran from asp.net.
Get-AdGroupMember -Identity {groupname} -Recursive | Get-AdUser -Properties Department | Select-Object Name, Department | Sort Department, Name

Export DataTable to Excel using PowerShell

I have a function to create System.Data.Datatables from a simple input of TableName and ColumnName-Array. After filling the tables I want to add them to a dataset and export this one into an excel document.
The code below does that, however in the export to excel there is one bit that I find a bit unelegant. Every table will have to be exported into a csv and then reimported to excel.
Is there a better cleaner way to use DataTables directly in Excel?
Function MakeTable ($TableName, $ColumnArray)
{
$btab = New-Object System.Data.DataTable("$TableName")
foreach($Col in $ColumnArray)
{
$MCol = New-Object System.Data.DataColumn $Col;
$btab.Columns.Add($MCol)
}
return , $btab
}
function DataSetToExcel ($Ds, $workdirectory)
{
$excel = New-Object -ComObject excel.application
$workbook = $excel.Workbooks.Add(1)
$i = 0
for($DsIndex=0;$DsIndex -lt $ds.Tables.Count;$DsIndex++)
{
$Table = $ds.tables[$Dsindex]
if($Dsindex -ne 0)
{
$workbook.worksheets.Add() | Out-Null #Erstellt neues Arbeitsblatt
}
$Table | Export-Csv "$workdirectory\input.csv" -Encoding UTF8 -NoTypeInformation -Force -Delimiter ";"
$inputCSV = "C:\Temp\Test\input.csv"
$worksheet = $workbook.worksheets.Item(1)
$worksheet.Name = $Table.TableName
$TxtConnector = ("TEXT;" + $inputCSV)
$Connector = $worksheet.QueryTables.add($TxtConnector,$worksheet.Range("A1"))
$query = $worksheet.QueryTables.item($Connector.name)
$query.TextFileOtherDelimiter = $Excel.Application.International(5)
$query.TextFileParseType = 1
$query.AdjustColumnWidth = 1
$query.Refresh() | Out-Null
$query.Delete()
}
$outputXLSX = "$workdirectory\output.xlsx"
$Workbook.SaveAs($outputXLSX,51)
$excel.Quit()
}
function MakeTestTable ($TableName)
{
$TestTable = MakeTable $TableName #("A","B")
for($i=0;$i -lt 10; $i++)
{
$aRow = $TestTable.NewRow()
$aRow["A"] = (10-$i).ToString()
$aRow["B"] = $i.ToString()
$TestTable.Rows.Add($aRow)
}
return , $TestTable
}
$db = New-Object System.Data.DataSet
for($cx=0;$cx -lt 10;$cx++)
{
$tab1 = MakeTestTable "$cx"
$db.Tables.Add($tab1)
}
DataSetToExcel $db "C:\Temp\Test"
Check out my PowerShell Excel Module on Github. You can also grab it from the PowerShell Gallery.
It also works directly with CSV format using Import-Csv or ConvertFrom-Csv (basically any PowerShell object array).
function New-Person {
param($First,$Last)
$row=$dataTable.NewRow()
$row["First"]=$First
$row["Last"]=$Last
$dataTable.Rows.Add($row)
}
$dataTable = New-Object System.Data.DataTable("Test")
$dataTable.Columns.Add((New-Object System.Data.DataColumn "First"))
$dataTable.Columns.Add((New-Object System.Data.DataColumn "Last"))
New-Person John Doe
New-Person Tom Doe
New-Person Jane Doe
New-Person Mary Doe
$dataTable |
Select First, Last |
Export-Excel c:\temp\people.xlsx -AutoSize -Show
Since you tagged this with C#, If you have excel on the computer this will be run on, you can use the interop library. I used it for a project I did, using code I found in this SO question.

How to get a driver list in Windows?

What is the best way to create a list of all locally installed drivers with C# and the .net Framework?
It should work for Vista based Windows versions.
The list should contain:
Name of the driver
Version of the driver
Location of the driver on the HDD.
Any suggestions / help is appreciated.
Till now I have found a wmi query: that points to the right direction.
Win32_PnPSignedDriver class
("Select * from Win32_PnPSignedDriver")
This should get you started:
SelectQuery query = new System.Management.SelectQuery(
"select name, pathname from Win32_Service");
using (ManagementObjectSearcher searcher =
new System.Management.ManagementObjectSearcher(query))
{
foreach (ManagementObject service in searcher.Get())
{
Console.WriteLine(string.Format(
"Name: {0}\tPath : {1}", service["Name"], service["pathname"]));
}
}
To get a list of drivers use the powershell script:
Get-WmiObject -Class "Win32_PnPSignedDriver" | Select Caption, Description, DeviceID, DeviceClass, DriverVersion, DriverDate, DriverProviderName, InfName
To get a list of driver paths use the powershell script:
Get-WmiObject -Class "Win32_PnPSignedDriverCIMDataFile" | Select Dependent| foreach {
$y = $_ -match '(?<=")(.*?)(?=")'
$Matches[0]
}
At the moment i am just not sure if there are other drivers that this query doesn't match.
To use Powershell in C# use: System.Management.Automation

Categories